@sideboard-ai/core 0.1.89 → 0.1.92

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-JXQ5QHDU.js} +4 -4
  4. package/dist/{agents-ODBP7J6E.js → agents-TUV4NH7S.js} +5 -5
  5. package/dist/{chunk-RJLBSYUO.js → chunk-35LKGGOC.js} +45 -77
  6. package/dist/{chunk-WANQFU3S.js → chunk-6XBXVXX2.js} +2 -2
  7. package/dist/{chunk-7D27DD2X.js → chunk-CIRXAYWS.js} +260 -61
  8. package/dist/{chunk-B2KIO2SD.js → chunk-CLGO7TLO.js} +2 -2
  9. package/dist/{chunk-JE75QW2I.js → chunk-GJ2HJQIU.js} +236 -96
  10. package/dist/{chunk-CBJSPTBG.js → chunk-GXSYI7FH.js} +206 -5
  11. package/dist/{chunk-UHTNJKZX.js → chunk-NR6APJLD.js} +2 -2
  12. package/dist/{chunk-6EZRSCIT.js → chunk-QKYO6BHB.js} +2 -2
  13. package/dist/{chunk-ZXYWWSHZ.js → chunk-R7BQBSDT.js} +254 -61
  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 +941 -455
  21. package/dist/index.d.cts +77 -19
  22. package/dist/index.d.ts +77 -19
  23. package/dist/index.js +166 -42
  24. package/dist/mcp/run-stdio.cjs +815 -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) {
@@ -936,14 +1009,14 @@ function writeMcpServersConfig(servers) {
936
1009
  ...env ? { env } : {}
937
1010
  };
938
1011
  }
939
- const dir = mkdtempSync(join(tmpdir(), "sideboard-mcp-"));
940
- const cfgPath = join(dir, "mcp.json");
1012
+ const dir = mkdtempSync(join3(tmpdir(), "sideboard-mcp-"));
1013
+ const cfgPath = join3(dir, "mcp.json");
941
1014
  writeFileSync(cfgPath, JSON.stringify({ mcpServers }, null, 2));
942
1015
  return cfgPath;
943
1016
  }
944
1017
 
945
1018
  // 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.";
1019
+ 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
1020
  function permissionMode(thread) {
948
1021
  if (thread.sourceType === "orchestration") {
949
1022
  return {
@@ -1085,7 +1158,7 @@ var claudeAdapter = {
1085
1158
  async detect() {
1086
1159
  const claude = resolveClaudeExecutable();
1087
1160
  if (claude !== "claude") {
1088
- if (!existsSync3(claude)) {
1161
+ if (!existsSync5(claude)) {
1089
1162
  return {
1090
1163
  agent: "claude",
1091
1164
  installed: false,
@@ -1134,7 +1207,7 @@ var claudeAdapter = {
1134
1207
  );
1135
1208
  }
1136
1209
  const mode = permissionMode(thread);
1137
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-2YZ2V4I5.js");
1210
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-3GNPQCLE.js");
1138
1211
  const isOrchestrator = isOrchestratorThread2(thread);
1139
1212
  const injectedServers = await buildInjectedMcpServers({
1140
1213
  includeSideboard: true,
@@ -1336,9 +1409,9 @@ function parseIssuesJson(raw) {
1336
1409
  }
1337
1410
 
1338
1411
  // 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";
1412
+ import { existsSync as existsSync6, readFileSync, statSync } from "fs";
1413
+ import { homedir as homedir2 } from "os";
1414
+ import { join as join4 } from "path";
1342
1415
  var CODEX_PROMPT_ARG_MAX = 2e5;
1343
1416
  var FALLBACK_CODEX_MODELS = [
1344
1417
  { id: "gpt-5.6-sol", displayName: "GPT-5.6 Sol" },
@@ -1358,7 +1431,7 @@ async function listCodexModels() {
1358
1431
  if (codex === "codex") {
1359
1432
  const which = await run("which", ["codex"], { reject: false });
1360
1433
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
1361
- } else if (!existsSync4(codex)) {
1434
+ } else if (!existsSync6(codex)) {
1362
1435
  return FALLBACK_CODEX_MODELS;
1363
1436
  }
1364
1437
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -1393,11 +1466,11 @@ function usageFromCodex(usage) {
1393
1466
  }
1394
1467
  function codexConfigHasNetworkAccess() {
1395
1468
  const candidates = [
1396
- join2(homedir(), ".codex", "config.toml"),
1397
- join2(homedir(), ".config", "codex", "config.toml")
1469
+ join4(homedir2(), ".codex", "config.toml"),
1470
+ join4(homedir2(), ".config", "codex", "config.toml")
1398
1471
  ];
1399
1472
  for (const path of candidates) {
1400
- if (!existsSync4(path)) continue;
1473
+ if (!existsSync6(path)) continue;
1401
1474
  const text = readFileSync(path, "utf8");
1402
1475
  if (/network_access\s*=\s*true/.test(text)) return true;
1403
1476
  }
@@ -1430,8 +1503,8 @@ function asRecord(value) {
1430
1503
  return void 0;
1431
1504
  }
1432
1505
  function codexLooksAuthenticated() {
1433
- const authPath = join2(homedir(), ".codex", "auth.json");
1434
- if (!existsSync4(authPath)) return false;
1506
+ const authPath = join4(homedir2(), ".codex", "auth.json");
1507
+ if (!existsSync6(authPath)) return false;
1435
1508
  try {
1436
1509
  return statSync(authPath).size > 2;
1437
1510
  } catch {
@@ -1443,7 +1516,7 @@ var codexAdapter = {
1443
1516
  async detect() {
1444
1517
  const codex = resolveAgentExecutable("codex");
1445
1518
  if (codex !== "codex") {
1446
- if (!existsSync4(codex)) {
1519
+ if (!existsSync6(codex)) {
1447
1520
  return {
1448
1521
  agent: "codex",
1449
1522
  installed: false,
@@ -1516,8 +1589,13 @@ var codexAdapter = {
1516
1589
  // `codex exec` rejects `--ask-for-approval` (global-only on newer CLIs).
1517
1590
  "-c",
1518
1591
  'approval_policy="never"',
1519
- // Seatbelt cannot use the login Keychain; default policy also strips GH_TOKEN.
1520
- ...codexUnattendedGitConfigArgs(mode.codexSandbox),
1592
+ // Seatbelt cannot use the login Keychain; inherit GH_CONFIG_DIR / GIT_CONFIG_*.
1593
+ // Default policy also strips *TOKEN*. Linked worktrees need the main
1594
+ // repo `.git` (+ `.git/worktrees/<name>`) as writable_roots so git commit
1595
+ // can create index.lock.
1596
+ ...codexUnattendedGitConfigArgs(mode.codexSandbox, {
1597
+ writableRoots: mode.codexSandbox === "workspace-write" ? await resolveCodexGitWritableRoots(thread.worktreePath) : []
1598
+ }),
1521
1599
  ...model ? ["--model", model] : [],
1522
1600
  ...mcpOverrides
1523
1601
  ];
@@ -1662,10 +1740,10 @@ var codexAdapter = {
1662
1740
  };
1663
1741
 
1664
1742
  // 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";
1743
+ import { existsSync as existsSync8 } from "fs";
1744
+ import { createRequire as createRequire3 } from "module";
1745
+ import { dirname as dirname3, join as join6 } from "path";
1746
+ import { fileURLToPath as fileURLToPath3 } from "url";
1669
1747
  import { Cursor } from "@cursor/sdk";
1670
1748
 
1671
1749
  // src/agents/cursor-events.ts
@@ -1837,6 +1915,65 @@ function parseCursorRunnerLine(line) {
1837
1915
  }
1838
1916
  }
1839
1917
 
1918
+ // src/agents/cursor-ripgrep.ts
1919
+ import { existsSync as existsSync7 } from "fs";
1920
+ import { createRequire as createRequire2 } from "module";
1921
+ import { dirname as dirname2, isAbsolute, join as join5, parse, resolve as resolvePath } from "path";
1922
+ import { fileURLToPath as fileURLToPath2 } from "url";
1923
+ var RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
1924
+ function rgBinaryName() {
1925
+ return process.platform === "win32" ? "rg.exe" : "rg";
1926
+ }
1927
+ function platformRipgrepPackage() {
1928
+ return `@cursor/sdk-${process.platform}-${process.arch}`;
1929
+ }
1930
+ function usableRipgrepPath(candidate) {
1931
+ const raw = candidate?.trim();
1932
+ if (!raw || !isAbsolute(raw)) return null;
1933
+ const readable = nodeReadableScriptPath(raw);
1934
+ if (!existsSync7(readable) || isAsarPath(readable)) return null;
1935
+ return readable;
1936
+ }
1937
+ function walkForBundledRipgrep(startFile) {
1938
+ if (!startFile) return null;
1939
+ const pkg = platformRipgrepPackage();
1940
+ const name = rgBinaryName();
1941
+ let dir = dirname2(resolvePath(startFile));
1942
+ const root = parse(dir).root;
1943
+ while (dir !== root) {
1944
+ const hit = usableRipgrepPath(join5(dir, "node_modules", pkg, "bin", name));
1945
+ if (hit) return hit;
1946
+ const next = dirname2(dir);
1947
+ if (next === dir) break;
1948
+ dir = next;
1949
+ }
1950
+ return null;
1951
+ }
1952
+ function requireResolveBundledRipgrep(fromFile) {
1953
+ try {
1954
+ const req = createRequire2(fromFile);
1955
+ const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
1956
+ return usableRipgrepPath(join5(dirname2(pkgJson), "bin", rgBinaryName()));
1957
+ } catch {
1958
+ return null;
1959
+ }
1960
+ }
1961
+ function resolveCursorRipgrepPath(opts) {
1962
+ const env = opts?.env ?? process.env;
1963
+ const fromEnv = usableRipgrepPath(env[RIPGREP_ENV]);
1964
+ if (fromEnv) return fromEnv;
1965
+ const fromPackaged = usableRipgrepPath(
1966
+ packagedCursorRipgrepCandidate(platformRipgrepPackage(), rgBinaryName())
1967
+ );
1968
+ if (fromPackaged) return fromPackaged;
1969
+ const start = opts?.startFile?.trim() || process.argv[1] || fileURLToPath2(import.meta.url);
1970
+ return walkForBundledRipgrep(start) ?? requireResolveBundledRipgrep(start);
1971
+ }
1972
+ function cursorRipgrepEnv(opts) {
1973
+ const path = resolveCursorRipgrepPath(opts);
1974
+ return path ? { [RIPGREP_ENV]: path } : {};
1975
+ }
1976
+
1840
1977
  // src/agents/cursor.ts
1841
1978
  var FALLBACK_CURSOR_MODELS = [
1842
1979
  { id: "default", displayName: "Auto" },
@@ -1883,30 +2020,32 @@ function entryDir() {
1883
2020
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
1884
2021
  if (cjsDir) return cjsDir;
1885
2022
  try {
1886
- return dirname2(fileURLToPath2(import.meta.url));
2023
+ return dirname3(fileURLToPath3(import.meta.url));
1887
2024
  } catch {
1888
2025
  try {
1889
- const req = createRequire2(process.cwd() + "/");
1890
- return dirname2(req.resolve("@sideboard-ai/core"));
2026
+ const req = createRequire3(process.cwd() + "/");
2027
+ return dirname3(req.resolve("@sideboard-ai/core"));
1891
2028
  } catch {
1892
2029
  return process.cwd();
1893
2030
  }
1894
2031
  }
1895
2032
  }
1896
2033
  function cursorRunnerPath() {
2034
+ const packaged = packagedCursorRunnerPath();
2035
+ if (packaged) return packaged;
1897
2036
  const root = entryDir();
1898
2037
  const candidates = [
1899
- join3(root, "agents", "cursor-runner.js"),
1900
- join3(root, "agents", "cursor-runner.cjs"),
2038
+ join6(root, "agents", "cursor-runner.js"),
2039
+ join6(root, "agents", "cursor-runner.cjs"),
1901
2040
  // 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"),
2041
+ join6(root, "dist", "agents", "cursor-runner.js"),
2042
+ join6(root, "dist", "agents", "cursor-runner.cjs"),
1904
2043
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
1905
- join3(root, "cursor-runner.ts"),
1906
- join3(root, "src", "agents", "cursor-runner.ts")
2044
+ join6(root, "cursor-runner.ts"),
2045
+ join6(root, "src", "agents", "cursor-runner.ts")
1907
2046
  ];
1908
2047
  for (const candidate of candidates) {
1909
- if (existsSync5(candidate)) return candidate;
2048
+ if (existsSync8(candidate)) return candidate;
1910
2049
  }
1911
2050
  return candidates[0];
1912
2051
  }
@@ -1969,6 +2108,7 @@ var cursorAdapter = {
1969
2108
  stdin: JSON.stringify(req),
1970
2109
  env: {
1971
2110
  ...launch.env,
2111
+ ...cursorRipgrepEnv({ startFile: runner }),
1972
2112
  ...apiKey ? { CURSOR_API_KEY: apiKey } : {}
1973
2113
  }
1974
2114
  };
@@ -1991,7 +2131,7 @@ var cursorAdapter = {
1991
2131
  };
1992
2132
 
1993
2133
  // src/agents/opencode.ts
1994
- import { existsSync as existsSync6 } from "fs";
2134
+ import { existsSync as existsSync9 } from "fs";
1995
2135
  var FALLBACK_OPENCODE_MODELS = [
1996
2136
  { id: "opencode/big-pickle", displayName: "opencode \xB7 big-pickle" },
1997
2137
  {
@@ -2032,7 +2172,7 @@ async function listOpencodeModels() {
2032
2172
  if (opencode === "opencode") {
2033
2173
  const which = await run("which", ["opencode"], { reject: false });
2034
2174
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
2035
- } else if (!existsSync6(opencode)) {
2175
+ } else if (!existsSync9(opencode)) {
2036
2176
  return FALLBACK_OPENCODE_MODELS;
2037
2177
  }
2038
2178
  const listed = await run(opencode, ["models"], { reject: false });
@@ -2067,7 +2207,7 @@ var opencodeAdapter = {
2067
2207
  async detect() {
2068
2208
  const opencode = resolveAgentExecutable("opencode");
2069
2209
  if (opencode !== "opencode") {
2070
- if (!existsSync6(opencode)) {
2210
+ if (!existsSync9(opencode)) {
2071
2211
  return {
2072
2212
  agent: "opencode",
2073
2213
  installed: false,