fix: support Claude stream-json verbose mode
This commit is contained in:
@@ -154,7 +154,7 @@ describe("ClaudeAdapter", () => {
|
|||||||
beforeEach(() => { tmpDir = makeTmpDir(); });
|
beforeEach(() => { tmpDir = makeTmpDir(); });
|
||||||
afterEach(() => { cleanupDir(tmpDir); });
|
afterEach(() => { cleanupDir(tmpDir); });
|
||||||
|
|
||||||
it("start includes --session-id and -p flags", async () => {
|
it("start includes --session-id, -p, --verbose, and --output-format flags", async () => {
|
||||||
const argsFile = path.join(tmpDir, "args.txt");
|
const argsFile = path.join(tmpDir, "args.txt");
|
||||||
const fakeBin = writeFakeCli(tmpDir, {
|
const fakeBin = writeFakeCli(tmpDir, {
|
||||||
argsFile,
|
argsFile,
|
||||||
@@ -170,10 +170,17 @@ describe("ClaudeAdapter", () => {
|
|||||||
config: { binary: fakeBin },
|
config: { binary: fakeBin },
|
||||||
});
|
});
|
||||||
|
|
||||||
const capturedArgs = fs.existsSync(argsFile) ? fs.readFileSync(argsFile, "utf8") : "";
|
const capturedArgs = fs.existsSync(argsFile)
|
||||||
|
? fs.readFileSync(argsFile, "utf8").split("\0").filter(Boolean)
|
||||||
|
: [];
|
||||||
expect(capturedArgs).toContain("-p");
|
expect(capturedArgs).toContain("-p");
|
||||||
expect(capturedArgs).toContain("--output-format");
|
expect(capturedArgs).toContain("--verbose");
|
||||||
expect(capturedArgs).toContain("--session-id");
|
const outputFormatIdx = capturedArgs.indexOf("--output-format");
|
||||||
|
expect(outputFormatIdx).toBeGreaterThanOrEqual(0);
|
||||||
|
expect(capturedArgs[outputFormatIdx + 1]).toBe("stream-json");
|
||||||
|
const sessionIdIdx = capturedArgs.indexOf("--session-id");
|
||||||
|
expect(sessionIdIdx).toBeGreaterThanOrEqual(0);
|
||||||
|
expect(capturedArgs[sessionIdIdx + 1]).toMatch(/^[0-9a-f-]{36}$/i);
|
||||||
expect(result.sessionHandle?.kind).toBe("claude");
|
expect(result.sessionHandle?.kind).toBe("claude");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -192,9 +199,17 @@ describe("ClaudeAdapter", () => {
|
|||||||
config: { binary: fakeBin },
|
config: { binary: fakeBin },
|
||||||
});
|
});
|
||||||
|
|
||||||
const capturedArgs = fs.existsSync(argsFile) ? fs.readFileSync(argsFile, "utf8") : "";
|
const capturedArgs = fs.existsSync(argsFile)
|
||||||
expect(capturedArgs).toContain("--resume");
|
? fs.readFileSync(argsFile, "utf8").split("\0").filter(Boolean)
|
||||||
expect(capturedArgs).toContain("captured-session-id");
|
: [];
|
||||||
|
expect(capturedArgs).toContain("-p");
|
||||||
|
expect(capturedArgs).toContain("--verbose");
|
||||||
|
const outputFormatIdx = capturedArgs.indexOf("--output-format");
|
||||||
|
expect(outputFormatIdx).toBeGreaterThanOrEqual(0);
|
||||||
|
expect(capturedArgs[outputFormatIdx + 1]).toBe("stream-json");
|
||||||
|
const resumeIdx = capturedArgs.indexOf("--resume");
|
||||||
|
expect(resumeIdx).toBeGreaterThanOrEqual(0);
|
||||||
|
expect(capturedArgs[resumeIdx + 1]).toBe("captured-session-id");
|
||||||
expect(result.sessionHandle?.kind).toBe("claude");
|
expect(result.sessionHandle?.kind).toBe("claude");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -338,10 +353,15 @@ printf '%s\\0' "$@" >> "${argsFile}"
|
|||||||
config: { binary: trackingBin },
|
config: { binary: trackingBin },
|
||||||
});
|
});
|
||||||
|
|
||||||
// 1) --output-format stream-json was passed
|
// 1) --output-format stream-json, -p, --verbose were passed
|
||||||
const capturedArgs = fs.existsSync(argsFile) ? fs.readFileSync(argsFile, "utf8") : "";
|
const capturedArgs = fs.existsSync(argsFile)
|
||||||
expect(capturedArgs).toContain("--output-format");
|
? fs.readFileSync(argsFile, "utf8").split("\0").filter(Boolean)
|
||||||
expect(capturedArgs).toContain("stream-json");
|
: [];
|
||||||
|
expect(capturedArgs).toContain("-p");
|
||||||
|
expect(capturedArgs).toContain("--verbose");
|
||||||
|
const outputFormatIdx = capturedArgs.indexOf("--output-format");
|
||||||
|
expect(outputFormatIdx).toBeGreaterThanOrEqual(0);
|
||||||
|
expect(capturedArgs[outputFormatIdx + 1]).toBe("stream-json");
|
||||||
|
|
||||||
// 2) Exact session preservation
|
// 2) Exact session preservation
|
||||||
if (result.sessionHandle?.kind === "claude") {
|
if (result.sessionHandle?.kind === "claude") {
|
||||||
@@ -384,11 +404,17 @@ printf '%s\\0' "$@" >> "${argsFile}"
|
|||||||
expect(sidecar!.phase).toBe("failed");
|
expect(sidecar!.phase).toBe("failed");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("resume: preserves session ID from the handle", async () => {
|
it("resume: preserves session ID from the handle and passes expected args", async () => {
|
||||||
|
const argsFile = path.join(tmpDir, "args.txt");
|
||||||
const fakeBin = makeFakeClaude([
|
const fakeBin = makeFakeClaude([
|
||||||
'{"type":"system","subtype":"init","session_id":"resumed-session-999"}',
|
'{"type":"system","subtype":"init","session_id":"resumed-session-999"}',
|
||||||
'{"type":"result","result":"completed"}',
|
'{"type":"result","result":"completed"}',
|
||||||
]);
|
]);
|
||||||
|
const trackingBin = path.join(tmpDir, "tracking-claude.sh");
|
||||||
|
fs.writeFileSync(trackingBin, `#!/bin/bash
|
||||||
|
printf '%s\\0' "$@" >> "${argsFile}"
|
||||||
|
"${fakeBin}" "$@"
|
||||||
|
`, { mode: 0o755 });
|
||||||
|
|
||||||
const adapter = createExecutorAdapter("claude");
|
const adapter = createExecutorAdapter("claude");
|
||||||
const logFilePath = path.join(tmpDir, "claude-resume.log");
|
const logFilePath = path.join(tmpDir, "claude-resume.log");
|
||||||
@@ -400,9 +426,21 @@ printf '%s\\0' "$@" >> "${argsFile}"
|
|||||||
runDir: tmpDir,
|
runDir: tmpDir,
|
||||||
cycleIndex: 2,
|
cycleIndex: 2,
|
||||||
logFilePath,
|
logFilePath,
|
||||||
config: { binary: fakeBin },
|
config: { binary: trackingBin },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const capturedArgs = fs.existsSync(argsFile)
|
||||||
|
? fs.readFileSync(argsFile, "utf8").split("\0").filter(Boolean)
|
||||||
|
: [];
|
||||||
|
expect(capturedArgs).toContain("-p");
|
||||||
|
expect(capturedArgs).toContain("--verbose");
|
||||||
|
const outputFormatIdx = capturedArgs.indexOf("--output-format");
|
||||||
|
expect(outputFormatIdx).toBeGreaterThanOrEqual(0);
|
||||||
|
expect(capturedArgs[outputFormatIdx + 1]).toBe("stream-json");
|
||||||
|
const resumeIdx = capturedArgs.indexOf("--resume");
|
||||||
|
expect(resumeIdx).toBeGreaterThanOrEqual(0);
|
||||||
|
expect(capturedArgs[resumeIdx + 1]).toBe("resumed-session-999");
|
||||||
|
|
||||||
if (result.sessionHandle?.kind === "claude") {
|
if (result.sessionHandle?.kind === "claude") {
|
||||||
expect(result.sessionHandle.sessionId).toBe("resumed-session-999");
|
expect(result.sessionHandle.sessionId).toBe("resumed-session-999");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -631,6 +631,7 @@ class ClaudeAdapter implements ExecutorAdapter {
|
|||||||
|
|
||||||
const args: string[] = [
|
const args: string[] = [
|
||||||
"-p",
|
"-p",
|
||||||
|
"--verbose",
|
||||||
"--safe-mode",
|
"--safe-mode",
|
||||||
"--permission-mode", "bypassPermissions",
|
"--permission-mode", "bypassPermissions",
|
||||||
"--output-format", "stream-json",
|
"--output-format", "stream-json",
|
||||||
@@ -703,6 +704,7 @@ class ClaudeAdapter implements ExecutorAdapter {
|
|||||||
|
|
||||||
const args: string[] = [
|
const args: string[] = [
|
||||||
"-p",
|
"-p",
|
||||||
|
"--verbose",
|
||||||
"--safe-mode",
|
"--safe-mode",
|
||||||
"--permission-mode", "bypassPermissions",
|
"--permission-mode", "bypassPermissions",
|
||||||
"--output-format", "stream-json",
|
"--output-format", "stream-json",
|
||||||
|
|||||||
Reference in New Issue
Block a user