@sideboard-ai/core 0.1.99 → 0.1.103

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 (52) hide show
  1. package/dist/agents/cursor-runner.cjs +22 -22
  2. package/dist/agents/cursor-runner.js +2 -2
  3. package/dist/{agents-ESJKIQQA.js → agents-UT5GCJH3.js} +8 -8
  4. package/dist/{agents-3MWWWSMF.js → agents-XZBAKBO2.js} +9 -9
  5. package/dist/{app-settings-BRF7VKTQ.js → app-settings-EKJM2344.js} +2 -2
  6. package/dist/{app-settings-ZXPAB3QN.js → app-settings-VDJK2BZ2.js} +2 -2
  7. package/dist/{caffeinate-hold-U3QJBV67.js → caffeinate-hold-NBRUWYXO.js} +2 -2
  8. package/dist/{caffeinate-hold-I7SG6UQR.js → caffeinate-hold-X3JNPR42.js} +2 -2
  9. package/dist/{chunk-UYQYK2RY.js → chunk-27MCESES.js} +3 -3
  10. package/dist/{chunk-QSLE4VEM.js → chunk-2GO3YKBA.js} +4 -4
  11. package/dist/{chunk-DKHGWYWR.js → chunk-7YKXHBIW.js} +1 -1
  12. package/dist/{chunk-JL4SJ6V7.js → chunk-BD2ICC4D.js} +4 -0
  13. package/dist/{chunk-NZPGMNFC.js → chunk-DCOZABNT.js} +1 -1
  14. package/dist/{chunk-CIRXAYWS.js → chunk-DHAGMJIK.js} +55 -28
  15. package/dist/{chunk-XUWDLRAE.js → chunk-ETMRBJKA.js} +11 -11
  16. package/dist/{chunk-MBP3XG57.js → chunk-H6LP57EF.js} +7 -7
  17. package/dist/{chunk-FO67IJTY.js → chunk-HHLZWO7U.js} +5 -5
  18. package/dist/{chunk-GXSYI7FH.js → chunk-HUKCGRAT.js} +209 -59
  19. package/dist/{chunk-3WA37BRI.js → chunk-KGSVLZV6.js} +11 -4
  20. package/dist/{chunk-7KDBDMNC.js → chunk-KLBOWJ74.js} +1 -1
  21. package/dist/{chunk-FYS2BULQ.js → chunk-LANDJIAI.js} +213 -63
  22. package/dist/{chunk-OANJQTVG.js → chunk-ND6AO7C5.js} +3 -3
  23. package/dist/{chunk-HI2OTFFR.js → chunk-OW34MVDN.js} +5 -5
  24. package/dist/{chunk-JOF3XIEM.js → chunk-P3BQ5DOL.js} +11 -4
  25. package/dist/{chunk-B4R2VB2A.js → chunk-QZQEXME2.js} +4 -0
  26. package/dist/{chunk-R7BQBSDT.js → chunk-WA3DVVWG.js} +55 -28
  27. package/dist/{chunk-6LFV4VFI.js → chunk-WSYCND2U.js} +1 -1
  28. package/dist/{chunk-FT2SQOL4.js → chunk-XHZJJWLI.js} +1 -1
  29. package/dist/{chunk-XH2GS2LO.js → chunk-YJADJH5U.js} +11 -11
  30. package/dist/{connected-teams-SWHJWK2A.js → connected-teams-J4I5AKMR.js} +2 -2
  31. package/dist/{connected-teams-TLVKZPJP.js → connected-teams-M5XNXRI5.js} +2 -2
  32. package/dist/{coordinator-prompt-OQOOD5ET.js → coordinator-prompt-3DFZRMXE.js} +5 -5
  33. package/dist/{coordinator-prompt-AKEY4WSO.js → coordinator-prompt-UWHSD65V.js} +5 -5
  34. package/dist/{cursor-recover-S5ORPW34.js → cursor-recover-JBTIDARH.js} +1 -1
  35. package/dist/{cursor-recover-G34BYKL2.js → cursor-recover-ZUJG6XRQ.js} +1 -1
  36. package/dist/{global-workspace-WMF3BJP5.js → global-workspace-KJQS5S2C.js} +6 -6
  37. package/dist/{global-workspace-RSQXRLT7.js → global-workspace-UR4E3CCG.js} +6 -6
  38. package/dist/index.cjs +851 -232
  39. package/dist/index.d.cts +39 -6
  40. package/dist/index.d.ts +39 -6
  41. package/dist/index.js +561 -138
  42. package/dist/mcp/run-stdio.cjs +651 -256
  43. package/dist/mcp/run-stdio.js +345 -143
  44. package/dist/{paths-TZX4L5X7.js → paths-QCI3MTO5.js} +3 -1
  45. package/dist/{paths-JQM2XRAD.js → paths-UMEDHOS5.js} +3 -1
  46. package/dist/{thread-store-XAKWCV2E.js → thread-store-4OUEQ2DB.js} +2 -2
  47. package/dist/{thread-store-V7NOOXKE.js → thread-store-DQJGDKIJ.js} +2 -2
  48. package/dist/{workspaces-MZVQHRSJ.js → workspaces-NTIVI6DI.js} +7 -7
  49. package/dist/{workspaces-4ZY4QPWQ.js → workspaces-TKJXPNV4.js} +7 -7
  50. package/dist/{worktree-EO5QAGJU.js → worktree-NKWN5ZTS.js} +4 -4
  51. package/dist/{worktree-DA4BOV7G.js → worktree-PEUPFAKL.js} +4 -4
  52. package/package.json +2 -2
@@ -6,16 +6,16 @@ import {
6
6
  ensureCliTeamTracked,
7
7
  ensureConnectedBrightsyTeamTokens,
8
8
  loadBrightsyConfig
9
- } from "./chunk-DKHGWYWR.js";
9
+ } from "./chunk-7YKXHBIW.js";
10
10
  import {
11
11
  isOrchestratorThread
12
- } from "./chunk-HI2OTFFR.js";
12
+ } from "./chunk-OW34MVDN.js";
13
13
  import {
14
14
  codexUnattendedGitConfigArgs,
15
15
  mergeAgentGitAuthEnv,
16
16
  resolveAgentGitAuthEnv,
17
17
  resolveCodexGitWritableRoots
18
- } from "./chunk-R7BQBSDT.js";
18
+ } from "./chunk-WA3DVVWG.js";
19
19
  import {
20
20
  claudeChromeEnabled,
21
21
  isElectronLikeCommand,
@@ -24,10 +24,10 @@ import {
24
24
  resolveClaudeExecutable,
25
25
  unwrapStrippedElectronLaunch,
26
26
  wrapElectronAsNodeLaunch
27
- } from "./chunk-6LFV4VFI.js";
27
+ } from "./chunk-WSYCND2U.js";
28
28
  import {
29
29
  appDataDir
30
- } from "./chunk-JL4SJ6V7.js";
30
+ } from "./chunk-BD2ICC4D.js";
31
31
  import {
32
32
  enrichPathWithNpmGlobalBin,
33
33
  isConductorBundledCli,
@@ -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-KJQS5S2C.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,
@@ -2,14 +2,14 @@
2
2
 
3
3
  import {
4
4
  isGlobalRepoPath
5
- } from "./chunk-HI2OTFFR.js";
5
+ } from "./chunk-OW34MVDN.js";
6
6
  import {
7
7
  ensureGhPreferOrigin,
8
8
  resolveRepoRoot
9
- } from "./chunk-R7BQBSDT.js";
9
+ } from "./chunk-WA3DVVWG.js";
10
10
  import {
11
11
  appDataDir
12
- } from "./chunk-JL4SJ6V7.js";
12
+ } from "./chunk-BD2ICC4D.js";
13
13
 
14
14
  // src/store/workspaces.ts
15
15
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -2,25 +2,25 @@
2
2
 
3
3
  import {
4
4
  ensureGlobalCoordinatorCwd
5
- } from "./chunk-XH2GS2LO.js";
5
+ } from "./chunk-YJADJH5U.js";
6
6
  import {
7
7
  allocateTeamName,
8
8
  takenSlugsFromThread,
9
9
  teamSlugFromName
10
- } from "./chunk-R7BQBSDT.js";
10
+ } from "./chunk-WA3DVVWG.js";
11
11
  import {
12
12
  createEmptyThread,
13
13
  listThreads,
14
14
  updateThread,
15
15
  writeThread
16
- } from "./chunk-JOF3XIEM.js";
16
+ } from "./chunk-P3BQ5DOL.js";
17
17
  import {
18
18
  resolveNewThreadOptions,
19
19
  resolveThreadDefaults
20
- } from "./chunk-6LFV4VFI.js";
20
+ } from "./chunk-WSYCND2U.js";
21
21
  import {
22
22
  globalAgentCwd
23
- } from "./chunk-JL4SJ6V7.js";
23
+ } from "./chunk-BD2ICC4D.js";
24
24
 
25
25
  // src/brightsy/cloud-connect-constants.ts
26
26
  var CLOUD_ORCHESTRATOR_GOAL = "Cloud-connected Sideboard orchestrator";
@@ -7,7 +7,7 @@ import {
7
7
  threadFilePath,
8
8
  threadLockPath,
9
9
  threadsDir
10
- } from "./chunk-JL4SJ6V7.js";
10
+ } from "./chunk-BD2ICC4D.js";
11
11
 
12
12
  // src/store/thread-store.ts
13
13
  import { randomUUID } from "crypto";
@@ -119,8 +119,11 @@ function writeThread(thread) {
119
119
  function idPath(id) {
120
120
  return id;
121
121
  }
122
+ function isThreadRecordFile(name) {
123
+ return name.endsWith(".json") && !name.endsWith(".live.json");
124
+ }
122
125
  function listThreads(opts) {
123
- const files = readdirSync(threadsDir()).filter((f) => f.endsWith(".json"));
126
+ const files = readdirSync(threadsDir()).filter(isThreadRecordFile);
124
127
  const threads = files.map((f) => {
125
128
  try {
126
129
  return normalizeThread(
@@ -129,7 +132,9 @@ function listThreads(opts) {
129
132
  } catch {
130
133
  return null;
131
134
  }
132
- }).filter((t) => t !== null).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
135
+ }).filter(
136
+ (t) => t !== null && typeof t.id === "string" && t.id.length > 0
137
+ ).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
133
138
  if (opts?.includeArchived) return threads;
134
139
  return threads.filter((t) => t.status !== "archived");
135
140
  }
@@ -161,7 +166,9 @@ function setStatus(id, status, lastError) {
161
166
  }
162
167
  function findThreadByRef(ref) {
163
168
  const all = listThreads({ includeArchived: true });
164
- return all.find((t) => t.id === ref || t.id.startsWith(ref) || t.branchName === ref || t.title === ref) ?? null;
169
+ return all.find(
170
+ (t) => t.id === ref || t.id.startsWith(ref) || t.branchName === ref || t.title === ref
171
+ ) ?? null;
165
172
  }
166
173
 
167
174
  export {
@@ -400,6 +400,9 @@ function worktreesRoot(repoPath) {
400
400
  function threadFilePath(id) {
401
401
  return join4(threadsDir(), `${id}.json`);
402
402
  }
403
+ function threadLivePath(id) {
404
+ return join4(threadsDir(), `${id}.live.json`);
405
+ }
403
406
  function threadLockPath(id) {
404
407
  return join4(locksDir(), `${id}.lock`);
405
408
  }
@@ -433,6 +436,7 @@ export {
433
436
  repoSlug,
434
437
  worktreesRoot,
435
438
  threadFilePath,
439
+ threadLivePath,
436
440
  threadLockPath,
437
441
  globalAgentCwd
438
442
  };
@@ -5,14 +5,14 @@ import {
5
5
  } from "./chunk-B3SJXYIJ.js";
6
6
  import {
7
7
  listThreads
8
- } from "./chunk-JOF3XIEM.js";
8
+ } from "./chunk-P3BQ5DOL.js";
9
9
  import {
10
10
  getGithubGitAuthMode,
11
11
  getGithubPat
12
- } from "./chunk-6LFV4VFI.js";
12
+ } from "./chunk-WSYCND2U.js";
13
13
  import {
14
14
  worktreesRoot
15
- } from "./chunk-JL4SJ6V7.js";
15
+ } from "./chunk-BD2ICC4D.js";
16
16
  import {
17
17
  gh,
18
18
  git,
@@ -787,7 +787,7 @@ function allocateTeamName(taken, random = Math.random) {
787
787
 
788
788
  // src/git/worktree-labels.ts
789
789
  function normalizeWorktreePath(worktreePath) {
790
- const trimmed = worktreePath.replace(/\/+$/, "") || "/";
790
+ const trimmed = (worktreePath ?? "").replace(/\/+$/, "") || "/";
791
791
  const absolute = trimmed.startsWith("/");
792
792
  const parts = trimmed.split("/").filter((p) => p && p !== ".");
793
793
  const out = [];
@@ -1154,6 +1154,30 @@ function formatGitAuthModeDirective(mode) {
1154
1154
  }
1155
1155
  }
1156
1156
 
1157
+ // src/util/enqueue-by-key.ts
1158
+ var tails = /* @__PURE__ */ new Map();
1159
+ function enqueueByKey(key, fn) {
1160
+ const prev = tails.get(key) ?? Promise.resolve();
1161
+ const next = prev.then(fn, fn);
1162
+ tails.set(
1163
+ key,
1164
+ next.then(
1165
+ () => void 0,
1166
+ () => void 0
1167
+ )
1168
+ );
1169
+ return next;
1170
+ }
1171
+
1172
+ // src/git/repo-git-lock.ts
1173
+ function repoLockKey(repoPath) {
1174
+ const trimmed = repoPath.replace(/\/+$/, "");
1175
+ return `git-worktree:${trimmed || "/"}`;
1176
+ }
1177
+ function withRepoGitLock(repoPath, fn) {
1178
+ return enqueueByKey(repoLockKey(repoPath), fn);
1179
+ }
1180
+
1157
1181
  // src/git/pr-gates.ts
1158
1182
  function prIsInMergeQueue(gate) {
1159
1183
  if (gate.isInMergeQueue) return true;
@@ -2223,12 +2247,13 @@ async function createThreadWorktree(opts) {
2223
2247
  `Invalid git reference: ${opts.sourceRef} (and fetch did not resolve it)`
2224
2248
  );
2225
2249
  }
2226
- const add = await git(
2227
- ["worktree", "add", "-b", branchName, worktreePath, startPoint],
2228
- opts.repoPath,
2229
- { reject: false, timeoutMs: 6e4 }
2230
- );
2231
- if (add.exitCode !== 0) {
2250
+ const added = await withRepoGitLock(opts.repoPath, async () => {
2251
+ const add = await git(
2252
+ ["worktree", "add", "-b", branchName, worktreePath, startPoint],
2253
+ opts.repoPath,
2254
+ { reject: false, timeoutMs: 6e4 }
2255
+ );
2256
+ if (add.exitCode === 0) return branchName;
2232
2257
  const err = `${add.stderr}
2233
2258
  ${add.stdout}`;
2234
2259
  if (/already used by worktree|already exists|checked out/i.test(err)) {
@@ -2239,17 +2264,14 @@ ${add.stdout}`;
2239
2264
  opts.repoPath,
2240
2265
  { reject: false, timeoutMs: 6e4 }
2241
2266
  );
2242
- if (retry.exitCode === 0) {
2243
- branchName = alt;
2244
- await ensureGhPreferOrigin(worktreePath);
2245
- return { branchName, worktreePath };
2246
- }
2267
+ if (retry.exitCode === 0) return alt;
2247
2268
  }
2248
2269
  }
2249
2270
  throw new Error(
2250
2271
  `Failed to create worktree: ${add.stderr.trim() || add.stdout.trim() || `exit ${add.exitCode}`}`
2251
2272
  );
2252
- }
2273
+ });
2274
+ branchName = added;
2253
2275
  await ensureGhPreferOrigin(worktreePath);
2254
2276
  return { branchName, worktreePath };
2255
2277
  }
@@ -2273,12 +2295,13 @@ async function createExistingBranchWorktree(opts) {
2273
2295
  );
2274
2296
  }
2275
2297
  const startPoint = await resolveWorktreeStartPoint(opts.repoPath, branchName);
2276
- const add = await git(
2277
- ["worktree", "add", worktreePath, startPoint],
2278
- opts.repoPath,
2279
- { reject: false }
2280
- );
2281
- if (add.exitCode !== 0) {
2298
+ await withRepoGitLock(opts.repoPath, async () => {
2299
+ const add = await git(
2300
+ ["worktree", "add", worktreePath, startPoint],
2301
+ opts.repoPath,
2302
+ { reject: false }
2303
+ );
2304
+ if (add.exitCode === 0) return;
2282
2305
  const retry = await git(
2283
2306
  ["worktree", "add", worktreePath, branchName],
2284
2307
  opts.repoPath,
@@ -2289,7 +2312,7 @@ async function createExistingBranchWorktree(opts) {
2289
2312
  `Failed to create worktree for ${branchName}: ${retry.stderr.trim() || add.stderr.trim() || retry.stdout.trim() || add.stdout.trim() || `exit ${add.exitCode}`}`
2290
2313
  );
2291
2314
  }
2292
- }
2315
+ });
2293
2316
  const head = await git(["rev-parse", "--abbrev-ref", "HEAD"], worktreePath, {
2294
2317
  reject: false
2295
2318
  });
@@ -2300,12 +2323,14 @@ async function createExistingBranchWorktree(opts) {
2300
2323
  return { branchName, worktreePath };
2301
2324
  }
2302
2325
  async function removeWorktree(repoPath, worktreePath, opts) {
2303
- await git(["worktree", "remove", "--force", worktreePath], repoPath, {
2304
- reject: false
2326
+ await withRepoGitLock(repoPath, async () => {
2327
+ await git(["worktree", "remove", "--force", worktreePath], repoPath, {
2328
+ reject: false
2329
+ });
2330
+ if (opts?.deleteBranch) {
2331
+ await git(["branch", "-D", opts.deleteBranch], repoPath, { reject: false });
2332
+ }
2305
2333
  });
2306
- if (opts?.deleteBranch) {
2307
- await git(["branch", "-D", opts.deleteBranch], repoPath, { reject: false });
2308
- }
2309
2334
  }
2310
2335
  async function listWorktrees(repoPath) {
2311
2336
  const { stdout } = await git(
@@ -2606,6 +2631,8 @@ export {
2606
2631
  resolveCodexGitWritableRoots,
2607
2632
  codexUnattendedGitConfigArgs,
2608
2633
  formatGitAuthModeDirective,
2634
+ enqueueByKey,
2635
+ withRepoGitLock,
2609
2636
  detectGhStack,
2610
2637
  getPrStack,
2611
2638
  initPrStack,
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-KGZBYWZ3.js";
10
10
  import {
11
11
  appDataDir
12
- } from "./chunk-JL4SJ6V7.js";
12
+ } from "./chunk-BD2ICC4D.js";
13
13
 
14
14
  // src/store/app-settings.ts
15
15
  import { randomUUID } from "crypto";
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-77WWLBCI.js";
11
11
  import {
12
12
  appDataDir
13
- } from "./chunk-B4R2VB2A.js";
13
+ } from "./chunk-QZQEXME2.js";
14
14
 
15
15
  // src/store/app-settings.ts
16
16
  import { randomUUID } from "crypto";