@sideboard-ai/core 0.1.110 → 0.1.115
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/cursor-runner.cjs +32 -23
- package/dist/agents/cursor-runner.js +3 -3
- package/dist/{agents-WK54VP7J.js → agents-3X3EFCQY.js} +7 -7
- package/dist/{agents-MQDW3YXL.js → agents-AHAFC6FR.js} +10 -10
- package/dist/{chunk-4EWPKYOU.js → chunk-4OJMZ6P2.js} +2 -2
- package/dist/{chunk-VOJSO3RM.js → chunk-66XTXHR3.js} +277 -49
- package/dist/{chunk-KQBI5HNT.js → chunk-7WC5UWEB.js} +2 -2
- package/dist/{chunk-WIHKHR5R.js → chunk-AXQ4ZWHK.js} +5 -0
- package/dist/{chunk-RSIWPLRG.js → chunk-C6OBY6IC.js} +268 -27
- package/dist/{chunk-EAAB4EK5.js → chunk-DCNR7NAL.js} +44 -32
- package/dist/{chunk-LGXBYZZA.js → chunk-DVM4ID64.js} +69 -13
- package/dist/{chunk-2GO3YKBA.js → chunk-EKIDHL2T.js} +4 -4
- package/dist/{chunk-C4KHDW3U.js → chunk-FZCIQYNQ.js} +1 -1
- package/dist/{chunk-7KWYXGIU.js → chunk-K3TIQXOH.js} +2 -2
- package/dist/{chunk-3KETJKYA.js → chunk-KPIYENTF.js} +69 -13
- package/dist/{chunk-XOZDAVOP.js → chunk-MZ6HJ7VL.js} +52 -35
- package/dist/{chunk-3UOKB6VQ.js → chunk-SLU5JVKD.js} +282 -228
- package/dist/{chunk-VOD3HFLP.js → chunk-XOYQ7LNQ.js} +2 -2
- package/dist/{chunk-7YKXHBIW.js → chunk-YMRT2DU6.js} +3 -3
- package/dist/{chunk-YXDR43ZC.js → chunk-ZMROW673.js} +5 -5
- package/dist/{chunk-YFAXVUY2.js → chunk-ZRCX43LS.js} +2 -2
- package/dist/{chunk-AROMOP3C.js → chunk-ZYEFCSZJ.js} +2 -2
- package/dist/{connected-teams-M5XNXRI5.js → connected-teams-O6D4PM7A.js} +2 -2
- package/dist/{connected-teams-J4I5AKMR.js → connected-teams-ZCOU6KCD.js} +2 -2
- package/dist/{coordinator-prompt-AR66L3N4.js → coordinator-prompt-4KCALEKD.js} +3 -3
- package/dist/{coordinator-prompt-BHMLWL64.js → coordinator-prompt-FML4I5AR.js} +3 -3
- package/dist/{global-workspace-XSUFEIAQ.js → global-workspace-CSWABOG5.js} +4 -4
- package/dist/{global-workspace-SKFODUQQ.js → global-workspace-H4YNASM6.js} +4 -4
- package/dist/index.cjs +825 -443
- package/dist/index.d.cts +53 -1
- package/dist/index.d.ts +53 -1
- package/dist/index.js +33 -15
- package/dist/mcp/run-stdio.cjs +947 -644
- package/dist/mcp/run-stdio.js +18 -14
- package/dist/{orchestrator-SCATSB3O.js → orchestrator-GKLYKLRC.js} +8 -8
- package/dist/{orchestrator-FCZVCKBK.js → orchestrator-TXASYNHT.js} +10 -10
- package/dist/{run-XKTAJRWF.js → run-USF6FRKV.js} +3 -1
- package/dist/{run-CFKZPY7F.js → run-XQKGHQZ2.js} +3 -1
- package/dist/{workspaces-XAQVKTLO.js → workspaces-HJ3EVATC.js} +5 -5
- package/dist/{workspaces-HV3J4TTW.js → workspaces-QG6PGFQR.js} +5 -5
- package/dist/{worktree-XFJED3VU.js → worktree-IW3BX26B.js} +2 -2
- package/dist/{worktree-N2EV24EE.js → worktree-OTFQO2W7.js} +2 -2
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-4TR3HZFT.js";
|
|
5
5
|
import {
|
|
6
6
|
run
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-DVM4ID64.js";
|
|
8
8
|
|
|
9
9
|
// src/agents/error-detail.ts
|
|
10
10
|
function formatUnknownDetail(err) {
|
|
@@ -52,7 +52,7 @@ function extractJsonErrorMessage(obj) {
|
|
|
52
52
|
var NODE_VERSION_FOOTER = /^Node\.js v\d+/i;
|
|
53
53
|
function isPinnedStderrLine(line) {
|
|
54
54
|
if (/^\s*at\s/.test(line)) return false;
|
|
55
|
-
return /cannot find (?:package|module)|ERR_MODULE_NOT_FOUND|cursor startup failed
|
|
55
|
+
return /cannot find (?:package|module)|ERR_MODULE_NOT_FOUND|cursor startup failed:|FATAL ERROR|heap out of memory|javascript heap|OOMErrorHandler|FatalProcessOutOfMemory/i.test(
|
|
56
56
|
line
|
|
57
57
|
);
|
|
58
58
|
}
|
|
@@ -75,15 +75,22 @@ function looksLikeMinifiedJsDump(line) {
|
|
|
75
75
|
function looksLikeNestedElectronCrash(line) {
|
|
76
76
|
return /HasCustomHostObject|ElectronInitializeICUandStartNode/i.test(line);
|
|
77
77
|
}
|
|
78
|
-
function
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
function looksLikeNativeEventLoopCrash(text) {
|
|
79
|
+
return /uv_run|uv__io_poll|SpinEventLoopInternal/i.test(text);
|
|
80
|
+
}
|
|
81
|
+
function looksLikeV8Oom(text) {
|
|
82
|
+
return /javascript heap|reached heap limit|OOMErrorHandler|FatalProcessOutOfMemory|Allocation failed - JavaScript heap/i.test(
|
|
83
|
+
text
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
function looksLikeHomebrewLibuvCrash(text) {
|
|
87
|
+
if (!looksLikeNativeEventLoopCrash(text)) return false;
|
|
88
|
+
return /Cellar\/(?:libuv|node)|libuv\.\d+\.dylib/i.test(text);
|
|
84
89
|
}
|
|
85
90
|
var NESTED_ELECTRON_SUMMARY = "Cursor local agent crashed at Electron startup (nested Chromium / HasCustomHostObject)";
|
|
86
91
|
var HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 22 LTS (`brew install node@22`) and retry.";
|
|
92
|
+
var BUNDLED_NODE_CRASH_SUMMARY = "Cursor runner crashed in Node. Retry the turn.";
|
|
93
|
+
var V8_OOM_SUMMARY = "Agent ran out of memory (JavaScript heap). If it keeps happening, exclude large files from the project folder.";
|
|
87
94
|
var MINIFIED_DUMP_SUMMARY = "Cursor local agent crashed during startup (truncated crash dump)";
|
|
88
95
|
function clipStderr(text, maxChars) {
|
|
89
96
|
const trimmed = text.trim();
|
|
@@ -97,7 +104,12 @@ function summarizeTurnStderr(tail, maxChars = 500) {
|
|
|
97
104
|
const cursorRunFailed = [...tail].reverse().find((line) => /^cursor run failed\b/i.test(line.trim()));
|
|
98
105
|
if (cursorRunFailed) return clipStderr(cursorRunFailed, maxChars);
|
|
99
106
|
if (tail.some(looksLikeNestedElectronCrash)) return NESTED_ELECTRON_SUMMARY;
|
|
100
|
-
|
|
107
|
+
const blob = tail.join("\n");
|
|
108
|
+
if (looksLikeV8Oom(blob)) return V8_OOM_SUMMARY;
|
|
109
|
+
if (looksLikeHomebrewLibuvCrash(blob)) return HOMEBREW_LIBUV_SUMMARY;
|
|
110
|
+
if (looksLikeNativeEventLoopCrash(blob)) {
|
|
111
|
+
return BUNDLED_NODE_CRASH_SUMMARY;
|
|
112
|
+
}
|
|
101
113
|
if (tail.some(
|
|
102
114
|
(line) => /\[resource_exhausted\]|resource_exhausted/i.test(line) || /findFilesWithRipgrep/.test(line)
|
|
103
115
|
)) {
|
|
@@ -123,15 +135,17 @@ function looksLikeInvalidAgentSession(text) {
|
|
|
123
135
|
function looksLikeRetryableRunnerCrash(text) {
|
|
124
136
|
if (looksLikeAgentFailureMessage(text)) return false;
|
|
125
137
|
if (looksLikeInvalidAgentSession(text)) return false;
|
|
138
|
+
if (looksLikeV8Oom(text)) return false;
|
|
126
139
|
const lower = text.trim().toLowerCase();
|
|
127
140
|
if (/cannot find (?:package|module)|err_module_not_found/.test(lower)) return false;
|
|
128
141
|
if (!lower) return true;
|
|
129
|
-
return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|connection stalled|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
|
|
142
|
+
return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|cursor runner crashed in node|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|connection stalled|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
|
|
130
143
|
lower
|
|
131
144
|
);
|
|
132
145
|
}
|
|
133
146
|
function shouldRetryFailedAgentTurn(detail, opts) {
|
|
134
147
|
if (looksLikeInvalidAgentSession(detail) && opts.hasSession) return true;
|
|
148
|
+
if (looksLikeV8Oom(detail) && opts.hasSession) return true;
|
|
135
149
|
return looksLikeRetryableRunnerCrash(detail);
|
|
136
150
|
}
|
|
137
151
|
function looksLikeAgentFailureMessage(text) {
|
|
@@ -178,9 +192,15 @@ function humanizeAgentFailDetail(detail) {
|
|
|
178
192
|
if (/hascustomhostobject|electroninitializeicuandstartnode|nested chromium/i.test(lower)) {
|
|
179
193
|
return `${raw} \u2014 retry the turn; if it keeps failing, pick another agent.`;
|
|
180
194
|
}
|
|
181
|
-
if (/
|
|
195
|
+
if (looksLikeV8Oom(raw) || /javascript heap out of memory/i.test(lower)) {
|
|
196
|
+
return /ran out of memory/i.test(raw) ? raw : V8_OOM_SUMMARY;
|
|
197
|
+
}
|
|
198
|
+
if (/homebrew node \+ shared libuv|Cellar\/(?:libuv|node)|libuv\.\d+\.dylib/i.test(raw)) {
|
|
182
199
|
return /brew install node@22/i.test(raw) ? raw : `${raw} \u2014 install Node 22 LTS (\`brew install node@22\`) and retry.`;
|
|
183
200
|
}
|
|
201
|
+
if (/uv_run|spineventloopinternal|uv__io_poll|cursor runner crashed in node/i.test(lower)) {
|
|
202
|
+
return /retry the turn/i.test(raw) ? raw : BUNDLED_NODE_CRASH_SUMMARY;
|
|
203
|
+
}
|
|
184
204
|
if (/corrupt local agent checkpoint|missing root blob|truncated crash dump/.test(lower)) {
|
|
185
205
|
return `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
|
|
186
206
|
}
|
|
@@ -211,6 +231,250 @@ function formatTurnExitError(exitCode, stderrSummary) {
|
|
|
211
231
|
return `exit ${code}: ${detail}`;
|
|
212
232
|
}
|
|
213
233
|
|
|
234
|
+
// src/agents/node-launch.ts
|
|
235
|
+
import { existsSync as existsSync2, readdirSync, realpathSync } from "fs";
|
|
236
|
+
import { homedir } from "os";
|
|
237
|
+
import { join as join2 } from "path";
|
|
238
|
+
|
|
239
|
+
// src/agents/packaged-runtime.ts
|
|
240
|
+
import { existsSync } from "fs";
|
|
241
|
+
import { join } from "path";
|
|
242
|
+
function electronResourcesPath() {
|
|
243
|
+
const resources = process.resourcesPath;
|
|
244
|
+
if (typeof resources !== "string" || !resources) return null;
|
|
245
|
+
return resources;
|
|
246
|
+
}
|
|
247
|
+
function packagedCursorRuntimeDir() {
|
|
248
|
+
const resources = electronResourcesPath();
|
|
249
|
+
if (!resources) return null;
|
|
250
|
+
const dir = join(resources, "cursor-runtime");
|
|
251
|
+
if (!existsSync(join(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
252
|
+
return dir;
|
|
253
|
+
}
|
|
254
|
+
function packagedCursorRunnerPath() {
|
|
255
|
+
const dir = packagedCursorRuntimeDir();
|
|
256
|
+
return dir ? join(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
257
|
+
}
|
|
258
|
+
function packagedMcpDir() {
|
|
259
|
+
const resources = electronResourcesPath();
|
|
260
|
+
if (!resources) return null;
|
|
261
|
+
const dir = join(resources, "sideboard-mcp");
|
|
262
|
+
if (!existsSync(join(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
263
|
+
return dir;
|
|
264
|
+
}
|
|
265
|
+
function packagedMcpStdioPath() {
|
|
266
|
+
const dir = packagedMcpDir();
|
|
267
|
+
return dir ? join(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
268
|
+
}
|
|
269
|
+
function packagedBundledNodePath() {
|
|
270
|
+
const resources = electronResourcesPath();
|
|
271
|
+
if (!resources) return null;
|
|
272
|
+
const bin = join(resources, "node", "bin", "node");
|
|
273
|
+
if (!existsSync(bin)) return null;
|
|
274
|
+
return bin;
|
|
275
|
+
}
|
|
276
|
+
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
277
|
+
const dir = packagedCursorRuntimeDir();
|
|
278
|
+
if (!dir) return null;
|
|
279
|
+
return join(dir, "node_modules", platformPkg, "bin", binName);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// src/agents/node-launch.ts
|
|
283
|
+
var AGENT_RUNNER_MAX_OLD_SPACE_MB = 8192;
|
|
284
|
+
var MAX_OLD_SPACE_FLAG = /(?:^|\s)(--max[-_]old[-_]space[-_]size)(?:[= ](\d+))?(?=\s|$)/;
|
|
285
|
+
function withMaxOldSpaceSize(nodeOptions, heapMb) {
|
|
286
|
+
const existing = (nodeOptions ?? "").trim();
|
|
287
|
+
const match = MAX_OLD_SPACE_FLAG.exec(existing);
|
|
288
|
+
if (match) {
|
|
289
|
+
const current = match[2] ? Number(match[2]) : 0;
|
|
290
|
+
if (Number.isFinite(current) && current >= heapMb) return existing;
|
|
291
|
+
return existing.replace(MAX_OLD_SPACE_FLAG, ` --max-old-space-size=${heapMb}`).trim();
|
|
292
|
+
}
|
|
293
|
+
return existing ? `${existing} --max-old-space-size=${heapMb}` : `--max-old-space-size=${heapMb}`;
|
|
294
|
+
}
|
|
295
|
+
function applyAgentRunnerHeapEnv(env) {
|
|
296
|
+
env.NODE_OPTIONS = withMaxOldSpaceSize(
|
|
297
|
+
env.NODE_OPTIONS,
|
|
298
|
+
AGENT_RUNNER_MAX_OLD_SPACE_MB
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
function envWithAgentHeap(env) {
|
|
302
|
+
const next = { ...env };
|
|
303
|
+
applyAgentRunnerHeapEnv(next);
|
|
304
|
+
return next;
|
|
305
|
+
}
|
|
306
|
+
function isAsarPath(filePath) {
|
|
307
|
+
if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
|
|
308
|
+
return /\.asar([/\\]|$)/.test(filePath);
|
|
309
|
+
}
|
|
310
|
+
function unpackedAsarPath(filePath) {
|
|
311
|
+
if (!isAsarPath(filePath)) return null;
|
|
312
|
+
const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
|
|
313
|
+
if (unpacked === filePath) return null;
|
|
314
|
+
return existsSync2(unpacked) ? unpacked : null;
|
|
315
|
+
}
|
|
316
|
+
function nodeReadableScriptPath(scriptPath) {
|
|
317
|
+
return unpackedAsarPath(scriptPath) ?? scriptPath;
|
|
318
|
+
}
|
|
319
|
+
var PREFERRED_LTS_MAJORS = [24, 22, 20];
|
|
320
|
+
function parseNodeMajor(version) {
|
|
321
|
+
const match = /^v?(\d+)/.exec(version.trim());
|
|
322
|
+
if (!match) return null;
|
|
323
|
+
const major = Number(match[1]);
|
|
324
|
+
return Number.isInteger(major) ? major : null;
|
|
325
|
+
}
|
|
326
|
+
function scoreNodeForAgentRuntime(candidate) {
|
|
327
|
+
const major = parseNodeMajor(candidate.version);
|
|
328
|
+
if (major == null) return Number.NEGATIVE_INFINITY;
|
|
329
|
+
if (major < 20) return major - 100;
|
|
330
|
+
const posix = candidate.path.replace(/\\/g, "/");
|
|
331
|
+
let score = 0;
|
|
332
|
+
if (major % 2 === 0) {
|
|
333
|
+
score += 1e3 + major * 10;
|
|
334
|
+
} else {
|
|
335
|
+
score += major;
|
|
336
|
+
}
|
|
337
|
+
if (/\/Cellar\/node\/\d/.test(posix) && !/\/Cellar\/node@\d+/.test(posix)) {
|
|
338
|
+
score -= 50;
|
|
339
|
+
}
|
|
340
|
+
return score;
|
|
341
|
+
}
|
|
342
|
+
function pickPreferredNode(candidates) {
|
|
343
|
+
let best = null;
|
|
344
|
+
let bestScore = Number.NEGATIVE_INFINITY;
|
|
345
|
+
for (const candidate of candidates) {
|
|
346
|
+
const score = scoreNodeForAgentRuntime(candidate);
|
|
347
|
+
if (score > bestScore) {
|
|
348
|
+
bestScore = score;
|
|
349
|
+
best = candidate;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return best;
|
|
353
|
+
}
|
|
354
|
+
function versionDirNodeBins(root, toBin) {
|
|
355
|
+
if (!existsSync2(root)) return [];
|
|
356
|
+
try {
|
|
357
|
+
return readdirSync(root).map(toBin);
|
|
358
|
+
} catch {
|
|
359
|
+
return [];
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function defaultNodeBinCandidates(home = homedir()) {
|
|
363
|
+
const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
|
|
364
|
+
(prefix) => PREFERRED_LTS_MAJORS.map((major) => join2(prefix, "opt", `node@${major}`, "bin", "node"))
|
|
365
|
+
);
|
|
366
|
+
return [
|
|
367
|
+
...kegs,
|
|
368
|
+
"/opt/homebrew/bin/node",
|
|
369
|
+
"/usr/local/bin/node",
|
|
370
|
+
join2(home, ".local/share/fnm/aliases/default/bin/node"),
|
|
371
|
+
join2(home, ".nvm/current/bin/node"),
|
|
372
|
+
join2(home, ".volta/bin/node"),
|
|
373
|
+
join2(home, ".asdf/shims/node"),
|
|
374
|
+
join2(home, ".local/share/mise/shims/node"),
|
|
375
|
+
...versionDirNodeBins(
|
|
376
|
+
join2(home, ".nvm", "versions", "node"),
|
|
377
|
+
(name) => join2(home, ".nvm", "versions", "node", name, "bin", "node")
|
|
378
|
+
),
|
|
379
|
+
...versionDirNodeBins(
|
|
380
|
+
join2(home, ".local/share/fnm", "node-versions"),
|
|
381
|
+
(name) => join2(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
|
|
382
|
+
),
|
|
383
|
+
...versionDirNodeBins(
|
|
384
|
+
join2(home, ".volta", "tools", "image", "node"),
|
|
385
|
+
(name) => join2(home, ".volta", "tools", "image", "node", name, "bin", "node")
|
|
386
|
+
)
|
|
387
|
+
];
|
|
388
|
+
}
|
|
389
|
+
function uniqueExistingNodeBins(paths) {
|
|
390
|
+
const seen = /* @__PURE__ */ new Set();
|
|
391
|
+
const out = [];
|
|
392
|
+
for (const raw of paths) {
|
|
393
|
+
const p = raw.trim();
|
|
394
|
+
if (!p || !existsSync2(p) || isElectronLikeCommand(p)) continue;
|
|
395
|
+
let key = p;
|
|
396
|
+
try {
|
|
397
|
+
key = realpathSync(p);
|
|
398
|
+
} catch {
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
if (seen.has(key)) continue;
|
|
402
|
+
seen.add(key);
|
|
403
|
+
out.push(p);
|
|
404
|
+
}
|
|
405
|
+
return out;
|
|
406
|
+
}
|
|
407
|
+
async function whichAllNode() {
|
|
408
|
+
if (process.platform === "win32") {
|
|
409
|
+
const located = await run("where", ["node"], { reject: false, timeoutMs: 5e3 });
|
|
410
|
+
if (located.exitCode !== 0) return [];
|
|
411
|
+
return located.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
412
|
+
}
|
|
413
|
+
const all = await run("which", ["-a", "node"], { reject: false, timeoutMs: 5e3 });
|
|
414
|
+
if (all.exitCode === 0 && all.stdout.trim()) {
|
|
415
|
+
return all.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
416
|
+
}
|
|
417
|
+
const single = await run("which", ["node"], { reject: false, timeoutMs: 5e3 });
|
|
418
|
+
if (single.exitCode !== 0 || !single.stdout.trim()) return [];
|
|
419
|
+
return [single.stdout.trim()];
|
|
420
|
+
}
|
|
421
|
+
async function probeNodeVersion(bin) {
|
|
422
|
+
const probed = await run(bin, ["-v"], { reject: false, timeoutMs: 4e3 });
|
|
423
|
+
if (probed.exitCode !== 0) return null;
|
|
424
|
+
const version = probed.stdout.trim().split(/\r?\n/).find(Boolean);
|
|
425
|
+
return version || null;
|
|
426
|
+
}
|
|
427
|
+
async function findSystemNode() {
|
|
428
|
+
const fromPath = await whichAllNode();
|
|
429
|
+
const bins = uniqueExistingNodeBins([...fromPath, ...defaultNodeBinCandidates()]);
|
|
430
|
+
if (bins.length === 0) return null;
|
|
431
|
+
const probed = await Promise.all(
|
|
432
|
+
bins.map(async (path) => {
|
|
433
|
+
const version = await probeNodeVersion(path);
|
|
434
|
+
return version ? { path, version } : null;
|
|
435
|
+
})
|
|
436
|
+
);
|
|
437
|
+
return pickPreferredNode(probed.filter((c) => c != null));
|
|
438
|
+
}
|
|
439
|
+
function applyNodeLaunch(launch, args) {
|
|
440
|
+
const readableArgs = args.map(nodeReadableScriptPath);
|
|
441
|
+
if (!launch.env.ELECTRON_RUN_AS_NODE) {
|
|
442
|
+
return {
|
|
443
|
+
file: launch.file,
|
|
444
|
+
args: readableArgs,
|
|
445
|
+
env: envWithAgentHeap(launch.env)
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
const wrapped = wrapElectronAsNodeLaunch(launch.file, readableArgs);
|
|
449
|
+
if (process.platform === "win32") {
|
|
450
|
+
return {
|
|
451
|
+
file: wrapped.file,
|
|
452
|
+
args: wrapped.args,
|
|
453
|
+
env: envWithAgentHeap(launch.env)
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
const env = envWithAgentHeap(launch.env);
|
|
457
|
+
delete env.ELECTRON_RUN_AS_NODE;
|
|
458
|
+
return { file: wrapped.file, args: wrapped.args, env };
|
|
459
|
+
}
|
|
460
|
+
async function resolveNodeLaunch(scriptPath) {
|
|
461
|
+
const script = nodeReadableScriptPath(scriptPath);
|
|
462
|
+
if (!isAsarPath(script)) {
|
|
463
|
+
const bundled = packagedBundledNodePath();
|
|
464
|
+
if (bundled && !isElectronLikeCommand(bundled)) {
|
|
465
|
+
return { file: bundled, env: {} };
|
|
466
|
+
}
|
|
467
|
+
const node = await findSystemNode();
|
|
468
|
+
if (node) {
|
|
469
|
+
return { file: node.path, env: {}, nodeVersion: node.version };
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
return {
|
|
473
|
+
file: process.execPath,
|
|
474
|
+
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
214
478
|
// src/agents/cursor-events.ts
|
|
215
479
|
function usageFromCursor(usage) {
|
|
216
480
|
if (!usage) return null;
|
|
@@ -423,222 +687,6 @@ function parseCursorRunnerLine(line) {
|
|
|
423
687
|
import { existsSync as existsSync3 } from "fs";
|
|
424
688
|
import { createRequire } from "module";
|
|
425
689
|
import { dirname, isAbsolute, join as join3, parse, resolve as resolvePath } from "path";
|
|
426
|
-
import { fileURLToPath } from "url";
|
|
427
|
-
|
|
428
|
-
// src/agents/node-launch.ts
|
|
429
|
-
import { existsSync as existsSync2, readdirSync, realpathSync } from "fs";
|
|
430
|
-
import { homedir } from "os";
|
|
431
|
-
import { join as join2 } from "path";
|
|
432
|
-
|
|
433
|
-
// src/agents/packaged-runtime.ts
|
|
434
|
-
import { existsSync } from "fs";
|
|
435
|
-
import { join } from "path";
|
|
436
|
-
function electronResourcesPath() {
|
|
437
|
-
const resources = process.resourcesPath;
|
|
438
|
-
if (typeof resources !== "string" || !resources) return null;
|
|
439
|
-
return resources;
|
|
440
|
-
}
|
|
441
|
-
function packagedCursorRuntimeDir() {
|
|
442
|
-
const resources = electronResourcesPath();
|
|
443
|
-
if (!resources) return null;
|
|
444
|
-
const dir = join(resources, "cursor-runtime");
|
|
445
|
-
if (!existsSync(join(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
446
|
-
return dir;
|
|
447
|
-
}
|
|
448
|
-
function packagedCursorRunnerPath() {
|
|
449
|
-
const dir = packagedCursorRuntimeDir();
|
|
450
|
-
return dir ? join(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
451
|
-
}
|
|
452
|
-
function packagedMcpDir() {
|
|
453
|
-
const resources = electronResourcesPath();
|
|
454
|
-
if (!resources) return null;
|
|
455
|
-
const dir = join(resources, "sideboard-mcp");
|
|
456
|
-
if (!existsSync(join(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
457
|
-
return dir;
|
|
458
|
-
}
|
|
459
|
-
function packagedMcpStdioPath() {
|
|
460
|
-
const dir = packagedMcpDir();
|
|
461
|
-
return dir ? join(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
462
|
-
}
|
|
463
|
-
function packagedBundledNodePath() {
|
|
464
|
-
const resources = electronResourcesPath();
|
|
465
|
-
if (!resources) return null;
|
|
466
|
-
const bin = join(resources, "node", "bin", "node");
|
|
467
|
-
if (!existsSync(bin)) return null;
|
|
468
|
-
return bin;
|
|
469
|
-
}
|
|
470
|
-
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
471
|
-
const dir = packagedCursorRuntimeDir();
|
|
472
|
-
if (!dir) return null;
|
|
473
|
-
return join(dir, "node_modules", platformPkg, "bin", binName);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
// src/agents/node-launch.ts
|
|
477
|
-
function isAsarPath(filePath) {
|
|
478
|
-
if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
|
|
479
|
-
return /\.asar([/\\]|$)/.test(filePath);
|
|
480
|
-
}
|
|
481
|
-
function unpackedAsarPath(filePath) {
|
|
482
|
-
if (!isAsarPath(filePath)) return null;
|
|
483
|
-
const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
|
|
484
|
-
if (unpacked === filePath) return null;
|
|
485
|
-
return existsSync2(unpacked) ? unpacked : null;
|
|
486
|
-
}
|
|
487
|
-
function nodeReadableScriptPath(scriptPath) {
|
|
488
|
-
return unpackedAsarPath(scriptPath) ?? scriptPath;
|
|
489
|
-
}
|
|
490
|
-
var PREFERRED_LTS_MAJORS = [24, 22, 20];
|
|
491
|
-
function parseNodeMajor(version) {
|
|
492
|
-
const match = /^v?(\d+)/.exec(version.trim());
|
|
493
|
-
if (!match) return null;
|
|
494
|
-
const major = Number(match[1]);
|
|
495
|
-
return Number.isInteger(major) ? major : null;
|
|
496
|
-
}
|
|
497
|
-
function scoreNodeForAgentRuntime(candidate) {
|
|
498
|
-
const major = parseNodeMajor(candidate.version);
|
|
499
|
-
if (major == null) return Number.NEGATIVE_INFINITY;
|
|
500
|
-
if (major < 20) return major - 100;
|
|
501
|
-
const posix = candidate.path.replace(/\\/g, "/");
|
|
502
|
-
let score = 0;
|
|
503
|
-
if (major % 2 === 0) {
|
|
504
|
-
score += 1e3 + major * 10;
|
|
505
|
-
} else {
|
|
506
|
-
score += major;
|
|
507
|
-
}
|
|
508
|
-
if (/\/Cellar\/node\/\d/.test(posix) && !/\/Cellar\/node@\d+/.test(posix)) {
|
|
509
|
-
score -= 50;
|
|
510
|
-
}
|
|
511
|
-
return score;
|
|
512
|
-
}
|
|
513
|
-
function pickPreferredNode(candidates) {
|
|
514
|
-
let best = null;
|
|
515
|
-
let bestScore = Number.NEGATIVE_INFINITY;
|
|
516
|
-
for (const candidate of candidates) {
|
|
517
|
-
const score = scoreNodeForAgentRuntime(candidate);
|
|
518
|
-
if (score > bestScore) {
|
|
519
|
-
bestScore = score;
|
|
520
|
-
best = candidate;
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
return best;
|
|
524
|
-
}
|
|
525
|
-
function versionDirNodeBins(root, toBin) {
|
|
526
|
-
if (!existsSync2(root)) return [];
|
|
527
|
-
try {
|
|
528
|
-
return readdirSync(root).map(toBin);
|
|
529
|
-
} catch {
|
|
530
|
-
return [];
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
function defaultNodeBinCandidates(home = homedir()) {
|
|
534
|
-
const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
|
|
535
|
-
(prefix) => PREFERRED_LTS_MAJORS.map((major) => join2(prefix, "opt", `node@${major}`, "bin", "node"))
|
|
536
|
-
);
|
|
537
|
-
return [
|
|
538
|
-
...kegs,
|
|
539
|
-
"/opt/homebrew/bin/node",
|
|
540
|
-
"/usr/local/bin/node",
|
|
541
|
-
join2(home, ".local/share/fnm/aliases/default/bin/node"),
|
|
542
|
-
join2(home, ".nvm/current/bin/node"),
|
|
543
|
-
join2(home, ".volta/bin/node"),
|
|
544
|
-
join2(home, ".asdf/shims/node"),
|
|
545
|
-
join2(home, ".local/share/mise/shims/node"),
|
|
546
|
-
...versionDirNodeBins(
|
|
547
|
-
join2(home, ".nvm", "versions", "node"),
|
|
548
|
-
(name) => join2(home, ".nvm", "versions", "node", name, "bin", "node")
|
|
549
|
-
),
|
|
550
|
-
...versionDirNodeBins(
|
|
551
|
-
join2(home, ".local/share/fnm", "node-versions"),
|
|
552
|
-
(name) => join2(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
|
|
553
|
-
),
|
|
554
|
-
...versionDirNodeBins(
|
|
555
|
-
join2(home, ".volta", "tools", "image", "node"),
|
|
556
|
-
(name) => join2(home, ".volta", "tools", "image", "node", name, "bin", "node")
|
|
557
|
-
)
|
|
558
|
-
];
|
|
559
|
-
}
|
|
560
|
-
function uniqueExistingNodeBins(paths) {
|
|
561
|
-
const seen = /* @__PURE__ */ new Set();
|
|
562
|
-
const out = [];
|
|
563
|
-
for (const raw of paths) {
|
|
564
|
-
const p = raw.trim();
|
|
565
|
-
if (!p || !existsSync2(p) || isElectronLikeCommand(p)) continue;
|
|
566
|
-
let key = p;
|
|
567
|
-
try {
|
|
568
|
-
key = realpathSync(p);
|
|
569
|
-
} catch {
|
|
570
|
-
continue;
|
|
571
|
-
}
|
|
572
|
-
if (seen.has(key)) continue;
|
|
573
|
-
seen.add(key);
|
|
574
|
-
out.push(p);
|
|
575
|
-
}
|
|
576
|
-
return out;
|
|
577
|
-
}
|
|
578
|
-
async function whichAllNode() {
|
|
579
|
-
if (process.platform === "win32") {
|
|
580
|
-
const located = await run("where", ["node"], { reject: false, timeoutMs: 5e3 });
|
|
581
|
-
if (located.exitCode !== 0) return [];
|
|
582
|
-
return located.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
583
|
-
}
|
|
584
|
-
const all = await run("which", ["-a", "node"], { reject: false, timeoutMs: 5e3 });
|
|
585
|
-
if (all.exitCode === 0 && all.stdout.trim()) {
|
|
586
|
-
return all.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
587
|
-
}
|
|
588
|
-
const single = await run("which", ["node"], { reject: false, timeoutMs: 5e3 });
|
|
589
|
-
if (single.exitCode !== 0 || !single.stdout.trim()) return [];
|
|
590
|
-
return [single.stdout.trim()];
|
|
591
|
-
}
|
|
592
|
-
async function probeNodeVersion(bin) {
|
|
593
|
-
const probed = await run(bin, ["-v"], { reject: false, timeoutMs: 4e3 });
|
|
594
|
-
if (probed.exitCode !== 0) return null;
|
|
595
|
-
const version = probed.stdout.trim().split(/\r?\n/).find(Boolean);
|
|
596
|
-
return version || null;
|
|
597
|
-
}
|
|
598
|
-
async function findSystemNode() {
|
|
599
|
-
const fromPath = await whichAllNode();
|
|
600
|
-
const bins = uniqueExistingNodeBins([...fromPath, ...defaultNodeBinCandidates()]);
|
|
601
|
-
if (bins.length === 0) return null;
|
|
602
|
-
const probed = await Promise.all(
|
|
603
|
-
bins.map(async (path) => {
|
|
604
|
-
const version = await probeNodeVersion(path);
|
|
605
|
-
return version ? { path, version } : null;
|
|
606
|
-
})
|
|
607
|
-
);
|
|
608
|
-
return pickPreferredNode(probed.filter((c) => c != null));
|
|
609
|
-
}
|
|
610
|
-
function applyNodeLaunch(launch, args) {
|
|
611
|
-
const readableArgs = args.map(nodeReadableScriptPath);
|
|
612
|
-
if (!launch.env.ELECTRON_RUN_AS_NODE) {
|
|
613
|
-
return { file: launch.file, args: readableArgs, env: launch.env };
|
|
614
|
-
}
|
|
615
|
-
const wrapped = wrapElectronAsNodeLaunch(launch.file, readableArgs);
|
|
616
|
-
if (process.platform === "win32") {
|
|
617
|
-
return { file: wrapped.file, args: wrapped.args, env: launch.env };
|
|
618
|
-
}
|
|
619
|
-
const env = { ...launch.env };
|
|
620
|
-
delete env.ELECTRON_RUN_AS_NODE;
|
|
621
|
-
return { file: wrapped.file, args: wrapped.args, env };
|
|
622
|
-
}
|
|
623
|
-
async function resolveNodeLaunch(scriptPath) {
|
|
624
|
-
const script = nodeReadableScriptPath(scriptPath);
|
|
625
|
-
if (!isAsarPath(script)) {
|
|
626
|
-
const bundled = packagedBundledNodePath();
|
|
627
|
-
if (bundled && !isElectronLikeCommand(bundled)) {
|
|
628
|
-
return { file: bundled, env: {} };
|
|
629
|
-
}
|
|
630
|
-
const node = await findSystemNode();
|
|
631
|
-
if (node) {
|
|
632
|
-
return { file: node.path, env: {}, nodeVersion: node.version };
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
return {
|
|
636
|
-
file: process.execPath,
|
|
637
|
-
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
638
|
-
};
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
// src/agents/cursor-ripgrep.ts
|
|
642
690
|
var RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
|
|
643
691
|
function rgBinaryName() {
|
|
644
692
|
return process.platform === "win32" ? "rg.exe" : "rg";
|
|
@@ -685,7 +733,9 @@ function resolveCursorRipgrepPath(opts) {
|
|
|
685
733
|
packagedCursorRipgrepCandidate(platformRipgrepPackage(), rgBinaryName())
|
|
686
734
|
);
|
|
687
735
|
if (fromPackaged) return fromPackaged;
|
|
688
|
-
const start = opts?.startFile?.trim() || process.argv[1] ||
|
|
736
|
+
const start = opts?.startFile?.trim() || process.argv[1] || // CJS bundle only — ESM has no __filename; argv[1] is the running script.
|
|
737
|
+
// eslint-disable-next-line camelcase
|
|
738
|
+
(typeof __filename !== "undefined" ? __filename : "");
|
|
689
739
|
return walkForBundledRipgrep(start) ?? requireResolveBundledRipgrep(start);
|
|
690
740
|
}
|
|
691
741
|
function cursorRipgrepEnv(opts) {
|
|
@@ -703,6 +753,7 @@ export {
|
|
|
703
753
|
formatUnknownDetail,
|
|
704
754
|
extractJsonErrorMessage,
|
|
705
755
|
pushTurnStderr,
|
|
756
|
+
looksLikeV8Oom,
|
|
706
757
|
summarizeTurnStderr,
|
|
707
758
|
looksLikeInvalidAgentSession,
|
|
708
759
|
shouldRetryFailedAgentTurn,
|
|
@@ -712,6 +763,9 @@ export {
|
|
|
712
763
|
formatTurnExitError,
|
|
713
764
|
packagedCursorRunnerPath,
|
|
714
765
|
packagedMcpStdioPath,
|
|
766
|
+
AGENT_RUNNER_MAX_OLD_SPACE_MB,
|
|
767
|
+
withMaxOldSpaceSize,
|
|
768
|
+
applyAgentRunnerHeapEnv,
|
|
715
769
|
isAsarPath,
|
|
716
770
|
applyNodeLaunch,
|
|
717
771
|
resolveNodeLaunch,
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
ensureGlobalCoordinatorCwd
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ZYEFCSZJ.js";
|
|
6
6
|
import {
|
|
7
7
|
allocateTeamName,
|
|
8
8
|
takenSlugsFromThread,
|
|
9
9
|
teamSlugFromName
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-ZMROW673.js";
|
|
11
11
|
import {
|
|
12
12
|
createEmptyThread,
|
|
13
13
|
listThreads,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
run
|
|
5
|
+
} from "./chunk-KPIYENTF.js";
|
|
3
6
|
import {
|
|
4
7
|
appDataDir
|
|
5
8
|
} from "./chunk-BD2ICC4D.js";
|
|
6
|
-
import {
|
|
7
|
-
run
|
|
8
|
-
} from "./chunk-3KETJKYA.js";
|
|
9
9
|
|
|
10
10
|
// src/brightsy/connected-teams.ts
|
|
11
11
|
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
@@ -6,6 +6,11 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
listThreads
|
|
8
8
|
} from "./chunk-KYOTBZ6S.js";
|
|
9
|
+
import {
|
|
10
|
+
gh,
|
|
11
|
+
git,
|
|
12
|
+
resolveGhAuthToken
|
|
13
|
+
} from "./chunk-KPIYENTF.js";
|
|
9
14
|
import {
|
|
10
15
|
getGithubGitAuthMode,
|
|
11
16
|
getGithubPat
|
|
@@ -13,11 +18,6 @@ import {
|
|
|
13
18
|
import {
|
|
14
19
|
worktreesRoot
|
|
15
20
|
} from "./chunk-BD2ICC4D.js";
|
|
16
|
-
import {
|
|
17
|
-
gh,
|
|
18
|
-
git,
|
|
19
|
-
resolveGhAuthToken
|
|
20
|
-
} from "./chunk-3KETJKYA.js";
|
|
21
21
|
|
|
22
22
|
// src/git/worktree.ts
|
|
23
23
|
import { existsSync as existsSync2, readdirSync } from "fs";
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
isGlobalRepoPath
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-XOYQ7LNQ.js";
|
|
6
6
|
import {
|
|
7
7
|
ensureGhPreferOrigin,
|
|
8
8
|
resolveRepoRoot
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ZMROW673.js";
|
|
10
10
|
import {
|
|
11
11
|
appDataDir
|
|
12
12
|
} from "./chunk-BD2ICC4D.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
resolveGithubRepoSlug
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ZMROW673.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveThreadDefaults
|
|
8
8
|
} from "./chunk-SGEVS5SY.js";
|
|
@@ -63,7 +63,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
|
|
|
63
63
|
"- fork_worktree \u2014 fork a worktree chat into a NEW git worktree + chat (transcript attached); optional agent; leave model unset (Auto) unless you have a reason. Not for orchestration chats.",
|
|
64
64
|
"- fork_chat \u2014 fork a worktree chat (same worktree tab) OR a Global orchestration chat (new orchestration tab); optional agent; leave model unset (Auto) unless you have a reason. Remote coordinators: use this to continue another orchestration chat on a different agent after session limits.",
|
|
65
65
|
"- send_to_thread \u2014 queue a prompt (start/continue a chat turn); pass force_stop: true to interrupt mid-turn / clear stale queued prompts before replacing with a new request",
|
|
66
|
-
"- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply. wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success.",
|
|
66
|
+
"- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply. wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. status=queued with no lastActivityAt means the child has not started yet (concurrency cap) \u2014 keep waiting; do not force_stop or send a check-in. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success.",
|
|
67
67
|
"- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
|
|
68
68
|
"- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
|
|
69
69
|
"Setup / run:",
|