From 263e3a31f82a11f90d1b640429b9c4e19e1ed073 Mon Sep 17 00:00:00 2001 From: cynarAI <155274210+cynarAI@users.noreply.github.com> Date: Tue, 20 Oct 2026 09:34:40 +0200 Subject: [PATCH] Fix red main: mobile group kind, i18n catalogs, project picker check (#218) * Fix red main: mobile group kind, i18n catalogs, project picker check Main CI failed on typecheck, unit tests and web E2E after the last two direct pushes. MobileGroup now carries the optional chat kind the mobile screens read, the Lingui catalogs are re-extracted with German strings for the new voice texts, the project overview plus icon meets the UI scale guard, and the sidebar E2E expects the renamed project lead. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01R8L4XgqjAemFR2remB5hVY * Format files merged from main Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01Wy1md9QE1ayJbDCwJ4vAQs * Align E2E with the canvas close button and per-chat drafts The in-app browser now closes from the side panel header, and each chat keeps its own unsent draft. The group chat test waits for the settings save to land before switching chats, so the switch no longer races the panel closing. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01Wy1md9QE1ayJbDCwJ4vAQs --------- Co-authored-by: Claude --- apps/api/src/thread-target.test.ts | 5 +---- apps/api/src/thread-target.ts | 4 +--- apps/mobile/app/thread.tsx | 4 +--- apps/web/e2e/group-chats.spec.ts | 10 +++++++++- apps/web/e2e/in-app-browser.spec.ts | 4 ++-- apps/web/e2e/unterhaltungen-sidebar.spec.ts | 4 ++-- apps/web/src/pages/shell/project-overview.tsx | 2 +- packages/contracts/src/rpc.ts | 14 ++++++-------- 8 files changed, 23 insertions(+), 24 deletions(-) diff --git a/apps/api/src/thread-target.test.ts b/apps/api/src/thread-target.test.ts index c7d6b7c..326848a 100644 --- a/apps/api/src/thread-target.test.ts +++ b/apps/api/src/thread-target.test.ts @@ -2144,9 +2144,7 @@ describe("stopThreadRuns", () => { updateMany: vi.fn().mockResolvedValue({ count: 1 }), }, run: { - updateManyAndReturn: vi - .fn() - .mockResolvedValue([{ id: "run-old", taskId: "task-old" }]), + updateManyAndReturn: vi.fn().mockResolvedValue([{ id: "run-old", taskId: "task-old" }]), create: vi.fn().mockResolvedValue({ id: "run-new", status: "queued" }), }, task: { @@ -2230,4 +2228,3 @@ describe("stopThreadRuns", () => { expect(events.notify).toHaveBeenCalledWith("thread-1", 42); }); }); - diff --git a/apps/api/src/thread-target.ts b/apps/api/src/thread-target.ts index 326fa1d..1efc9d4 100644 --- a/apps/api/src/thread-target.ts +++ b/apps/api/src/thread-target.ts @@ -1424,9 +1424,7 @@ export async function sendQueuedThreadMessagesNow( status: "queued", }, }); - const runCreatedAt = new Date( - Math.max(Date.now(), last.message.createdAt.getTime() + 1), - ); + const runCreatedAt = new Date(Math.max(Date.now(), last.message.createdAt.getTime() + 1)); const run = await tx.run.create({ data: { spaceId: actor.spaceId, diff --git a/apps/mobile/app/thread.tsx b/apps/mobile/app/thread.tsx index 511c88d..c4e2f5a 100644 --- a/apps/mobile/app/thread.tsx +++ b/apps/mobile/app/thread.tsx @@ -1660,9 +1660,7 @@ function Thread() { marginTop: 4, }} > - - {t("Queued")} - + {t("Queued")} (await calls()).at(-1)?.[0]).toBe("show"); - await browser.getByRole("button", { name: "Close panel" }).click(); + await page.getByTestId("side-panel").getByRole("button", { name: "Close panel" }).click(); await expect.poll(async () => (await calls()).at(-1)?.[0]).toBe("hide"); }); diff --git a/apps/web/e2e/unterhaltungen-sidebar.spec.ts b/apps/web/e2e/unterhaltungen-sidebar.spec.ts index a4154d0..e9e7a59 100644 --- a/apps/web/e2e/unterhaltungen-sidebar.spec.ts +++ b/apps/web/e2e/unterhaltungen-sidebar.spec.ts @@ -47,14 +47,14 @@ test("conversations and projects stay separate; + opens bot picker", async ({ pa await expect(projekte.getByText("Side project", { exact: true })).toBeVisible(); await expect(unterhaltungenOnly(page).getByText("Side project", { exact: true })).toHaveCount(0); - // The main agent leads the picker, even after other bots exist. + // The new project's main agent leads the picker, even after other bots exist. await unterhaltungen.getByTestId("conversation-picker-trigger").click(); await expect( page .getByTestId("conversation-bot-picker") .locator("[data-testid^='conversation-picker-bot-']") .first(), - ).toHaveText("Chief"); + ).toHaveText("Projektmanager"); await page.keyboard.press("Escape"); // Creating a project that already exists opens it instead of listing it twice. diff --git a/apps/web/src/pages/shell/project-overview.tsx b/apps/web/src/pages/shell/project-overview.tsx index 611c81f..2683491 100644 --- a/apps/web/src/pages/shell/project-overview.tsx +++ b/apps/web/src/pages/shell/project-overview.tsx @@ -466,7 +466,7 @@ export function AgentOverview({ onClick={onAddRoutine} className="gap-1 text-ui-label" > - + Routine ) : null} diff --git a/packages/contracts/src/rpc.ts b/packages/contracts/src/rpc.ts index 34302e1..e9cd17b 100644 --- a/packages/contracts/src/rpc.ts +++ b/packages/contracts/src/rpc.ts @@ -509,14 +509,12 @@ export const appContract = { ) .output(z.object({ ok: z.literal(true) })), stop: oc.input(threadTarget).output(z.object({ ok: z.literal(true) })), - sendNow: oc - .input(threadTarget.safeExtend({ messageId: Id.optional() })) - .output( - z.object({ - ok: z.literal(true), - runIds: z.array(Id), - }), - ), + sendNow: oc.input(threadTarget.safeExtend({ messageId: Id.optional() })).output( + z.object({ + ok: z.literal(true), + runIds: z.array(Id), + }), + ), followUp: oc .input(threadTarget.safeExtend({ text: z.string().min(1) })) .output(z.object({ ok: z.literal(true) })),