@sideboard-ai/core 0.1.294 → 0.1.296
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/dist/agents/claude-runner.cjs +55 -0
- package/dist/agents/claude-runner.js +57 -1
- package/dist/agents/cursor-runner.cjs +128 -50
- package/dist/agents/cursor-runner.js +63 -44
- package/dist/{agents-2PDBDZPS.js → agents-DZTPUKVF.js} +5 -5
- package/dist/{agents-73JXQXF2.js → agents-ICHYDSCD.js} +8 -8
- package/dist/{chunk-SVQTKVXH.js → chunk-2O3ICR77.js} +4 -4
- package/dist/{chunk-YKO6HG74.js → chunk-67BWWLEB.js} +6 -6
- package/dist/{chunk-JEYJGQ33.js → chunk-6GTABVNG.js} +7 -7
- package/dist/{chunk-YEIPPZ5W.js → chunk-BGEECLKH.js} +2 -2
- package/dist/{chunk-AFLNFGGB.js → chunk-ED4ZXQVO.js} +1 -0
- package/dist/{chunk-MIVX7QKI.js → chunk-HO5R3ZRH.js} +1 -0
- package/dist/{chunk-7UUILVMV.js → chunk-IOY2LF3Y.js} +1 -1
- package/dist/{chunk-K6IOJI3L.js → chunk-J54UPHXZ.js} +71 -2
- package/dist/{chunk-ZEP6JIRF.js → chunk-JWXJXEA3.js} +1 -1
- package/dist/{chunk-YSLCWCMJ.js → chunk-Q3DPZ4DE.js} +1 -1
- package/dist/{chunk-NYBFYFK7.js → chunk-QDA6NXRA.js} +1 -0
- package/dist/{chunk-CECZUHA5.js → chunk-QT36F4TD.js} +55 -26
- package/dist/{chunk-YRXV3E7J.js → chunk-TVN4TDFB.js} +9 -0
- package/dist/{chunk-6SGYGYH7.js → chunk-VXNZG4J6.js} +1 -1
- package/dist/{chunk-BYAFYLLZ.js → chunk-W2A63ZOK.js} +179 -42
- package/dist/{chunk-E7G7RY6T.js → chunk-WQREAX35.js} +2 -2
- package/dist/{chunk-QB5MDOHL.js → chunk-WZLV4WNS.js} +9 -0
- package/dist/{chunk-BJUHZSZQ.js → chunk-ZXWRNA4G.js} +5 -5
- package/dist/{conductor-7DEMFEIO.js → conductor-HJFDYIZD.js} +5 -5
- package/dist/{conductor-ZQZTYXSX.js → conductor-ZXDIA6OF.js} +6 -6
- package/dist/{coordinator-prompt-AROMFCP2.js → coordinator-prompt-ILHSVPOG.js} +3 -3
- package/dist/{coordinator-prompt-K6XHUG3N.js → coordinator-prompt-L3V2CMWX.js} +3 -3
- package/dist/{global-workspace-4WAU4PAL.js → global-workspace-47G453ZU.js} +3 -3
- package/dist/{global-workspace-PX4GUVLW.js → global-workspace-NMRUGGFF.js} +3 -3
- package/dist/index.cjs +1039 -700
- package/dist/index.d.cts +25 -4
- package/dist/index.d.ts +25 -4
- package/dist/index.js +299 -125
- package/dist/mcp/run-stdio.cjs +250 -144
- package/dist/mcp/run-stdio.js +70 -11
- package/dist/{orchestrator-LIEGSQ6M.js → orchestrator-MR7TCIPP.js} +7 -7
- package/dist/{orchestrator-YNEEEP6O.js → orchestrator-ZQU62CES.js} +10 -10
- package/dist/{thread-store-DPKESDFR.js → thread-store-H6D6MDUM.js} +1 -1
- package/dist/{thread-store-X6S2GIR5.js → thread-store-SADLLKRE.js} +1 -1
- package/dist/{workspaces-MFU3IGAP.js → workspaces-PGY4UWZ3.js} +3 -3
- package/dist/{workspaces-U7SSD27C.js → workspaces-WGZPRQJX.js} +3 -3
- package/dist/{worktree-TQKASYPZ.js → worktree-3MF5J5XZ.js} +2 -2
- package/dist/{worktree-2VSHRI72.js → worktree-JZXDAKQF.js} +2 -2
- package/package.json +1 -1
|
@@ -384,6 +384,53 @@ function createClaudePilotSdkServer(createSdkMcpServer, tool, opts) {
|
|
|
384
384
|
return { server, exec };
|
|
385
385
|
}
|
|
386
386
|
|
|
387
|
+
// src/agents/claude-permission.ts
|
|
388
|
+
function deny(message) {
|
|
389
|
+
return { behavior: "deny", message, decisionClassification: "user_reject" };
|
|
390
|
+
}
|
|
391
|
+
function fromAnswer(raw) {
|
|
392
|
+
if (!raw || typeof raw !== "object") return deny("Sideboard did not return a permission decision.");
|
|
393
|
+
const rec = raw;
|
|
394
|
+
if (rec.behavior === "allow") {
|
|
395
|
+
return {
|
|
396
|
+
behavior: "allow",
|
|
397
|
+
...Array.isArray(rec.updatedPermissions) && rec.updatedPermissions.length > 0 ? { updatedPermissions: rec.updatedPermissions } : {},
|
|
398
|
+
decisionClassification: rec.decisionClassification === "user_permanent" ? "user_permanent" : "user_temporary"
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
const message = typeof rec.message === "string" && rec.message.trim() ? rec.message.trim() : "The user denied this action.";
|
|
402
|
+
return deny(message);
|
|
403
|
+
}
|
|
404
|
+
async function claudePermissionResult(input) {
|
|
405
|
+
if (input.permissionMode === "plan") {
|
|
406
|
+
return deny("Plan mode is on, so this action stays blocked.");
|
|
407
|
+
}
|
|
408
|
+
const threadId = input.threadId.trim();
|
|
409
|
+
if (!threadId) return deny("Sideboard could not tell which chat to ask.");
|
|
410
|
+
if (input.options.signal?.aborted) return deny("The turn was cancelled.");
|
|
411
|
+
const call = input.call ?? (input.rpc ? (method, params) => new AgentRpcClient(input.rpc).call(method, params) : null);
|
|
412
|
+
if (!call) return deny("Sideboard has no permission prompt for this turn.");
|
|
413
|
+
try {
|
|
414
|
+
const raw = await call("permission.ask", {
|
|
415
|
+
threadId,
|
|
416
|
+
toolName: input.toolName,
|
|
417
|
+
input: input.toolInput,
|
|
418
|
+
blockedPath: input.options.blockedPath,
|
|
419
|
+
title: input.options.title,
|
|
420
|
+
description: input.options.description,
|
|
421
|
+
displayName: input.options.displayName,
|
|
422
|
+
suggestions: input.options.suggestions,
|
|
423
|
+
suppressAlwaysAllow: input.options.suppressAlwaysAllowRule === true,
|
|
424
|
+
defaultToNo: input.options.defaultToNo === true
|
|
425
|
+
});
|
|
426
|
+
if (input.options.signal?.aborted) return deny("The turn was cancelled.");
|
|
427
|
+
return fromAnswer(raw);
|
|
428
|
+
} catch (err) {
|
|
429
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
430
|
+
return deny(message || "Sideboard could not ask for permission.");
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
387
434
|
// src/agents/claude-runner.ts
|
|
388
435
|
dropNestedElectronEnvFromProcess();
|
|
389
436
|
function emit(value) {
|
|
@@ -446,6 +493,14 @@ async function main() {
|
|
|
446
493
|
if (req.systemPrompt) options.appendSystemPrompt = req.systemPrompt;
|
|
447
494
|
if (req.effort) options.effort = req.effort;
|
|
448
495
|
if (req.chrome) options.chrome = true;
|
|
496
|
+
options.canUseTool = (toolName, toolInput, toolOpts) => claudePermissionResult({
|
|
497
|
+
permissionMode: req.permissionMode,
|
|
498
|
+
threadId: process.env.SIDEBOARD_THREAD_ID?.trim() || "",
|
|
499
|
+
toolName,
|
|
500
|
+
toolInput,
|
|
501
|
+
options: toolOpts,
|
|
502
|
+
rpc: req.agentRpc
|
|
503
|
+
});
|
|
449
504
|
options.settingSources = [];
|
|
450
505
|
for await (const message of sdk.query({ prompt: req.prompt, options })) {
|
|
451
506
|
emit(message);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
AGENT_RPC_CLAUDE_SDK_SERVER,
|
|
4
|
+
AgentRpcClient,
|
|
4
5
|
PILOT_TOOL_DESCRIPTIONS,
|
|
5
6
|
createPilotRpcExecutors
|
|
6
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-QDA6NXRA.js";
|
|
7
8
|
import {
|
|
8
9
|
dropNestedElectronEnvFromProcess
|
|
9
10
|
} from "../chunk-4TR3HZFT.js";
|
|
@@ -55,6 +56,53 @@ function createClaudePilotSdkServer(createSdkMcpServer, tool, opts) {
|
|
|
55
56
|
return { server, exec };
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
// src/agents/claude-permission.ts
|
|
60
|
+
function deny(message) {
|
|
61
|
+
return { behavior: "deny", message, decisionClassification: "user_reject" };
|
|
62
|
+
}
|
|
63
|
+
function fromAnswer(raw) {
|
|
64
|
+
if (!raw || typeof raw !== "object") return deny("Sideboard did not return a permission decision.");
|
|
65
|
+
const rec = raw;
|
|
66
|
+
if (rec.behavior === "allow") {
|
|
67
|
+
return {
|
|
68
|
+
behavior: "allow",
|
|
69
|
+
...Array.isArray(rec.updatedPermissions) && rec.updatedPermissions.length > 0 ? { updatedPermissions: rec.updatedPermissions } : {},
|
|
70
|
+
decisionClassification: rec.decisionClassification === "user_permanent" ? "user_permanent" : "user_temporary"
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const message = typeof rec.message === "string" && rec.message.trim() ? rec.message.trim() : "The user denied this action.";
|
|
74
|
+
return deny(message);
|
|
75
|
+
}
|
|
76
|
+
async function claudePermissionResult(input) {
|
|
77
|
+
if (input.permissionMode === "plan") {
|
|
78
|
+
return deny("Plan mode is on, so this action stays blocked.");
|
|
79
|
+
}
|
|
80
|
+
const threadId = input.threadId.trim();
|
|
81
|
+
if (!threadId) return deny("Sideboard could not tell which chat to ask.");
|
|
82
|
+
if (input.options.signal?.aborted) return deny("The turn was cancelled.");
|
|
83
|
+
const call = input.call ?? (input.rpc ? (method, params) => new AgentRpcClient(input.rpc).call(method, params) : null);
|
|
84
|
+
if (!call) return deny("Sideboard has no permission prompt for this turn.");
|
|
85
|
+
try {
|
|
86
|
+
const raw = await call("permission.ask", {
|
|
87
|
+
threadId,
|
|
88
|
+
toolName: input.toolName,
|
|
89
|
+
input: input.toolInput,
|
|
90
|
+
blockedPath: input.options.blockedPath,
|
|
91
|
+
title: input.options.title,
|
|
92
|
+
description: input.options.description,
|
|
93
|
+
displayName: input.options.displayName,
|
|
94
|
+
suggestions: input.options.suggestions,
|
|
95
|
+
suppressAlwaysAllow: input.options.suppressAlwaysAllowRule === true,
|
|
96
|
+
defaultToNo: input.options.defaultToNo === true
|
|
97
|
+
});
|
|
98
|
+
if (input.options.signal?.aborted) return deny("The turn was cancelled.");
|
|
99
|
+
return fromAnswer(raw);
|
|
100
|
+
} catch (err) {
|
|
101
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
102
|
+
return deny(message || "Sideboard could not ask for permission.");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
58
106
|
// src/agents/claude-runner.ts
|
|
59
107
|
dropNestedElectronEnvFromProcess();
|
|
60
108
|
function emit(value) {
|
|
@@ -117,6 +165,14 @@ async function main() {
|
|
|
117
165
|
if (req.systemPrompt) options.appendSystemPrompt = req.systemPrompt;
|
|
118
166
|
if (req.effort) options.effort = req.effort;
|
|
119
167
|
if (req.chrome) options.chrome = true;
|
|
168
|
+
options.canUseTool = (toolName, toolInput, toolOpts) => claudePermissionResult({
|
|
169
|
+
permissionMode: req.permissionMode,
|
|
170
|
+
threadId: process.env.SIDEBOARD_THREAD_ID?.trim() || "",
|
|
171
|
+
toolName,
|
|
172
|
+
toolInput,
|
|
173
|
+
options: toolOpts,
|
|
174
|
+
rpc: req.agentRpc
|
|
175
|
+
});
|
|
120
176
|
options.settingSources = [];
|
|
121
177
|
for await (const message of sdk.query({ prompt: req.prompt, options })) {
|
|
122
178
|
emit(message);
|
|
@@ -1402,6 +1402,113 @@ function clipAgentEventForEmit(event, cwd) {
|
|
|
1402
1402
|
return event;
|
|
1403
1403
|
}
|
|
1404
1404
|
|
|
1405
|
+
// src/agents/cursor-tool-guard.ts
|
|
1406
|
+
var CURSOR_TOOL_RECOVERY_HINT = "Continue with a smaller request. If you were reading a large file or API payload, pass offset and limit or write the output to .context/cli/ and read a slice. Do not retry the same call.";
|
|
1407
|
+
function cursorToolErrorText(err) {
|
|
1408
|
+
const raw = formatUnknownDetail(err).replace(/\s+/g, " ").trim();
|
|
1409
|
+
const message = looksLikeHugeToolResultDump(raw) ? HUGE_TOOL_RESULT_SUMMARY : (raw || "unknown tool error").slice(0, 500);
|
|
1410
|
+
return `Error: ${message}
|
|
1411
|
+
${CURSOR_TOOL_RECOVERY_HINT}`;
|
|
1412
|
+
}
|
|
1413
|
+
function cursorToolErrorResult(err) {
|
|
1414
|
+
return {
|
|
1415
|
+
isError: true,
|
|
1416
|
+
content: [{ type: "text", text: cursorToolErrorText(err) }]
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
function boundedCursorToolResult(result, opts) {
|
|
1420
|
+
const prefix = opts?.name ?? "cursor-tool";
|
|
1421
|
+
if (typeof result === "string") {
|
|
1422
|
+
return spillAndClipToolResult(result, { cwd: opts?.cwd, prefix });
|
|
1423
|
+
}
|
|
1424
|
+
if (result == null) {
|
|
1425
|
+
return cursorToolErrorText(new Error("tool returned no result"));
|
|
1426
|
+
}
|
|
1427
|
+
let json;
|
|
1428
|
+
try {
|
|
1429
|
+
json = JSON.stringify(result);
|
|
1430
|
+
} catch (err) {
|
|
1431
|
+
return cursorToolErrorText(err);
|
|
1432
|
+
}
|
|
1433
|
+
return spillAndClipToolResult(json, { cwd: opts?.cwd, prefix });
|
|
1434
|
+
}
|
|
1435
|
+
function guardCursorCustomTool(tool, opts) {
|
|
1436
|
+
const execute = tool.execute.bind(tool);
|
|
1437
|
+
return {
|
|
1438
|
+
...tool,
|
|
1439
|
+
execute: async (args, context) => {
|
|
1440
|
+
try {
|
|
1441
|
+
const result = await execute(args, context);
|
|
1442
|
+
return boundedCursorToolResult(result, opts);
|
|
1443
|
+
} catch (err) {
|
|
1444
|
+
return cursorToolErrorResult(err);
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
var NON_RECOVERABLE_RUN_ERROR = /invalid (?:user )?api key|not logged in|not authenticated|unauthorized|credit balance|out of credits|insufficient.?quota|usage limit|you've hit your|too many requests|rate.?limit/;
|
|
1450
|
+
function shouldReturnRunErrorToAgent(detail) {
|
|
1451
|
+
const text = detail.trim();
|
|
1452
|
+
if (!text) return false;
|
|
1453
|
+
if (looksLikeHugeToolResultDump(text) || looksLikeCursorStreamCutOff(text)) return true;
|
|
1454
|
+
const head = text.slice(0, 2e3).toLowerCase();
|
|
1455
|
+
if (NON_RECOVERABLE_RUN_ERROR.test(head)) return false;
|
|
1456
|
+
return true;
|
|
1457
|
+
}
|
|
1458
|
+
function cursorRunErrorRecoveryPrompt(detail) {
|
|
1459
|
+
const summary = looksLikeHugeToolResultDump(detail) ? HUGE_TOOL_RESULT_SUMMARY : detail.replace(/\s+/g, " ").trim().slice(0, 400);
|
|
1460
|
+
return [
|
|
1461
|
+
"A tool call failed before its result reached you. The session is still open.",
|
|
1462
|
+
`Error: ${summary || "unknown"}`,
|
|
1463
|
+
CURSOR_TOOL_RECOVERY_HINT
|
|
1464
|
+
].join("\n");
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
// src/agents/cursor-stale-runs.ts
|
|
1468
|
+
async function cancelStaleCursorRuns(Agent, agentId, opts) {
|
|
1469
|
+
let cancelled = 0;
|
|
1470
|
+
const listed = await Agent.listRuns(agentId, {
|
|
1471
|
+
runtime: "local",
|
|
1472
|
+
cwd: opts.cwd,
|
|
1473
|
+
store: opts.store,
|
|
1474
|
+
limit: 20
|
|
1475
|
+
});
|
|
1476
|
+
for (const run2 of listed.items) {
|
|
1477
|
+
if (run2.status !== "running") continue;
|
|
1478
|
+
try {
|
|
1479
|
+
await Agent.cancelRun(run2.id, {
|
|
1480
|
+
runtime: "local",
|
|
1481
|
+
cwd: opts.cwd,
|
|
1482
|
+
store: opts.store
|
|
1483
|
+
});
|
|
1484
|
+
cancelled += 1;
|
|
1485
|
+
} catch {
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
if (cancelled > 0 || !opts.apiKey) return cancelled;
|
|
1489
|
+
try {
|
|
1490
|
+
const cloud = await Agent.listRuns(agentId, {
|
|
1491
|
+
runtime: "cloud",
|
|
1492
|
+
apiKey: opts.apiKey,
|
|
1493
|
+
limit: 20
|
|
1494
|
+
});
|
|
1495
|
+
for (const run2 of cloud.items) {
|
|
1496
|
+
if (run2.status !== "running") continue;
|
|
1497
|
+
try {
|
|
1498
|
+
await Agent.cancelRun(run2.id, {
|
|
1499
|
+
runtime: "cloud",
|
|
1500
|
+
agentId,
|
|
1501
|
+
apiKey: opts.apiKey
|
|
1502
|
+
});
|
|
1503
|
+
cancelled += 1;
|
|
1504
|
+
} catch {
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
} catch {
|
|
1508
|
+
}
|
|
1509
|
+
return cancelled;
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1405
1512
|
// src/agents/cursor-events.ts
|
|
1406
1513
|
function usageFromCursor(usage) {
|
|
1407
1514
|
if (!usage) return null;
|
|
@@ -1784,49 +1891,6 @@ function localAgentStore(Store, threadId) {
|
|
|
1784
1891
|
(0, import_node_fs18.mkdirSync)(root, { recursive: true });
|
|
1785
1892
|
return new Store(root);
|
|
1786
1893
|
}
|
|
1787
|
-
async function cancelStaleRuns(Agent, agentId, opts) {
|
|
1788
|
-
let cancelled = 0;
|
|
1789
|
-
const listed = await Agent.listRuns(agentId, {
|
|
1790
|
-
runtime: "local",
|
|
1791
|
-
cwd: opts.cwd,
|
|
1792
|
-
store: opts.store,
|
|
1793
|
-
limit: 20
|
|
1794
|
-
});
|
|
1795
|
-
for (const run2 of listed.items) {
|
|
1796
|
-
if (run2.status !== "running") continue;
|
|
1797
|
-
try {
|
|
1798
|
-
await Agent.cancelRun(run2.id, {
|
|
1799
|
-
runtime: "local",
|
|
1800
|
-
cwd: opts.cwd,
|
|
1801
|
-
store: opts.store
|
|
1802
|
-
});
|
|
1803
|
-
cancelled += 1;
|
|
1804
|
-
} catch {
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
if (cancelled > 0 || !opts.apiKey) return cancelled;
|
|
1808
|
-
try {
|
|
1809
|
-
const cloud = await Agent.listRuns(agentId, {
|
|
1810
|
-
runtime: "cloud",
|
|
1811
|
-
apiKey: opts.apiKey,
|
|
1812
|
-
limit: 20
|
|
1813
|
-
});
|
|
1814
|
-
for (const run2 of cloud.items) {
|
|
1815
|
-
if (run2.status !== "running") continue;
|
|
1816
|
-
try {
|
|
1817
|
-
await Agent.cancelRun(run2.id, {
|
|
1818
|
-
runtime: "cloud",
|
|
1819
|
-
agentId,
|
|
1820
|
-
apiKey: opts.apiKey
|
|
1821
|
-
});
|
|
1822
|
-
cancelled += 1;
|
|
1823
|
-
} catch {
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
} catch {
|
|
1827
|
-
}
|
|
1828
|
-
return cancelled;
|
|
1829
|
-
}
|
|
1830
1894
|
async function readStdinJson() {
|
|
1831
1895
|
const rl = (0, import_node_readline2.createInterface)({ input: process.stdin, crlfDelay: Infinity });
|
|
1832
1896
|
const chunks = [];
|
|
@@ -1896,10 +1960,16 @@ async function main() {
|
|
|
1896
1960
|
}
|
|
1897
1961
|
}
|
|
1898
1962
|
}) : {};
|
|
1899
|
-
const
|
|
1963
|
+
const rawCustomTools = {
|
|
1900
1964
|
read: slicedReadCustomToolConfig(req.cwd),
|
|
1901
1965
|
...rpcTools
|
|
1902
1966
|
};
|
|
1967
|
+
const customTools = Object.fromEntries(
|
|
1968
|
+
Object.entries(rawCustomTools).map(([name, tool]) => [
|
|
1969
|
+
name,
|
|
1970
|
+
guardCursorCustomTool(tool, { cwd: req.cwd, name })
|
|
1971
|
+
])
|
|
1972
|
+
);
|
|
1903
1973
|
const local = withCursorLocalHangGuards({
|
|
1904
1974
|
cwd: req.cwd,
|
|
1905
1975
|
store,
|
|
@@ -1946,7 +2016,7 @@ async function main() {
|
|
|
1946
2016
|
}
|
|
1947
2017
|
}
|
|
1948
2018
|
async function retryAfterBusy(agent) {
|
|
1949
|
-
const n = await
|
|
2019
|
+
const n = await cancelStaleCursorRuns(Agent, agent.agentId, {
|
|
1950
2020
|
cwd: req.cwd,
|
|
1951
2021
|
store,
|
|
1952
2022
|
...apiKey ? { apiKey } : {}
|
|
@@ -1959,17 +2029,17 @@ async function main() {
|
|
|
1959
2029
|
await new Promise((resolve2) => setTimeout(resolve2, CURSOR_BUSY_RETRY_DELAY_MS));
|
|
1960
2030
|
}
|
|
1961
2031
|
}
|
|
1962
|
-
async function sendPrompt(agent, extra) {
|
|
2032
|
+
async function sendPrompt(agent, prompt, extra) {
|
|
1963
2033
|
const sendOpts = {
|
|
1964
2034
|
...cursorSendOptions(mcpServers),
|
|
1965
2035
|
...extra
|
|
1966
2036
|
};
|
|
1967
2037
|
try {
|
|
1968
|
-
return await retryTransport(() => agent.send(
|
|
2038
|
+
return await retryTransport(() => agent.send(prompt, sendOpts));
|
|
1969
2039
|
} catch (err) {
|
|
1970
2040
|
if (!isAgentBusyError(err)) throw err;
|
|
1971
2041
|
await retryAfterBusy(agent);
|
|
1972
|
-
return retryTransport(() => agent.send(
|
|
2042
|
+
return retryTransport(() => agent.send(prompt, sendOpts));
|
|
1973
2043
|
}
|
|
1974
2044
|
}
|
|
1975
2045
|
let liveRun = null;
|
|
@@ -1997,7 +2067,7 @@ async function main() {
|
|
|
1997
2067
|
};
|
|
1998
2068
|
process.once("SIGTERM", onSignal);
|
|
1999
2069
|
process.once("SIGINT", onSignal);
|
|
2000
|
-
async function runTurn(agent) {
|
|
2070
|
+
async function runTurn(agent, prompt = req.prompt, recoveryLeft = 1) {
|
|
2001
2071
|
emit({ type: "session_id", data: agent.agentId });
|
|
2002
2072
|
const stream = createAgentStreamCoalescer(emit);
|
|
2003
2073
|
const activity = { at: Date.now() };
|
|
@@ -2011,7 +2081,7 @@ async function main() {
|
|
|
2011
2081
|
} catch {
|
|
2012
2082
|
}
|
|
2013
2083
|
let lastUsageRunId;
|
|
2014
|
-
const run2 = await sendPrompt(agent, {
|
|
2084
|
+
const run2 = await sendPrompt(agent, prompt, {
|
|
2015
2085
|
onDelta: ({ update }) => {
|
|
2016
2086
|
bump();
|
|
2017
2087
|
for (const event of cursorDeltaToEvents(update)) {
|
|
@@ -2056,6 +2126,14 @@ async function main() {
|
|
|
2056
2126
|
if (isAgentBusyError(detail)) {
|
|
2057
2127
|
throw Object.assign(new Error(detail || "agent still running"), { name: "AgentBusyError" });
|
|
2058
2128
|
}
|
|
2129
|
+
if (recoveryLeft > 0 && shouldReturnRunErrorToAgent(detail)) {
|
|
2130
|
+
const brief = detail.replace(/\s+/g, " ").trim().slice(0, 240);
|
|
2131
|
+
emit({
|
|
2132
|
+
type: "stderr",
|
|
2133
|
+
data: `Cursor tool error \u2014 handing it back to the agent (${brief})`
|
|
2134
|
+
});
|
|
2135
|
+
return runTurn(agent, cursorRunErrorRecoveryPrompt(detail), 0);
|
|
2136
|
+
}
|
|
2059
2137
|
emit({
|
|
2060
2138
|
type: "stderr",
|
|
2061
2139
|
data: detail ? `Cursor run failed (${result.id}): ${detail}` : `Cursor run failed (${result.id})`
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
clipAgentEventForEmit,
|
|
4
|
+
cursorRunErrorRecoveryPrompt,
|
|
5
|
+
guardCursorCustomTool,
|
|
6
|
+
shouldReturnRunErrorToAgent,
|
|
4
7
|
sideboardCursorRpcTools
|
|
5
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-J54UPHXZ.js";
|
|
6
9
|
import {
|
|
7
10
|
createAgentStreamCoalescer
|
|
8
11
|
} from "../chunk-AXQ4ZWHK.js";
|
|
@@ -17,18 +20,18 @@ import {
|
|
|
17
20
|
fetchCursorTurnCostUsd,
|
|
18
21
|
importCursorSdk,
|
|
19
22
|
resolveCursorSdkRoot
|
|
20
|
-
} from "../chunk-
|
|
23
|
+
} from "../chunk-IOY2LF3Y.js";
|
|
21
24
|
import {
|
|
22
25
|
TOOL_RESULT_STORE_MAX_CHARS,
|
|
23
26
|
formatUnknownDetail,
|
|
24
27
|
looksLikeCursorStreamCutOff
|
|
25
|
-
} from "../chunk-
|
|
28
|
+
} from "../chunk-HO5R3ZRH.js";
|
|
26
29
|
import "../chunk-6K64FJDD.js";
|
|
27
30
|
import {
|
|
28
31
|
cursorSdkStoreDir
|
|
29
32
|
} from "../chunk-UWQ6UCIB.js";
|
|
30
33
|
import "../chunk-QVN2WOKJ.js";
|
|
31
|
-
import "../chunk-
|
|
34
|
+
import "../chunk-QDA6NXRA.js";
|
|
32
35
|
import {
|
|
33
36
|
dropNestedElectronEnvFromProcess
|
|
34
37
|
} from "../chunk-4TR3HZFT.js";
|
|
@@ -559,39 +562,8 @@ function slicedReadCustomToolConfig(cwd) {
|
|
|
559
562
|
};
|
|
560
563
|
}
|
|
561
564
|
|
|
562
|
-
// src/agents/cursor-
|
|
563
|
-
function
|
|
564
|
-
const raw = model && model.trim() || "";
|
|
565
|
-
const id = !raw || raw.toLowerCase() === "auto" || raw.toLowerCase() === "default" ? "default" : raw;
|
|
566
|
-
const isGrok47 = /^grok-4\.7(?:$|-)/i.test(id);
|
|
567
|
-
const params = [];
|
|
568
|
-
if (isGrok47) {
|
|
569
|
-
params.push({ id: "context", value: "256k" });
|
|
570
|
-
}
|
|
571
|
-
const effort = (opts.effort ?? "").trim().toLowerCase();
|
|
572
|
-
const normalized = effort === "normal" ? "medium" : effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" || effort === "max" ? effort : "";
|
|
573
|
-
if (normalized) {
|
|
574
|
-
params.push({
|
|
575
|
-
id: isGrok47 ? "reasoning_effort" : "effort",
|
|
576
|
-
value: isGrok47 && normalized === "max" ? "xhigh" : normalized
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
params.push({ id: "fast", value: opts.fast ? "true" : "false" });
|
|
580
|
-
return { id, params };
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
// src/agents/cursor-runner.ts
|
|
584
|
-
dropNestedElectronEnvFromProcess();
|
|
585
|
-
function emit(event) {
|
|
586
|
-
process.stdout.write(`${JSON.stringify(clipAgentEventForEmit(event, process.cwd()))}
|
|
587
|
-
`);
|
|
588
|
-
}
|
|
589
|
-
function localAgentStore(Store, threadId) {
|
|
590
|
-
const root = cursorSdkStoreDir(threadId);
|
|
591
|
-
mkdirSync2(root, { recursive: true });
|
|
592
|
-
return new Store(root);
|
|
593
|
-
}
|
|
594
|
-
async function cancelStaleRuns(Agent, agentId, opts) {
|
|
565
|
+
// src/agents/cursor-stale-runs.ts
|
|
566
|
+
async function cancelStaleCursorRuns(Agent, agentId, opts) {
|
|
595
567
|
let cancelled = 0;
|
|
596
568
|
const listed = await Agent.listRuns(agentId, {
|
|
597
569
|
runtime: "local",
|
|
@@ -634,6 +606,39 @@ async function cancelStaleRuns(Agent, agentId, opts) {
|
|
|
634
606
|
}
|
|
635
607
|
return cancelled;
|
|
636
608
|
}
|
|
609
|
+
|
|
610
|
+
// src/agents/cursor-model-selection.ts
|
|
611
|
+
function buildCursorModelSelection(model, opts) {
|
|
612
|
+
const raw = model && model.trim() || "";
|
|
613
|
+
const id = !raw || raw.toLowerCase() === "auto" || raw.toLowerCase() === "default" ? "default" : raw;
|
|
614
|
+
const isGrok47 = /^grok-4\.7(?:$|-)/i.test(id);
|
|
615
|
+
const params = [];
|
|
616
|
+
if (isGrok47) {
|
|
617
|
+
params.push({ id: "context", value: "256k" });
|
|
618
|
+
}
|
|
619
|
+
const effort = (opts.effort ?? "").trim().toLowerCase();
|
|
620
|
+
const normalized = effort === "normal" ? "medium" : effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" || effort === "max" ? effort : "";
|
|
621
|
+
if (normalized) {
|
|
622
|
+
params.push({
|
|
623
|
+
id: isGrok47 ? "reasoning_effort" : "effort",
|
|
624
|
+
value: isGrok47 && normalized === "max" ? "xhigh" : normalized
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
params.push({ id: "fast", value: opts.fast ? "true" : "false" });
|
|
628
|
+
return { id, params };
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// src/agents/cursor-runner.ts
|
|
632
|
+
dropNestedElectronEnvFromProcess();
|
|
633
|
+
function emit(event) {
|
|
634
|
+
process.stdout.write(`${JSON.stringify(clipAgentEventForEmit(event, process.cwd()))}
|
|
635
|
+
`);
|
|
636
|
+
}
|
|
637
|
+
function localAgentStore(Store, threadId) {
|
|
638
|
+
const root = cursorSdkStoreDir(threadId);
|
|
639
|
+
mkdirSync2(root, { recursive: true });
|
|
640
|
+
return new Store(root);
|
|
641
|
+
}
|
|
637
642
|
async function readStdinJson() {
|
|
638
643
|
const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
639
644
|
const chunks = [];
|
|
@@ -703,10 +708,16 @@ async function main() {
|
|
|
703
708
|
}
|
|
704
709
|
}
|
|
705
710
|
}) : {};
|
|
706
|
-
const
|
|
711
|
+
const rawCustomTools = {
|
|
707
712
|
read: slicedReadCustomToolConfig(req.cwd),
|
|
708
713
|
...rpcTools
|
|
709
714
|
};
|
|
715
|
+
const customTools = Object.fromEntries(
|
|
716
|
+
Object.entries(rawCustomTools).map(([name, tool]) => [
|
|
717
|
+
name,
|
|
718
|
+
guardCursorCustomTool(tool, { cwd: req.cwd, name })
|
|
719
|
+
])
|
|
720
|
+
);
|
|
710
721
|
const local = withCursorLocalHangGuards({
|
|
711
722
|
cwd: req.cwd,
|
|
712
723
|
store,
|
|
@@ -753,7 +764,7 @@ async function main() {
|
|
|
753
764
|
}
|
|
754
765
|
}
|
|
755
766
|
async function retryAfterBusy(agent) {
|
|
756
|
-
const n = await
|
|
767
|
+
const n = await cancelStaleCursorRuns(Agent, agent.agentId, {
|
|
757
768
|
cwd: req.cwd,
|
|
758
769
|
store,
|
|
759
770
|
...apiKey ? { apiKey } : {}
|
|
@@ -766,17 +777,17 @@ async function main() {
|
|
|
766
777
|
await new Promise((resolve2) => setTimeout(resolve2, CURSOR_BUSY_RETRY_DELAY_MS));
|
|
767
778
|
}
|
|
768
779
|
}
|
|
769
|
-
async function sendPrompt(agent, extra) {
|
|
780
|
+
async function sendPrompt(agent, prompt, extra) {
|
|
770
781
|
const sendOpts = {
|
|
771
782
|
...cursorSendOptions(mcpServers),
|
|
772
783
|
...extra
|
|
773
784
|
};
|
|
774
785
|
try {
|
|
775
|
-
return await retryTransport(() => agent.send(
|
|
786
|
+
return await retryTransport(() => agent.send(prompt, sendOpts));
|
|
776
787
|
} catch (err) {
|
|
777
788
|
if (!isAgentBusyError(err)) throw err;
|
|
778
789
|
await retryAfterBusy(agent);
|
|
779
|
-
return retryTransport(() => agent.send(
|
|
790
|
+
return retryTransport(() => agent.send(prompt, sendOpts));
|
|
780
791
|
}
|
|
781
792
|
}
|
|
782
793
|
let liveRun = null;
|
|
@@ -804,7 +815,7 @@ async function main() {
|
|
|
804
815
|
};
|
|
805
816
|
process.once("SIGTERM", onSignal);
|
|
806
817
|
process.once("SIGINT", onSignal);
|
|
807
|
-
async function runTurn(agent) {
|
|
818
|
+
async function runTurn(agent, prompt = req.prompt, recoveryLeft = 1) {
|
|
808
819
|
emit({ type: "session_id", data: agent.agentId });
|
|
809
820
|
const stream = createAgentStreamCoalescer(emit);
|
|
810
821
|
const activity = { at: Date.now() };
|
|
@@ -818,7 +829,7 @@ async function main() {
|
|
|
818
829
|
} catch {
|
|
819
830
|
}
|
|
820
831
|
let lastUsageRunId;
|
|
821
|
-
const run = await sendPrompt(agent, {
|
|
832
|
+
const run = await sendPrompt(agent, prompt, {
|
|
822
833
|
onDelta: ({ update }) => {
|
|
823
834
|
bump();
|
|
824
835
|
for (const event of cursorDeltaToEvents(update)) {
|
|
@@ -863,6 +874,14 @@ async function main() {
|
|
|
863
874
|
if (isAgentBusyError(detail)) {
|
|
864
875
|
throw Object.assign(new Error(detail || "agent still running"), { name: "AgentBusyError" });
|
|
865
876
|
}
|
|
877
|
+
if (recoveryLeft > 0 && shouldReturnRunErrorToAgent(detail)) {
|
|
878
|
+
const brief = detail.replace(/\s+/g, " ").trim().slice(0, 240);
|
|
879
|
+
emit({
|
|
880
|
+
type: "stderr",
|
|
881
|
+
data: `Cursor tool error \u2014 handing it back to the agent (${brief})`
|
|
882
|
+
});
|
|
883
|
+
return runTurn(agent, cursorRunErrorRecoveryPrompt(detail), 0);
|
|
884
|
+
}
|
|
866
885
|
emit({
|
|
867
886
|
type: "stderr",
|
|
868
887
|
data: detail ? `Cursor run failed (${result.id}): ${detail}` : `Cursor run failed (${result.id})`
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
resolveCursorSdkRoot,
|
|
47
47
|
resolveQuotaFallbackAgent,
|
|
48
48
|
turnCostUsdFromCursorUsage
|
|
49
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-2O3ICR77.js";
|
|
50
50
|
import {
|
|
51
51
|
getAgentSetupInfo,
|
|
52
52
|
installAgent,
|
|
@@ -62,9 +62,9 @@ import {
|
|
|
62
62
|
import "./chunk-7IAMHN2N.js";
|
|
63
63
|
import "./chunk-PXMLMBMI.js";
|
|
64
64
|
import "./chunk-2GPQZZLY.js";
|
|
65
|
-
import "./chunk-
|
|
66
|
-
import "./chunk-
|
|
67
|
-
import "./chunk-
|
|
65
|
+
import "./chunk-ED4ZXQVO.js";
|
|
66
|
+
import "./chunk-WQREAX35.js";
|
|
67
|
+
import "./chunk-VXNZG4J6.js";
|
|
68
68
|
import "./chunk-N2WW62LF.js";
|
|
69
69
|
import "./chunk-DD67JWTN.js";
|
|
70
70
|
import {
|
|
@@ -88,7 +88,7 @@ import "./chunk-NSTQ6QKD.js";
|
|
|
88
88
|
import "./chunk-WWUABK6B.js";
|
|
89
89
|
import "./chunk-FJZWM2ON.js";
|
|
90
90
|
import "./chunk-UN5Q7POQ.js";
|
|
91
|
-
import "./chunk-
|
|
91
|
+
import "./chunk-TVN4TDFB.js";
|
|
92
92
|
import "./chunk-4RZRHTSZ.js";
|
|
93
93
|
import "./chunk-KGZBYWZ3.js";
|
|
94
94
|
import "./chunk-H5XL4KUS.js";
|
|
@@ -37,9 +37,9 @@ import {
|
|
|
37
37
|
planModeTurnInstruction,
|
|
38
38
|
resolveCursorModelId,
|
|
39
39
|
resolveQuotaFallbackAgent
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-6GTABVNG.js";
|
|
41
41
|
import "./chunk-VGNLMGBK.js";
|
|
42
|
-
import "./chunk-
|
|
42
|
+
import "./chunk-Q3DPZ4DE.js";
|
|
43
43
|
import {
|
|
44
44
|
getAgentSetupInfo,
|
|
45
45
|
installAgent,
|
|
@@ -52,9 +52,9 @@ import {
|
|
|
52
52
|
resolveLoginCommand,
|
|
53
53
|
whichOnPath
|
|
54
54
|
} from "./chunk-B42H6GJR.js";
|
|
55
|
-
import "./chunk-
|
|
56
|
-
import "./chunk-
|
|
57
|
-
import "./chunk-
|
|
55
|
+
import "./chunk-BGEECLKH.js";
|
|
56
|
+
import "./chunk-JWXJXEA3.js";
|
|
57
|
+
import "./chunk-WZLV4WNS.js";
|
|
58
58
|
import "./chunk-2P4XKWV2.js";
|
|
59
59
|
import "./chunk-33KDPEK4.js";
|
|
60
60
|
import "./chunk-JAT3JFOS.js";
|
|
@@ -66,8 +66,8 @@ import {
|
|
|
66
66
|
preferredCursorCostCents,
|
|
67
67
|
resolveCursorSdkRoot,
|
|
68
68
|
turnCostUsdFromCursorUsage
|
|
69
|
-
} from "./chunk-
|
|
70
|
-
import "./chunk-
|
|
69
|
+
} from "./chunk-IOY2LF3Y.js";
|
|
70
|
+
import "./chunk-HO5R3ZRH.js";
|
|
71
71
|
import "./chunk-6K64FJDD.js";
|
|
72
72
|
import "./chunk-UWQ6UCIB.js";
|
|
73
73
|
import {
|
|
@@ -81,7 +81,7 @@ import {
|
|
|
81
81
|
resolveCommandBinarySync,
|
|
82
82
|
withExportedPath
|
|
83
83
|
} from "./chunk-QVN2WOKJ.js";
|
|
84
|
-
import "./chunk-
|
|
84
|
+
import "./chunk-QDA6NXRA.js";
|
|
85
85
|
import {
|
|
86
86
|
ORCHESTRATOR_AGENT_KINDS,
|
|
87
87
|
assertOrchestratorCapableAgent,
|
|
@@ -21,16 +21,16 @@ import {
|
|
|
21
21
|
looksLikeSkillBody,
|
|
22
22
|
skillCommandFromBody,
|
|
23
23
|
withEventParentId
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-ED4ZXQVO.js";
|
|
25
25
|
import {
|
|
26
26
|
isOrchestratorThread
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-WQREAX35.js";
|
|
28
28
|
import {
|
|
29
29
|
codexUnattendedGitConfigArgs,
|
|
30
30
|
mergeAgentGitAuthEnv,
|
|
31
31
|
resolveAgentGitAuthEnv,
|
|
32
32
|
resolveCodexGitWritableRoots
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-VXNZG4J6.js";
|
|
34
34
|
import {
|
|
35
35
|
npmGlobalNodeModules,
|
|
36
36
|
run
|
|
@@ -2018,7 +2018,7 @@ var claudeAdapter = {
|
|
|
2018
2018
|
);
|
|
2019
2019
|
}
|
|
2020
2020
|
const mode = permissionMode(thread);
|
|
2021
|
-
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-
|
|
2021
|
+
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-NMRUGGFF.js");
|
|
2022
2022
|
const isOrchestrator = isOrchestratorThread2(thread);
|
|
2023
2023
|
const rpc = worktreeAgentRpc(isOrchestrator);
|
|
2024
2024
|
const injectedServers = await buildInjectedMcpServers({
|