From fa6850050b2b49d971177551090dfd2bb0a1f984 Mon Sep 17 00:00:00 2001 From: "paseo-bot[bot]" <266920839+paseo-bot[bot]@users.noreply.github.com> Date: Fri, 6 Nov 2026 14:02:32 +0000 Subject: [PATCH] test(server): exercise current daemon creation and permission contracts The workspace resume regression shares this suite with creation checks that still waited for legacy status frames and permission listeners without an owned subscription. Verify the returned error snapshot and acquire event demand so the complete suite can validate workspace identity changes. Co-authored-by: Darrell --- .../src/server/daemon-client.e2e.test.ts | 74 +++++-------------- 1 file changed, 19 insertions(+), 55 deletions(-) diff --git a/packages/server/src/server/daemon-client.e2e.test.ts b/packages/server/src/server/daemon-client.e2e.test.ts index 701a7f6108..55aa4537c1 100644 --- a/packages/server/src/server/daemon-client.e2e.test.ts +++ b/packages/server/src/server/daemon-client.e2e.test.ts @@ -406,7 +406,7 @@ class RejectingMcpResumeClient implements AgentClient { } } -test("createAgent fails when the initial turn cannot start", async () => { +test("createAgent preserves the error snapshot when the initial turn cannot start", async () => { const testAgent = new StubAgentClient({ sessionId: "start-turn-failure-session", supportsStreaming: false, @@ -425,16 +425,18 @@ test("createAgent fails when the initial turn cannot start", async () => { await client.connect(); await client.fetchAgents({ subscribe: {} }); - await expect( - client.createAgent({ - provider: "codex", - cwd: tmpCwd(), - title: "Start failure agent", - modeId: "full-access", - model: "gpt-5.4-mini", - initialPrompt: "Run exactly: sleep 30", - }), - ).rejects.toThrow("Initial turn failed to start"); + const created = await client.createAgent({ + provider: "codex", + cwd: tmpCwd(), + title: "Start failure agent", + modeId: "full-access", + model: "gpt-5.4-mini", + initialPrompt: "Run exactly: sleep 30", + }); + expect(created.status).toBe("error"); + expect(created.lastError).toBe("Initial turn failed to start"); + const fetched = await client.fetchAgent({ agentId: created.id }); + expect(fetched?.agent.lastError).toBe("Initial turn failed to start"); } finally { await client.close(); await daemon.close(); @@ -1405,27 +1407,6 @@ test("creates agent and exercises lifecycle", async () => { }); const createRequestId = `create-${Date.now()}`; - const createdStatusPromise = waitForSignal(15000, (resolve) => { - const unsubscribe = ctx.client.on("status", (message) => { - if (message.type !== "status") { - return; - } - const payload = message.payload as { - status?: string; - agentId?: string; - requestId?: string; - }; - if (payload.status !== "agent_created") { - return; - } - if (payload.requestId !== createRequestId) { - return; - } - resolve(message); - }); - return unsubscribe; - }); - const agent = await ctx.client.createAgent({ ...getFullAccessConfig("codex"), cwd, @@ -1440,30 +1421,8 @@ test("creates agent and exercises lifecycle", async () => { const agentUpdate = await agentUpdatePromise; expect(agentUpdate.payload.agent.id).toBe(agent.id); - const createdStatus = await createdStatusPromise; - expect((createdStatus.payload as { agentId?: string }).agentId).toBe(agent.id); const failRequestId = `fail-${Date.now()}`; - const failedStatusPromise = waitForSignal(15000, (resolve) => { - const unsubscribe = ctx.client.on("status", (message) => { - if (message.type !== "status") { - return; - } - const payload = message.payload as { - status?: string; - requestId?: string; - }; - if (payload.status !== "agent_create_failed") { - return; - } - if (payload.requestId !== failRequestId) { - return; - } - resolve(message); - }); - return unsubscribe; - }); - await expect( ctx.client.createAgent({ ...getFullAccessConfig("codex"), @@ -1472,7 +1431,6 @@ test("creates agent and exercises lifecycle", async () => { requestId: failRequestId, }), ).rejects.toThrow("Working directory does not exist"); - await failedStatusPromise; let sawRefresh = false; const unsubscribe = ctx.client.subscribe((event) => { @@ -1651,6 +1609,11 @@ test("creates agent and exercises lifecycle", async () => { }, 300000); test("handles permission flow", async () => { + const permissionEvents = ctx.client.observeEvents([ + "agent_permission_request", + "agent_permission_resolved", + ]); + await permissionEvents.ready; const cwd = tmpCwd(); const filePath = path.join(cwd, "permission.txt"); @@ -1719,6 +1682,7 @@ test("handles permission flow", async () => { // Prevent unhandled rejections if the test fails before promises resolve. await permissionRequestPromise.catch(() => {}); await permissionResolvedPromise.catch(() => {}); + await permissionEvents.release(); await ctx.client.deleteAgent(agent.id); rmSync(cwd, { recursive: true, force: true }); }