@sideboard-ai/core 0.1.98 → 0.1.100

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.
Files changed (26) hide show
  1. package/dist/agents/cursor-runner.cjs +69 -24
  2. package/dist/agents/cursor-runner.js +48 -3
  3. package/dist/{agents-ESJKIQQA.js → agents-CLP5BG4O.js} +3 -3
  4. package/dist/{agents-3MWWWSMF.js → agents-OXZDMPSE.js} +4 -4
  5. package/dist/{chunk-FYS2BULQ.js → chunk-EQPQTLW6.js} +209 -59
  6. package/dist/{chunk-FO67IJTY.js → chunk-GR4JKWR4.js} +1 -1
  7. package/dist/{chunk-GXSYI7FH.js → chunk-HUKCGRAT.js} +209 -59
  8. package/dist/{chunk-XUWDLRAE.js → chunk-HYKZEP5A.js} +2 -2
  9. package/dist/{chunk-XH2GS2LO.js → chunk-IFHKPZHA.js} +2 -2
  10. package/dist/{chunk-UYQYK2RY.js → chunk-MHJV4WS3.js} +1 -1
  11. package/dist/{chunk-OANJQTVG.js → chunk-MRBKGFTL.js} +1 -1
  12. package/dist/{chunk-MBP3XG57.js → chunk-OXC3MEFI.js} +3 -3
  13. package/dist/{chunk-HI2OTFFR.js → chunk-WQTTUC4N.js} +1 -1
  14. package/dist/{coordinator-prompt-AKEY4WSO.js → coordinator-prompt-HHRKQWCX.js} +1 -1
  15. package/dist/{coordinator-prompt-OQOOD5ET.js → coordinator-prompt-OOBSQCWQ.js} +1 -1
  16. package/dist/{global-workspace-RSQXRLT7.js → global-workspace-KYEBFWKB.js} +2 -2
  17. package/dist/{global-workspace-WMF3BJP5.js → global-workspace-YZWYHLQY.js} +2 -2
  18. package/dist/index.cjs +662 -440
  19. package/dist/index.d.cts +16 -2
  20. package/dist/index.d.ts +16 -2
  21. package/dist/index.js +194 -128
  22. package/dist/mcp/run-stdio.cjs +424 -227
  23. package/dist/mcp/run-stdio.js +141 -92
  24. package/dist/{workspaces-MZVQHRSJ.js → workspaces-ENVUDK6C.js} +3 -3
  25. package/dist/{workspaces-4ZY4QPWQ.js → workspaces-NNPD7QVV.js} +3 -3
  26. package/package.json +2 -2
@@ -61,9 +61,9 @@ var import_node_path9 = require("path");
61
61
  var import_node_url = require("url");
62
62
 
63
63
  // src/agents/node-launch.ts
64
- var import_node_fs6 = require("fs");
64
+ var import_node_fs7 = require("fs");
65
65
  var import_node_os4 = require("os");
66
- var import_node_path7 = require("path");
66
+ var import_node_path8 = require("path");
67
67
 
68
68
  // src/git/run.ts
69
69
  var import_execa2 = require("execa");
@@ -74,24 +74,9 @@ var import_node_child_process = require("child_process");
74
74
  var import_node_os3 = require("os");
75
75
  var import_node_path6 = require("path");
76
76
 
77
- // src/agents/node-launch.ts
78
- function isAsarPath(filePath) {
79
- if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
80
- return /\.asar([/\\]|$)/.test(filePath);
81
- }
82
- function unpackedAsarPath(filePath) {
83
- if (!isAsarPath(filePath)) return null;
84
- const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
85
- if (unpacked === filePath) return null;
86
- return (0, import_node_fs6.existsSync)(unpacked) ? unpacked : null;
87
- }
88
- function nodeReadableScriptPath(scriptPath) {
89
- return unpackedAsarPath(scriptPath) ?? scriptPath;
90
- }
91
-
92
77
  // src/agents/packaged-runtime.ts
93
- var import_node_fs7 = require("fs");
94
- var import_node_path8 = require("path");
78
+ var import_node_fs6 = require("fs");
79
+ var import_node_path7 = require("path");
95
80
  function electronResourcesPath() {
96
81
  const resources = process.resourcesPath;
97
82
  if (typeof resources !== "string" || !resources) return null;
@@ -100,14 +85,29 @@ function electronResourcesPath() {
100
85
  function packagedCursorRuntimeDir() {
101
86
  const resources = electronResourcesPath();
102
87
  if (!resources) return null;
103
- const dir = (0, import_node_path8.join)(resources, "cursor-runtime");
104
- if (!(0, import_node_fs7.existsSync)((0, import_node_path8.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
88
+ const dir = (0, import_node_path7.join)(resources, "cursor-runtime");
89
+ if (!(0, import_node_fs6.existsSync)((0, import_node_path7.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
105
90
  return dir;
106
91
  }
107
92
  function packagedCursorRipgrepCandidate(platformPkg, binName) {
108
93
  const dir = packagedCursorRuntimeDir();
109
94
  if (!dir) return null;
110
- return (0, import_node_path8.join)(dir, "node_modules", platformPkg, "bin", binName);
95
+ return (0, import_node_path7.join)(dir, "node_modules", platformPkg, "bin", binName);
96
+ }
97
+
98
+ // src/agents/node-launch.ts
99
+ function isAsarPath(filePath) {
100
+ if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
101
+ return /\.asar([/\\]|$)/.test(filePath);
102
+ }
103
+ function unpackedAsarPath(filePath) {
104
+ if (!isAsarPath(filePath)) return null;
105
+ const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
106
+ if (unpacked === filePath) return null;
107
+ return (0, import_node_fs7.existsSync)(unpacked) ? unpacked : null;
108
+ }
109
+ function nodeReadableScriptPath(scriptPath) {
110
+ return unpackedAsarPath(scriptPath) ?? scriptPath;
111
111
  }
112
112
 
113
113
  // src/agents/cursor-ripgrep.ts
@@ -203,6 +203,34 @@ function cursorSendOptions(mcpServers) {
203
203
  function withCursorLocalHangGuards(local) {
204
204
  return { ...local, enableAgentRetries: false };
205
205
  }
206
+ var CURSOR_STREAM_IDLE_MS = 18e4;
207
+ async function* iterateUntilIdle(iterable, idleMs, onIdle) {
208
+ const iterator = iterable[Symbol.asyncIterator]();
209
+ try {
210
+ while (true) {
211
+ let idleTimer;
212
+ const next = iterator.next();
213
+ const raced = await Promise.race([
214
+ next.then((result) => ({ kind: "item", result })),
215
+ new Promise((resolve) => {
216
+ idleTimer = setTimeout(() => resolve({ kind: "idle" }), idleMs);
217
+ idleTimer.unref?.();
218
+ })
219
+ ]);
220
+ if (idleTimer) clearTimeout(idleTimer);
221
+ if (raced.kind === "idle") {
222
+ onIdle?.();
223
+ void iterator.return?.();
224
+ return;
225
+ }
226
+ if (raced.result.done) return;
227
+ yield raced.result.value;
228
+ }
229
+ } catch (err) {
230
+ void iterator.return?.();
231
+ throw err;
232
+ }
233
+ }
206
234
 
207
235
  // src/agents/error-detail.ts
208
236
  function formatUnknownDetail(err) {
@@ -601,14 +629,31 @@ async function main() {
601
629
  const run2 = await sendPrompt(agent);
602
630
  liveRun = run2;
603
631
  const stream = createAgentStreamCoalescer(emit);
632
+ let streamIdle = false;
604
633
  try {
605
- for await (const msg of run2.stream()) {
634
+ for await (const msg of iterateUntilIdle(
635
+ run2.stream(),
636
+ CURSOR_STREAM_IDLE_MS,
637
+ () => {
638
+ streamIdle = true;
639
+ emit({
640
+ type: "stderr",
641
+ data: "Cursor stream idle \u2014 finishing the turn (SDK stream did not close)"
642
+ });
643
+ void cancelLiveRun();
644
+ }
645
+ )) {
606
646
  for (const event of cursorSdkMessageToEvents(msg)) {
607
647
  stream.push(event);
608
648
  }
609
649
  }
610
650
  stream.flush();
611
- const result = await run2.wait();
651
+ const result = streamIdle ? await Promise.race([
652
+ run2.wait(),
653
+ new Promise((resolve) => {
654
+ setTimeout(() => resolve({ status: "cancelled" }), 5e3);
655
+ })
656
+ ]) : await run2.wait();
612
657
  if (result.status === "error") {
613
658
  const detail = formatUnknownDetail(result.error);
614
659
  emit({
@@ -6,7 +6,7 @@ import {
6
6
  cursorSdkMessageToEvents,
7
7
  ensureCursorRipgrepPath,
8
8
  formatUnknownDetail
9
- } from "../chunk-GXSYI7FH.js";
9
+ } from "../chunk-HUKCGRAT.js";
10
10
  import {
11
11
  dropNestedElectronEnvFromProcess
12
12
  } from "../chunk-TLPJHLLM.js";
@@ -56,6 +56,34 @@ function cursorSendOptions(mcpServers) {
56
56
  function withCursorLocalHangGuards(local) {
57
57
  return { ...local, enableAgentRetries: false };
58
58
  }
59
+ var CURSOR_STREAM_IDLE_MS = 18e4;
60
+ async function* iterateUntilIdle(iterable, idleMs, onIdle) {
61
+ const iterator = iterable[Symbol.asyncIterator]();
62
+ try {
63
+ while (true) {
64
+ let idleTimer;
65
+ const next = iterator.next();
66
+ const raced = await Promise.race([
67
+ next.then((result) => ({ kind: "item", result })),
68
+ new Promise((resolve) => {
69
+ idleTimer = setTimeout(() => resolve({ kind: "idle" }), idleMs);
70
+ idleTimer.unref?.();
71
+ })
72
+ ]);
73
+ if (idleTimer) clearTimeout(idleTimer);
74
+ if (raced.kind === "idle") {
75
+ onIdle?.();
76
+ void iterator.return?.();
77
+ return;
78
+ }
79
+ if (raced.result.done) return;
80
+ yield raced.result.value;
81
+ }
82
+ } catch (err) {
83
+ void iterator.return?.();
84
+ throw err;
85
+ }
86
+ }
59
87
 
60
88
  // src/agents/cursor-runner.ts
61
89
  dropNestedElectronEnvFromProcess();
@@ -215,14 +243,31 @@ async function main() {
215
243
  const run = await sendPrompt(agent);
216
244
  liveRun = run;
217
245
  const stream = createAgentStreamCoalescer(emit);
246
+ let streamIdle = false;
218
247
  try {
219
- for await (const msg of run.stream()) {
248
+ for await (const msg of iterateUntilIdle(
249
+ run.stream(),
250
+ CURSOR_STREAM_IDLE_MS,
251
+ () => {
252
+ streamIdle = true;
253
+ emit({
254
+ type: "stderr",
255
+ data: "Cursor stream idle \u2014 finishing the turn (SDK stream did not close)"
256
+ });
257
+ void cancelLiveRun();
258
+ }
259
+ )) {
220
260
  for (const event of cursorSdkMessageToEvents(msg)) {
221
261
  stream.push(event);
222
262
  }
223
263
  }
224
264
  stream.flush();
225
- const result = await run.wait();
265
+ const result = streamIdle ? await Promise.race([
266
+ run.wait(),
267
+ new Promise((resolve) => {
268
+ setTimeout(() => resolve({ status: "cancelled" }), 5e3);
269
+ })
270
+ ]) : await run.wait();
226
271
  if (result.status === "error") {
227
272
  const detail = formatUnknownDetail(result.error);
228
273
  emit({
@@ -32,15 +32,15 @@ import {
32
32
  resolveCursorModelId,
33
33
  resolveLoginCommand,
34
34
  resolveQuotaFallbackAgent
35
- } from "./chunk-FYS2BULQ.js";
35
+ } from "./chunk-EQPQTLW6.js";
36
36
  import "./chunk-DKHGWYWR.js";
37
37
  import {
38
38
  ORCHESTRATOR_AGENT_KINDS,
39
39
  assertOrchestratorCapableAgent,
40
40
  coerceOrchestratorAgent,
41
41
  isOrchestratorCapableAgent
42
- } from "./chunk-HI2OTFFR.js";
43
- import "./chunk-XH2GS2LO.js";
42
+ } from "./chunk-WQTTUC4N.js";
43
+ import "./chunk-IFHKPZHA.js";
44
44
  import "./chunk-R7BQBSDT.js";
45
45
  import "./chunk-B3SJXYIJ.js";
46
46
  import "./chunk-JOF3XIEM.js";
@@ -28,19 +28,19 @@ import {
28
28
  resolveCursorModelId,
29
29
  resolveLoginCommand,
30
30
  resolveQuotaFallbackAgent
31
- } from "./chunk-MBP3XG57.js";
31
+ } from "./chunk-OXC3MEFI.js";
32
32
  import {
33
33
  ORCHESTRATOR_AGENT_KINDS,
34
34
  assertOrchestratorCapableAgent,
35
35
  coerceOrchestratorAgent,
36
36
  isOrchestratorCapableAgent
37
- } from "./chunk-FO67IJTY.js";
38
- import "./chunk-XUWDLRAE.js";
37
+ } from "./chunk-GR4JKWR4.js";
38
+ import "./chunk-HYKZEP5A.js";
39
39
  import "./chunk-QSLE4VEM.js";
40
40
  import {
41
41
  cursorSdkMessageToEvents,
42
42
  parseCursorRunnerLine
43
- } from "./chunk-GXSYI7FH.js";
43
+ } from "./chunk-HUKCGRAT.js";
44
44
  import "./chunk-CIRXAYWS.js";
45
45
  import "./chunk-FKOIHGKV.js";
46
46
  import "./chunk-FT2SQOL4.js";
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-DKHGWYWR.js";
10
10
  import {
11
11
  isOrchestratorThread
12
- } from "./chunk-HI2OTFFR.js";
12
+ } from "./chunk-WQTTUC4N.js";
13
13
  import {
14
14
  codexUnattendedGitConfigArgs,
15
15
  mergeAgentGitAuthEnv,
@@ -178,7 +178,15 @@ function looksLikeMinifiedJsDump(line) {
178
178
  function looksLikeNestedElectronCrash(line) {
179
179
  return /HasCustomHostObject|ElectronInitializeICUandStartNode/i.test(line);
180
180
  }
181
+ function looksLikeHomebrewLibuvCrash(line) {
182
+ const uvRun = /uv_run/i.test(line);
183
+ const spin = /SpinEventLoopInternal/i.test(line);
184
+ const homebrewUv = /Cellar\/libuv|libuv\.\d\.dylib/i.test(line);
185
+ const homebrewNode = /Cellar\/node\//i.test(line);
186
+ return uvRun && (homebrewUv || spin || homebrewNode) || spin && (homebrewUv || homebrewNode);
187
+ }
181
188
  var NESTED_ELECTRON_SUMMARY = "Cursor local agent crashed at Electron startup (nested Chromium / HasCustomHostObject)";
189
+ var HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 22 LTS (`brew install node@22`) and retry.";
182
190
  var MINIFIED_DUMP_SUMMARY = "Cursor local agent crashed during startup (truncated crash dump)";
183
191
  function clipStderr(text, maxChars) {
184
192
  const trimmed = text.trim();
@@ -190,6 +198,7 @@ function summarizeTurnStderr(tail, maxChars = 500) {
190
198
  const cursorStartup = [...tail].reverse().find((line) => /cursor startup failed:/i.test(line));
191
199
  if (cursorStartup) return clipStderr(cursorStartup, maxChars);
192
200
  if (tail.some(looksLikeNestedElectronCrash)) return NESTED_ELECTRON_SUMMARY;
201
+ if (tail.some(looksLikeHomebrewLibuvCrash)) return HOMEBREW_LIBUV_SUMMARY;
193
202
  if (tail.some(
194
203
  (line) => /\[resource_exhausted\]|resource_exhausted/i.test(line) || /findFilesWithRipgrep/.test(line)
195
204
  )) {
@@ -212,6 +221,20 @@ function looksLikeInvalidAgentSession(text) {
212
221
  if (!lower) return false;
213
222
  return /session not found/.test(lower) || /no conversation found/.test(lower) || /conversation .+ not found/.test(lower) || /thread .+ not found/.test(lower) || /unknown session/.test(lower) || /invalid session/.test(lower) || /session .+ (missing|expired|deleted|gone)/.test(lower) || /cannot resume/.test(lower) || /failed to (load|resume|open) session/.test(lower) || /corrupt local agent checkpoint/.test(lower) || /missing root blob/.test(lower) || /\bagent\b.{0,120}\bnot found\b/.test(lower);
214
223
  }
224
+ function looksLikeRetryableRunnerCrash(text) {
225
+ if (looksLikeAgentFailureMessage(text)) return false;
226
+ if (looksLikeInvalidAgentSession(text)) return false;
227
+ const lower = text.trim().toLowerCase();
228
+ if (/cannot find (?:package|module)|err_module_not_found/.test(lower)) return false;
229
+ if (!lower) return true;
230
+ return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
231
+ lower
232
+ );
233
+ }
234
+ function shouldRetryFailedAgentTurn(detail, opts) {
235
+ if (looksLikeInvalidAgentSession(detail) && opts.hasSession) return true;
236
+ return looksLikeRetryableRunnerCrash(detail);
237
+ }
215
238
  function looksLikeAgentFailureMessage(text) {
216
239
  const lower = text.trim().toLowerCase();
217
240
  if (!lower) return false;
@@ -256,11 +279,22 @@ function humanizeAgentFailDetail(detail) {
256
279
  if (/hascustomhostobject|electroninitializeicuandstartnode|nested chromium/i.test(lower)) {
257
280
  return `${raw} \u2014 retry the turn; if it keeps failing, pick another agent.`;
258
281
  }
282
+ if (/homebrew node \+ shared libuv|uv_run|spineventloopinternal/i.test(lower)) {
283
+ return /brew install node@22/i.test(raw) ? raw : `${raw} \u2014 install Node 22 LTS (\`brew install node@22\`) and retry.`;
284
+ }
259
285
  if (/corrupt local agent checkpoint|missing root blob|truncated crash dump/.test(lower)) {
260
286
  return `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
261
287
  }
262
288
  return raw;
263
289
  }
290
+ function turnFailChatText(opts) {
291
+ const chat = opts.assistantText.trim();
292
+ if (chat) return chat;
293
+ if (opts.exitCode === 0) return "";
294
+ const detail = opts.detail.trim();
295
+ if (detail) return humanizeAgentFailDetail(detail);
296
+ return formatTurnExitError(opts.exitCode ?? 1, "");
297
+ }
264
298
  function formatTurnExitError(exitCode, stderrSummary) {
265
299
  const code = exitCode ?? 1;
266
300
  const raw = stderrSummary.trim();
@@ -639,9 +673,54 @@ function sideboardMcpProfile(env = process.env) {
639
673
  }
640
674
 
641
675
  // src/agents/node-launch.ts
642
- import { existsSync as existsSync2 } from "fs";
676
+ import { existsSync as existsSync3, readdirSync, realpathSync } from "fs";
643
677
  import { homedir } from "os";
678
+ import { join as join2 } from "path";
679
+
680
+ // src/agents/packaged-runtime.ts
681
+ import { existsSync as existsSync2 } from "fs";
644
682
  import { join } from "path";
683
+ function electronResourcesPath() {
684
+ const resources = process.resourcesPath;
685
+ if (typeof resources !== "string" || !resources) return null;
686
+ return resources;
687
+ }
688
+ function packagedCursorRuntimeDir() {
689
+ const resources = electronResourcesPath();
690
+ if (!resources) return null;
691
+ const dir = join(resources, "cursor-runtime");
692
+ if (!existsSync2(join(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
693
+ return dir;
694
+ }
695
+ function packagedCursorRunnerPath() {
696
+ const dir = packagedCursorRuntimeDir();
697
+ return dir ? join(dir, "core-dist", "agents", "cursor-runner.js") : null;
698
+ }
699
+ function packagedMcpDir() {
700
+ const resources = electronResourcesPath();
701
+ if (!resources) return null;
702
+ const dir = join(resources, "sideboard-mcp");
703
+ if (!existsSync2(join(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
704
+ return dir;
705
+ }
706
+ function packagedMcpStdioPath() {
707
+ const dir = packagedMcpDir();
708
+ return dir ? join(dir, "core-dist", "mcp", "run-stdio.js") : null;
709
+ }
710
+ function packagedBundledNodePath() {
711
+ const resources = electronResourcesPath();
712
+ if (!resources) return null;
713
+ const bin = join(resources, "node", "bin", "node");
714
+ if (!existsSync2(bin)) return null;
715
+ return bin;
716
+ }
717
+ function packagedCursorRipgrepCandidate(platformPkg, binName) {
718
+ const dir = packagedCursorRuntimeDir();
719
+ if (!dir) return null;
720
+ return join(dir, "node_modules", platformPkg, "bin", binName);
721
+ }
722
+
723
+ // src/agents/node-launch.ts
645
724
  function isAsarPath(filePath) {
646
725
  if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
647
726
  return /\.asar([/\\]|$)/.test(filePath);
@@ -650,28 +729,130 @@ function unpackedAsarPath(filePath) {
650
729
  if (!isAsarPath(filePath)) return null;
651
730
  const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
652
731
  if (unpacked === filePath) return null;
653
- return existsSync2(unpacked) ? unpacked : null;
732
+ return existsSync3(unpacked) ? unpacked : null;
654
733
  }
655
734
  function nodeReadableScriptPath(scriptPath) {
656
735
  return unpackedAsarPath(scriptPath) ?? scriptPath;
657
736
  }
658
- var WELL_KNOWN_NODE_BINS = [
659
- "/opt/homebrew/bin/node",
660
- "/usr/local/bin/node"
661
- ];
662
- async function findSystemNode() {
663
- const whichNode = await run("which", ["node"], { reject: false });
664
- const fromWhich = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : "";
665
- if (fromWhich && !isElectronLikeCommand(fromWhich)) return fromWhich;
666
- const fallbacks = [
667
- ...WELL_KNOWN_NODE_BINS,
668
- join(homedir(), ".local/share/fnm/aliases/default/bin/node"),
669
- join(homedir(), ".nvm/current/bin/node")
737
+ var PREFERRED_LTS_MAJORS = [24, 22, 20];
738
+ function parseNodeMajor(version) {
739
+ const match = /^v?(\d+)/.exec(version.trim());
740
+ if (!match) return null;
741
+ const major = Number(match[1]);
742
+ return Number.isInteger(major) ? major : null;
743
+ }
744
+ function scoreNodeForAgentRuntime(candidate) {
745
+ const major = parseNodeMajor(candidate.version);
746
+ if (major == null) return Number.NEGATIVE_INFINITY;
747
+ if (major < 20) return major - 100;
748
+ const posix = candidate.path.replace(/\\/g, "/");
749
+ let score = 0;
750
+ if (major % 2 === 0) {
751
+ score += 1e3 + major * 10;
752
+ } else {
753
+ score += major;
754
+ }
755
+ if (/\/Cellar\/node\/\d/.test(posix) && !/\/Cellar\/node@\d+/.test(posix)) {
756
+ score -= 50;
757
+ }
758
+ return score;
759
+ }
760
+ function pickPreferredNode(candidates) {
761
+ let best = null;
762
+ let bestScore = Number.NEGATIVE_INFINITY;
763
+ for (const candidate of candidates) {
764
+ const score = scoreNodeForAgentRuntime(candidate);
765
+ if (score > bestScore) {
766
+ bestScore = score;
767
+ best = candidate;
768
+ }
769
+ }
770
+ return best;
771
+ }
772
+ function versionDirNodeBins(root, toBin) {
773
+ if (!existsSync3(root)) return [];
774
+ try {
775
+ return readdirSync(root).map(toBin);
776
+ } catch {
777
+ return [];
778
+ }
779
+ }
780
+ function defaultNodeBinCandidates(home = homedir()) {
781
+ const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
782
+ (prefix) => PREFERRED_LTS_MAJORS.map((major) => join2(prefix, "opt", `node@${major}`, "bin", "node"))
783
+ );
784
+ return [
785
+ ...kegs,
786
+ "/opt/homebrew/bin/node",
787
+ "/usr/local/bin/node",
788
+ join2(home, ".local/share/fnm/aliases/default/bin/node"),
789
+ join2(home, ".nvm/current/bin/node"),
790
+ join2(home, ".volta/bin/node"),
791
+ join2(home, ".asdf/shims/node"),
792
+ join2(home, ".local/share/mise/shims/node"),
793
+ ...versionDirNodeBins(
794
+ join2(home, ".nvm", "versions", "node"),
795
+ (name) => join2(home, ".nvm", "versions", "node", name, "bin", "node")
796
+ ),
797
+ ...versionDirNodeBins(
798
+ join2(home, ".local/share/fnm", "node-versions"),
799
+ (name) => join2(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
800
+ ),
801
+ ...versionDirNodeBins(
802
+ join2(home, ".volta", "tools", "image", "node"),
803
+ (name) => join2(home, ".volta", "tools", "image", "node", name, "bin", "node")
804
+ )
670
805
  ];
671
- for (const bin of fallbacks) {
672
- if (existsSync2(bin) && !isElectronLikeCommand(bin)) return bin;
806
+ }
807
+ function uniqueExistingNodeBins(paths) {
808
+ const seen = /* @__PURE__ */ new Set();
809
+ const out = [];
810
+ for (const raw of paths) {
811
+ const p = raw.trim();
812
+ if (!p || !existsSync3(p) || isElectronLikeCommand(p)) continue;
813
+ let key = p;
814
+ try {
815
+ key = realpathSync(p);
816
+ } catch {
817
+ continue;
818
+ }
819
+ if (seen.has(key)) continue;
820
+ seen.add(key);
821
+ out.push(p);
673
822
  }
674
- return null;
823
+ return out;
824
+ }
825
+ async function whichAllNode() {
826
+ if (process.platform === "win32") {
827
+ const located = await run("where", ["node"], { reject: false, timeoutMs: 5e3 });
828
+ if (located.exitCode !== 0) return [];
829
+ return located.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
830
+ }
831
+ const all = await run("which", ["-a", "node"], { reject: false, timeoutMs: 5e3 });
832
+ if (all.exitCode === 0 && all.stdout.trim()) {
833
+ return all.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
834
+ }
835
+ const single = await run("which", ["node"], { reject: false, timeoutMs: 5e3 });
836
+ if (single.exitCode !== 0 || !single.stdout.trim()) return [];
837
+ return [single.stdout.trim()];
838
+ }
839
+ async function probeNodeVersion(bin) {
840
+ const probed = await run(bin, ["-v"], { reject: false, timeoutMs: 4e3 });
841
+ if (probed.exitCode !== 0) return null;
842
+ const version = probed.stdout.trim().split(/\r?\n/).find(Boolean);
843
+ return version || null;
844
+ }
845
+ async function findSystemNode() {
846
+ const fromPath = await whichAllNode();
847
+ const bins = uniqueExistingNodeBins([...fromPath, ...defaultNodeBinCandidates()]);
848
+ if (bins.length === 0) return null;
849
+ const probed = await Promise.all(
850
+ bins.map(async (path) => {
851
+ const version = await probeNodeVersion(path);
852
+ return version ? { path, version } : null;
853
+ })
854
+ );
855
+ return pickPreferredNode(probed.filter((c) => c != null));
675
856
  }
676
857
  function applyNodeLaunch(launch, args) {
677
858
  const readableArgs = args.map(nodeReadableScriptPath);
@@ -689,9 +870,13 @@ function applyNodeLaunch(launch, args) {
689
870
  async function resolveNodeLaunch(scriptPath) {
690
871
  const script = nodeReadableScriptPath(scriptPath);
691
872
  if (!isAsarPath(script)) {
692
- const nodeBin = await findSystemNode();
693
- if (nodeBin) {
694
- return { file: nodeBin, env: {} };
873
+ const bundled = packagedBundledNodePath();
874
+ if (bundled && !isElectronLikeCommand(bundled)) {
875
+ return { file: bundled, env: {} };
876
+ }
877
+ const node = await findSystemNode();
878
+ if (node) {
879
+ return { file: node.path, env: {}, nodeVersion: node.version };
695
880
  }
696
881
  }
697
882
  return {
@@ -700,42 +885,6 @@ async function resolveNodeLaunch(scriptPath) {
700
885
  };
701
886
  }
702
887
 
703
- // src/agents/packaged-runtime.ts
704
- import { existsSync as existsSync3 } from "fs";
705
- import { join as join2 } from "path";
706
- function electronResourcesPath() {
707
- const resources = process.resourcesPath;
708
- if (typeof resources !== "string" || !resources) return null;
709
- return resources;
710
- }
711
- function packagedCursorRuntimeDir() {
712
- const resources = electronResourcesPath();
713
- if (!resources) return null;
714
- const dir = join2(resources, "cursor-runtime");
715
- if (!existsSync3(join2(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
716
- return dir;
717
- }
718
- function packagedCursorRunnerPath() {
719
- const dir = packagedCursorRuntimeDir();
720
- return dir ? join2(dir, "core-dist", "agents", "cursor-runner.js") : null;
721
- }
722
- function packagedMcpDir() {
723
- const resources = electronResourcesPath();
724
- if (!resources) return null;
725
- const dir = join2(resources, "sideboard-mcp");
726
- if (!existsSync3(join2(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
727
- return dir;
728
- }
729
- function packagedMcpStdioPath() {
730
- const dir = packagedMcpDir();
731
- return dir ? join2(dir, "core-dist", "mcp", "run-stdio.js") : null;
732
- }
733
- function packagedCursorRipgrepCandidate(platformPkg, binName) {
734
- const dir = packagedCursorRuntimeDir();
735
- if (!dir) return null;
736
- return join2(dir, "node_modules", platformPkg, "bin", binName);
737
- }
738
-
739
888
  // src/agents/injected-mcp.ts
740
889
  var SIDEBOARD_MCP_ALLOWED_TOOLS = [
741
890
  "mcp__sideboard",
@@ -1208,7 +1357,7 @@ var claudeAdapter = {
1208
1357
  );
1209
1358
  }
1210
1359
  const mode = permissionMode(thread);
1211
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-WMF3BJP5.js");
1360
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-YZWYHLQY.js");
1212
1361
  const isOrchestrator = isOrchestratorThread2(thread);
1213
1362
  const injectedServers = await buildInjectedMcpServers({
1214
1363
  includeSideboard: true,
@@ -2841,9 +2990,10 @@ export {
2841
2990
  pushTurnStderr,
2842
2991
  summarizeTurnStderr,
2843
2992
  looksLikeInvalidAgentSession,
2993
+ shouldRetryFailedAgentTurn,
2844
2994
  looksLikeAgentFailureMessage,
2845
2995
  fallbackTurnFailDetail,
2846
- humanizeAgentFailDetail,
2996
+ turnFailChatText,
2847
2997
  formatTurnExitError,
2848
2998
  applyTurnUsage,
2849
2999
  encodeBrightsyTarget,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ensureGlobalCoordinatorCwd
3
- } from "./chunk-XUWDLRAE.js";
3
+ } from "./chunk-HYKZEP5A.js";
4
4
  import {
5
5
  allocateTeamName,
6
6
  takenSlugsFromThread,