fix: avoid claude-cli session id collisions

This commit is contained in:
Peter Steinberger
2026-01-09 04:20:58 +00:00
parent 64fc5fa9fc
commit ef1ce5d9a8
2 changed files with 69 additions and 6 deletions

View File

@@ -0,0 +1,68 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { runClaudeCliAgent } from "./claude-cli-runner.js";
const runCommandWithTimeoutMock = vi.fn();
vi.mock("../process/exec.js", () => ({
runCommandWithTimeout: (...args: unknown[]) => runCommandWithTimeoutMock(...args),
}));
describe("runClaudeCliAgent", () => {
beforeEach(() => {
runCommandWithTimeoutMock.mockReset();
});
it("starts a new session without --session-id when no resume id", async () => {
runCommandWithTimeoutMock.mockResolvedValueOnce({
stdout: JSON.stringify({ message: "ok", session_id: "sid-1" }),
stderr: "",
code: 0,
signal: null,
killed: false,
});
await runClaudeCliAgent({
sessionId: "clawdbot-session",
sessionFile: "/tmp/session.jsonl",
workspaceDir: "/tmp",
prompt: "hi",
model: "opus",
timeoutMs: 1_000,
runId: "run-1",
});
expect(runCommandWithTimeoutMock).toHaveBeenCalledTimes(1);
const argv = runCommandWithTimeoutMock.mock.calls[0]?.[0] as string[];
expect(argv).toContain("claude");
expect(argv).not.toContain("--session-id");
expect(argv).not.toContain("--resume");
});
it("uses --resume when a resume session id is provided", async () => {
runCommandWithTimeoutMock.mockResolvedValueOnce({
stdout: JSON.stringify({ message: "ok", session_id: "sid-2" }),
stderr: "",
code: 0,
signal: null,
killed: false,
});
await runClaudeCliAgent({
sessionId: "clawdbot-session",
sessionFile: "/tmp/session.jsonl",
workspaceDir: "/tmp",
prompt: "hi",
model: "opus",
timeoutMs: 1_000,
runId: "run-2",
resumeSessionId: "sid-1",
});
expect(runCommandWithTimeoutMock).toHaveBeenCalledTimes(1);
const argv = runCommandWithTimeoutMock.mock.calls[0]?.[0] as string[];
expect(argv).toContain("--resume");
expect(argv).toContain("sid-1");
expect(argv).not.toContain("--session-id");
});
});

View File

@@ -208,7 +208,6 @@ async function runClaudeCliOnce(params: {
systemPrompt: string;
timeoutMs: number;
resumeSessionId?: string;
sessionId?: string;
}): Promise<ClaudeCliOutput> {
const args = [
"-p",
@@ -226,8 +225,6 @@ async function runClaudeCliOnce(params: {
];
if (params.resumeSessionId) {
args.push("--resume", params.resumeSessionId);
} else if (params.sessionId) {
args.push("--session-id", params.sessionId);
}
args.push(params.prompt);
@@ -297,12 +294,11 @@ export async function runClaudeCliAgent(params: {
systemPrompt,
timeoutMs: params.timeoutMs,
resumeSessionId: params.resumeSessionId,
sessionId: params.sessionId,
});
} catch (err) {
if (!params.resumeSessionId) throw err;
log.warn(
`claude-cli resume failed for ${params.resumeSessionId}; retrying with --session-id (${params.sessionId})`,
`claude-cli resume failed for ${params.resumeSessionId}; retrying without resume`,
);
output = await runClaudeCliOnce({
prompt: params.prompt,
@@ -310,7 +306,6 @@ export async function runClaudeCliAgent(params: {
modelId,
systemPrompt,
timeoutMs: params.timeoutMs,
sessionId: params.sessionId,
});
}