fix: use stream-json output for Claude CLI backend to prevent watchdog timeouts

The Claude CLI backend uses `--output-format json`, which produces no
stdout until the entire request completes. When session context is large
(100K+ tokens) or API response is slow, the no-output watchdog timer
(max 180s for resume sessions) kills the process before it finishes,
resulting in "CLI produced no output for 180s and was terminated" errors.

Switch to `--output-format stream-json --verbose` so Claude CLI emits
NDJSON events throughout processing (init, assistant, rate_limit, result).
Each event resets the watchdog timer, which is the intended behavior —
the watchdog detects truly stuck processes, not slow-but-progressing ones.

Changes:
- cli-backends.ts: `json` → `stream-json --verbose`, `output: "jsonl"`
- helpers.ts: teach parseCliJsonl to extract text from Claude's
  `{"type":"result","result":"..."}` NDJSON line

Note: `--verbose` is required for stream-json in `-p` (print) mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
felear2022
2026-03-18 17:05:38 +08:00
committed by Peter Steinberger
parent 4ad7d51c01
commit 623f4d3056
5 changed files with 105 additions and 4 deletions

View File

@@ -233,6 +233,22 @@ export function parseCliJsonl(raw: string, backend: CliBackendConfig): CliOutput
if (isRecord(parsed.usage)) {
usage = toUsage(parsed.usage) ?? usage;
}
// Claude stream-json: {"type":"result","result":"...","session_id":"...","usage":{...}}
if (
typeof parsed.type === "string" &&
parsed.type === "result" &&
typeof parsed.result === "string"
) {
const resultText = parsed.result.trim();
if (resultText) {
return { text: resultText, sessionId, usage };
}
// Claude may finish with an empty result after tool-only work. Keep the
// resolved session handle and usage instead of dropping them.
return { text: "", sessionId, usage };
}
const item = isRecord(parsed.item) ? parsed.item : null;
if (item && typeof item.text === "string") {
const type = typeof item.type === "string" ? item.type.toLowerCase() : "";