copperhead 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -4
- package/dist/agent/animate.js +76 -0
- package/dist/agent/animate.js.map +1 -0
- package/dist/agent/box.js +89 -0
- package/dist/agent/box.js.map +1 -0
- package/dist/agent/dock-renderer.js +173 -0
- package/dist/agent/dock-renderer.js.map +1 -0
- package/dist/agent/logo.js +21 -0
- package/dist/agent/logo.js.map +1 -0
- package/dist/agent/loop.js +130 -18
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/prompts.js +2 -1
- package/dist/agent/prompts.js.map +1 -1
- package/dist/agent/providers/claude-code.js +85 -116
- package/dist/agent/providers/claude-code.js.map +1 -1
- package/dist/agent/providers/cursor.js +317 -0
- package/dist/agent/providers/cursor.js.map +1 -0
- package/dist/agent/providers/tool-protocol.js +205 -0
- package/dist/agent/providers/tool-protocol.js.map +1 -0
- package/dist/agent/recovery.js +148 -0
- package/dist/agent/recovery.js.map +1 -0
- package/dist/agent/render.js +44 -12
- package/dist/agent/render.js.map +1 -1
- package/dist/agent/response-cache.js +81 -0
- package/dist/agent/response-cache.js.map +1 -0
- package/dist/agent/runmeta.js +4 -5
- package/dist/agent/runmeta.js.map +1 -1
- package/dist/agent/theme.js +84 -0
- package/dist/agent/theme.js.map +1 -0
- package/dist/agent/tools.js +61 -4
- package/dist/agent/tools.js.map +1 -1
- package/dist/agent/transcript.js.map +1 -1
- package/dist/cli.js +134 -13
- package/dist/cli.js.map +1 -1
- package/dist/commands/create.js +482 -38
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/demo.js +146 -0
- package/dist/commands/demo.js.map +1 -0
- package/dist/commands/doctor.js +240 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/repl-inspect.js +342 -0
- package/dist/commands/repl-inspect.js.map +1 -0
- package/dist/commands/repl.js +618 -0
- package/dist/commands/repl.js.map +1 -0
- package/dist/config.js +24 -2
- package/dist/config.js.map +1 -1
- package/dist/kicad/bootstrap.js +166 -0
- package/dist/kicad/bootstrap.js.map +1 -0
- package/dist/kicad/cli.js +126 -6
- package/dist/kicad/cli.js.map +1 -1
- package/dist/kicad/spice.js +306 -0
- package/dist/kicad/spice.js.map +1 -0
- package/dist/kicad/symlib.js +228 -0
- package/dist/kicad/symlib.js.map +1 -0
- package/dist/memory/bom-table.js +193 -22
- package/dist/memory/bom-table.js.map +1 -1
- package/dist/memory/drift.js +33 -11
- package/dist/memory/drift.js.map +1 -1
- package/dist/util/cli-args.js +35 -0
- package/dist/util/cli-args.js.map +1 -0
- package/dist/util/dock.js +155 -0
- package/dist/util/dock.js.map +1 -0
- package/dist/util/git.js +165 -4
- package/dist/util/git.js.map +1 -1
- package/dist/util/live-prompt.js +542 -0
- package/dist/util/live-prompt.js.map +1 -0
- package/dist/util/paths.js +9 -0
- package/dist/util/paths.js.map +1 -1
- package/dist/util/preflight.js +37 -0
- package/dist/util/preflight.js.map +1 -1
- package/dist/util/retry.js +23 -0
- package/dist/util/retry.js.map +1 -1
- package/dist/util/select.js +172 -0
- package/dist/util/select.js.map +1 -0
- package/dist/util/tmp.js +119 -0
- package/dist/util/tmp.js.map +1 -0
- package/package.json +3 -2
- package/src/agent/animate.ts +90 -0
- package/src/agent/box.ts +99 -0
- package/src/agent/dock-renderer.ts +181 -0
- package/src/agent/logo.ts +23 -0
- package/src/agent/loop.ts +148 -18
- package/src/agent/prompts.ts +2 -1
- package/src/agent/providers/claude-code.ts +91 -122
- package/src/agent/providers/cursor.ts +364 -0
- package/src/agent/providers/tool-protocol.ts +212 -0
- package/src/agent/recovery.ts +162 -0
- package/src/agent/render.ts +56 -12
- package/src/agent/response-cache.ts +80 -0
- package/src/agent/runmeta.ts +6 -7
- package/src/agent/theme.ts +91 -0
- package/src/agent/tools.ts +62 -4
- package/src/agent/transcript.ts +1 -0
- package/src/agent/types.ts +17 -0
- package/src/cli.ts +139 -15
- package/src/commands/create.ts +581 -40
- package/src/commands/demo.ts +184 -0
- package/src/commands/doctor.ts +289 -0
- package/src/commands/repl-inspect.ts +353 -0
- package/src/commands/repl.ts +685 -0
- package/src/config.ts +40 -3
- package/src/kicad/bootstrap.ts +181 -0
- package/src/kicad/cli.ts +132 -7
- package/src/kicad/spice.ts +399 -0
- package/src/kicad/symlib.ts +248 -0
- package/src/layout/claude-ui-layout.md +72 -0
- package/src/layout/repl-ui-layout.md +139 -0
- package/src/memory/bom-table.ts +191 -20
- package/src/memory/drift.ts +42 -11
- package/src/util/cli-args.ts +42 -0
- package/src/util/dock.ts +161 -0
- package/src/util/git.ts +176 -4
- package/src/util/live-prompt.ts +595 -0
- package/src/util/paths.ts +10 -0
- package/src/util/preflight.ts +44 -0
- package/src/util/retry.ts +29 -0
- package/src/util/select.ts +192 -0
- package/src/util/tmp.ts +113 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { mkdtemp, rm } from 'node:fs/promises';
|
|
1
|
+
import { mkdtemp, rm, utimes } from 'node:fs/promises';
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { parseToolCalls, renderConversation, renderDelta, renderToolProtocol } from './tool-protocol.js';
|
|
4
5
|
/** Explicit deny list, belt-and-suspenders on top of the empty `tools` allowlist.
|
|
5
6
|
* `'*'` is the documented wildcard; the named entries stay for clarity and in
|
|
6
7
|
* case a given SDK build does not honor the wildcard. */
|
|
@@ -23,36 +24,65 @@ export class ClaudeCodeProvider {
|
|
|
23
24
|
model;
|
|
24
25
|
injectedQuery;
|
|
25
26
|
importSdk;
|
|
27
|
+
sessionResume;
|
|
26
28
|
name = 'claude-code';
|
|
27
29
|
callSeq = 0;
|
|
28
30
|
cwdPromise;
|
|
29
|
-
|
|
31
|
+
/** In-flight query aborters, so close() (called by the turn watchdog on a
|
|
32
|
+
* hung turn) can tear down the live subprocess, not just delete its cwd. */
|
|
33
|
+
inFlight = new Set();
|
|
34
|
+
/** Session-resume state (1.1). `sessionId` is the last session the SDK reported;
|
|
35
|
+
* `sentCount` is how many `messages` we have already handed it, so a resumed
|
|
36
|
+
* turn sends only the delta. Unused unless `sessionResume` is on. */
|
|
37
|
+
sessionId;
|
|
38
|
+
sentCount = 0;
|
|
39
|
+
constructor(model, injectedQuery, importSdk = (specifier) => import(specifier),
|
|
40
|
+
/**
|
|
41
|
+
* Opt-in: resume one SDK session across turns and send only new messages,
|
|
42
|
+
* instead of flattening and re-sending the entire conversation every turn
|
|
43
|
+
* (1.1). Cuts the ~quadratic history re-send that dominates long-stage cost.
|
|
44
|
+
* OFF by default and deliberately mutually exclusive with the response cache:
|
|
45
|
+
* the cache replays turns the resumed session never saw, so mixing them would
|
|
46
|
+
* desync the session. `makeProvider` enables it only when the cache is off.
|
|
47
|
+
*/
|
|
48
|
+
sessionResume = false) {
|
|
30
49
|
this.model = model;
|
|
31
50
|
this.injectedQuery = injectedQuery;
|
|
32
51
|
this.importSdk = importSdk;
|
|
52
|
+
this.sessionResume = sessionResume;
|
|
33
53
|
}
|
|
34
|
-
// `
|
|
35
|
-
// Code subprocess and exposes no per-call max-tokens knob.
|
|
36
|
-
//
|
|
37
|
-
|
|
54
|
+
// `opts.maxTokens` is intentionally ignored: the Agent SDK drives the Claude
|
|
55
|
+
// Code subprocess and exposes no per-call max-tokens knob. `opts.onStream` is
|
|
56
|
+
// honored: this provider streams, so it reports cumulative streamed-text length
|
|
57
|
+
// as blocks arrive, which the loop turns into a liveness heartbeat (5.1).
|
|
58
|
+
async chat(messages, tools, opts = {}) {
|
|
38
59
|
const query = await this.resolveQuery();
|
|
39
60
|
const system = messages
|
|
40
61
|
.filter((m) => m.role === 'system')
|
|
41
62
|
.map((m) => m.content)
|
|
42
63
|
.join('\n\n');
|
|
43
64
|
const systemPrompt = [system, renderToolProtocol(tools)].filter(Boolean).join('\n\n');
|
|
44
|
-
|
|
65
|
+
// Session-resume mode (1.1): once the SDK has given us a session id, resume it
|
|
66
|
+
// and send only the messages added since our last turn — the subprocess still
|
|
67
|
+
// holds the earlier conversation, so re-sending it would just re-bill it. The
|
|
68
|
+
// first turn (no session id yet) sends the full flattened history as usual.
|
|
69
|
+
const resume = this.sessionResume ? this.sessionId : undefined;
|
|
70
|
+
const prompt = resume ? renderDelta(messages, this.sentCount) : renderConversation(messages);
|
|
45
71
|
const catalog = new Set(tools.map((t) => t.name));
|
|
46
72
|
const cwd = await this.ensureCwd();
|
|
47
73
|
let text = null;
|
|
48
74
|
let inputTokens = 0;
|
|
49
75
|
let outputTokens = 0;
|
|
76
|
+
// One aborter per turn: close() aborts it to kill a hung subprocess.
|
|
77
|
+
const aborter = new AbortController();
|
|
78
|
+
this.inFlight.add(aborter);
|
|
50
79
|
try {
|
|
51
80
|
for await (const msg of query({
|
|
52
81
|
prompt,
|
|
53
82
|
options: {
|
|
54
83
|
systemPrompt,
|
|
55
84
|
...(this.model ? { model: this.model } : {}),
|
|
85
|
+
abortController: aborter,
|
|
56
86
|
// Layered "the SDK executes nothing" defense (D1/D5):
|
|
57
87
|
// 1. `tools: []` disables ALL built-in tools (Agent SDK 0.3.x docs:
|
|
58
88
|
// "[] (empty array) - Disable all built-in tools").
|
|
@@ -63,6 +93,7 @@ export class ClaudeCodeProvider {
|
|
|
63
93
|
// 4. The tool_use tripwire below fails the run loudly if one is
|
|
64
94
|
// emitted anyway. Any single layer failing is caught by the next.
|
|
65
95
|
tools: [],
|
|
96
|
+
...(resume ? { resume } : {}),
|
|
66
97
|
disallowedTools: DISALLOWED_BUILTINS,
|
|
67
98
|
canUseTool: async (toolName) => ({
|
|
68
99
|
behavior: 'deny',
|
|
@@ -82,6 +113,9 @@ export class ClaudeCodeProvider {
|
|
|
82
113
|
for (const block of msg.message?.content ?? []) {
|
|
83
114
|
if (block.type === 'text' && block.text) {
|
|
84
115
|
text = (text ?? '') + block.text;
|
|
116
|
+
// Report progress so the loop's heartbeat shows this turn is alive
|
|
117
|
+
// and streaming, not hung, during a multi-minute large-output turn.
|
|
118
|
+
opts.onStream?.(text.length);
|
|
85
119
|
}
|
|
86
120
|
else if (block.type === 'tool_use') {
|
|
87
121
|
// Load-bearing invariant (D1): the SDK must execute nothing, so it
|
|
@@ -100,6 +134,10 @@ export class ClaudeCodeProvider {
|
|
|
100
134
|
if (typeof msg.usage?.output_tokens === 'number')
|
|
101
135
|
outputTokens = msg.usage.output_tokens;
|
|
102
136
|
}
|
|
137
|
+
// The session id can arrive on any message (init/system/result); keep the
|
|
138
|
+
// latest so the next turn can resume it (1.1). No-op unless resume is on.
|
|
139
|
+
if (this.sessionResume && typeof msg.session_id === 'string')
|
|
140
|
+
this.sessionId = msg.session_id;
|
|
103
141
|
}
|
|
104
142
|
}
|
|
105
143
|
catch (err) {
|
|
@@ -111,12 +149,39 @@ export class ClaudeCodeProvider {
|
|
|
111
149
|
throw new Error(authHint(err.message));
|
|
112
150
|
throw err;
|
|
113
151
|
}
|
|
152
|
+
finally {
|
|
153
|
+
this.inFlight.delete(aborter);
|
|
154
|
+
}
|
|
155
|
+
// Only advance the high-water mark on a turn that completed: a thrown turn
|
|
156
|
+
// (rate limit, timeout) is retried, and must re-send the same delta so no
|
|
157
|
+
// message is lost from the resumed session (1.1).
|
|
158
|
+
if (this.sessionResume)
|
|
159
|
+
this.sentCount = messages.length;
|
|
114
160
|
const parsed = parseToolCalls(text, () => `cc-${++this.callSeq}`, catalog);
|
|
115
|
-
return {
|
|
161
|
+
return {
|
|
162
|
+
text: parsed.text,
|
|
163
|
+
toolCalls: parsed.toolCalls,
|
|
164
|
+
usage: { inputTokens, outputTokens },
|
|
165
|
+
nudge: parsed.nudge,
|
|
166
|
+
};
|
|
116
167
|
}
|
|
117
|
-
/**
|
|
118
|
-
*
|
|
168
|
+
/** Tear down in-flight work and remove the scratch cwd. Called by the turn
|
|
169
|
+
* watchdog on a hung turn (via withTimeout's onTimeout) AND once per run in a
|
|
170
|
+
* finally. Aborting first kills the `claude` subprocess a hung turn spawned —
|
|
171
|
+
* without it the process is orphaned and keeps writing to its temp cwd, which
|
|
172
|
+
* (with KiCad local history) was a source of the disk-fill halt (2.2/4.1, I8).
|
|
173
|
+
* A leftover empty dir in the OS tmpdir is harmless; the startup sweep reclaims
|
|
174
|
+
* any that a hard SIGKILL bypassed this cleanup for. */
|
|
119
175
|
async close() {
|
|
176
|
+
for (const aborter of this.inFlight) {
|
|
177
|
+
try {
|
|
178
|
+
aborter.abort();
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// best effort: a controller that already settled throws nothing useful
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
this.inFlight.clear();
|
|
120
185
|
const pending = this.cwdPromise;
|
|
121
186
|
this.cwdPromise = undefined;
|
|
122
187
|
if (!pending)
|
|
@@ -131,10 +196,18 @@ export class ClaudeCodeProvider {
|
|
|
131
196
|
/** One isolated scratch cwd per provider instance, created once and reused
|
|
132
197
|
* across turns so a long run does not leak a temp dir per turn. Even with
|
|
133
198
|
* tools disabled this guarantees the SDK has no path into the repo (D5). */
|
|
134
|
-
ensureCwd() {
|
|
199
|
+
async ensureCwd() {
|
|
135
200
|
if (!this.cwdPromise)
|
|
136
201
|
this.cwdPromise = mkdtemp(path.join(os.tmpdir(), 'copperhead-cc-'));
|
|
137
|
-
|
|
202
|
+
const cwd = await this.cwdPromise;
|
|
203
|
+
// Keep this reused scratch dir's mtime fresh on every turn. It is the only
|
|
204
|
+
// long-lived temp dir a run holds (kicad-cli dirs are per-call), so a
|
|
205
|
+
// multi-hour run would otherwise leave it with a stale mtime and a concurrent
|
|
206
|
+
// run's startup sweep (sweepStaleTempDirs, age-gated) could delete it out from
|
|
207
|
+
// under the live process (F4). Best-effort: a touch failure is harmless.
|
|
208
|
+
const now = new Date();
|
|
209
|
+
await utimes(cwd, now, now).catch(() => { });
|
|
210
|
+
return cwd;
|
|
138
211
|
}
|
|
139
212
|
async resolveQuery() {
|
|
140
213
|
if (this.injectedQuery)
|
|
@@ -162,110 +235,6 @@ export class ClaudeCodeProvider {
|
|
|
162
235
|
return query;
|
|
163
236
|
}
|
|
164
237
|
}
|
|
165
|
-
function renderToolProtocol(tools) {
|
|
166
|
-
if (!tools.length)
|
|
167
|
-
return '';
|
|
168
|
-
const lines = [
|
|
169
|
-
'# Tool protocol',
|
|
170
|
-
'',
|
|
171
|
-
'You are the reasoning half of a tool-driven workflow; you cannot run anything yourself.',
|
|
172
|
-
'To take an action, reply with EXACTLY ONE JSON object and nothing else, wrapped in a',
|
|
173
|
-
'```json fenced code block:',
|
|
174
|
-
'',
|
|
175
|
-
'```json',
|
|
176
|
-
'{"tool": "<tool_name>", "args": { ... }}',
|
|
177
|
-
'```',
|
|
178
|
-
'',
|
|
179
|
-
'Use only the tools listed below, with `args` matching the tool\'s JSON Schema. If you have',
|
|
180
|
-
'no tool to call and only want to say something, reply with plain prose and no JSON block.',
|
|
181
|
-
'',
|
|
182
|
-
'## Available tools',
|
|
183
|
-
];
|
|
184
|
-
for (const t of tools) {
|
|
185
|
-
lines.push('', `### ${t.name}`, t.description, `Parameters (JSON Schema): ${JSON.stringify(t.parameters)}`);
|
|
186
|
-
}
|
|
187
|
-
return lines.join('\n');
|
|
188
|
-
}
|
|
189
|
-
function renderConversation(messages) {
|
|
190
|
-
const idToName = new Map();
|
|
191
|
-
const parts = [];
|
|
192
|
-
for (const m of messages) {
|
|
193
|
-
if (m.role === 'system')
|
|
194
|
-
continue;
|
|
195
|
-
if (m.role === 'user') {
|
|
196
|
-
parts.push(`[user]\n${m.content}`);
|
|
197
|
-
}
|
|
198
|
-
else if (m.role === 'assistant') {
|
|
199
|
-
if (m.content)
|
|
200
|
-
parts.push(`[assistant]\n${m.content}`);
|
|
201
|
-
for (const call of m.toolCalls ?? []) {
|
|
202
|
-
idToName.set(call.id, call.name);
|
|
203
|
-
parts.push(`[assistant tool call]\n\`\`\`json\n${JSON.stringify({ tool: call.name, args: call.args })}\n\`\`\``);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
const name = idToName.get(m.toolCallId) ?? m.toolCallId;
|
|
208
|
-
parts.push(`[result of ${name}]\n${m.content}`);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return parts.join('\n\n');
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Extract tool-call JSON from the model's reply. Tolerant by design (D1):
|
|
215
|
-
* unparseable output is returned as plain text with no tool calls rather than
|
|
216
|
-
* throwing, so a non-conforming turn degrades to the loop's stall/nudge path.
|
|
217
|
-
* A parsed block only counts as a tool call when its name is in the current
|
|
218
|
-
* turn's catalog (`availableTools(ctx)`): a hallucinated or locked tool name is
|
|
219
|
-
* left as prose so the loop nudges, rather than dispatching a bogus call.
|
|
220
|
-
*/
|
|
221
|
-
function parseToolCalls(text, nextId, catalog) {
|
|
222
|
-
if (!text)
|
|
223
|
-
return { text: null, toolCalls: [] };
|
|
224
|
-
const toolCalls = [];
|
|
225
|
-
let prose = text;
|
|
226
|
-
const fence = /```(?:json)?\s*([\s\S]*?)```/gi;
|
|
227
|
-
let match;
|
|
228
|
-
const consumed = [];
|
|
229
|
-
while ((match = fence.exec(text)) !== null) {
|
|
230
|
-
const call = toToolCall(match[1], nextId, catalog);
|
|
231
|
-
if (call) {
|
|
232
|
-
toolCalls.push(call);
|
|
233
|
-
consumed.push(match[0]);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
for (const block of consumed)
|
|
237
|
-
prose = prose.replace(block, '');
|
|
238
|
-
// No fenced tool block: maybe the whole reply is a bare JSON object.
|
|
239
|
-
if (!toolCalls.length) {
|
|
240
|
-
const call = toToolCall(text, nextId, catalog);
|
|
241
|
-
if (call)
|
|
242
|
-
return { text: null, toolCalls: [call] };
|
|
243
|
-
}
|
|
244
|
-
const trimmed = prose.trim();
|
|
245
|
-
return { text: trimmed.length ? trimmed : null, toolCalls };
|
|
246
|
-
}
|
|
247
|
-
function toToolCall(raw, nextId, catalog) {
|
|
248
|
-
if (!raw)
|
|
249
|
-
return null;
|
|
250
|
-
let obj;
|
|
251
|
-
try {
|
|
252
|
-
obj = JSON.parse(raw.trim());
|
|
253
|
-
}
|
|
254
|
-
catch {
|
|
255
|
-
return null;
|
|
256
|
-
}
|
|
257
|
-
if (!obj || typeof obj !== 'object')
|
|
258
|
-
return null;
|
|
259
|
-
const rec = obj;
|
|
260
|
-
if (typeof rec.tool !== 'string')
|
|
261
|
-
return null;
|
|
262
|
-
// Only accept names the turn actually advertised. An empty catalog means the
|
|
263
|
-
// turn offered no tools, so nothing parses as a call.
|
|
264
|
-
if (!catalog.has(rec.tool))
|
|
265
|
-
return null;
|
|
266
|
-
const args = rec.args && typeof rec.args === 'object' ? rec.args : {};
|
|
267
|
-
return { id: nextId(), name: rec.tool, args };
|
|
268
|
-
}
|
|
269
238
|
function isAuthError(err) {
|
|
270
239
|
const status = err?.status
|
|
271
240
|
?? err?.statusCode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../src/agent/providers/claude-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../src/agent/providers/claude-code.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { mkdtemp, rm, utimes } from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { execa } from 'execa';
|
|
5
|
+
import { parseToolCalls, renderConversation, renderDelta, renderToolProtocol } from './tool-protocol.js';
|
|
6
|
+
const NATIVE_MUTATION_TYPES = new Set([
|
|
7
|
+
'tool_call',
|
|
8
|
+
'tool_use',
|
|
9
|
+
'tool-call',
|
|
10
|
+
'shell',
|
|
11
|
+
'write',
|
|
12
|
+
'edit',
|
|
13
|
+
'apply_patch',
|
|
14
|
+
'file_change',
|
|
15
|
+
'mcp_tool',
|
|
16
|
+
]);
|
|
17
|
+
/** Subtype tokens that indicate native execution (whole-token match). */
|
|
18
|
+
const NATIVE_SUBTYPE_RE = /(^|_)(tool|shell|write|edit|patch|mutation)(_|$)/;
|
|
19
|
+
export class CursorProvider {
|
|
20
|
+
model;
|
|
21
|
+
runFn;
|
|
22
|
+
sessionResume;
|
|
23
|
+
name = 'cursor';
|
|
24
|
+
callSeq = 0;
|
|
25
|
+
cwdPromise;
|
|
26
|
+
sessionId;
|
|
27
|
+
sentCount = 0;
|
|
28
|
+
inFlight = new Set();
|
|
29
|
+
constructor(model, runFn = defaultCursorRun,
|
|
30
|
+
/**
|
|
31
|
+
* Opt-in: resume one CLI session across turns and send only new messages.
|
|
32
|
+
* OFF by default and mutually exclusive with the response cache — mixing
|
|
33
|
+
* them desyncs the resumed session. `makeProvider` enables it only when
|
|
34
|
+
* the cache is off.
|
|
35
|
+
*/
|
|
36
|
+
sessionResume = false) {
|
|
37
|
+
this.model = model;
|
|
38
|
+
this.runFn = runFn;
|
|
39
|
+
this.sessionResume = sessionResume;
|
|
40
|
+
}
|
|
41
|
+
async chat(messages, tools, opts = {}) {
|
|
42
|
+
const system = messages
|
|
43
|
+
.filter((m) => m.role === 'system')
|
|
44
|
+
.map((m) => m.content)
|
|
45
|
+
.join('\n\n');
|
|
46
|
+
const systemPrompt = [system, renderToolProtocol(tools)].filter(Boolean).join('\n\n');
|
|
47
|
+
const resume = this.sessionResume ? this.sessionId : undefined;
|
|
48
|
+
const prompt = resume ? renderDelta(messages, this.sentCount) : renderConversation(messages);
|
|
49
|
+
const catalog = new Set(tools.map((t) => t.name));
|
|
50
|
+
const workspace = await this.ensureWorkspace();
|
|
51
|
+
const aborter = new AbortController();
|
|
52
|
+
this.inFlight.add(aborter);
|
|
53
|
+
let inputTokens = 0;
|
|
54
|
+
let outputTokens = 0;
|
|
55
|
+
let text = null;
|
|
56
|
+
try {
|
|
57
|
+
const result = await this.runFn({
|
|
58
|
+
prompt,
|
|
59
|
+
systemPrompt,
|
|
60
|
+
workspace,
|
|
61
|
+
...(this.model ? { model: this.model } : {}),
|
|
62
|
+
...(resume ? { resume } : {}),
|
|
63
|
+
signal: aborter.signal,
|
|
64
|
+
env: subprocessEnv(),
|
|
65
|
+
});
|
|
66
|
+
text = result.text;
|
|
67
|
+
if (this.sessionResume && result.sessionId)
|
|
68
|
+
this.sessionId = result.sessionId;
|
|
69
|
+
inputTokens = result.usage.inputTokens;
|
|
70
|
+
outputTokens = result.usage.outputTokens;
|
|
71
|
+
opts.onStream?.(text.length);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
if (isAuthError(err))
|
|
75
|
+
throw new Error(authHint(err.message));
|
|
76
|
+
throw enhanceCliError(err);
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
this.inFlight.delete(aborter);
|
|
80
|
+
}
|
|
81
|
+
// Only advance the high-water mark when resume is on (same as claude-code).
|
|
82
|
+
if (this.sessionResume)
|
|
83
|
+
this.sentCount = messages.length;
|
|
84
|
+
const parsed = parseToolCalls(text, () => `cur-${++this.callSeq}`, catalog);
|
|
85
|
+
return {
|
|
86
|
+
text: parsed.text,
|
|
87
|
+
toolCalls: parsed.toolCalls,
|
|
88
|
+
usage: { inputTokens, outputTokens },
|
|
89
|
+
nudge: parsed.nudge,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async close() {
|
|
93
|
+
for (const aborter of this.inFlight) {
|
|
94
|
+
try {
|
|
95
|
+
aborter.abort();
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// best effort
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
this.inFlight.clear();
|
|
102
|
+
const pending = this.cwdPromise;
|
|
103
|
+
this.cwdPromise = undefined;
|
|
104
|
+
if (!pending)
|
|
105
|
+
return;
|
|
106
|
+
try {
|
|
107
|
+
await rm(await pending, { recursive: true, force: true });
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// best effort
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async ensureWorkspace() {
|
|
114
|
+
if (!this.cwdPromise)
|
|
115
|
+
this.cwdPromise = mkdtemp(path.join(os.tmpdir(), 'copperhead-cursor-'));
|
|
116
|
+
const cwd = await this.cwdPromise;
|
|
117
|
+
const now = new Date();
|
|
118
|
+
await utimes(cwd, now, now).catch(() => { });
|
|
119
|
+
return cwd;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** Minimal env passed to the Cursor CLI subprocess (saved login via `agent login`). */
|
|
123
|
+
const CURSOR_SUBPROCESS_ENV_KEYS = [
|
|
124
|
+
'PATH',
|
|
125
|
+
'HOME',
|
|
126
|
+
'USER',
|
|
127
|
+
'LOGNAME',
|
|
128
|
+
'SHELL',
|
|
129
|
+
'TMPDIR',
|
|
130
|
+
'TEMP',
|
|
131
|
+
'TMP',
|
|
132
|
+
'LANG',
|
|
133
|
+
'LC_ALL',
|
|
134
|
+
'LC_CTYPE',
|
|
135
|
+
'LC_MESSAGES',
|
|
136
|
+
'TERM',
|
|
137
|
+
'XDG_CONFIG_HOME',
|
|
138
|
+
'XDG_DATA_HOME',
|
|
139
|
+
'XDG_CACHE_HOME',
|
|
140
|
+
'XDG_RUNTIME_DIR',
|
|
141
|
+
// Windows home / login-config location (`USERPROFILE\.cursor\cli-config.json`)
|
|
142
|
+
'USERPROFILE',
|
|
143
|
+
'HOMEDRIVE',
|
|
144
|
+
'HOMEPATH',
|
|
145
|
+
'SystemRoot',
|
|
146
|
+
'ComSpec',
|
|
147
|
+
'APPDATA',
|
|
148
|
+
'LOCALAPPDATA',
|
|
149
|
+
];
|
|
150
|
+
/** Build an allowlisted env for the Cursor Agent subprocess (no API keys or unrelated secrets). */
|
|
151
|
+
export function subprocessEnv() {
|
|
152
|
+
const env = {};
|
|
153
|
+
for (const key of CURSOR_SUBPROCESS_ENV_KEYS) {
|
|
154
|
+
const value = process.env[key];
|
|
155
|
+
if (value !== undefined)
|
|
156
|
+
env[key] = value;
|
|
157
|
+
}
|
|
158
|
+
return env;
|
|
159
|
+
}
|
|
160
|
+
/** Parse `--print --output-format json` stdout into assistant text and session id. */
|
|
161
|
+
export function parseCursorStdout(stdout) {
|
|
162
|
+
const trimmed = stdout.trim();
|
|
163
|
+
let text = '';
|
|
164
|
+
let sessionId;
|
|
165
|
+
let sawResult = false;
|
|
166
|
+
// Prefer a single pretty-printed JSON object (whole buffer) before NDJSON lines.
|
|
167
|
+
if (trimmed) {
|
|
168
|
+
try {
|
|
169
|
+
const whole = JSON.parse(trimmed);
|
|
170
|
+
const extracted = extractResultFields(whole);
|
|
171
|
+
if (extracted) {
|
|
172
|
+
return {
|
|
173
|
+
text: extracted.text,
|
|
174
|
+
sessionId: extracted.sessionId,
|
|
175
|
+
usage: { inputTokens: 0, outputTokens: 0 },
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
if (isCursorHardFail(err))
|
|
181
|
+
throw err;
|
|
182
|
+
// fall through to line-based parse
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const lines = trimmed
|
|
186
|
+
.split('\n')
|
|
187
|
+
.map((l) => l.trim())
|
|
188
|
+
.filter(Boolean);
|
|
189
|
+
for (const line of lines) {
|
|
190
|
+
let obj;
|
|
191
|
+
try {
|
|
192
|
+
obj = JSON.parse(line);
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
const extracted = extractResultFields(obj);
|
|
198
|
+
if (extracted) {
|
|
199
|
+
text = extracted.text;
|
|
200
|
+
sessionId = extracted.sessionId ?? sessionId;
|
|
201
|
+
sawResult = true;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (!sawResult && !text && lines.length) {
|
|
205
|
+
// Fallback: last parseable JSON line with a string result field
|
|
206
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
207
|
+
try {
|
|
208
|
+
const obj = JSON.parse(lines[i]);
|
|
209
|
+
if (typeof obj.result === 'string') {
|
|
210
|
+
assertNoNativeMutation(obj);
|
|
211
|
+
text = obj.result;
|
|
212
|
+
if (typeof obj.session_id === 'string')
|
|
213
|
+
sessionId = obj.session_id;
|
|
214
|
+
sawResult = true;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
if (isCursorHardFail(err))
|
|
220
|
+
throw err;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (!sawResult && trimmed) {
|
|
226
|
+
throw new Error(`cursor: could not parse Cursor Agent output as JSON — raw stdout: ${trimmed.slice(0, 500)}`);
|
|
227
|
+
}
|
|
228
|
+
// Official Cursor JSON schema does not expose token usage; callers see zeros.
|
|
229
|
+
return { text, sessionId, usage: { inputTokens: 0, outputTokens: 0 } };
|
|
230
|
+
}
|
|
231
|
+
function extractResultFields(obj) {
|
|
232
|
+
assertNoNativeMutation(obj);
|
|
233
|
+
const type = typeof obj.type === 'string' ? obj.type.toLowerCase() : '';
|
|
234
|
+
if (type === 'result' || typeof obj.result === 'string') {
|
|
235
|
+
if (obj.is_error === true) {
|
|
236
|
+
throw new Error(typeof obj.result === 'string' ? obj.result : 'Cursor Agent returned an error result');
|
|
237
|
+
}
|
|
238
|
+
if (typeof obj.result === 'string') {
|
|
239
|
+
return {
|
|
240
|
+
text: obj.result,
|
|
241
|
+
...(typeof obj.session_id === 'string' ? { sessionId: obj.session_id } : {}),
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
function isCursorHardFail(err) {
|
|
248
|
+
return (err instanceof Error &&
|
|
249
|
+
(err.message.includes('reasoning-only invariant') ||
|
|
250
|
+
err.message.includes('Cursor Agent returned an error') ||
|
|
251
|
+
err.message.startsWith('cursor:')));
|
|
252
|
+
}
|
|
253
|
+
function assertNoNativeMutation(obj) {
|
|
254
|
+
const type = typeof obj.type === 'string' ? obj.type.toLowerCase() : '';
|
|
255
|
+
if (NATIVE_MUTATION_TYPES.has(type)) {
|
|
256
|
+
throw new Error(`cursor: Cursor Agent emitted native tool event "${obj.type}" — reasoning-only invariant violated. Refusing to continue.`);
|
|
257
|
+
}
|
|
258
|
+
const subtype = typeof obj.subtype === 'string' ? obj.subtype.toLowerCase() : '';
|
|
259
|
+
if (subtype && NATIVE_SUBTYPE_RE.test(subtype) && type !== 'result') {
|
|
260
|
+
throw new Error(`cursor: Cursor Agent output subtype "${obj.subtype}" (line type "${obj.type ?? ''}") suggests native execution — reasoning-only invariant violated.`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/** Default subprocess runner: invokes `agent` (or `COPPERHEAD_CURSOR_PATH`) in plan mode. */
|
|
264
|
+
export async function defaultCursorRun(args) {
|
|
265
|
+
const bin = process.env.COPPERHEAD_CURSOR_PATH || 'agent';
|
|
266
|
+
const fullPrompt = [args.systemPrompt, args.prompt].filter(Boolean).join('\n\n---\n\n');
|
|
267
|
+
// Prompt goes on stdin — a single argv element caps at ~128 KiB on Linux
|
|
268
|
+
// (MAX_ARG_STRLEN); real .kicad_pcb reads routinely exceed that.
|
|
269
|
+
const cmdArgs = [
|
|
270
|
+
'--print',
|
|
271
|
+
'--output-format',
|
|
272
|
+
'json',
|
|
273
|
+
'--mode',
|
|
274
|
+
'plan',
|
|
275
|
+
'--trust',
|
|
276
|
+
'--sandbox',
|
|
277
|
+
'enabled',
|
|
278
|
+
'--workspace',
|
|
279
|
+
args.workspace,
|
|
280
|
+
];
|
|
281
|
+
if (args.model)
|
|
282
|
+
cmdArgs.push('--model', args.model);
|
|
283
|
+
if (args.resume)
|
|
284
|
+
cmdArgs.push('--resume', args.resume);
|
|
285
|
+
const { stdout } = await execa(bin, cmdArgs, {
|
|
286
|
+
input: fullPrompt,
|
|
287
|
+
env: args.env ?? subprocessEnv(),
|
|
288
|
+
cancelSignal: args.signal,
|
|
289
|
+
reject: true,
|
|
290
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
291
|
+
});
|
|
292
|
+
return parseCursorStdout(stdout);
|
|
293
|
+
}
|
|
294
|
+
function isAuthError(err) {
|
|
295
|
+
// Subprocess failures use exitCode, not HTTP status. Only treat real HTTP
|
|
296
|
+
// status fields as 401/403; otherwise match the CLI's auth message.
|
|
297
|
+
const status = err?.status ??
|
|
298
|
+
err?.statusCode;
|
|
299
|
+
if (status === 401 || status === 403)
|
|
300
|
+
return true;
|
|
301
|
+
const m = (err?.message ?? '').toLowerCase();
|
|
302
|
+
return /unauthenticat|unauthoriz|not logged in|please log in|login required|agent login/.test(m);
|
|
303
|
+
}
|
|
304
|
+
function authHint(detail) {
|
|
305
|
+
return ('cursor is not authenticated: run `agent login` and verify with `agent status`. ' +
|
|
306
|
+
`Set COPPERHEAD_CURSOR_PATH if the CLI is not on PATH (original error: ${detail})`);
|
|
307
|
+
}
|
|
308
|
+
function enhanceCliError(err) {
|
|
309
|
+
const original = err;
|
|
310
|
+
if (original.code === 'ENOENT') {
|
|
311
|
+
return new Error('Cursor Agent CLI not found on PATH. Install Cursor Agent or set COPPERHEAD_CURSOR_PATH to the `agent` binary.', { cause: err });
|
|
312
|
+
}
|
|
313
|
+
if (original.message?.includes('reasoning-only invariant'))
|
|
314
|
+
return original;
|
|
315
|
+
return new Error(`Cursor CLI provider failed: ${original.message}`, { cause: err });
|
|
316
|
+
}
|
|
317
|
+
//# sourceMappingURL=cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../../src/agent/providers/cursor.ts"],"names":[],"mappings":"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"}
|