Files
clawdbot/src/auto-reply/claude.ts
2025-11-25 03:48:49 +01:00

78 lines
2.3 KiB
TypeScript

// Helpers specific to Claude CLI output/argv handling.
// Preferred binary name for Claude CLI invocations.
export const CLAUDE_BIN = "claude";
function extractClaudeText(payload: unknown): string | undefined {
// Best-effort walker to find the primary text field in Claude JSON outputs.
if (payload == null) return undefined;
if (typeof payload === "string") return payload;
if (Array.isArray(payload)) {
for (const item of payload) {
const found = extractClaudeText(item);
if (found) return found;
}
return undefined;
}
if (typeof payload === "object") {
const obj = payload as Record<string, unknown>;
if (typeof obj.result === "string") return obj.result;
if (typeof obj.text === "string") return obj.text;
if (typeof obj.completion === "string") return obj.completion;
if (typeof obj.output === "string") return obj.output;
if (obj.message) {
const inner = extractClaudeText(obj.message);
if (inner) return inner;
}
if (Array.isArray(obj.messages)) {
const inner = extractClaudeText(obj.messages);
if (inner) return inner;
}
if (Array.isArray(obj.content)) {
for (const block of obj.content) {
if (
block &&
typeof block === "object" &&
(block as { type?: string }).type === "text" &&
typeof (block as { text?: unknown }).text === "string"
) {
return (block as { text: string }).text;
}
const inner = extractClaudeText(block);
if (inner) return inner;
}
}
}
return undefined;
}
export type ClaudeJsonParseResult = {
text?: string;
parsed: unknown;
};
export function parseClaudeJson(raw: string): ClaudeJsonParseResult | undefined {
// Handle a single JSON blob or newline-delimited JSON; return the first parsed payload.
let firstParsed: unknown;
const candidates = [raw, ...raw.split(/\n+/).map((s) => s.trim()).filter(Boolean)];
for (const candidate of candidates) {
try {
const parsed = JSON.parse(candidate);
if (firstParsed === undefined) firstParsed = parsed;
const text = extractClaudeText(parsed);
if (text) return { parsed, text };
} catch {
// ignore parse errors; try next candidate
}
}
if (firstParsed !== undefined) {
return { parsed: firstParsed, text: extractClaudeText(firstParsed) };
}
return undefined;
}
export function parseClaudeJsonText(raw: string): string | undefined {
const parsed = parseClaudeJson(raw);
return parsed?.text;
}