From 95548a9530d79e192d25c83c879ffce5b7e6144a Mon Sep 17 00:00:00 2001 From: neken Date: Fri, 10 Apr 2026 17:23:08 +0500 Subject: [PATCH] fix: switch from SDK to CLI wrapper (npx claude-code) for auth compatibility --- src/services/claude.ts | 89 +++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 36 deletions(-) diff --git a/src/services/claude.ts b/src/services/claude.ts index ab7c31d..5f23270 100644 --- a/src/services/claude.ts +++ b/src/services/claude.ts @@ -1,52 +1,69 @@ -import { query } from "@anthropic-ai/claude-agent-sdk"; +import { spawn } from "child_process"; export interface ClaudeResult { sessionId: string; result: string; } +interface CliJsonResult { + result?: string; + session_id?: string; + is_error?: boolean; +} + +function runClaude(args: string[], cwd: string): Promise { + return new Promise((resolve, reject) => { + const proc = spawn("npx", ["--yes", "@anthropic-ai/claude-code", ...args], { + cwd, + shell: true, + env: { ...process.env }, + }); + + let stdout = ""; + let stderr = ""; + + proc.stdout.on("data", (data: Buffer) => { + stdout += data.toString(); + }); + + proc.stderr.on("data", (data: Buffer) => { + stderr += data.toString(); + }); + + proc.on("close", (code: number | null) => { + if (code !== 0 && !stdout) { + reject(new Error(stderr || `claude exited with code ${code}`)); + } else { + resolve(stdout); + } + }); + + proc.on("error", reject); + }); +} + export class ClaudeService { async createSession(prompt: string, cwd: string): Promise { - let sessionId = ""; - let result = ""; + const raw = await runClaude( + ["-p", prompt, "--output-format", "json", "--dangerously-skip-permissions"], + cwd, + ); - for await (const message of query({ - prompt, - options: { - cwd, - permissionMode: "bypassPermissions", - allowedTools: [ - "Read", "Write", "Edit", "Bash", "Glob", "Grep", - "WebSearch", "WebFetch", "Agent", - ], - }, - })) { - if (message.type === "system" && message.subtype === "init") { - sessionId = message.session_id; - } - if ("result" in message && typeof message.result === "string") { - result = message.result; - } - } + const parsed = JSON.parse(raw.trim().split("\n").pop()!) as CliJsonResult; - return { sessionId, result }; + return { + sessionId: parsed.session_id ?? "", + result: parsed.result ?? "", + }; } async sendMessage(prompt: string, sessionId: string): Promise { - let result = ""; + const raw = await runClaude( + ["-p", prompt, "--output-format", "json", "--resume", sessionId, "--dangerously-skip-permissions"], + process.cwd(), + ); - for await (const message of query({ - prompt, - options: { - resume: sessionId, - permissionMode: "bypassPermissions", - }, - })) { - if ("result" in message && typeof message.result === "string") { - result = message.result; - } - } - - return result; + const parsed = JSON.parse(raw.trim().split("\n").pop()!) as CliJsonResult; + return parsed.result ?? ""; } }