fe23ffa100
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
65 lines
2.5 KiB
TypeScript
65 lines
2.5 KiB
TypeScript
/**
|
|
* 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<EditTurnResult> {
|
|
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(
|
|
`<instruction>\n${instruction}\n</instruction>\n<text>\n${selectedText}\n</text>`,
|
|
);
|
|
// 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 };
|
|
}
|