diff --git a/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts b/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts index 7ef6809af6ba92f3198e751a8a569e2e00781a97..7910dbdcd2d678e9a5e2f0edd15f571854ea1a2f 100644 --- a/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts +++ b/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts @@ -57,7 +57,7 @@ function createProviderServiceHarness( cwd: string, hasSession = true, sessionCwd = cwd, - providerName: "codex" | "claudeCode" = "codex", + providerName: ProviderSession["provider"] = "codex", ) { const now = new Date().toISOString(); const runtimeEventPubSub = Effect.runSync(PubSub.unbounded()); @@ -235,7 +235,6 @@ describe("CheckpointReactor", () => { readonly projectWorkspaceRoot?: string; readonly threadWorktreePath?: string | null; readonly providerSessionCwd?: string; - readonly providerName?: "codex" | "claudeCode"; }) { const cwd = createGitRepository(); tempDirs.push(cwd); @@ -243,7 +242,7 @@ describe("CheckpointReactor", () => { cwd, options?.hasSession ?? true, options?.providerSessionCwd ?? cwd, - options?.providerName ?? "codex", + "codex", ); const orchestrationLayer = OrchestrationEngineLive.pipe( Layer.provide(OrchestrationProjectionPipelineLive), @@ -476,69 +475,6 @@ describe("CheckpointReactor", () => { expect(thread.checkpoints[0]?.checkpointTurnCount).toBe(1); }); - it("captures pre-turn and completion checkpoints for claudeCode runtime events", async () => { - const harness = await createHarness({ - seedFilesystemCheckpoints: false, - providerName: "claudeCode", - }); - const createdAt = new Date().toISOString(); - - await Effect.runPromise( - harness.engine.dispatch({ - type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-capture-claude"), - threadId: ThreadId.makeUnsafe("thread-1"), - session: { - threadId: ThreadId.makeUnsafe("thread-1"), - status: "ready", - providerName: "claudeCode", - runtimeMode: "approval-required", - activeTurnId: null, - lastError: null, - updatedAt: createdAt, - }, - createdAt, - }), - ); - - harness.provider.emit({ - type: "turn.started", - eventId: EventId.makeUnsafe("evt-turn-started-claude-1"), - provider: "claudeCode", - - createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), - turnId: asTurnId("turn-claude-1"), - }); - await waitForGitRefExists( - harness.cwd, - checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0), - ); - - fs.writeFileSync(path.join(harness.cwd, "README.md"), "v2\n", "utf8"); - harness.provider.emit({ - type: "turn.completed", - eventId: EventId.makeUnsafe("evt-turn-completed-claude-1"), - provider: "claudeCode", - - createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), - turnId: asTurnId("turn-claude-1"), - payload: { state: "completed" }, - }); - - await waitForEvent(harness.engine, (event) => event.type === "thread.turn-diff-completed"); - const thread = await waitForThread( - harness.engine, - (entry) => entry.latestTurn?.turnId === "turn-claude-1" && entry.checkpoints.length === 1, - ); - - expect(thread.checkpoints[0]?.checkpointTurnCount).toBe(1); - expect( - gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1)), - ).toBe(true); - }); - it("appends capture failure activity when turn diff summary cannot be derived", async () => { const harness = await createHarness({ seedFilesystemCheckpoints: false }); const createdAt = new Date().toISOString(); @@ -845,7 +781,7 @@ describe("CheckpointReactor", () => { expect(thread.checkpoints[0]?.checkpointTurnCount).toBe(1); expect(harness.provider.rollbackConversation).toHaveBeenCalledTimes(1); expect(harness.provider.rollbackConversation).toHaveBeenCalledWith({ - + threadId: ThreadId.makeUnsafe("thread-1"), numTurns: 1, }); expect(fs.readFileSync(path.join(harness.cwd, "README.md"), "utf8")).toBe("v2\n"); @@ -854,75 +790,6 @@ describe("CheckpointReactor", () => { ).toBe(false); }); - it("executes provider revert and emits thread.reverted for claudeCode sessions", async () => { - const harness = await createHarness({ providerName: "claudeCode" }); - const createdAt = new Date().toISOString(); - - await Effect.runPromise( - harness.engine.dispatch({ - type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-claude"), - threadId: ThreadId.makeUnsafe("thread-1"), - session: { - threadId: ThreadId.makeUnsafe("thread-1"), - status: "ready", - providerName: "claudeCode", - runtimeMode: "approval-required", - activeTurnId: null, - lastError: null, - updatedAt: createdAt, - }, - createdAt, - }), - ); - - await Effect.runPromise( - harness.engine.dispatch({ - type: "thread.turn.diff.complete", - commandId: CommandId.makeUnsafe("cmd-diff-claude-1"), - threadId: ThreadId.makeUnsafe("thread-1"), - turnId: asTurnId("turn-claude-1"), - completedAt: createdAt, - checkpointRef: checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1), - status: "ready", - files: [], - checkpointTurnCount: 1, - createdAt, - }), - ); - await Effect.runPromise( - harness.engine.dispatch({ - type: "thread.turn.diff.complete", - commandId: CommandId.makeUnsafe("cmd-diff-claude-2"), - threadId: ThreadId.makeUnsafe("thread-1"), - turnId: asTurnId("turn-claude-2"), - completedAt: createdAt, - checkpointRef: checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 2), - status: "ready", - files: [], - checkpointTurnCount: 2, - createdAt, - }), - ); - - await Effect.runPromise( - harness.engine.dispatch({ - type: "thread.checkpoint.revert", - commandId: CommandId.makeUnsafe("cmd-revert-request-claude"), - threadId: ThreadId.makeUnsafe("thread-1"), - turnCount: 1, - createdAt, - }), - ); - - await waitForEvent(harness.engine, (event) => event.type === "thread.reverted"); - expect(harness.provider.rollbackConversation).toHaveBeenCalledTimes(1); - expect(harness.provider.rollbackConversation).toHaveBeenCalledWith({ - - numTurns: 1, - }); - }); - it("processes consecutive revert requests with deterministic rollback sequencing", async () => { const harness = await createHarness(); const createdAt = new Date().toISOString(); @@ -1008,11 +875,11 @@ describe("CheckpointReactor", () => { expect(harness.provider.rollbackConversation).toHaveBeenCalledTimes(2); expect(harness.provider.rollbackConversation.mock.calls[0]?.[0]).toEqual({ - + threadId: ThreadId.makeUnsafe("thread-1"), numTurns: 1, }); expect(harness.provider.rollbackConversation.mock.calls[1]?.[0]).toEqual({ - + threadId: ThreadId.makeUnsafe("thread-1"), numTurns: 1, }); }); diff --git a/apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts b/apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts index 0531c1c8b149dba585e2bc9e43fd5454774180d4..6e4e824f3968d1ab19b5c1ae03b9d7c6beeee3c1 100644 --- a/apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts +++ b/apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts @@ -102,6 +102,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => { projectId: ProjectId.makeUnsafe("project-1"), title: "Thread 1", model: "gpt-5-codex", + runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: now, @@ -372,6 +373,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => { projectId: ProjectId.makeUnsafe("project-clear-attachments"), title: "Thread Clear Attachments", model: "gpt-5-codex", + runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: now, @@ -498,6 +500,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => { projectId: ProjectId.makeUnsafe("project-overwrite"), title: "Thread Overwrite", model: "gpt-5-codex", + runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: now, @@ -648,6 +651,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => { projectId: ProjectId.makeUnsafe("project-rollback"), title: "Thread Rollback", model: "gpt-5-codex", + runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: now, @@ -778,6 +782,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => { projectId: ProjectId.makeUnsafe("project-revert-files"), title: "Thread Revert Files", model: "gpt-5-codex", + runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: now, @@ -992,6 +997,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => { projectId: ProjectId.makeUnsafe("project-delete-files"), title: "Thread Delete Files", model: "gpt-5-codex", + runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: now, @@ -1154,6 +1160,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => { projectId: ProjectId.makeUnsafe("project-a"), title: "Thread A", model: "gpt-5-codex", + runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: now, @@ -1277,6 +1284,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => { projectId: ProjectId.makeUnsafe("project-empty"), title: "Thread Empty", model: "gpt-5-codex", + runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: now, @@ -1413,6 +1421,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => { projectId: ProjectId.makeUnsafe("project-conflict"), title: "Thread Conflict", model: "gpt-5-codex", + runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: "2026-02-26T13:00:01.000Z", @@ -1553,6 +1562,7 @@ projectionLayer("OrchestrationProjectionPipeline", (it) => { projectId: ProjectId.makeUnsafe("project-revert"), title: "Thread Revert", model: "gpt-5-codex", + runtimeMode: "full-access", branch: null, worktreePath: null, createdAt: "2026-02-26T12:00:01.000Z", diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts index f3b6221f6aa62ec9f3eba8c9ff046a19c49d3a68..67a6aacd753a7ed25e81c4570e195c350a81a2ce 100644 --- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts +++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts @@ -94,7 +94,6 @@ describe("ProviderCommandReactor", () => { input !== null && "provider" in input && (input.provider === "codex" || - input.provider === "claudeCode" || input.provider === "cursor") ? input.provider : "codex"; @@ -385,43 +384,6 @@ describe("ProviderCommandReactor", () => { }); }); - it("starts first turn with requested provider when provider is specified", async () => { - const harness = await createHarness(); - const now = new Date().toISOString(); - - await Effect.runPromise( - harness.engine.dispatch({ - type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-provider-first"), - threadId: ThreadId.makeUnsafe("thread-1"), - message: { - messageId: asMessageId("user-message-provider-first"), - role: "user", - text: "hello claude", - attachments: [], - }, - provider: "claudeCode", - interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, - runtimeMode: "approval-required", - createdAt: now, - }), - ); - - await waitFor(() => harness.startSession.mock.calls.length === 1); - await waitFor(() => harness.sendTurn.mock.calls.length === 1); - expect(harness.startSession.mock.calls[0]?.[1]).toMatchObject({ - provider: "claudeCode", - cwd: "/tmp/provider-project", - model: "gpt-5-codex", - runtimeMode: "approval-required", - }); - - const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); - expect(thread?.session?.providerName).toBe("claudeCode"); - expect(thread?.session?.threadId).toBe("thread-1"); - }); - it("starts first turn with cursor provider when provider is specified", async () => { const harness = await createHarness(); const now = new Date().toISOString(); @@ -695,66 +657,6 @@ describe("ProviderCommandReactor", () => { expect(thread?.session?.runtimeMode).toBe("approval-required"); }); - it("switches provider by restarting the session when turn request provider changes", async () => { - const harness = await createHarness(); - const now = new Date().toISOString(); - - await Effect.runPromise( - harness.engine.dispatch({ - type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-provider-switch-1"), - threadId: ThreadId.makeUnsafe("thread-1"), - message: { - messageId: asMessageId("user-message-provider-switch-1"), - role: "user", - text: "first", - attachments: [], - }, - interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, - runtimeMode: "approval-required", - createdAt: now, - }), - ); - - await waitFor(() => harness.startSession.mock.calls.length === 1); - await waitFor(() => harness.sendTurn.mock.calls.length === 1); - - await Effect.runPromise( - harness.engine.dispatch({ - type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-provider-switch-2"), - threadId: ThreadId.makeUnsafe("thread-1"), - message: { - messageId: asMessageId("user-message-provider-switch-2"), - role: "user", - text: "second", - attachments: [], - }, - provider: "claudeCode", - interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, - runtimeMode: "approval-required", - createdAt: now, - }), - ); - - await waitFor(() => harness.startSession.mock.calls.length === 2); - await waitFor(() => harness.sendTurn.mock.calls.length === 2); - - expect(harness.stopSession.mock.calls.length).toBe(0); - expect(harness.startSession.mock.calls[1]?.[1]).toMatchObject({ - threadId: ThreadId.makeUnsafe("thread-1"), - provider: "claudeCode", - runtimeMode: "approval-required", - }); - expect(harness.startSession.mock.calls[1]?.[1]).not.toHaveProperty("resumeCursor"); - - const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); - expect(thread?.session?.threadId).toBe("thread-1"); - expect(thread?.session?.providerName).toBe("claudeCode"); - expect(thread?.session?.runtimeMode).toBe("approval-required"); - }); - it("does not stop the active session when restart fails before rebind", async () => { const harness = await createHarness(); const now = new Date().toISOString(); diff --git a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts index ec42c4ec7a53a797e8a59a6d93b08615e63f4551..1bafe2889107124c0663fc4d573e4bab5a5c78d5 100644 --- a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts +++ b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts @@ -437,60 +437,6 @@ describe("ProviderRuntimeIngestion", () => { ); }); - it("accepts claude turn lifecycle when seeded thread id is a synthetic placeholder", async () => { - const harness = await createHarness(); - const seededAt = new Date().toISOString(); - - await Effect.runPromise( - harness.engine.dispatch({ - type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-seed-claude-placeholder"), - threadId: ThreadId.makeUnsafe("thread-1"), - session: { - threadId: ThreadId.makeUnsafe("thread-1"), - status: "ready", - providerName: "claudeCode", - runtimeMode: "approval-required", - activeTurnId: null, - updatedAt: seededAt, - lastError: null, - }, - createdAt: seededAt, - }), - ); - - harness.emit({ - type: "turn.started", - eventId: asEventId("evt-turn-started-claude-placeholder"), - provider: "claudeCode", - createdAt: new Date().toISOString(), - threadId: asThreadId("thread-1"), - turnId: asTurnId("turn-claude-placeholder"), - }); - - await waitForThread( - harness.engine, - (thread) => - thread.session?.status === "running" && - thread.session?.activeTurnId === "turn-claude-placeholder", - ); - - harness.emit({ - type: "turn.completed", - eventId: asEventId("evt-turn-completed-claude-placeholder"), - provider: "claudeCode", - createdAt: new Date().toISOString(), - threadId: asThreadId("thread-1"), - turnId: asTurnId("turn-claude-placeholder"), - status: "completed", - }); - - await waitForThread( - harness.engine, - (thread) => thread.session?.status === "ready" && thread.session?.activeTurnId === null, - ); - }); - it("ignores non-active turn completion when runtime omits thread id", async () => { const harness = await createHarness(); const now = new Date().toISOString(); diff --git a/apps/server/src/orchestration/projector.test.ts b/apps/server/src/orchestration/projector.test.ts index ee42b48f3f5a43250d53355652a6d280cbaf504e..71f5b6bd4ba9ee0eccc5e093af253c71ae9e23ce 100644 --- a/apps/server/src/orchestration/projector.test.ts +++ b/apps/server/src/orchestration/projector.test.ts @@ -75,6 +75,7 @@ describe("orchestration projector", () => { title: "demo", model: "gpt-5-codex", runtimeMode: "full-access", + interactionMode: "default", branch: null, worktreePath: null, latestTurn: null, @@ -82,6 +83,7 @@ describe("orchestration projector", () => { updatedAt: now, deletedAt: null, messages: [], + proposedPlans: [], activities: [], checkpoints: [], session: null, diff --git a/apps/server/src/provider/Layers/ProviderService.test.ts b/apps/server/src/provider/Layers/ProviderService.test.ts index 505ce88bf41ab00392a9735bfb70d8b205a2b19f..08673c3cbf2d64f8413776d41d0c5363b7f68987 100644 --- a/apps/server/src/provider/Layers/ProviderService.test.ts +++ b/apps/server/src/provider/Layers/ProviderService.test.ts @@ -216,15 +216,12 @@ const sleep = (ms: number) => function makeProviderServiceLayer() { const codex = makeFakeCodexAdapter(); - const claude = makeFakeCodexAdapter("claudeCode"); const registry: typeof ProviderAdapterRegistry.Service = { getByProvider: (provider) => provider === "codex" ? Effect.succeed(codex.adapter) - : provider === "claudeCode" - ? Effect.succeed(claude.adapter) - : Effect.fail(new ProviderUnsupportedError({ provider })), - listProviders: () => Effect.succeed(["codex", "claudeCode"]), + : Effect.fail(new ProviderUnsupportedError({ provider })), + listProviders: () => Effect.succeed(["codex"]), }; const providerAdapterLayer = Layer.succeed(ProviderAdapterRegistry, registry); @@ -247,7 +244,6 @@ function makeProviderServiceLayer() { return { codex, - claude, layer, }; } @@ -496,29 +492,6 @@ routing.layer("ProviderServiceLive routing", (it) => { }), ); - it.effect("routes explicit claudeCode provider session starts to the claude adapter", () => - Effect.gen(function* () { - const provider = yield* ProviderService; - - const session = yield* provider.startSession(asThreadId("thread-claude"), { - provider: "claudeCode", - threadId: asThreadId("thread-claude"), - cwd: "/tmp/project-claude", - runtimeMode: "full-access", - }); - - assert.equal(session.provider, "claudeCode"); - assert.equal(routing.claude.startSession.mock.calls.length, 1); - const startInput = routing.claude.startSession.mock.calls[0]?.[0]; - assert.equal(typeof startInput === "object" && startInput !== null, true); - if (startInput && typeof startInput === "object") { - const startPayload = startInput as { provider?: string; cwd?: string }; - assert.equal(startPayload.provider, "claudeCode"); - assert.equal(startPayload.cwd, "/tmp/project-claude"); - } - }), - ); - it.effect("recovers stale persisted sessions for rollback by resuming thread identity", () => Effect.gen(function* () { const provider = yield* ProviderService;