@sideboard-ai/core 0.1.89 → 0.1.95

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 (30) hide show
  1. package/dist/agents/cursor-runner.cjs +129 -14
  2. package/dist/agents/cursor-runner.js +4 -1
  3. package/dist/{agents-LMUFTGKF.js → agents-HBLA6FEV.js} +4 -4
  4. package/dist/{agents-ODBP7J6E.js → agents-WS5QV6LE.js} +5 -5
  5. package/dist/{chunk-WANQFU3S.js → chunk-6XBXVXX2.js} +2 -2
  6. package/dist/{chunk-7D27DD2X.js → chunk-CIRXAYWS.js} +260 -61
  7. package/dist/{chunk-B2KIO2SD.js → chunk-CLGO7TLO.js} +2 -2
  8. package/dist/{chunk-CBJSPTBG.js → chunk-GXSYI7FH.js} +206 -5
  9. package/dist/{chunk-RJLBSYUO.js → chunk-KWNUZ4LR.js} +46 -77
  10. package/dist/{chunk-UHTNJKZX.js → chunk-NR6APJLD.js} +2 -2
  11. package/dist/{chunk-6EZRSCIT.js → chunk-QKYO6BHB.js} +2 -2
  12. package/dist/{chunk-ZXYWWSHZ.js → chunk-R7BQBSDT.js} +254 -61
  13. package/dist/{chunk-JE75QW2I.js → chunk-WBX46OPD.js} +237 -96
  14. package/dist/{chunk-OB6IRIFV.js → chunk-XH2GS2LO.js} +2 -2
  15. package/dist/{chunk-VZ2L4AEJ.js → chunk-XUWDLRAE.js} +2 -2
  16. package/dist/{coordinator-prompt-UK5LYFN5.js → coordinator-prompt-AKEY4WSO.js} +2 -2
  17. package/dist/{coordinator-prompt-CI5SHONJ.js → coordinator-prompt-OQOOD5ET.js} +2 -2
  18. package/dist/{global-workspace-2YZ2V4I5.js → global-workspace-3GNPQCLE.js} +3 -3
  19. package/dist/{global-workspace-JQQLPJM5.js → global-workspace-M3OMVDDH.js} +3 -3
  20. package/dist/index.cjs +1021 -473
  21. package/dist/index.d.cts +91 -20
  22. package/dist/index.d.ts +91 -20
  23. package/dist/index.js +244 -59
  24. package/dist/mcp/run-stdio.cjs +816 -428
  25. package/dist/mcp/run-stdio.js +77 -40
  26. package/dist/{workspaces-YWCC3WV4.js → workspaces-ERZC7ULY.js} +4 -4
  27. package/dist/{workspaces-FDO5L4NI.js → workspaces-J4WG6UFR.js} +4 -4
  28. package/dist/{worktree-7YNSJ224.js → worktree-DA4BOV7G.js} +7 -1
  29. package/dist/{worktree-4555QBQ7.js → worktree-EO5QAGJU.js} +7 -1
  30. package/package.json +1 -1
@@ -9,11 +9,13 @@ import {
9
9
  } from "./chunk-DKHGWYWR.js";
10
10
  import {
11
11
  isOrchestratorThread
12
- } from "./chunk-UHTNJKZX.js";
12
+ } from "./chunk-NR6APJLD.js";
13
13
  import {
14
14
  codexUnattendedGitConfigArgs,
15
- resolveAgentGitAuthEnv
16
- } from "./chunk-ZXYWWSHZ.js";
15
+ mergeAgentGitAuthEnv,
16
+ resolveAgentGitAuthEnv,
17
+ resolveCodexGitWritableRoots
18
+ } from "./chunk-R7BQBSDT.js";
17
19
  import {
18
20
  claudeChromeEnabled,
19
21
  isElectronLikeCommand,
@@ -151,17 +153,27 @@ function extractJsonErrorMessage(obj) {
151
153
  return null;
152
154
  }
153
155
  var NODE_VERSION_FOOTER = /^Node\.js v\d+/i;
156
+ function isPinnedStderrLine(line) {
157
+ if (/^\s*at\s/.test(line)) return false;
158
+ return /cannot find (?:package|module)|ERR_MODULE_NOT_FOUND|cursor startup failed:/i.test(
159
+ line
160
+ );
161
+ }
154
162
  function pushTurnStderr(tail, line, maxLines = 12) {
155
163
  const trimmed = line.trim();
156
164
  if (!trimmed) return;
157
165
  if (NODE_VERSION_FOOTER.test(trimmed)) return;
158
166
  if (/^reconnecting\.\.\./i.test(trimmed)) return;
159
167
  tail.push(trimmed);
160
- while (tail.length > maxLines) tail.shift();
168
+ while (tail.length > maxLines) {
169
+ const dropIdx = tail.findIndex((l) => !isPinnedStderrLine(l));
170
+ if (dropIdx === -1) tail.shift();
171
+ else tail.splice(dropIdx, 1);
172
+ }
161
173
  }
162
174
  function looksLikeMinifiedJsDump(line) {
163
175
  if (line.length < 200) return false;
164
- return /yield Promise\.all/.test(line) || /\(0,[A-Za-z$]\.\w+\)/.test(line) || /CURSOR_RIPGREP_PATH/.test(line);
176
+ return /yield Promise\.all/.test(line) || /\(0,[A-Za-z$]\.\w+\)/.test(line) || /CURSOR_RIPGREP_PATH/.test(line) || /findFilesWithRipgrep/.test(line) || /@cursor\/sdk\/dist\//.test(line);
165
177
  }
166
178
  function looksLikeNestedElectronCrash(line) {
167
179
  return /HasCustomHostObject|ElectronInitializeICUandStartNode/i.test(line);
@@ -178,7 +190,15 @@ function summarizeTurnStderr(tail, maxChars = 500) {
178
190
  const cursorStartup = [...tail].reverse().find((line) => /cursor startup failed:/i.test(line));
179
191
  if (cursorStartup) return clipStderr(cursorStartup, maxChars);
180
192
  if (tail.some(looksLikeNestedElectronCrash)) return NESTED_ELECTRON_SUMMARY;
181
- const moduleMissing = [...tail].reverse().find((line) => /cannot find module/i.test(line));
193
+ if (tail.some(
194
+ (line) => /\[resource_exhausted\]|resource_exhausted/i.test(line) || /findFilesWithRipgrep/.test(line)
195
+ )) {
196
+ return clipStderr(
197
+ "Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.",
198
+ maxChars
199
+ );
200
+ }
201
+ const moduleMissing = [...tail].reverse().find((line) => /cannot find (?:package|module)/i.test(line));
182
202
  if (moduleMissing) return clipStderr(moduleMissing, maxChars);
183
203
  const useful = tail.filter((line) => !looksLikeMinifiedJsDump(line));
184
204
  if (useful.length === 0 && tail.some(looksLikeMinifiedJsDump)) {
@@ -197,7 +217,7 @@ function looksLikeAgentFailureMessage(text) {
197
217
  if (!lower) return false;
198
218
  return /you've hit your|hit your (session|weekly|opus) limit|usage limit/.test(lower) || /credit balance is too low|out of credits|insufficient.?quota|quota.?exceeded/.test(lower) || /invalid user api key|invalid api key|not logged in|not authenticated|unauthorized/.test(
199
219
  lower
200
- ) || /\b429\b|too many requests|rate.?limit/.test(lower) || /prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower);
220
+ ) || /\b429\b|too many requests|rate.?limit/.test(lower) || /prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower) || /\[resource_exhausted\]|resource_exhausted/.test(lower) || /findFilesWithRipgrep/.test(text);
201
221
  }
202
222
  function fallbackTurnFailDetail(assistantText) {
203
223
  const t = assistantText.trim();
@@ -219,6 +239,9 @@ function humanizeAgentFailDetail(detail) {
219
239
  if (/\b429\b|rate.?limit|too many requests/.test(lower)) {
220
240
  return `${raw} \u2014 wait a moment and retry.`;
221
241
  }
242
+ if (/\[resource_exhausted\]|resource_exhausted|findfileswithripgrep/.test(lower)) {
243
+ return "Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.";
244
+ }
222
245
  if (/invalid user api key|invalid api key|not logged in|not authenticated|unauthorized|authentication|please run.*login|codex login|claude auth|cursor api/.test(
223
246
  lower
224
247
  )) {
@@ -566,7 +589,7 @@ var brightsyAdapter = {
566
589
  };
567
590
 
568
591
  // src/agents/claude.ts
569
- import { existsSync as existsSync3 } from "fs";
592
+ import { existsSync as existsSync5 } from "fs";
570
593
 
571
594
  // src/agents/claude-mcp.ts
572
595
  function parseMcpList(text) {
@@ -603,10 +626,10 @@ function mcpAllowTools(servers) {
603
626
  }
604
627
 
605
628
  // src/agents/injected-mcp.ts
606
- import { existsSync as existsSync2, mkdirSync, mkdtempSync, writeFileSync } from "fs";
629
+ import { existsSync as existsSync4, mkdtempSync, writeFileSync } from "fs";
607
630
  import { createRequire } from "module";
608
631
  import { tmpdir } from "os";
609
- import { dirname, join } from "path";
632
+ import { dirname, join as join3 } from "path";
610
633
  import { fileURLToPath } from "url";
611
634
 
612
635
  // src/mcp/profile.ts
@@ -616,14 +639,46 @@ function sideboardMcpProfile(env = process.env) {
616
639
  }
617
640
 
618
641
  // src/agents/node-launch.ts
642
+ import { existsSync as existsSync2 } from "fs";
643
+ import { homedir } from "os";
644
+ import { join } from "path";
619
645
  function isAsarPath(filePath) {
646
+ if (/\.asar\.unpacked([/\\]|$)/.test(filePath)) return false;
620
647
  return /\.asar([/\\]|$)/.test(filePath);
621
648
  }
649
+ function unpackedAsarPath(filePath) {
650
+ if (!isAsarPath(filePath)) return null;
651
+ const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
652
+ if (unpacked === filePath) return null;
653
+ return existsSync2(unpacked) ? unpacked : null;
654
+ }
655
+ function nodeReadableScriptPath(scriptPath) {
656
+ return unpackedAsarPath(scriptPath) ?? scriptPath;
657
+ }
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")
670
+ ];
671
+ for (const bin of fallbacks) {
672
+ if (existsSync2(bin) && !isElectronLikeCommand(bin)) return bin;
673
+ }
674
+ return null;
675
+ }
622
676
  function applyNodeLaunch(launch, args) {
677
+ const readableArgs = args.map(nodeReadableScriptPath);
623
678
  if (!launch.env.ELECTRON_RUN_AS_NODE) {
624
- return { file: launch.file, args, env: launch.env };
679
+ return { file: launch.file, args: readableArgs, env: launch.env };
625
680
  }
626
- const wrapped = wrapElectronAsNodeLaunch(launch.file, args);
681
+ const wrapped = wrapElectronAsNodeLaunch(launch.file, readableArgs);
627
682
  if (process.platform === "win32") {
628
683
  return { file: wrapped.file, args: wrapped.args, env: launch.env };
629
684
  }
@@ -632,16 +687,12 @@ function applyNodeLaunch(launch, args) {
632
687
  return { file: wrapped.file, args: wrapped.args, env };
633
688
  }
634
689
  async function resolveNodeLaunch(scriptPath) {
635
- if (isAsarPath(scriptPath)) {
636
- return {
637
- file: process.execPath,
638
- env: { ELECTRON_RUN_AS_NODE: "1" }
639
- };
640
- }
641
- const whichNode = await run("which", ["node"], { reject: false });
642
- const nodeBin = whichNode.exitCode === 0 && whichNode.stdout.trim() ? whichNode.stdout.trim() : null;
643
- if (nodeBin) {
644
- return { file: nodeBin, env: {} };
690
+ const script = nodeReadableScriptPath(scriptPath);
691
+ if (!isAsarPath(script)) {
692
+ const nodeBin = await findSystemNode();
693
+ if (nodeBin) {
694
+ return { file: nodeBin, env: {} };
695
+ }
645
696
  }
646
697
  return {
647
698
  file: process.execPath,
@@ -649,6 +700,42 @@ async function resolveNodeLaunch(scriptPath) {
649
700
  };
650
701
  }
651
702
 
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
+
652
739
  // src/agents/injected-mcp.ts
653
740
  var SIDEBOARD_MCP_ALLOWED_TOOLS = [
654
741
  "mcp__sideboard",
@@ -757,7 +844,7 @@ function corePackageDir() {
757
844
  } catch {
758
845
  }
759
846
  try {
760
- const req = createRequire(join(process.cwd(), "package.json"));
847
+ const req = createRequire(join3(process.cwd(), "package.json"));
761
848
  return dirname(req.resolve("@sideboard-ai/core"));
762
849
  } catch {
763
850
  return process.cwd();
@@ -765,20 +852,22 @@ function corePackageDir() {
765
852
  }
766
853
  function findSideboardMcpJsEntry() {
767
854
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
768
- if (override && existsSync2(override)) return override;
855
+ if (override && existsSync4(override)) return override;
856
+ const packaged = packagedMcpStdioPath();
857
+ if (packaged) return packaged;
769
858
  let dir = corePackageDir();
770
859
  for (let i = 0; i < 10; i++) {
771
860
  const candidates = [
772
- join(dir, "mcp/run-stdio.js"),
773
- join(dir, "mcp/run-stdio.cjs"),
774
- join(dir, "dist/mcp/run-stdio.js"),
775
- join(dir, "dist/mcp/run-stdio.cjs"),
776
- join(dir, "packages/core/dist/mcp/run-stdio.js"),
777
- join(dir, "packages/cli/dist/index.js"),
778
- join(dir, "cli/dist/index.js")
861
+ join3(dir, "mcp/run-stdio.js"),
862
+ join3(dir, "mcp/run-stdio.cjs"),
863
+ join3(dir, "dist/mcp/run-stdio.js"),
864
+ join3(dir, "dist/mcp/run-stdio.cjs"),
865
+ join3(dir, "packages/core/dist/mcp/run-stdio.js"),
866
+ join3(dir, "packages/cli/dist/index.js"),
867
+ join3(dir, "cli/dist/index.js")
779
868
  ];
780
869
  for (const p of candidates) {
781
- if (existsSync2(p)) return p;
870
+ if (existsSync4(p) && !isAsarPath(p)) return p;
782
871
  }
783
872
  const parent = dirname(dir);
784
873
  if (parent === dir) break;
@@ -792,12 +881,14 @@ async function resolveSideboardMcpServer() {
792
881
  const isCli = /[/\\]cli[/\\]dist[/\\]index\.js$/.test(entry);
793
882
  const scriptArgs = isCli ? [entry, "mcp"] : [entry];
794
883
  const launch = applyNodeLaunch(await resolveNodeLaunch(entry), scriptArgs);
795
- return {
796
- name: "sideboard",
797
- command: launch.file,
798
- args: launch.args,
799
- ...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
800
- };
884
+ if (launch.file !== "/bin/sh" && !isElectronLikeCommand(launch.file)) {
885
+ return {
886
+ name: "sideboard",
887
+ command: launch.file,
888
+ args: launch.args,
889
+ ...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
890
+ };
891
+ }
801
892
  }
802
893
  const which = await run("which", ["sideboard"], { reject: false });
803
894
  if (which.exitCode === 0 && which.stdout.trim()) {
@@ -820,7 +911,10 @@ async function buildInjectedMcpServers(opts) {
820
911
  sideboard.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID = orchId;
821
912
  }
822
913
  try {
823
- Object.assign(sideboard.env, await resolveAgentGitAuthEnv(sideboard.env));
914
+ mergeAgentGitAuthEnv(
915
+ sideboard.env,
916
+ await resolveAgentGitAuthEnv(sideboard.env)
917
+ );
824
918
  } catch {
825
919
  }
826
920
  servers.push(sideboard);
@@ -842,9 +936,6 @@ async function buildInjectedMcpServers(opts) {
842
936
  }
843
937
  return servers;
844
938
  }
845
- function shSingleQuote(value) {
846
- return `'${value.replace(/'/g, `'\\''`)}'`;
847
- }
848
939
  function cursorSafeMcpLaunch(command, args) {
849
940
  if (process.platform === "win32") {
850
941
  return args && args.length > 0 ? { command, args } : { command };
@@ -852,31 +943,13 @@ function cursorSafeMcpLaunch(command, args) {
852
943
  const unwrapped = unwrapStrippedElectronLaunch(command, args);
853
944
  const file = unwrapped?.file ?? command;
854
945
  const fileArgs = unwrapped?.args ?? args ?? [];
855
- if (!isElectronLikeCommand(file)) {
856
- return fileArgs.length > 0 ? { command: file, args: fileArgs } : { command: file };
857
- }
858
- const dir = join(appDataDir(), "mcp-launch");
859
- mkdirSync(dir, { recursive: true });
860
- const wrap = join(dir, "cursor-electron-as-node.sh");
861
- const execLine = [file, ...fileArgs].map(shSingleQuote).join(" ");
862
- writeFileSync(
863
- wrap,
864
- [
865
- "#!/bin/sh",
866
- "vars=`printenv | awk -F= '/^(ELECTRON_|CHROME_)/{print $1}'`",
867
- '[ -n "$vars" ] && unset $vars',
868
- "export ELECTRON_RUN_AS_NODE=1",
869
- `exec ${execLine} "$@"`,
870
- ""
871
- ].join("\n"),
872
- { mode: 493 }
873
- );
874
- return { command: wrap };
946
+ return fileArgs.length > 0 ? { command: file, args: fileArgs } : { command: file };
875
947
  }
876
948
  function mcpSpawnEnv(env) {
877
949
  if (!env) return void 0;
878
950
  const out = { ...env };
879
951
  delete out.ELECTRON_RUN_AS_NODE;
952
+ delete out.ELECTRON_RUN_AS_NODE;
880
953
  return Object.keys(out).length > 0 ? out : void 0;
881
954
  }
882
955
  function toCursorMcpServers(servers) {
@@ -885,6 +958,7 @@ function toCursorMcpServers(servers) {
885
958
  const env = mcpSpawnEnv(s.env);
886
959
  const launch = cursorSafeMcpLaunch(s.command, s.args);
887
960
  out[s.name] = {
961
+ type: "stdio",
888
962
  command: launch.command,
889
963
  ...launch.args && launch.args.length > 0 ? { args: launch.args } : {},
890
964
  ...env ? { env } : {}
@@ -936,14 +1010,14 @@ function writeMcpServersConfig(servers) {
936
1010
  ...env ? { env } : {}
937
1011
  };
938
1012
  }
939
- const dir = mkdtempSync(join(tmpdir(), "sideboard-mcp-"));
940
- const cfgPath = join(dir, "mcp.json");
1013
+ const dir = mkdtempSync(join3(tmpdir(), "sideboard-mcp-"));
1014
+ const cfgPath = join3(dir, "mcp.json");
941
1015
  writeFileSync(cfgPath, JSON.stringify({ mcpServers }, null, 2));
942
1016
  return cfgPath;
943
1017
  }
944
1018
 
945
1019
  // src/agents/types.ts
946
- var PLAN_MODE_INSTRUCTION = "Plan mode is active and must remain active until the user turns Plan mode off in the UI (or Approves / Hands off the plan). Analyze the codebase, search and read files as needed, and produce or refine a clear implementation plan. Do not modify, create, or delete any project files except via Sideboard MCP present_plan (writes .context/attachments/plan.md). When you need a clarifying decision (approach forks, auth choice, scope): (1) first write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it) \u2014 do not leave the user staring at bare labels; (2) then call Sideboard MCP ask_user with the same options, including a description on every option. Sideboard shows questions in the composer and mirrors them in chat. After ask_user, wait for the user's next message with their answers before finalizing the plan. When the plan is ready for approval: (1) call present_plan with the full markdown plan (title + content) so Sideboard saves .context/attachments/plan.md and shows it in chat for Approve / Hand off / Copy; (2) Claude should also call ExitPlanMode after present_plan. Do not skip present_plan \u2014 the plan must be a markdown file, not only chat prose.";
1020
+ var PLAN_MODE_INSTRUCTION = "Plan mode is active and must remain active until the user turns Plan mode off in the UI (or Approves / Hands off the plan). Analyze the codebase, search and read files as needed, and produce or refine a clear implementation plan. Do not modify, create, or delete any project files except via Sideboard MCP present_plan (writes .context/attachments/plan.md). When you need a clarifying decision (approach forks, auth choice, scope) \u2014 not greetings, check-ins, or an invented task menu: (1) first write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it) \u2014 do not leave the user staring at bare labels; (2) then call Sideboard MCP ask_user with the same options, including a description on every option. If one option is the obvious default, proceed without asking. Sideboard shows questions in the composer and mirrors them in chat. After ask_user, wait for the user's next message with their answers before finalizing the plan. When the plan is ready for approval: (1) call present_plan with the full markdown plan (title + content) so Sideboard saves .context/attachments/plan.md and shows it in chat for Approve / Hand off / Copy; (2) Claude should also call ExitPlanMode after present_plan. Do not skip present_plan \u2014 the plan must be a markdown file, not only chat prose.";
947
1021
  function permissionMode(thread) {
948
1022
  if (thread.sourceType === "orchestration") {
949
1023
  return {
@@ -1085,7 +1159,7 @@ var claudeAdapter = {
1085
1159
  async detect() {
1086
1160
  const claude = resolveClaudeExecutable();
1087
1161
  if (claude !== "claude") {
1088
- if (!existsSync3(claude)) {
1162
+ if (!existsSync5(claude)) {
1089
1163
  return {
1090
1164
  agent: "claude",
1091
1165
  installed: false,
@@ -1134,7 +1208,7 @@ var claudeAdapter = {
1134
1208
  );
1135
1209
  }
1136
1210
  const mode = permissionMode(thread);
1137
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-2YZ2V4I5.js");
1211
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-3GNPQCLE.js");
1138
1212
  const isOrchestrator = isOrchestratorThread2(thread);
1139
1213
  const injectedServers = await buildInjectedMcpServers({
1140
1214
  includeSideboard: true,
@@ -1336,9 +1410,9 @@ function parseIssuesJson(raw) {
1336
1410
  }
1337
1411
 
1338
1412
  // src/agents/codex.ts
1339
- import { existsSync as existsSync4, readFileSync, statSync } from "fs";
1340
- import { homedir } from "os";
1341
- import { join as join2 } from "path";
1413
+ import { existsSync as existsSync6, readFileSync, statSync } from "fs";
1414
+ import { homedir as homedir2 } from "os";
1415
+ import { join as join4 } from "path";
1342
1416
  var CODEX_PROMPT_ARG_MAX = 2e5;
1343
1417
  var FALLBACK_CODEX_MODELS = [
1344
1418
  { id: "gpt-5.6-sol", displayName: "GPT-5.6 Sol" },
@@ -1358,7 +1432,7 @@ async function listCodexModels() {
1358
1432
  if (codex === "codex") {
1359
1433
  const which = await run("which", ["codex"], { reject: false });
1360
1434
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
1361
- } else if (!existsSync4(codex)) {
1435
+ } else if (!existsSync6(codex)) {
1362
1436
  return FALLBACK_CODEX_MODELS;
1363
1437
  }
1364
1438
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -1393,11 +1467,11 @@ function usageFromCodex(usage) {
1393
1467
  }
1394
1468
  function codexConfigHasNetworkAccess() {
1395
1469
  const candidates = [
1396
- join2(homedir(), ".codex", "config.toml"),
1397
- join2(homedir(), ".config", "codex", "config.toml")
1470
+ join4(homedir2(), ".codex", "config.toml"),
1471
+ join4(homedir2(), ".config", "codex", "config.toml")
1398
1472
  ];
1399
1473
  for (const path of candidates) {
1400
- if (!existsSync4(path)) continue;
1474
+ if (!existsSync6(path)) continue;
1401
1475
  const text = readFileSync(path, "utf8");
1402
1476
  if (/network_access\s*=\s*true/.test(text)) return true;
1403
1477
  }
@@ -1430,8 +1504,8 @@ function asRecord(value) {
1430
1504
  return void 0;
1431
1505
  }
1432
1506
  function codexLooksAuthenticated() {
1433
- const authPath = join2(homedir(), ".codex", "auth.json");
1434
- if (!existsSync4(authPath)) return false;
1507
+ const authPath = join4(homedir2(), ".codex", "auth.json");
1508
+ if (!existsSync6(authPath)) return false;
1435
1509
  try {
1436
1510
  return statSync(authPath).size > 2;
1437
1511
  } catch {
@@ -1443,7 +1517,7 @@ var codexAdapter = {
1443
1517
  async detect() {
1444
1518
  const codex = resolveAgentExecutable("codex");
1445
1519
  if (codex !== "codex") {
1446
- if (!existsSync4(codex)) {
1520
+ if (!existsSync6(codex)) {
1447
1521
  return {
1448
1522
  agent: "codex",
1449
1523
  installed: false,
@@ -1516,8 +1590,13 @@ var codexAdapter = {
1516
1590
  // `codex exec` rejects `--ask-for-approval` (global-only on newer CLIs).
1517
1591
  "-c",
1518
1592
  'approval_policy="never"',
1519
- // Seatbelt cannot use the login Keychain; default policy also strips GH_TOKEN.
1520
- ...codexUnattendedGitConfigArgs(mode.codexSandbox),
1593
+ // Seatbelt cannot use the login Keychain; inherit GH_CONFIG_DIR / GIT_CONFIG_*.
1594
+ // Default policy also strips *TOKEN*. Linked worktrees need the main
1595
+ // repo `.git` (+ `.git/worktrees/<name>`) as writable_roots so git commit
1596
+ // can create index.lock.
1597
+ ...codexUnattendedGitConfigArgs(mode.codexSandbox, {
1598
+ writableRoots: mode.codexSandbox === "workspace-write" ? await resolveCodexGitWritableRoots(thread.worktreePath) : []
1599
+ }),
1521
1600
  ...model ? ["--model", model] : [],
1522
1601
  ...mcpOverrides
1523
1602
  ];
@@ -1662,10 +1741,10 @@ var codexAdapter = {
1662
1741
  };
1663
1742
 
1664
1743
  // src/agents/cursor.ts
1665
- import { existsSync as existsSync5 } from "fs";
1666
- import { createRequire as createRequire2 } from "module";
1667
- import { dirname as dirname2, join as join3 } from "path";
1668
- import { fileURLToPath as fileURLToPath2 } from "url";
1744
+ import { existsSync as existsSync8 } from "fs";
1745
+ import { createRequire as createRequire3 } from "module";
1746
+ import { dirname as dirname3, join as join6 } from "path";
1747
+ import { fileURLToPath as fileURLToPath3 } from "url";
1669
1748
  import { Cursor } from "@cursor/sdk";
1670
1749
 
1671
1750
  // src/agents/cursor-events.ts
@@ -1837,6 +1916,65 @@ function parseCursorRunnerLine(line) {
1837
1916
  }
1838
1917
  }
1839
1918
 
1919
+ // src/agents/cursor-ripgrep.ts
1920
+ import { existsSync as existsSync7 } from "fs";
1921
+ import { createRequire as createRequire2 } from "module";
1922
+ import { dirname as dirname2, isAbsolute, join as join5, parse, resolve as resolvePath } from "path";
1923
+ import { fileURLToPath as fileURLToPath2 } from "url";
1924
+ var RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
1925
+ function rgBinaryName() {
1926
+ return process.platform === "win32" ? "rg.exe" : "rg";
1927
+ }
1928
+ function platformRipgrepPackage() {
1929
+ return `@cursor/sdk-${process.platform}-${process.arch}`;
1930
+ }
1931
+ function usableRipgrepPath(candidate) {
1932
+ const raw = candidate?.trim();
1933
+ if (!raw || !isAbsolute(raw)) return null;
1934
+ const readable = nodeReadableScriptPath(raw);
1935
+ if (!existsSync7(readable) || isAsarPath(readable)) return null;
1936
+ return readable;
1937
+ }
1938
+ function walkForBundledRipgrep(startFile) {
1939
+ if (!startFile) return null;
1940
+ const pkg = platformRipgrepPackage();
1941
+ const name = rgBinaryName();
1942
+ let dir = dirname2(resolvePath(startFile));
1943
+ const root = parse(dir).root;
1944
+ while (dir !== root) {
1945
+ const hit = usableRipgrepPath(join5(dir, "node_modules", pkg, "bin", name));
1946
+ if (hit) return hit;
1947
+ const next = dirname2(dir);
1948
+ if (next === dir) break;
1949
+ dir = next;
1950
+ }
1951
+ return null;
1952
+ }
1953
+ function requireResolveBundledRipgrep(fromFile) {
1954
+ try {
1955
+ const req = createRequire2(fromFile);
1956
+ const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
1957
+ return usableRipgrepPath(join5(dirname2(pkgJson), "bin", rgBinaryName()));
1958
+ } catch {
1959
+ return null;
1960
+ }
1961
+ }
1962
+ function resolveCursorRipgrepPath(opts) {
1963
+ const env = opts?.env ?? process.env;
1964
+ const fromEnv = usableRipgrepPath(env[RIPGREP_ENV]);
1965
+ if (fromEnv) return fromEnv;
1966
+ const fromPackaged = usableRipgrepPath(
1967
+ packagedCursorRipgrepCandidate(platformRipgrepPackage(), rgBinaryName())
1968
+ );
1969
+ if (fromPackaged) return fromPackaged;
1970
+ const start = opts?.startFile?.trim() || process.argv[1] || fileURLToPath2(import.meta.url);
1971
+ return walkForBundledRipgrep(start) ?? requireResolveBundledRipgrep(start);
1972
+ }
1973
+ function cursorRipgrepEnv(opts) {
1974
+ const path = resolveCursorRipgrepPath(opts);
1975
+ return path ? { [RIPGREP_ENV]: path } : {};
1976
+ }
1977
+
1840
1978
  // src/agents/cursor.ts
1841
1979
  var FALLBACK_CURSOR_MODELS = [
1842
1980
  { id: "default", displayName: "Auto" },
@@ -1883,30 +2021,32 @@ function entryDir() {
1883
2021
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
1884
2022
  if (cjsDir) return cjsDir;
1885
2023
  try {
1886
- return dirname2(fileURLToPath2(import.meta.url));
2024
+ return dirname3(fileURLToPath3(import.meta.url));
1887
2025
  } catch {
1888
2026
  try {
1889
- const req = createRequire2(process.cwd() + "/");
1890
- return dirname2(req.resolve("@sideboard-ai/core"));
2027
+ const req = createRequire3(process.cwd() + "/");
2028
+ return dirname3(req.resolve("@sideboard-ai/core"));
1891
2029
  } catch {
1892
2030
  return process.cwd();
1893
2031
  }
1894
2032
  }
1895
2033
  }
1896
2034
  function cursorRunnerPath() {
2035
+ const packaged = packagedCursorRunnerPath();
2036
+ if (packaged) return packaged;
1897
2037
  const root = entryDir();
1898
2038
  const candidates = [
1899
- join3(root, "agents", "cursor-runner.js"),
1900
- join3(root, "agents", "cursor-runner.cjs"),
2039
+ join6(root, "agents", "cursor-runner.js"),
2040
+ join6(root, "agents", "cursor-runner.cjs"),
1901
2041
  // If somehow resolved from package root instead of dist/
1902
- join3(root, "dist", "agents", "cursor-runner.js"),
1903
- join3(root, "dist", "agents", "cursor-runner.cjs"),
2042
+ join6(root, "dist", "agents", "cursor-runner.js"),
2043
+ join6(root, "dist", "agents", "cursor-runner.cjs"),
1904
2044
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
1905
- join3(root, "cursor-runner.ts"),
1906
- join3(root, "src", "agents", "cursor-runner.ts")
2045
+ join6(root, "cursor-runner.ts"),
2046
+ join6(root, "src", "agents", "cursor-runner.ts")
1907
2047
  ];
1908
2048
  for (const candidate of candidates) {
1909
- if (existsSync5(candidate)) return candidate;
2049
+ if (existsSync8(candidate)) return candidate;
1910
2050
  }
1911
2051
  return candidates[0];
1912
2052
  }
@@ -1969,6 +2109,7 @@ var cursorAdapter = {
1969
2109
  stdin: JSON.stringify(req),
1970
2110
  env: {
1971
2111
  ...launch.env,
2112
+ ...cursorRipgrepEnv({ startFile: runner }),
1972
2113
  ...apiKey ? { CURSOR_API_KEY: apiKey } : {}
1973
2114
  }
1974
2115
  };
@@ -1991,7 +2132,7 @@ var cursorAdapter = {
1991
2132
  };
1992
2133
 
1993
2134
  // src/agents/opencode.ts
1994
- import { existsSync as existsSync6 } from "fs";
2135
+ import { existsSync as existsSync9 } from "fs";
1995
2136
  var FALLBACK_OPENCODE_MODELS = [
1996
2137
  { id: "opencode/big-pickle", displayName: "opencode \xB7 big-pickle" },
1997
2138
  {
@@ -2032,7 +2173,7 @@ async function listOpencodeModels() {
2032
2173
  if (opencode === "opencode") {
2033
2174
  const which = await run("which", ["opencode"], { reject: false });
2034
2175
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
2035
- } else if (!existsSync6(opencode)) {
2176
+ } else if (!existsSync9(opencode)) {
2036
2177
  return FALLBACK_OPENCODE_MODELS;
2037
2178
  }
2038
2179
  const listed = await run(opencode, ["models"], { reject: false });
@@ -2067,7 +2208,7 @@ var opencodeAdapter = {
2067
2208
  async detect() {
2068
2209
  const opencode = resolveAgentExecutable("opencode");
2069
2210
  if (opencode !== "opencode") {
2070
- if (!existsSync6(opencode)) {
2211
+ if (!existsSync9(opencode)) {
2071
2212
  return {
2072
2213
  agent: "opencode",
2073
2214
  installed: false,
@@ -2,7 +2,7 @@
2
2
 
3
3
  import {
4
4
  resolveGithubRepoSlug
5
- } from "./chunk-ZXYWWSHZ.js";
5
+ } from "./chunk-R7BQBSDT.js";
6
6
  import {
7
7
  resolveThreadDefaults
8
8
  } from "./chunk-6LFV4VFI.js";
@@ -53,7 +53,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
53
53
  "- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
54
54
  "- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
55
55
  "- list_threads / get_thread \u2014 fleet status (what is going on)",
56
- "- ask_user \u2014 multiple-choice questions in the composer (any mode, not only Plan). Explain options in chat first, include a description on every option, then wait for answers.",
56
+ "- ask_user \u2014 composer multiple-choice only when blocked on a concrete choice (approach fork, which API). Never for hellos, check-ins, or invented \u201Cwhat should we do?\u201D menus \u2014 reply in chat. Explain options first, description on every option, then wait.",
57
57
  "- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for Slack / away-from-keyboard work. Turn OFF when the user says they are done, wrapping up, going to sleep, or no longer need the machine awake. Closing this chat also releases it.",
58
58
  "Workspaces:",
59
59
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveGithubRepoSlug
3
- } from "./chunk-7D27DD2X.js";
3
+ } from "./chunk-CIRXAYWS.js";
4
4
  import {
5
5
  resolveThreadDefaults
6
6
  } from "./chunk-FT2SQOL4.js";
@@ -51,7 +51,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
51
51
  "- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
52
52
  "- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
53
53
  "- list_threads / get_thread \u2014 fleet status (what is going on)",
54
- "- ask_user \u2014 multiple-choice questions in the composer (any mode, not only Plan). Explain options in chat first, include a description on every option, then wait for answers.",
54
+ "- ask_user \u2014 composer multiple-choice only when blocked on a concrete choice (approach fork, which API). Never for hellos, check-ins, or invented \u201Cwhat should we do?\u201D menus \u2014 reply in chat. Explain options first, description on every option, then wait.",
55
55
  "- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for Slack / away-from-keyboard work. Turn OFF when the user says they are done, wrapping up, going to sleep, or no longer need the machine awake. Closing this chat also releases it.",
56
56
  "Workspaces:",
57
57
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
@@ -7,8 +7,8 @@ import {
7
7
  enrichWorkspacesWithGithub,
8
8
  ensureGlobalCoordinatorCwd,
9
9
  formatWorkspaceInventory
10
- } from "./chunk-VZ2L4AEJ.js";
11
- import "./chunk-7D27DD2X.js";
10
+ } from "./chunk-XUWDLRAE.js";
11
+ import "./chunk-CIRXAYWS.js";
12
12
  import "./chunk-FKOIHGKV.js";
13
13
  import "./chunk-FT2SQOL4.js";
14
14
  import "./chunk-TLPJHLLM.js";
@@ -9,8 +9,8 @@ import {
9
9
  enrichWorkspacesWithGithub,
10
10
  ensureGlobalCoordinatorCwd,
11
11
  formatWorkspaceInventory
12
- } from "./chunk-OB6IRIFV.js";
13
- import "./chunk-ZXYWWSHZ.js";
12
+ } from "./chunk-XH2GS2LO.js";
13
+ import "./chunk-R7BQBSDT.js";
14
14
  import "./chunk-B3SJXYIJ.js";
15
15
  import "./chunk-JOF3XIEM.js";
16
16
  import "./chunk-6LFV4VFI.js";