import pc from "picocolors"; function asErrorText(value: unknown): string { if (typeof value === "string") return value; if (typeof value !== "object" || value === null || Array.isArray(value)) return ""; const obj = value as Record; const message = (typeof obj.message === "string" && obj.message) || (typeof obj.error === "string" && obj.error) || (typeof obj.code === "string" && obj.code) || ""; if (message) return message; try { return JSON.stringify(obj); } catch { return ""; } } export function printClaudeStreamEvent(raw: string, debug: boolean): void { const line = raw.trim(); if (!line) return; let parsed: Record | null = null; try { parsed = JSON.parse(line) as Record; } catch { console.log(line); return; } const type = typeof parsed.type === "string" ? parsed.type : ""; if (type === "system" && parsed.subtype === "init") { const model = typeof parsed.model === "string" ? parsed.model : "unknown"; const sessionId = typeof parsed.session_id === "string" ? parsed.session_id : ""; console.log(pc.blue(`Claude initialized (model: ${model}${sessionId ? `, session: ${sessionId}` : ""})`)); return; } if (type === "assistant") { const message = typeof parsed.message === "object" && parsed.message !== null && !Array.isArray(parsed.message) ? (parsed.message as Record) : {}; const content = Array.isArray(message.content) ? message.content : []; for (const blockRaw of content) { if (typeof blockRaw !== "object" || blockRaw === null || Array.isArray(blockRaw)) continue; const block = blockRaw as Record; const blockType = typeof block.type === "string" ? block.type : ""; if (blockType === "text") { const text = typeof block.text === "string" ? block.text : ""; if (text) console.log(pc.green(`assistant: ${text}`)); } else if (blockType === "tool_use") { const name = typeof block.name === "string" ? block.name : "unknown"; console.log(pc.yellow(`tool_call: ${name}`)); if (block.input !== undefined) { console.log(pc.gray(JSON.stringify(block.input, null, 2))); } } } return; } if (type === "result") { const usage = typeof parsed.usage === "object" && parsed.usage !== null && !Array.isArray(parsed.usage) ? (parsed.usage as Record) : {}; const input = Number(usage.input_tokens ?? 0); const output = Number(usage.output_tokens ?? 0); const cached = Number(usage.cache_read_input_tokens ?? 0); const cost = Number(parsed.total_cost_usd ?? 0); const subtype = typeof parsed.subtype === "string" ? parsed.subtype : ""; const isError = parsed.is_error === true; const resultText = typeof parsed.result === "string" ? parsed.result : ""; if (resultText) { console.log(pc.green("result:")); console.log(resultText); } const errors = Array.isArray(parsed.errors) ? parsed.errors.map(asErrorText).filter(Boolean) : []; if (subtype.startsWith("error") || isError || errors.length > 0) { console.log(pc.red(`claude_result: subtype=${subtype || "unknown"} is_error=${isError ? "true" : "false"}`)); if (errors.length > 0) { console.log(pc.red(`claude_errors: ${errors.join(" | ")}`)); } } console.log( pc.blue( `tokens: in=${Number.isFinite(input) ? input : 0} out=${Number.isFinite(output) ? output : 0} cached=${Number.isFinite(cached) ? cached : 0} cost=$${Number.isFinite(cost) ? cost.toFixed(6) : "0.000000"}`, ), ); return; } if (debug) { console.log(pc.gray(line)); } }