diff --git a/packages/core/src/__tests__/lifecycle-manager.test.ts b/packages/core/src/__tests__/lifecycle-manager.test.ts index 5fc9c0e76..bd7cf5985 100644 --- a/packages/core/src/__tests__/lifecycle-manager.test.ts +++ b/packages/core/src/__tests__/lifecycle-manager.test.ts @@ -227,7 +227,7 @@ describe("check (single session)", () => { expect(lm.getStates().get("app-1")).toBe("killed"); }); - it("detects killed state when agent process exits (idle terminal + dead process)", async () => { + it("detects killed state when getActivityState returns exited", async () => { vi.mocked(mockAgent.getActivityState).mockResolvedValue({ state: "exited" }); const session = makeSession({ status: "working" }); @@ -251,8 +251,10 @@ describe("check (single session)", () => { expect(lm.getStates().get("app-1")).toBe("killed"); }); - it("detects killed state when agent process exits (active terminal + dead process)", async () => { - vi.mocked(mockAgent.getActivityState).mockResolvedValue({ state: "exited" }); + it("detects killed via terminal fallback when getActivityState returns null", async () => { + vi.mocked(mockAgent.getActivityState).mockResolvedValue(null); + vi.mocked(mockAgent.detectActivity).mockReturnValue("idle"); + vi.mocked(mockAgent.isProcessRunning).mockResolvedValue(false); const session = makeSession({ status: "working" }); vi.mocked(mockSessionManager.get).mockResolvedValue(session); @@ -275,7 +277,8 @@ describe("check (single session)", () => { expect(lm.getStates().get("app-1")).toBe("killed"); }); - it("stays working when agent is idle but process is still running", async () => { + it("stays working when agent is idle but process is still running (fallback path)", async () => { + vi.mocked(mockAgent.getActivityState).mockResolvedValue(null); vi.mocked(mockAgent.detectActivity).mockReturnValue("idle"); vi.mocked(mockAgent.isProcessRunning).mockResolvedValue(true); diff --git a/packages/core/src/lifecycle-manager.ts b/packages/core/src/lifecycle-manager.ts index 264d07954..663fd7488 100644 --- a/packages/core/src/lifecycle-manager.ts +++ b/packages/core/src/lifecycle-manager.ts @@ -200,7 +200,7 @@ export function createLifecycleManager(deps: LifecycleManagerDeps): LifecycleMan if (agent && session.runtimeHandle) { try { // Try JSONL-based activity detection first (reads agent's session files directly) - const activityState = await agent.getActivityState(session); + const activityState = await agent.getActivityState(session, config.readyThresholdMs); if (activityState) { if (activityState.state === "waiting_input") return "needs_input"; if (activityState.state === "exited") return "killed";