/** * LiveTurn — the minimal machine-edit ingress (spec §6.2): one @cline/sdk * Agent turn on the built-in `claude-code` provider, which rides the * operator's local Claude Code Pro/Max login — the extension holds NO * credentials of any kind (INV-8). vscode-free; the editSelection command * (extension.ts) feeds the result into the applyAgentEdit seam (INV-9). * * Like src/cline.ts: @cline/sdk is ESM-only, loaded via dynamic import(), * never bundled (esbuild keeps it external). */ export interface EditTurnResult { replacement: string; model: string; /** the SDK run id — recorded as provenance sessionId. */ sessionId: string; } const SYSTEM_PROMPT = [ "You are a precise text editor embedded in VS Code.", "You will be given a piece of text and an instruction.", "Respond with ONLY the edited replacement text — no explanation, no preamble,", "no markdown code fences. Preserve the original's leading/trailing whitespace", "unless the instruction says otherwise.", ].join(" "); /** * Strip a wrapping markdown code fence if the model added one anyway. * If `selectedText` itself was fence-wrapped (i.e. the user's selection was a * fenced block), the model mirroring that format is correct — return * `outputText` unchanged so the fence is preserved. */ export function extractReplacement(outputText: string, selectedText: string): string { const fencePattern = /^\s*```[^\n]*\n[\s\S]*?\n?```\s*$/; if (fencePattern.test(selectedText)) return outputText; const m = outputText.match(/^\s*```[^\n]*\n([\s\S]*?)\n?```\s*$/); return m ? m[1] : outputText; } export async function runEditTurn( instruction: string, selectedText: string, opts?: { modelId?: string }, ): Promise { const sdk = await import("@cline/sdk"); const modelId = opts?.modelId ?? "sonnet"; const agent = new sdk.Agent({ providerId: "claude-code", modelId, systemPrompt: SYSTEM_PROMPT, }); const result = await agent.run( `\n${instruction}\n\n\n${selectedText}\n`, ); // The SDK's AgentRunResult.status union is "completed" | "aborted" | "failed" // (@cline/shared agent.d.ts) — "completed" is the success status. if (result.status !== "completed") { throw new Error( `claude-code turn ${result.status}: ${result.error?.message ?? "unknown error"} ` + "(is Claude Code installed and signed in?)", ); } return { replacement: extractReplacement(result.outputText, selectedText), model: modelId, sessionId: result.runId }; }