@sideboard-ai/core 0.1.217 → 0.1.219

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 (59) hide show
  1. package/dist/{abletime-QGGYL2G4.js → abletime-BF253OZT.js} +5 -4
  2. package/dist/{abletime-GDZLZRMY.js → abletime-D6773P33.js} +5 -5
  3. package/dist/{abletime-oauth-F335TWKY.js → abletime-oauth-H4672PRH.js} +4 -3
  4. package/dist/{abletime-oauth-3X3BAPTF.js → abletime-oauth-KQPVVBKA.js} +4 -4
  5. package/dist/{abletime-rest-PLJVY3H3.js → abletime-rest-DAFPXZ7H.js} +4 -4
  6. package/dist/{abletime-rest-LAGTPAJL.js → abletime-rest-OPEVV3XC.js} +4 -3
  7. package/dist/agents/cursor-runner.js +5 -5
  8. package/dist/{agents-HETHRRZJ.js → agents-IFVGY77W.js} +9 -9
  9. package/dist/{agents-WBDDLRBY.js → agents-IK3U4Z2O.js} +8 -7
  10. package/dist/{app-settings-XCRNCEEE.js → app-settings-5RQMQKSB.js} +2 -1
  11. package/dist/{app-settings-2TN3WLZV.js → app-settings-V2BBCX2H.js} +2 -2
  12. package/dist/{chunk-MN6YUD4O.js → chunk-3NWUHXU3.js} +3 -3
  13. package/dist/{chunk-G4TANQC3.js → chunk-646I442S.js} +5 -5
  14. package/dist/{chunk-FNQNJOHY.js → chunk-ABOBTSO6.js} +4 -1
  15. package/dist/{chunk-YVE4PXCJ.js → chunk-CLI5DVU4.js} +2 -2
  16. package/dist/{chunk-C32SBNA3.js → chunk-EIICOB7P.js} +457 -294
  17. package/dist/{chunk-LS6TSOCE.js → chunk-HSYE5ID6.js} +5 -5
  18. package/dist/{chunk-UFHNSFAS.js → chunk-HVUVQXZ2.js} +5 -1
  19. package/dist/{chunk-7MTVRNP4.js → chunk-IAP5NXQ4.js} +1206 -1192
  20. package/dist/{chunk-SALM35KD.js → chunk-IILG7DPX.js} +5 -5
  21. package/dist/{chunk-DFTVZEZY.js → chunk-K642ORWF.js} +1085 -1057
  22. package/dist/{chunk-NI243N27.js → chunk-KTZESHYH.js} +15 -7
  23. package/dist/{chunk-FNGXKY5W.js → chunk-N2VST3NL.js} +68 -8
  24. package/dist/{chunk-XYKVRRC2.js → chunk-NFWPDEN4.js} +15 -7
  25. package/dist/{chunk-KFD2OXCE.js → chunk-P2EAAM3H.js} +68 -8
  26. package/dist/{chunk-QQKDGPUI.js → chunk-PO4M4JAJ.js} +1 -1
  27. package/dist/{chunk-2M5B7YNY.js → chunk-RRW2XWAY.js} +2 -2
  28. package/dist/{chunk-REZRGCKV.js → chunk-SOGGKYFV.js} +3 -3
  29. package/dist/{chunk-3OHR73VK.js → chunk-SVXIJ2IC.js} +1 -1
  30. package/dist/{chunk-SYFVUF2C.js → chunk-SZJZEFTY.js} +1 -1
  31. package/dist/{chunk-42IULNIY.js → chunk-THLVCXLF.js} +3 -3
  32. package/dist/{chunk-JZHRZ3DR.js → chunk-TQBUXKIB.js} +5 -5
  33. package/dist/chunk-WWUABK6B.js +56 -0
  34. package/dist/{chunk-D2IKXMF3.js → chunk-XGE6YUO6.js} +453 -289
  35. package/dist/{chunk-BTC2D6LS.js → chunk-Y5JES2VV.js} +3 -51
  36. package/dist/{connected-teams-WK47ATT7.js → connected-teams-LX5DLL2I.js} +3 -2
  37. package/dist/{connected-teams-PU4AMFNA.js → connected-teams-PQETXUWV.js} +3 -2
  38. package/dist/{coordinator-prompt-FQX6ALAI.js → coordinator-prompt-JLMQVORO.js} +6 -6
  39. package/dist/{coordinator-prompt-LE2GQZ2X.js → coordinator-prompt-VZ7OSRLD.js} +6 -5
  40. package/dist/{global-workspace-6P236KKG.js → global-workspace-3FDAUNN2.js} +6 -6
  41. package/dist/{global-workspace-KT3FRHZL.js → global-workspace-QPSJEXGR.js} +6 -5
  42. package/dist/index.cjs +1107 -826
  43. package/dist/index.d.cts +15 -1
  44. package/dist/index.d.ts +15 -1
  45. package/dist/index.js +24 -18
  46. package/dist/mcp/run-stdio.cjs +1912 -1652
  47. package/dist/mcp/run-stdio.js +16 -14
  48. package/dist/{orchestrator-MI7A5DQZ.js → orchestrator-5VVR7LOU.js} +9 -8
  49. package/dist/{orchestrator-WVZPTHBV.js → orchestrator-LFC3V3AX.js} +10 -10
  50. package/dist/{run-EBWL2Q4N.js → run-QDZCTP4Y.js} +2 -1
  51. package/dist/{run-CAGKZLHA.js → run-UEQM4JMZ.js} +2 -1
  52. package/dist/{workspaces-R5LJCJRB.js → workspaces-76W7IEKR.js} +8 -6
  53. package/dist/{workspaces-KM7KTLVO.js → workspaces-TDBA64II.js} +8 -5
  54. package/dist/{worktree-MDMTCAHX.js → worktree-7V67XTEO.js} +5 -5
  55. package/dist/{worktree-VXRI7LYM.js → worktree-I573UOPD.js} +5 -4
  56. package/dist/{worktree-exclude-N5X5I422.js → worktree-exclude-K7QK4RI5.js} +3 -2
  57. package/dist/{worktree-exclude-X54WSOXM.js → worktree-exclude-L32WEBX6.js} +3 -2
  58. package/package.json +1 -1
  59. package/dist/{chunk-L5CIEBLR.js → chunk-EWHJNJHV.js} +3 -3
package/dist/index.cjs CHANGED
@@ -6890,7 +6890,7 @@ async function run(file, args, opts) {
6890
6890
  try {
6891
6891
  const result = await (0, import_execa2.execa)(file, args, {
6892
6892
  cwd: opts?.cwd,
6893
- env: { ...process.env, ...opts?.env },
6893
+ env: { ...stripNestedElectronEnv(process.env), ...opts?.env },
6894
6894
  reject: opts?.reject ?? true,
6895
6895
  ...opts?.timeoutMs != null ? { timeout: opts.timeoutMs } : {}
6896
6896
  });
@@ -6987,6 +6987,7 @@ var init_run = __esm({
6987
6987
  "use strict";
6988
6988
  import_execa2 = require("execa");
6989
6989
  init_path();
6990
+ init_nested_electron_env();
6990
6991
  init_github_agent_auth();
6991
6992
  init_stale_lock();
6992
6993
  }
@@ -8079,7 +8080,14 @@ function slugify(input) {
8079
8080
  }
8080
8081
  async function resolveRepoRoot(cwd) {
8081
8082
  const { stdout } = await git(["rev-parse", "--show-toplevel"], cwd);
8082
- return canonicalizeRepoPath(stdout.trim());
8083
+ const toplevel = canonicalizeRepoPath(stdout.trim());
8084
+ try {
8085
+ const listed = await listWorktrees(cwd);
8086
+ const primary = listed[0]?.path;
8087
+ if (primary) return canonicalizeRepoPath(primary);
8088
+ } catch {
8089
+ }
8090
+ return toplevel;
8083
8091
  }
8084
8092
  function canonicalizeRepoPath(path2) {
8085
8093
  try {
@@ -8099,7 +8107,8 @@ function parseGithubSlugFromRemoteUrl(url) {
8099
8107
  }
8100
8108
  async function slugFromGitRemote(repoPath, remote) {
8101
8109
  const result = await git(["remote", "get-url", remote], repoPath, {
8102
- reject: false
8110
+ reject: false,
8111
+ timeoutMs: 5e3
8103
8112
  });
8104
8113
  if (result.exitCode !== 0 || !result.stdout.trim()) return null;
8105
8114
  return parseGithubSlugFromRemoteUrl(result.stdout);
@@ -8112,7 +8121,7 @@ async function resolveGithubRepoSlug(repoPath) {
8112
8121
  const viaGh = await gh(
8113
8122
  ["repo", "view", "--json", "nameWithOwner", "--jq", ".nameWithOwner"],
8114
8123
  repoPath,
8115
- { reject: false }
8124
+ { reject: false, timeoutMs: 8e3 }
8116
8125
  );
8117
8126
  if (viaGh.exitCode === 0 && viaGh.stdout.trim()) {
8118
8127
  return viaGh.stdout.trim();
@@ -9041,7 +9050,7 @@ async function listWorktrees(repoPath) {
9041
9050
  const { stdout } = await git(
9042
9051
  ["worktree", "list", "--porcelain"],
9043
9052
  repoPath,
9044
- { reject: false }
9053
+ { reject: false, timeoutMs: 8e3 }
9045
9054
  );
9046
9055
  if (!stdout.trim()) return [];
9047
9056
  const entries = [];
@@ -9465,6 +9474,7 @@ __export(workspaces_exports, {
9465
9474
  addWorkspace: () => addWorkspace,
9466
9475
  ensureWorkspace: () => ensureWorkspace,
9467
9476
  listWorkspaces: () => listWorkspaces,
9477
+ primaryCheckoutFromLinkedWorktree: () => primaryCheckoutFromLinkedWorktree,
9468
9478
  removeWorkspace: () => removeWorkspace,
9469
9479
  syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
9470
9480
  });
@@ -9520,6 +9530,41 @@ function listWorkspaces() {
9520
9530
  if (valid.length !== all.length) writeAll2(valid);
9521
9531
  return valid.sort((a, b) => a.name.localeCompare(b.name));
9522
9532
  }
9533
+ function isLinkedWorktreeOf(path2, mainRepo) {
9534
+ if (!path2 || path2 === mainRepo) return false;
9535
+ const git2 = (0, import_node_path22.join)(path2, ".git");
9536
+ try {
9537
+ if (!(0, import_node_fs19.existsSync)(git2) || (0, import_node_fs19.statSync)(git2).isDirectory()) return false;
9538
+ const text7 = (0, import_node_fs19.readFileSync)(git2, "utf8");
9539
+ const needle = `${mainRepo.replace(/\/+$/, "")}/.git`;
9540
+ return text7.includes(needle);
9541
+ } catch {
9542
+ return false;
9543
+ }
9544
+ }
9545
+ function primaryCheckoutFromLinkedWorktree(path2) {
9546
+ if (!path2) return null;
9547
+ const git2 = (0, import_node_path22.join)(path2, ".git");
9548
+ try {
9549
+ if (!(0, import_node_fs19.existsSync)(git2) || (0, import_node_fs19.statSync)(git2).isDirectory()) return null;
9550
+ const text7 = (0, import_node_fs19.readFileSync)(git2, "utf8");
9551
+ const match = /^\s*gitdir:\s*(.+)$/m.exec(text7);
9552
+ if (!match) return null;
9553
+ const gitdir = match[1].trim().replace(/\/+$/, "");
9554
+ const worktrees = gitdir.lastIndexOf("/.git/worktrees/");
9555
+ const root = worktrees > 0 ? gitdir.slice(0, worktrees) : gitdir.endsWith("/.git") ? gitdir.slice(0, -5) : null;
9556
+ if (!root) return null;
9557
+ return canonicalizeRepoPath(root);
9558
+ } catch {
9559
+ return null;
9560
+ }
9561
+ }
9562
+ function resolveSyncWorkspacePath(path2) {
9563
+ if (!path2 || path2 === "/") return null;
9564
+ const primary = primaryCheckoutFromLinkedWorktree(path2);
9565
+ if (primary) return primary;
9566
+ return canonicalizeRepoPath(path2);
9567
+ }
9523
9568
  async function addWorkspace(repoPath) {
9524
9569
  const root = await resolveRepoRoot(repoPath);
9525
9570
  if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
@@ -9528,13 +9573,14 @@ async function addWorkspace(repoPath) {
9528
9573
  await ensureGhPreferOrigin(root);
9529
9574
  const current = readAll2();
9530
9575
  const existing = current.find((w) => w.path === root);
9531
- if (existing) return existing;
9532
- const next = {
9576
+ const withoutLinked = current.filter((w) => !isLinkedWorktreeOf(w.path, root));
9577
+ if (existing && withoutLinked.length === current.length) return existing;
9578
+ const next = existing ?? {
9533
9579
  path: root,
9534
9580
  name: (0, import_node_path22.basename)(root),
9535
9581
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
9536
9582
  };
9537
- writeAll2([...current, next]);
9583
+ writeAll2(existing ? withoutLinked : [...withoutLinked, next]);
9538
9584
  return next;
9539
9585
  }
9540
9586
  function removeWorkspace(repoPath) {
@@ -9547,9 +9593,24 @@ async function ensureWorkspace(repoPath) {
9547
9593
  function syncWorkspacesFromThreads(repoPaths) {
9548
9594
  const current = readAll2();
9549
9595
  const removed = readRemoved();
9550
- const byPath = new Map(current.map((w) => [w.path, w]));
9596
+ const byPath = /* @__PURE__ */ new Map();
9551
9597
  let dirty = false;
9552
- for (const path2 of repoPaths) {
9598
+ for (const w of current) {
9599
+ const resolved = resolveSyncWorkspacePath(w.path) ?? w.path;
9600
+ if (resolved !== w.path) dirty = true;
9601
+ if (!resolved || resolved === "/" || isGlobalRepoPath(resolved) || removed.has(resolved)) {
9602
+ dirty = true;
9603
+ continue;
9604
+ }
9605
+ if (!byPath.has(resolved)) {
9606
+ byPath.set(
9607
+ resolved,
9608
+ resolved === w.path ? w : { ...w, path: resolved, name: (0, import_node_path22.basename)(resolved) }
9609
+ );
9610
+ }
9611
+ }
9612
+ for (const raw of repoPaths) {
9613
+ const path2 = resolveSyncWorkspacePath(raw);
9553
9614
  if (!path2 || path2 === "/" || isGlobalRepoPath(path2) || byPath.has(path2) || removed.has(path2)) {
9554
9615
  continue;
9555
9616
  }
@@ -9562,6 +9623,13 @@ function syncWorkspacesFromThreads(repoPaths) {
9562
9623
  byPath.set(path2, ws);
9563
9624
  dirty = true;
9564
9625
  }
9626
+ for (const [path2] of byPath) {
9627
+ const mains = [...byPath.keys()];
9628
+ if (mains.some((main) => isLinkedWorktreeOf(path2, main))) {
9629
+ byPath.delete(path2);
9630
+ dirty = true;
9631
+ }
9632
+ }
9565
9633
  const next = [...byPath.values()];
9566
9634
  if (dirty) writeAll2(next);
9567
9635
  return next.sort((a, b) => a.name.localeCompare(b.name));
@@ -10647,36 +10715,71 @@ var init_outbound_watch = __esm({
10647
10715
  }
10648
10716
  });
10649
10717
 
10718
+ // src/agents/turn-trace.ts
10719
+ function traceTurn(phase, extra) {
10720
+ try {
10721
+ const line = `${JSON.stringify({ t: (/* @__PURE__ */ new Date()).toISOString(), phase, ...extra })}
10722
+ `;
10723
+ (0, import_node_fs23.appendFileSync)((0, import_node_path27.join)(appDataDir(), "turn-spawn.log"), line);
10724
+ } catch {
10725
+ }
10726
+ }
10727
+ async function withTimeout(promise, ms, label) {
10728
+ let timer;
10729
+ try {
10730
+ return await Promise.race([
10731
+ promise,
10732
+ new Promise((_, reject) => {
10733
+ timer = setTimeout(
10734
+ () => reject(new Error(`${label} timed out after ${ms}ms`)),
10735
+ ms
10736
+ );
10737
+ })
10738
+ ]);
10739
+ } finally {
10740
+ if (timer) clearTimeout(timer);
10741
+ }
10742
+ }
10743
+ var import_node_fs23, import_node_path27;
10744
+ var init_turn_trace = __esm({
10745
+ "src/agents/turn-trace.ts"() {
10746
+ "use strict";
10747
+ import_node_fs23 = require("fs");
10748
+ import_node_path27 = require("path");
10749
+ init_paths();
10750
+ }
10751
+ });
10752
+
10650
10753
  // src/brightsy/config.ts
10651
10754
  function brightsyConfigPath() {
10652
10755
  const override = process.env.BRIGHTSY_CONFIG?.trim();
10653
10756
  if (override) return override;
10654
- return (0, import_node_path27.join)((0, import_node_os7.homedir)(), ".brightsy", "config.json");
10757
+ return (0, import_node_path28.join)((0, import_node_os7.homedir)(), ".brightsy", "config.json");
10655
10758
  }
10656
10759
  function loadBrightsyConfig() {
10657
10760
  const path2 = brightsyConfigPath();
10658
- if (!(0, import_node_fs23.existsSync)(path2)) {
10761
+ if (!(0, import_node_fs24.existsSync)(path2)) {
10659
10762
  throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
10660
10763
  }
10661
- const raw = JSON.parse((0, import_node_fs23.readFileSync)(path2, "utf8"));
10764
+ const raw = JSON.parse((0, import_node_fs24.readFileSync)(path2, "utf8"));
10662
10765
  if (!raw.access_token || !raw.account_id) {
10663
10766
  throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
10664
10767
  }
10665
10768
  return raw;
10666
10769
  }
10667
10770
  function saveBrightsyConfig(cfg) {
10668
- (0, import_node_fs23.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
10771
+ (0, import_node_fs24.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
10669
10772
  `, {
10670
10773
  mode: 384
10671
10774
  });
10672
10775
  }
10673
- var import_node_fs23, import_node_os7, import_node_path27;
10776
+ var import_node_fs24, import_node_os7, import_node_path28;
10674
10777
  var init_config = __esm({
10675
10778
  "src/brightsy/config.ts"() {
10676
10779
  "use strict";
10677
- import_node_fs23 = require("fs");
10780
+ import_node_fs24 = require("fs");
10678
10781
  import_node_os7 = require("os");
10679
- import_node_path27 = require("path");
10782
+ import_node_path28 = require("path");
10680
10783
  }
10681
10784
  });
10682
10785
 
@@ -10903,22 +11006,22 @@ __export(connected_teams_exports, {
10903
11006
  listConnectedBrightsyTeams: () => listConnectedBrightsyTeams
10904
11007
  });
10905
11008
  function storePath4() {
10906
- return (0, import_node_path28.join)(appDataDir(), "brightsy-teams.json");
11009
+ return (0, import_node_path29.join)(appDataDir(), "brightsy-teams.json");
10907
11010
  }
10908
11011
  function readStore4() {
10909
11012
  const path2 = storePath4();
10910
- if (!(0, import_node_fs24.existsSync)(path2)) return [];
11013
+ if (!(0, import_node_fs25.existsSync)(path2)) return [];
10911
11014
  try {
10912
- const parsed = JSON.parse((0, import_node_fs24.readFileSync)(path2, "utf8"));
11015
+ const parsed = JSON.parse((0, import_node_fs25.readFileSync)(path2, "utf8"));
10913
11016
  return Array.isArray(parsed.teams) ? parsed.teams : [];
10914
11017
  } catch {
10915
11018
  return [];
10916
11019
  }
10917
11020
  }
10918
11021
  function writeStore3(teams) {
10919
- (0, import_node_fs24.mkdirSync)(appDataDir(), { recursive: true });
11022
+ (0, import_node_fs25.mkdirSync)(appDataDir(), { recursive: true });
10920
11023
  const path2 = storePath4();
10921
- (0, import_node_fs24.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
11024
+ (0, import_node_fs25.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
10922
11025
  `, {
10923
11026
  mode: 384
10924
11027
  });
@@ -11074,12 +11177,12 @@ function brightsyMcpServerName(slug) {
11074
11177
  const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
11075
11178
  return `brightsy_${cleaned || "team"}`;
11076
11179
  }
11077
- var import_node_fs24, import_node_path28;
11180
+ var import_node_fs25, import_node_path29;
11078
11181
  var init_connected_teams = __esm({
11079
11182
  "src/brightsy/connected-teams.ts"() {
11080
11183
  "use strict";
11081
- import_node_fs24 = require("fs");
11082
- import_node_path28 = require("path");
11184
+ import_node_fs25 = require("fs");
11185
+ import_node_path29 = require("path");
11083
11186
  init_paths();
11084
11187
  init_accounts();
11085
11188
  init_config();
@@ -11444,11 +11547,11 @@ async function syncCliForTarget(accountId) {
11444
11547
  }
11445
11548
  applyConnectedTeamToCli(team);
11446
11549
  }
11447
- var import_node_fs25, brightsyAdapter;
11550
+ var import_node_fs26, brightsyAdapter;
11448
11551
  var init_brightsy = __esm({
11449
11552
  "src/agents/brightsy.ts"() {
11450
11553
  "use strict";
11451
- import_node_fs25 = require("fs");
11554
+ import_node_fs26 = require("fs");
11452
11555
  init_run();
11453
11556
  init_connected_teams();
11454
11557
  init_config();
@@ -11463,7 +11566,7 @@ var init_brightsy = __esm({
11463
11566
  async detect() {
11464
11567
  const brightsy = resolveAgentExecutable("brightsy");
11465
11568
  if (brightsy !== "brightsy") {
11466
- if (!(0, import_node_fs25.existsSync)(brightsy)) {
11569
+ if (!(0, import_node_fs26.existsSync)(brightsy)) {
11467
11570
  return {
11468
11571
  agent: "brightsy",
11469
11572
  installed: false,
@@ -11571,6 +11674,11 @@ function mcpAllowTools(servers) {
11571
11674
  }
11572
11675
  return out;
11573
11676
  }
11677
+ function mcpAllowToolsFromNames(names) {
11678
+ return mcpAllowTools(
11679
+ [...names].map((name) => name.trim()).filter(Boolean).map((name) => ({ name, connected: true, needsAuth: false }))
11680
+ );
11681
+ }
11574
11682
  function mcpAuthWarnings(servers) {
11575
11683
  const needing = servers.filter((s) => s.needsAuth).map((s) => s.name);
11576
11684
  if (needing.length === 0) return [];
@@ -11639,7 +11747,7 @@ function splitPemCertificates(pem) {
11639
11747
  }
11640
11748
  function readExistingFile(path2) {
11641
11749
  try {
11642
- return (0, import_node_fs26.existsSync)(path2) ? (0, import_node_fs26.readFileSync)(path2, "utf8") : "";
11750
+ return (0, import_node_fs27.existsSync)(path2) ? (0, import_node_fs27.readFileSync)(path2, "utf8") : "";
11643
11751
  } catch {
11644
11752
  return "";
11645
11753
  }
@@ -11671,13 +11779,13 @@ function collectSystemCaPem(io = {}) {
11671
11779
  return "";
11672
11780
  }
11673
11781
  function systemCaBundlePath(io = {}) {
11674
- return (0, import_node_path29.join)((io.appData ?? appDataDir)(), BUNDLE_NAME);
11782
+ return (0, import_node_path30.join)((io.appData ?? appDataDir)(), BUNDLE_NAME);
11675
11783
  }
11676
11784
  function bundleIsFresh(path2, now) {
11677
11785
  try {
11678
- if (!(0, import_node_fs26.existsSync)(path2)) return false;
11679
- if (splitPemCertificates((0, import_node_fs26.readFileSync)(path2, "utf8")).length === 0) return false;
11680
- return now - (0, import_node_fs26.statSync)(path2).mtimeMs < BUNDLE_MAX_AGE_MS;
11786
+ if (!(0, import_node_fs27.existsSync)(path2)) return false;
11787
+ if (splitPemCertificates((0, import_node_fs27.readFileSync)(path2, "utf8")).length === 0) return false;
11788
+ return now - (0, import_node_fs27.statSync)(path2).mtimeMs < BUNDLE_MAX_AGE_MS;
11681
11789
  } catch {
11682
11790
  return false;
11683
11791
  }
@@ -11698,11 +11806,11 @@ function materializeSystemCaBundle(io = {}) {
11698
11806
  if (bundleIsFresh(dest, now)) return dest;
11699
11807
  const pem = collectSystemCaPem(io);
11700
11808
  if (splitPemCertificates(pem).length === 0) {
11701
- return (0, import_node_fs26.existsSync)(dest) && splitPemCertificates(readExistingFile(dest)).length > 0 ? dest : void 0;
11809
+ return (0, import_node_fs27.existsSync)(dest) && splitPemCertificates(readExistingFile(dest)).length > 0 ? dest : void 0;
11702
11810
  }
11703
11811
  try {
11704
- (0, import_node_fs26.mkdirSync)((0, import_node_path29.dirname)(dest), { recursive: true });
11705
- (0, import_node_fs26.writeFileSync)(dest, pem.endsWith("\n") ? pem : `${pem}
11812
+ (0, import_node_fs27.mkdirSync)((0, import_node_path30.dirname)(dest), { recursive: true });
11813
+ (0, import_node_fs27.writeFileSync)(dest, pem.endsWith("\n") ? pem : `${pem}
11706
11814
  `, { mode: 384 });
11707
11815
  return dest;
11708
11816
  } catch {
@@ -11742,13 +11850,13 @@ function trustSystemCertificates(io = {}) {
11742
11850
  return false;
11743
11851
  }
11744
11852
  }
11745
- var import_node_child_process4, import_node_fs26, import_node_path29, import_node_tls, NODE_USE_SYSTEM_CA, NODE_EXTRA_CA_CERTS, BUNDLE_NAME, BUNDLE_MAX_AGE_MS, LINUX_CA_FILES, PEM_CERT_RE;
11853
+ var import_node_child_process4, import_node_fs27, import_node_path30, import_node_tls, NODE_USE_SYSTEM_CA, NODE_EXTRA_CA_CERTS, BUNDLE_NAME, BUNDLE_MAX_AGE_MS, LINUX_CA_FILES, PEM_CERT_RE;
11746
11854
  var init_system_ca = __esm({
11747
11855
  "src/http/system-ca.ts"() {
11748
11856
  "use strict";
11749
11857
  import_node_child_process4 = require("child_process");
11750
- import_node_fs26 = require("fs");
11751
- import_node_path29 = require("path");
11858
+ import_node_fs27 = require("fs");
11859
+ import_node_path30 = require("path");
11752
11860
  import_node_tls = __toESM(require("tls"), 1);
11753
11861
  init_paths();
11754
11862
  NODE_USE_SYSTEM_CA = "NODE_USE_SYSTEM_CA";
@@ -11774,43 +11882,43 @@ function electronResourcesPath() {
11774
11882
  function packagedCursorRuntimeDir() {
11775
11883
  const resources = electronResourcesPath();
11776
11884
  if (!resources) return null;
11777
- const dir = (0, import_node_path30.join)(resources, "cursor-runtime");
11778
- if (!(0, import_node_fs27.existsSync)((0, import_node_path30.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
11885
+ const dir = (0, import_node_path31.join)(resources, "cursor-runtime");
11886
+ if (!(0, import_node_fs28.existsSync)((0, import_node_path31.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
11779
11887
  return dir;
11780
11888
  }
11781
11889
  function packagedCursorRunnerPath() {
11782
11890
  const dir = packagedCursorRuntimeDir();
11783
- return dir ? (0, import_node_path30.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
11891
+ return dir ? (0, import_node_path31.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
11784
11892
  }
11785
11893
  function packagedMcpDir() {
11786
11894
  const resources = electronResourcesPath();
11787
11895
  if (!resources) return null;
11788
- const dir = (0, import_node_path30.join)(resources, "sideboard-mcp");
11789
- if (!(0, import_node_fs27.existsSync)((0, import_node_path30.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
11896
+ const dir = (0, import_node_path31.join)(resources, "sideboard-mcp");
11897
+ if (!(0, import_node_fs28.existsSync)((0, import_node_path31.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
11790
11898
  return dir;
11791
11899
  }
11792
11900
  function packagedMcpStdioPath() {
11793
11901
  const dir = packagedMcpDir();
11794
- return dir ? (0, import_node_path30.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
11902
+ return dir ? (0, import_node_path31.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
11795
11903
  }
11796
11904
  function packagedBundledNodePath() {
11797
11905
  const resources = electronResourcesPath();
11798
11906
  if (!resources) return null;
11799
- const bin = (0, import_node_path30.join)(resources, "node", "bin", "node");
11800
- if (!(0, import_node_fs27.existsSync)(bin)) return null;
11907
+ const bin = (0, import_node_path31.join)(resources, "node", "bin", "node");
11908
+ if (!(0, import_node_fs28.existsSync)(bin)) return null;
11801
11909
  return bin;
11802
11910
  }
11803
11911
  function packagedCursorRipgrepCandidate(platformPkg, binName) {
11804
11912
  const dir = packagedCursorRuntimeDir();
11805
11913
  if (!dir) return null;
11806
- return (0, import_node_path30.join)(dir, "node_modules", platformPkg, "bin", binName);
11914
+ return (0, import_node_path31.join)(dir, "node_modules", platformPkg, "bin", binName);
11807
11915
  }
11808
- var import_node_fs27, import_node_path30;
11916
+ var import_node_fs28, import_node_path31;
11809
11917
  var init_packaged_runtime = __esm({
11810
11918
  "src/agents/packaged-runtime.ts"() {
11811
11919
  "use strict";
11812
- import_node_fs27 = require("fs");
11813
- import_node_path30 = require("path");
11920
+ import_node_fs28 = require("fs");
11921
+ import_node_path31 = require("path");
11814
11922
  }
11815
11923
  });
11816
11924
 
@@ -11845,7 +11953,7 @@ function unpackedAsarPath(filePath) {
11845
11953
  if (!isAsarPath(filePath)) return null;
11846
11954
  const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
11847
11955
  if (unpacked === filePath) return null;
11848
- return (0, import_node_fs28.existsSync)(unpacked) ? unpacked : null;
11956
+ return (0, import_node_fs29.existsSync)(unpacked) ? unpacked : null;
11849
11957
  }
11850
11958
  function nodeReadableScriptPath(scriptPath) {
11851
11959
  return unpackedAsarPath(scriptPath) ?? scriptPath;
@@ -11885,37 +11993,37 @@ function pickPreferredNode(candidates) {
11885
11993
  return best;
11886
11994
  }
11887
11995
  function versionDirNodeBins(root, toBin) {
11888
- if (!(0, import_node_fs28.existsSync)(root)) return [];
11996
+ if (!(0, import_node_fs29.existsSync)(root)) return [];
11889
11997
  try {
11890
- return (0, import_node_fs28.readdirSync)(root).map(toBin);
11998
+ return (0, import_node_fs29.readdirSync)(root).map(toBin);
11891
11999
  } catch {
11892
12000
  return [];
11893
12001
  }
11894
12002
  }
11895
12003
  function defaultNodeBinCandidates(home = (0, import_node_os8.homedir)()) {
11896
12004
  const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
11897
- (prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path31.join)(prefix, "opt", `node@${major}`, "bin", "node"))
12005
+ (prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path32.join)(prefix, "opt", `node@${major}`, "bin", "node"))
11898
12006
  );
11899
12007
  return [
11900
12008
  ...kegs,
11901
12009
  "/opt/homebrew/bin/node",
11902
12010
  "/usr/local/bin/node",
11903
- (0, import_node_path31.join)(home, ".local/share/fnm/aliases/default/bin/node"),
11904
- (0, import_node_path31.join)(home, ".nvm/current/bin/node"),
11905
- (0, import_node_path31.join)(home, ".volta/bin/node"),
11906
- (0, import_node_path31.join)(home, ".asdf/shims/node"),
11907
- (0, import_node_path31.join)(home, ".local/share/mise/shims/node"),
12011
+ (0, import_node_path32.join)(home, ".local/share/fnm/aliases/default/bin/node"),
12012
+ (0, import_node_path32.join)(home, ".nvm/current/bin/node"),
12013
+ (0, import_node_path32.join)(home, ".volta/bin/node"),
12014
+ (0, import_node_path32.join)(home, ".asdf/shims/node"),
12015
+ (0, import_node_path32.join)(home, ".local/share/mise/shims/node"),
11908
12016
  ...versionDirNodeBins(
11909
- (0, import_node_path31.join)(home, ".nvm", "versions", "node"),
11910
- (name) => (0, import_node_path31.join)(home, ".nvm", "versions", "node", name, "bin", "node")
12017
+ (0, import_node_path32.join)(home, ".nvm", "versions", "node"),
12018
+ (name) => (0, import_node_path32.join)(home, ".nvm", "versions", "node", name, "bin", "node")
11911
12019
  ),
11912
12020
  ...versionDirNodeBins(
11913
- (0, import_node_path31.join)(home, ".local/share/fnm", "node-versions"),
11914
- (name) => (0, import_node_path31.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
12021
+ (0, import_node_path32.join)(home, ".local/share/fnm", "node-versions"),
12022
+ (name) => (0, import_node_path32.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
11915
12023
  ),
11916
12024
  ...versionDirNodeBins(
11917
- (0, import_node_path31.join)(home, ".volta", "tools", "image", "node"),
11918
- (name) => (0, import_node_path31.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
12025
+ (0, import_node_path32.join)(home, ".volta", "tools", "image", "node"),
12026
+ (name) => (0, import_node_path32.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
11919
12027
  )
11920
12028
  ];
11921
12029
  }
@@ -11924,10 +12032,10 @@ function uniqueExistingNodeBins(paths) {
11924
12032
  const out = [];
11925
12033
  for (const raw of paths) {
11926
12034
  const p = raw.trim();
11927
- if (!p || !(0, import_node_fs28.existsSync)(p) || isElectronLikeCommand(p)) continue;
12035
+ if (!p || !(0, import_node_fs29.existsSync)(p) || isElectronLikeCommand(p)) continue;
11928
12036
  let key = p;
11929
12037
  try {
11930
- key = (0, import_node_fs28.realpathSync)(p);
12038
+ key = (0, import_node_fs29.realpathSync)(p);
11931
12039
  } catch {
11932
12040
  continue;
11933
12041
  }
@@ -12007,13 +12115,13 @@ async function resolveNodeLaunch(scriptPath) {
12007
12115
  env: { ELECTRON_RUN_AS_NODE: "1" }
12008
12116
  };
12009
12117
  }
12010
- var import_node_fs28, import_node_os8, import_node_path31, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
12118
+ var import_node_fs29, import_node_os8, import_node_path32, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
12011
12119
  var init_node_launch = __esm({
12012
12120
  "src/agents/node-launch.ts"() {
12013
12121
  "use strict";
12014
- import_node_fs28 = require("fs");
12122
+ import_node_fs29 = require("fs");
12015
12123
  import_node_os8 = require("os");
12016
- import_node_path31 = require("path");
12124
+ import_node_path32 = require("path");
12017
12125
  init_nested_electron_env();
12018
12126
  init_system_ca();
12019
12127
  init_run();
@@ -12115,37 +12223,37 @@ function corePackageDir() {
12115
12223
  try {
12116
12224
  const url = import_meta.url;
12117
12225
  if (typeof url === "string" && url.length > 0) {
12118
- return (0, import_node_path32.dirname)((0, import_node_url.fileURLToPath)(url));
12226
+ return (0, import_node_path33.dirname)((0, import_node_url.fileURLToPath)(url));
12119
12227
  }
12120
12228
  } catch {
12121
12229
  }
12122
12230
  try {
12123
- const req = (0, import_node_module.createRequire)((0, import_node_path32.join)(process.cwd(), "package.json"));
12124
- return (0, import_node_path32.dirname)(req.resolve("@sideboard-ai/core"));
12231
+ const req = (0, import_node_module.createRequire)((0, import_node_path33.join)(process.cwd(), "package.json"));
12232
+ return (0, import_node_path33.dirname)(req.resolve("@sideboard-ai/core"));
12125
12233
  } catch {
12126
12234
  return process.cwd();
12127
12235
  }
12128
12236
  }
12129
12237
  function findSideboardMcpJsEntry() {
12130
12238
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
12131
- if (override && (0, import_node_fs29.existsSync)(override)) return override;
12239
+ if (override && (0, import_node_fs30.existsSync)(override)) return override;
12132
12240
  const packaged = packagedMcpStdioPath();
12133
12241
  if (packaged) return packaged;
12134
12242
  let dir = corePackageDir();
12135
12243
  for (let i = 0; i < 10; i++) {
12136
12244
  const candidates = [
12137
- (0, import_node_path32.join)(dir, "mcp/run-stdio.js"),
12138
- (0, import_node_path32.join)(dir, "mcp/run-stdio.cjs"),
12139
- (0, import_node_path32.join)(dir, "dist/mcp/run-stdio.js"),
12140
- (0, import_node_path32.join)(dir, "dist/mcp/run-stdio.cjs"),
12141
- (0, import_node_path32.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
12142
- (0, import_node_path32.join)(dir, "packages/cli/dist/index.js"),
12143
- (0, import_node_path32.join)(dir, "cli/dist/index.js")
12245
+ (0, import_node_path33.join)(dir, "mcp/run-stdio.js"),
12246
+ (0, import_node_path33.join)(dir, "mcp/run-stdio.cjs"),
12247
+ (0, import_node_path33.join)(dir, "dist/mcp/run-stdio.js"),
12248
+ (0, import_node_path33.join)(dir, "dist/mcp/run-stdio.cjs"),
12249
+ (0, import_node_path33.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
12250
+ (0, import_node_path33.join)(dir, "packages/cli/dist/index.js"),
12251
+ (0, import_node_path33.join)(dir, "cli/dist/index.js")
12144
12252
  ];
12145
12253
  for (const p of candidates) {
12146
- if ((0, import_node_fs29.existsSync)(p) && !isAsarPath(p)) return p;
12254
+ if ((0, import_node_fs30.existsSync)(p) && !isAsarPath(p)) return p;
12147
12255
  }
12148
- const parent = (0, import_node_path32.dirname)(dir);
12256
+ const parent = (0, import_node_path33.dirname)(dir);
12149
12257
  if (parent === dir) break;
12150
12258
  dir = parent;
12151
12259
  }
@@ -12281,8 +12389,16 @@ function toOpencodeMcpConfigContent(servers, opts) {
12281
12389
  }
12282
12390
  return JSON.stringify({ mcp });
12283
12391
  }
12284
- function writeMcpServersConfig(servers) {
12285
- if (servers.length === 0) return null;
12392
+ function stripElectronFromUserMcpEntry(entry) {
12393
+ const next = { ...entry };
12394
+ const env = next.env;
12395
+ if (!env || typeof env !== "object" || Array.isArray(env)) return next;
12396
+ const cleaned = { ...env };
12397
+ delete cleaned.ELECTRON_RUN_AS_NODE;
12398
+ next.env = cleaned;
12399
+ return next;
12400
+ }
12401
+ function writeMcpServersConfig(servers, extraServers) {
12286
12402
  const mcpServers = {};
12287
12403
  for (const s of servers) {
12288
12404
  const env = mcpSpawnEnv(s.env);
@@ -12292,22 +12408,30 @@ function writeMcpServersConfig(servers) {
12292
12408
  ...env ? { env } : {}
12293
12409
  };
12294
12410
  }
12295
- const dir = (0, import_node_fs29.mkdtempSync)((0, import_node_path32.join)((0, import_node_os9.tmpdir)(), "sideboard-mcp-"));
12296
- const cfgPath = (0, import_node_path32.join)(dir, "mcp.json");
12297
- (0, import_node_fs29.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
12411
+ if (extraServers) {
12412
+ for (const [rawName, entry] of Object.entries(extraServers)) {
12413
+ const name = rawName.trim();
12414
+ if (!name || mcpServers[name] || !entry) continue;
12415
+ mcpServers[name] = stripElectronFromUserMcpEntry(entry);
12416
+ }
12417
+ }
12418
+ if (Object.keys(mcpServers).length === 0) return null;
12419
+ const dir = (0, import_node_fs30.mkdtempSync)((0, import_node_path33.join)((0, import_node_os9.tmpdir)(), "sideboard-mcp-"));
12420
+ const cfgPath = (0, import_node_path33.join)(dir, "mcp.json");
12421
+ (0, import_node_fs30.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
12298
12422
  return cfgPath;
12299
12423
  }
12300
12424
  async function writeInjectedMcpConfig(opts) {
12301
12425
  return writeMcpServersConfig(await buildInjectedMcpServers(opts));
12302
12426
  }
12303
- var import_node_fs29, import_node_module, import_node_os9, import_node_path32, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, SIDEBOARD_GITHUB_MCP_ALLOWED_TOOLS, SIDEBOARD_LINEAR_MCP_ALLOWED_TOOLS, SIDEBOARD_ABLETIME_MCP_ALLOWED_TOOLS, BRIGHTSY_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
12427
+ var import_node_fs30, import_node_module, import_node_os9, import_node_path33, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, SIDEBOARD_GITHUB_MCP_ALLOWED_TOOLS, SIDEBOARD_LINEAR_MCP_ALLOWED_TOOLS, SIDEBOARD_ABLETIME_MCP_ALLOWED_TOOLS, BRIGHTSY_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
12304
12428
  var init_injected_mcp = __esm({
12305
12429
  "src/agents/injected-mcp.ts"() {
12306
12430
  "use strict";
12307
- import_node_fs29 = require("fs");
12431
+ import_node_fs30 = require("fs");
12308
12432
  import_node_module = require("module");
12309
12433
  import_node_os9 = require("os");
12310
- import_node_path32 = require("path");
12434
+ import_node_path33 = require("path");
12311
12435
  import_node_url = require("url");
12312
12436
  init_run();
12313
12437
  init_config();
@@ -12347,6 +12471,205 @@ var init_injected_mcp = __esm({
12347
12471
  }
12348
12472
  });
12349
12473
 
12474
+ // src/agents/user-mcp-config.ts
12475
+ function userCursorMcpConfigPath() {
12476
+ return (0, import_node_path34.join)((0, import_node_os10.homedir)(), ".cursor", "mcp.json");
12477
+ }
12478
+ function userClaudeMcpConfigPath() {
12479
+ return (0, import_node_path34.join)((0, import_node_os10.homedir)(), ".claude.json");
12480
+ }
12481
+ function asObject(value) {
12482
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
12483
+ return { ...value };
12484
+ }
12485
+ function stripElectronSpawnEnv(env) {
12486
+ if (!env) return void 0;
12487
+ const next = { ...env };
12488
+ delete next.ELECTRON_RUN_AS_NODE;
12489
+ delete next.ELECTRON_RUN_AS_NODE;
12490
+ return Object.keys(next).length > 0 ? next : void 0;
12491
+ }
12492
+ function mergeSideboardIntoMcpServersJson(existing, sideboard) {
12493
+ const root = asObject(existing);
12494
+ const servers = asObject(root.mcpServers);
12495
+ const env = stripElectronSpawnEnv(sideboard.env);
12496
+ servers.sideboard = {
12497
+ type: "stdio",
12498
+ command: sideboard.command,
12499
+ ...sideboard.args && sideboard.args.length > 0 ? { args: sideboard.args } : {},
12500
+ ...env ? { env } : {}
12501
+ };
12502
+ return { ...root, mcpServers: servers };
12503
+ }
12504
+ function writeMergedMcpServersJson(configPath, sideboard) {
12505
+ let existing = {};
12506
+ if ((0, import_node_fs31.existsSync)(configPath)) {
12507
+ try {
12508
+ existing = JSON.parse((0, import_node_fs31.readFileSync)(configPath, "utf8"));
12509
+ } catch {
12510
+ existing = {};
12511
+ }
12512
+ }
12513
+ const next = mergeSideboardIntoMcpServersJson(existing, sideboard);
12514
+ (0, import_node_fs31.mkdirSync)((0, import_node_path34.dirname)(configPath), { recursive: true });
12515
+ (0, import_node_fs31.writeFileSync)(configPath, `${JSON.stringify(next, null, 2)}
12516
+ `);
12517
+ }
12518
+ function launchFromResolved(server) {
12519
+ return {
12520
+ command: server.command,
12521
+ args: server.args,
12522
+ env: {
12523
+ ...server.env ?? {},
12524
+ SIDEBOARD_APP_DATA: appDataDir()
12525
+ }
12526
+ };
12527
+ }
12528
+ async function registerPackagedUserMcpClients() {
12529
+ const launch = launchFromResolved(await resolveSideboardMcpServer());
12530
+ const cursor = userCursorMcpConfigPath();
12531
+ writeMergedMcpServersJson(cursor, launch);
12532
+ const claude = userClaudeMcpConfigPath();
12533
+ if ((0, import_node_fs31.existsSync)(claude)) {
12534
+ writeMergedMcpServersJson(claude, launch);
12535
+ return { cursor, claude };
12536
+ }
12537
+ return { cursor };
12538
+ }
12539
+ var import_node_fs31, import_node_os10, import_node_path34;
12540
+ var init_user_mcp_config = __esm({
12541
+ "src/agents/user-mcp-config.ts"() {
12542
+ "use strict";
12543
+ import_node_fs31 = require("fs");
12544
+ import_node_os10 = require("os");
12545
+ import_node_path34 = require("path");
12546
+ init_paths();
12547
+ init_injected_mcp();
12548
+ }
12549
+ });
12550
+
12551
+ // src/agents/orch-mcp-isolation.ts
12552
+ function isInjectedOrchMcpName(name) {
12553
+ const n = name.trim().toLowerCase();
12554
+ return n === "sideboard" || n === "brightsy" || n.startsWith("brightsy_");
12555
+ }
12556
+ function asObject2(value) {
12557
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
12558
+ return value;
12559
+ }
12560
+ function listMcpNamesFromJsonMap(raw, key) {
12561
+ return Object.keys(asObject2(asObject2(raw)[key])).filter((n) => n.trim());
12562
+ }
12563
+ function listMcpNamesFromCodexToml(text7) {
12564
+ try {
12565
+ const parsed = (0, import_smol_toml2.parse)(text7);
12566
+ return Object.keys(asObject2(parsed.mcp_servers)).filter((n) => n.trim());
12567
+ } catch {
12568
+ return [];
12569
+ }
12570
+ }
12571
+ function readJsonObject(path2) {
12572
+ try {
12573
+ return JSON.parse((0, import_node_fs32.readFileSync)(path2, "utf8"));
12574
+ } catch {
12575
+ return {};
12576
+ }
12577
+ }
12578
+ function readText(path2) {
12579
+ try {
12580
+ return (0, import_node_fs32.readFileSync)(path2, "utf8");
12581
+ } catch {
12582
+ return "";
12583
+ }
12584
+ }
12585
+ function userCodexConfigPaths(home = (0, import_node_os11.homedir)()) {
12586
+ return [(0, import_node_path35.join)(home, ".codex", "config.toml"), (0, import_node_path35.join)(home, ".config", "codex", "config.toml")];
12587
+ }
12588
+ function userOpencodeConfigPaths(home = (0, import_node_os11.homedir)()) {
12589
+ return [
12590
+ (0, import_node_path35.join)(home, ".config", "opencode", "opencode.json"),
12591
+ (0, import_node_path35.join)(home, ".config", "opencode", "opencode.jsonc")
12592
+ ];
12593
+ }
12594
+ function userMcpNamesToDisable(opts) {
12595
+ const keep = new Set(
12596
+ [...opts.injectedNames ?? []].map((n) => n.trim().toLowerCase()).filter(Boolean)
12597
+ );
12598
+ const out = [];
12599
+ const seen = /* @__PURE__ */ new Set();
12600
+ for (const raw of opts.names) {
12601
+ const name = raw.trim();
12602
+ if (!name) continue;
12603
+ const key = name.toLowerCase();
12604
+ if (seen.has(key) || keep.has(key) || isInjectedOrchMcpName(name)) continue;
12605
+ seen.add(key);
12606
+ out.push(name);
12607
+ }
12608
+ return out;
12609
+ }
12610
+ function listUserCodexMcpNames(home = (0, import_node_os11.homedir)()) {
12611
+ const names = [];
12612
+ for (const path2 of userCodexConfigPaths(home)) {
12613
+ if (!(0, import_node_fs32.existsSync)(path2)) continue;
12614
+ names.push(...listMcpNamesFromCodexToml(readText(path2)));
12615
+ }
12616
+ return names;
12617
+ }
12618
+ function listUserOpencodeMcpNames(home = (0, import_node_os11.homedir)()) {
12619
+ const names = [];
12620
+ for (const path2 of userOpencodeConfigPaths(home)) {
12621
+ if (!(0, import_node_fs32.existsSync)(path2)) continue;
12622
+ names.push(...listMcpNamesFromJsonMap(readJsonObject(path2), "mcp"));
12623
+ }
12624
+ return names;
12625
+ }
12626
+ function userClaudeMcpConfigObject(home = (0, import_node_os11.homedir)()) {
12627
+ const claudePath = home === (0, import_node_os11.homedir)() ? userClaudeMcpConfigPath() : (0, import_node_path35.join)(home, ".claude.json");
12628
+ if (!(0, import_node_fs32.existsSync)(claudePath)) return {};
12629
+ return asObject2(asObject2(readJsonObject(claudePath)).mcpServers);
12630
+ }
12631
+ function listUserClaudeMcpServerEntries(home = (0, import_node_os11.homedir)()) {
12632
+ const out = {};
12633
+ for (const [rawName, value] of Object.entries(userClaudeMcpConfigObject(home))) {
12634
+ const name = rawName.trim();
12635
+ if (!name || isInjectedOrchMcpName(name)) continue;
12636
+ if (!value || typeof value !== "object" || Array.isArray(value)) continue;
12637
+ out[name] = value;
12638
+ }
12639
+ return out;
12640
+ }
12641
+ function toCodexDisableUserMcpArgs(names) {
12642
+ const args = [];
12643
+ for (const name of names) {
12644
+ if (!/^[A-Za-z0-9_-]+$/.test(name)) continue;
12645
+ args.push("-c", `mcp_servers.${name}.enabled=false`);
12646
+ }
12647
+ return args;
12648
+ }
12649
+ function toCodexUnattendedAppsArgs() {
12650
+ return [
12651
+ "-c",
12652
+ "features.apps=false",
12653
+ "-c",
12654
+ "apps._default.enabled=false",
12655
+ "-c",
12656
+ "apps.posthog.enabled=false",
12657
+ "-c",
12658
+ "features.plugins=false"
12659
+ ];
12660
+ }
12661
+ var import_node_fs32, import_node_os11, import_node_path35, import_smol_toml2;
12662
+ var init_orch_mcp_isolation = __esm({
12663
+ "src/agents/orch-mcp-isolation.ts"() {
12664
+ "use strict";
12665
+ import_node_fs32 = require("fs");
12666
+ import_node_os11 = require("os");
12667
+ import_node_path35 = require("path");
12668
+ import_smol_toml2 = require("smol-toml");
12669
+ init_user_mcp_config();
12670
+ }
12671
+ });
12672
+
12350
12673
  // src/agents/types.ts
12351
12674
  function permissionMode(thread) {
12352
12675
  if (thread.sourceType === "orchestration") {
@@ -12395,16 +12718,8 @@ var init_types = __esm({
12395
12718
  });
12396
12719
 
12397
12720
  // src/agents/claude.ts
12398
- async function loadMcpServers() {
12399
- if (mcpListCache && Date.now() - mcpListCache.at < 3e4) {
12400
- return mcpListCache.servers;
12401
- }
12402
- const claude = resolveClaudeExecutable();
12403
- const mcpText = await run(claude, ["mcp", "list"], { reject: false });
12404
- const servers = parseMcpList(`${mcpText.stdout}
12405
- ${mcpText.stderr}`);
12406
- mcpListCache = { at: Date.now(), servers };
12407
- return servers;
12721
+ function isLocalDevAppDataDir(dir = process.env.SIDEBOARD_APP_DATA) {
12722
+ return /[/\\]\.sideboard[/\\]dev-app-data(?:[/\\]|$)/.test(dir ?? "");
12408
12723
  }
12409
12724
  function usageFromClaude(usage) {
12410
12725
  if (!usage) return null;
@@ -12712,14 +13027,15 @@ function parseIssuesJson(raw) {
12712
13027
  }
12713
13028
  return [];
12714
13029
  }
12715
- var import_node_fs30, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
13030
+ var import_node_fs33, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
12716
13031
  var init_claude = __esm({
12717
13032
  "src/agents/claude.ts"() {
12718
13033
  "use strict";
12719
- import_node_fs30 = require("fs");
13034
+ import_node_fs33 = require("fs");
12720
13035
  init_run();
12721
13036
  init_app_settings();
12722
13037
  init_claude_mcp();
13038
+ init_orch_mcp_isolation();
12723
13039
  init_error_detail();
12724
13040
  init_message_parts();
12725
13041
  init_injected_mcp();
@@ -12750,13 +13066,12 @@ var init_claude = __esm({
12750
13066
  "Skill(claude-in-chrome)"
12751
13067
  ];
12752
13068
  CLAUDE_PROMPT_ARG_MAX = 2e5;
12753
- mcpListCache = null;
12754
13069
  claudeAdapter = {
12755
13070
  kind: "claude",
12756
13071
  async detect() {
12757
13072
  const claude = resolveClaudeExecutable();
12758
13073
  if (claude !== "claude") {
12759
- if (!(0, import_node_fs30.existsSync)(claude)) {
13074
+ if (!(0, import_node_fs33.existsSync)(claude)) {
12760
13075
  return {
12761
13076
  agent: "claude",
12762
13077
  installed: false,
@@ -12816,6 +13131,7 @@ var init_claude = __esm({
12816
13131
  });
12817
13132
  const injectedBrightsyNames = injectedServers.filter((s) => s.name === "brightsy" || s.name.startsWith("brightsy_")).map((s) => s.name);
12818
13133
  const chromeOn = claudeChromeEnabled();
13134
+ const userMcpEntries = isOrchestrator ? {} : listUserClaudeMcpServerEntries();
12819
13135
  let allowedTools;
12820
13136
  if (isOrchestrator) {
12821
13137
  allowedTools = [
@@ -12824,10 +13140,9 @@ var init_claude = __esm({
12824
13140
  ...brightsyMcpAllowedTools(injectedBrightsyNames)
12825
13141
  ];
12826
13142
  } else {
12827
- const servers = await loadMcpServers();
12828
13143
  allowedTools = [
12829
13144
  ...BASE_ALLOWED_TOOLS,
12830
- ...mcpAllowTools(servers),
13145
+ ...mcpAllowToolsFromNames(Object.keys(userMcpEntries)),
12831
13146
  ...sideboardWorktreeAllowedTools({
12832
13147
  github: true,
12833
13148
  linear: isLinearConnected(),
@@ -12852,12 +13167,10 @@ var init_claude = __esm({
12852
13167
  if (systemPrompt) {
12853
13168
  args.push("--append-system-prompt", systemPrompt);
12854
13169
  }
12855
- const mcpConfigPath = writeMcpServersConfig(injectedServers);
13170
+ const mcpConfigPath = writeMcpServersConfig(injectedServers, userMcpEntries);
12856
13171
  if (mcpConfigPath) {
12857
13172
  args.push("--mcp-config", mcpConfigPath);
12858
- if (isOrchestrator) {
12859
- args.push("--strict-mcp-config");
12860
- }
13173
+ args.push("--strict-mcp-config");
12861
13174
  }
12862
13175
  if (chromeOn) {
12863
13176
  args.push("--chrome");
@@ -12889,8 +13202,10 @@ var init_claude = __esm({
12889
13202
  CLAUDE_CODE_FORWARD_SUBAGENT_TEXT: "1",
12890
13203
  CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS: process.env.CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS ?? String(CLAUDE_PRINT_BG_WAIT_CEILING_MS),
12891
13204
  // `--strict-mcp-config` still fetches claude.ai connectors on some CLI
12892
- // builds (anthropics/claude-code#60252). Coordinators do not need them.
12893
- ...isOrchestrator ? { ENABLE_CLAUDEAI_MCP_SERVERS: "false" } : {}
13205
+ // builds (anthropics/claude-code#60252). Coordinators never need them.
13206
+ // Local `pnpm dev` also disables them: those HTTP connectors hang the
13207
+ // first worktree turn when Electron's cwd is this Sideboard repo.
13208
+ ...isOrchestrator || isLocalDevAppDataDir() ? { ENABLE_CLAUDEAI_MCP_SERVERS: "false" } : {}
12894
13209
  }
12895
13210
  };
12896
13211
  },
@@ -12952,249 +13267,65 @@ var init_claude = __esm({
12952
13267
  if (delta?.text) return withEventParentId({ type: "stdout", data: delta.text }, parentId);
12953
13268
  if (delta?.thinking) {
12954
13269
  return withEventParentId({ type: "thinking", data: delta.thinking }, parentId);
12955
- }
12956
- return null;
12957
- }
12958
- if (obj.type === "result") {
12959
- const events = [];
12960
- const errorDetail = claudeResultErrorDetail(obj);
12961
- if (errorDetail) {
12962
- events.push({ type: "stderr", data: errorDetail });
12963
- } else {
12964
- const text7 = obj.result;
12965
- if (typeof text7 === "string" && text7) events.push({ type: "stdout", data: text7 });
12966
- }
12967
- const usage = usageFromClaude(obj.usage);
12968
- if (usage) {
12969
- const costUsd = costUsdFromClaudeResult(obj);
12970
- if (costUsd != null) usage.costUsd = costUsd;
12971
- events.push({ type: "usage", data: usage, scope: "turn" });
12972
- }
12973
- if (events.length === 0) return null;
12974
- return events.length === 1 ? events[0] : events;
12975
- }
12976
- return null;
12977
- } catch {
12978
- return { type: "stdout", data: line };
12979
- }
12980
- },
12981
- async resolveSessionId(_worktreePath, cached) {
12982
- return cached;
12983
- },
12984
- async buildAttach(thread) {
12985
- const claude = resolveClaudeExecutable();
12986
- const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
12987
- const args = sessionId ? ["--resume", sessionId] : [];
12988
- if (claudeChromeEnabled()) {
12989
- args.push("--chrome");
12990
- }
12991
- return { file: claude, args, cwd: thread.worktreePath };
12992
- },
12993
- async listLinearIssues(_repoPath) {
12994
- const claude = resolveClaudeExecutable();
12995
- const prompt = "List my assigned Linear issues as JSON array only, no markdown. Each item: id, identifier, title, url, labels (string[]).";
12996
- const { stdout, exitCode } = await run(
12997
- claude,
12998
- [
12999
- "-p",
13000
- prompt,
13001
- "--output-format",
13002
- "json",
13003
- "--permission-mode",
13004
- "bypassPermissions",
13005
- "--allowedTools",
13006
- "mcp__linear__*"
13007
- ],
13008
- { reject: false }
13009
- );
13010
- if (exitCode !== 0) return [];
13011
- return parseIssuesJson(stdout);
13012
- }
13013
- };
13014
- }
13015
- });
13016
-
13017
- // src/agents/user-mcp-config.ts
13018
- function userCursorMcpConfigPath() {
13019
- return (0, import_node_path33.join)((0, import_node_os10.homedir)(), ".cursor", "mcp.json");
13020
- }
13021
- function userClaudeMcpConfigPath() {
13022
- return (0, import_node_path33.join)((0, import_node_os10.homedir)(), ".claude.json");
13023
- }
13024
- function asObject(value) {
13025
- if (!value || typeof value !== "object" || Array.isArray(value)) return {};
13026
- return { ...value };
13027
- }
13028
- function stripElectronSpawnEnv(env) {
13029
- if (!env) return void 0;
13030
- const next = { ...env };
13031
- delete next.ELECTRON_RUN_AS_NODE;
13032
- delete next.ELECTRON_RUN_AS_NODE;
13033
- return Object.keys(next).length > 0 ? next : void 0;
13034
- }
13035
- function mergeSideboardIntoMcpServersJson(existing, sideboard) {
13036
- const root = asObject(existing);
13037
- const servers = asObject(root.mcpServers);
13038
- const env = stripElectronSpawnEnv(sideboard.env);
13039
- servers.sideboard = {
13040
- type: "stdio",
13041
- command: sideboard.command,
13042
- ...sideboard.args && sideboard.args.length > 0 ? { args: sideboard.args } : {},
13043
- ...env ? { env } : {}
13044
- };
13045
- return { ...root, mcpServers: servers };
13046
- }
13047
- function writeMergedMcpServersJson(configPath, sideboard) {
13048
- let existing = {};
13049
- if ((0, import_node_fs31.existsSync)(configPath)) {
13050
- try {
13051
- existing = JSON.parse((0, import_node_fs31.readFileSync)(configPath, "utf8"));
13052
- } catch {
13053
- existing = {};
13054
- }
13055
- }
13056
- const next = mergeSideboardIntoMcpServersJson(existing, sideboard);
13057
- (0, import_node_fs31.mkdirSync)((0, import_node_path33.dirname)(configPath), { recursive: true });
13058
- (0, import_node_fs31.writeFileSync)(configPath, `${JSON.stringify(next, null, 2)}
13059
- `);
13060
- }
13061
- function launchFromResolved(server) {
13062
- return {
13063
- command: server.command,
13064
- args: server.args,
13065
- env: {
13066
- ...server.env ?? {},
13067
- SIDEBOARD_APP_DATA: appDataDir()
13068
- }
13069
- };
13070
- }
13071
- async function registerPackagedUserMcpClients() {
13072
- const launch = launchFromResolved(await resolveSideboardMcpServer());
13073
- const cursor = userCursorMcpConfigPath();
13074
- writeMergedMcpServersJson(cursor, launch);
13075
- const claude = userClaudeMcpConfigPath();
13076
- if ((0, import_node_fs31.existsSync)(claude)) {
13077
- writeMergedMcpServersJson(claude, launch);
13078
- return { cursor, claude };
13079
- }
13080
- return { cursor };
13081
- }
13082
- var import_node_fs31, import_node_os10, import_node_path33;
13083
- var init_user_mcp_config = __esm({
13084
- "src/agents/user-mcp-config.ts"() {
13085
- "use strict";
13086
- import_node_fs31 = require("fs");
13087
- import_node_os10 = require("os");
13088
- import_node_path33 = require("path");
13089
- init_paths();
13090
- init_injected_mcp();
13091
- }
13092
- });
13093
-
13094
- // src/agents/orch-mcp-isolation.ts
13095
- function isInjectedOrchMcpName(name) {
13096
- const n = name.trim().toLowerCase();
13097
- return n === "sideboard" || n === "brightsy" || n.startsWith("brightsy_");
13098
- }
13099
- function asObject2(value) {
13100
- if (!value || typeof value !== "object" || Array.isArray(value)) return {};
13101
- return value;
13102
- }
13103
- function listMcpNamesFromJsonMap(raw, key) {
13104
- return Object.keys(asObject2(asObject2(raw)[key])).filter((n) => n.trim());
13105
- }
13106
- function listMcpNamesFromCodexToml(text7) {
13107
- try {
13108
- const parsed = (0, import_smol_toml2.parse)(text7);
13109
- return Object.keys(asObject2(parsed.mcp_servers)).filter((n) => n.trim());
13110
- } catch {
13111
- return [];
13112
- }
13113
- }
13114
- function readJsonObject(path2) {
13115
- try {
13116
- return JSON.parse((0, import_node_fs32.readFileSync)(path2, "utf8"));
13117
- } catch {
13118
- return {};
13119
- }
13120
- }
13121
- function readText(path2) {
13122
- try {
13123
- return (0, import_node_fs32.readFileSync)(path2, "utf8");
13124
- } catch {
13125
- return "";
13126
- }
13127
- }
13128
- function userCodexConfigPaths(home = (0, import_node_os11.homedir)()) {
13129
- return [(0, import_node_path34.join)(home, ".codex", "config.toml"), (0, import_node_path34.join)(home, ".config", "codex", "config.toml")];
13130
- }
13131
- function userOpencodeConfigPaths(home = (0, import_node_os11.homedir)()) {
13132
- return [
13133
- (0, import_node_path34.join)(home, ".config", "opencode", "opencode.json"),
13134
- (0, import_node_path34.join)(home, ".config", "opencode", "opencode.jsonc")
13135
- ];
13136
- }
13137
- function userMcpNamesToDisable(opts) {
13138
- const keep = new Set(
13139
- [...opts.injectedNames ?? []].map((n) => n.trim().toLowerCase()).filter(Boolean)
13140
- );
13141
- const out = [];
13142
- const seen = /* @__PURE__ */ new Set();
13143
- for (const raw of opts.names) {
13144
- const name = raw.trim();
13145
- if (!name) continue;
13146
- const key = name.toLowerCase();
13147
- if (seen.has(key) || keep.has(key) || isInjectedOrchMcpName(name)) continue;
13148
- seen.add(key);
13149
- out.push(name);
13150
- }
13151
- return out;
13152
- }
13153
- function listUserCodexMcpNames(home = (0, import_node_os11.homedir)()) {
13154
- const names = [];
13155
- for (const path2 of userCodexConfigPaths(home)) {
13156
- if (!(0, import_node_fs32.existsSync)(path2)) continue;
13157
- names.push(...listMcpNamesFromCodexToml(readText(path2)));
13158
- }
13159
- return names;
13160
- }
13161
- function listUserOpencodeMcpNames(home = (0, import_node_os11.homedir)()) {
13162
- const names = [];
13163
- for (const path2 of userOpencodeConfigPaths(home)) {
13164
- if (!(0, import_node_fs32.existsSync)(path2)) continue;
13165
- names.push(...listMcpNamesFromJsonMap(readJsonObject(path2), "mcp"));
13166
- }
13167
- return names;
13168
- }
13169
- function toCodexDisableUserMcpArgs(names) {
13170
- const args = [];
13171
- for (const name of names) {
13172
- if (!/^[A-Za-z0-9_-]+$/.test(name)) continue;
13173
- args.push("-c", `mcp_servers.${name}.enabled=false`);
13174
- }
13175
- return args;
13176
- }
13177
- function toCodexUnattendedAppsArgs() {
13178
- return [
13179
- "-c",
13180
- "features.apps=false",
13181
- "-c",
13182
- "apps._default.enabled=false",
13183
- "-c",
13184
- "apps.posthog.enabled=false",
13185
- "-c",
13186
- "features.plugins=false"
13187
- ];
13188
- }
13189
- var import_node_fs32, import_node_os11, import_node_path34, import_smol_toml2;
13190
- var init_orch_mcp_isolation = __esm({
13191
- "src/agents/orch-mcp-isolation.ts"() {
13192
- "use strict";
13193
- import_node_fs32 = require("fs");
13194
- import_node_os11 = require("os");
13195
- import_node_path34 = require("path");
13196
- import_smol_toml2 = require("smol-toml");
13197
- init_user_mcp_config();
13270
+ }
13271
+ return null;
13272
+ }
13273
+ if (obj.type === "result") {
13274
+ const events = [];
13275
+ const errorDetail = claudeResultErrorDetail(obj);
13276
+ if (errorDetail) {
13277
+ events.push({ type: "stderr", data: errorDetail });
13278
+ } else {
13279
+ const text7 = obj.result;
13280
+ if (typeof text7 === "string" && text7) events.push({ type: "stdout", data: text7 });
13281
+ }
13282
+ const usage = usageFromClaude(obj.usage);
13283
+ if (usage) {
13284
+ const costUsd = costUsdFromClaudeResult(obj);
13285
+ if (costUsd != null) usage.costUsd = costUsd;
13286
+ events.push({ type: "usage", data: usage, scope: "turn" });
13287
+ }
13288
+ if (events.length === 0) return null;
13289
+ return events.length === 1 ? events[0] : events;
13290
+ }
13291
+ return null;
13292
+ } catch {
13293
+ return { type: "stdout", data: line };
13294
+ }
13295
+ },
13296
+ async resolveSessionId(_worktreePath, cached) {
13297
+ return cached;
13298
+ },
13299
+ async buildAttach(thread) {
13300
+ const claude = resolveClaudeExecutable();
13301
+ const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
13302
+ const args = sessionId ? ["--resume", sessionId] : [];
13303
+ if (claudeChromeEnabled()) {
13304
+ args.push("--chrome");
13305
+ }
13306
+ return { file: claude, args, cwd: thread.worktreePath };
13307
+ },
13308
+ async listLinearIssues(_repoPath) {
13309
+ const claude = resolveClaudeExecutable();
13310
+ const prompt = "List my assigned Linear issues as JSON array only, no markdown. Each item: id, identifier, title, url, labels (string[]).";
13311
+ const { stdout, exitCode } = await run(
13312
+ claude,
13313
+ [
13314
+ "-p",
13315
+ prompt,
13316
+ "--output-format",
13317
+ "json",
13318
+ "--permission-mode",
13319
+ "bypassPermissions",
13320
+ "--allowedTools",
13321
+ "mcp__linear__*"
13322
+ ],
13323
+ { reject: false }
13324
+ );
13325
+ if (exitCode !== 0) return [];
13326
+ return parseIssuesJson(stdout);
13327
+ }
13328
+ };
13198
13329
  }
13199
13330
  });
13200
13331
 
@@ -13208,7 +13339,7 @@ async function listCodexModels() {
13208
13339
  if (codex === "codex") {
13209
13340
  const which = await run("which", ["codex"], { reject: false });
13210
13341
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
13211
- } else if (!(0, import_node_fs33.existsSync)(codex)) {
13342
+ } else if (!(0, import_node_fs34.existsSync)(codex)) {
13212
13343
  return FALLBACK_CODEX_MODELS;
13213
13344
  }
13214
13345
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -13243,12 +13374,12 @@ function usageFromCodex(usage) {
13243
13374
  }
13244
13375
  function codexConfigHasNetworkAccess() {
13245
13376
  const candidates = [
13246
- (0, import_node_path35.join)((0, import_node_os12.homedir)(), ".codex", "config.toml"),
13247
- (0, import_node_path35.join)((0, import_node_os12.homedir)(), ".config", "codex", "config.toml")
13377
+ (0, import_node_path36.join)((0, import_node_os12.homedir)(), ".codex", "config.toml"),
13378
+ (0, import_node_path36.join)((0, import_node_os12.homedir)(), ".config", "codex", "config.toml")
13248
13379
  ];
13249
13380
  for (const path2 of candidates) {
13250
- if (!(0, import_node_fs33.existsSync)(path2)) continue;
13251
- const text7 = (0, import_node_fs33.readFileSync)(path2, "utf8");
13381
+ if (!(0, import_node_fs34.existsSync)(path2)) continue;
13382
+ const text7 = (0, import_node_fs34.readFileSync)(path2, "utf8");
13252
13383
  if (/network_access\s*=\s*true/.test(text7)) return true;
13253
13384
  }
13254
13385
  return false;
@@ -13280,21 +13411,21 @@ function asRecord2(value) {
13280
13411
  return void 0;
13281
13412
  }
13282
13413
  function codexLooksAuthenticated() {
13283
- const authPath = (0, import_node_path35.join)((0, import_node_os12.homedir)(), ".codex", "auth.json");
13284
- if (!(0, import_node_fs33.existsSync)(authPath)) return false;
13414
+ const authPath = (0, import_node_path36.join)((0, import_node_os12.homedir)(), ".codex", "auth.json");
13415
+ if (!(0, import_node_fs34.existsSync)(authPath)) return false;
13285
13416
  try {
13286
- return (0, import_node_fs33.statSync)(authPath).size > 2;
13417
+ return (0, import_node_fs34.statSync)(authPath).size > 2;
13287
13418
  } catch {
13288
13419
  return false;
13289
13420
  }
13290
13421
  }
13291
- var import_node_fs33, import_node_os12, import_node_path35, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
13422
+ var import_node_fs34, import_node_os12, import_node_path36, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
13292
13423
  var init_codex = __esm({
13293
13424
  "src/agents/codex.ts"() {
13294
13425
  "use strict";
13295
- import_node_fs33 = require("fs");
13426
+ import_node_fs34 = require("fs");
13296
13427
  import_node_os12 = require("os");
13297
- import_node_path35 = require("path");
13428
+ import_node_path36 = require("path");
13298
13429
  init_run();
13299
13430
  init_app_settings();
13300
13431
  init_global_workspace();
@@ -13320,7 +13451,7 @@ var init_codex = __esm({
13320
13451
  async detect() {
13321
13452
  const codex = resolveAgentExecutable("codex");
13322
13453
  if (codex !== "codex") {
13323
- if (!(0, import_node_fs33.existsSync)(codex)) {
13454
+ if (!(0, import_node_fs34.existsSync)(codex)) {
13324
13455
  return {
13325
13456
  agent: "codex",
13326
13457
  installed: false,
@@ -13820,21 +13951,21 @@ function platformRipgrepPackage() {
13820
13951
  }
13821
13952
  function usableRipgrepPath(candidate) {
13822
13953
  const raw = candidate?.trim();
13823
- if (!raw || !(0, import_node_path36.isAbsolute)(raw)) return null;
13954
+ if (!raw || !(0, import_node_path37.isAbsolute)(raw)) return null;
13824
13955
  const readable = nodeReadableScriptPath(raw);
13825
- if (!(0, import_node_fs34.existsSync)(readable) || isAsarPath(readable)) return null;
13956
+ if (!(0, import_node_fs35.existsSync)(readable) || isAsarPath(readable)) return null;
13826
13957
  return readable;
13827
13958
  }
13828
13959
  function walkForBundledRipgrep(startFile) {
13829
13960
  if (!startFile) return null;
13830
13961
  const pkg = platformRipgrepPackage();
13831
13962
  const name = rgBinaryName();
13832
- let dir = (0, import_node_path36.dirname)((0, import_node_path36.resolve)(startFile));
13833
- const root = (0, import_node_path36.parse)(dir).root;
13963
+ let dir = (0, import_node_path37.dirname)((0, import_node_path37.resolve)(startFile));
13964
+ const root = (0, import_node_path37.parse)(dir).root;
13834
13965
  while (dir !== root) {
13835
- const hit = usableRipgrepPath((0, import_node_path36.join)(dir, "node_modules", pkg, "bin", name));
13966
+ const hit = usableRipgrepPath((0, import_node_path37.join)(dir, "node_modules", pkg, "bin", name));
13836
13967
  if (hit) return hit;
13837
- const next = (0, import_node_path36.dirname)(dir);
13968
+ const next = (0, import_node_path37.dirname)(dir);
13838
13969
  if (next === dir) break;
13839
13970
  dir = next;
13840
13971
  }
@@ -13844,7 +13975,7 @@ function requireResolveBundledRipgrep(fromFile) {
13844
13975
  try {
13845
13976
  const req = (0, import_node_module2.createRequire)(fromFile);
13846
13977
  const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
13847
- return usableRipgrepPath((0, import_node_path36.join)((0, import_node_path36.dirname)(pkgJson), "bin", rgBinaryName()));
13978
+ return usableRipgrepPath((0, import_node_path37.join)((0, import_node_path37.dirname)(pkgJson), "bin", rgBinaryName()));
13848
13979
  } catch {
13849
13980
  return null;
13850
13981
  }
@@ -13866,13 +13997,13 @@ function cursorRipgrepEnv(opts) {
13866
13997
  const path2 = resolveCursorRipgrepPath(opts);
13867
13998
  return path2 ? { [RIPGREP_ENV]: path2 } : {};
13868
13999
  }
13869
- var import_node_fs34, import_node_module2, import_node_path36, RIPGREP_ENV;
14000
+ var import_node_fs35, import_node_module2, import_node_path37, RIPGREP_ENV;
13870
14001
  var init_cursor_ripgrep = __esm({
13871
14002
  "src/agents/cursor-ripgrep.ts"() {
13872
14003
  "use strict";
13873
- import_node_fs34 = require("fs");
14004
+ import_node_fs35 = require("fs");
13874
14005
  import_node_module2 = require("module");
13875
- import_node_path36 = require("path");
14006
+ import_node_path37 = require("path");
13876
14007
  init_node_launch();
13877
14008
  init_packaged_runtime();
13878
14009
  RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
@@ -13921,11 +14052,11 @@ function entryDir() {
13921
14052
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
13922
14053
  if (cjsDir) return cjsDir;
13923
14054
  try {
13924
- return (0, import_node_path37.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
14055
+ return (0, import_node_path38.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
13925
14056
  } catch {
13926
14057
  try {
13927
14058
  const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
13928
- return (0, import_node_path37.dirname)(req.resolve("@sideboard-ai/core"));
14059
+ return (0, import_node_path38.dirname)(req.resolve("@sideboard-ai/core"));
13929
14060
  } catch {
13930
14061
  return process.cwd();
13931
14062
  }
@@ -13936,27 +14067,27 @@ function cursorRunnerPath() {
13936
14067
  if (packaged) return packaged;
13937
14068
  const root = entryDir();
13938
14069
  const candidates = [
13939
- (0, import_node_path37.join)(root, "agents", "cursor-runner.js"),
13940
- (0, import_node_path37.join)(root, "agents", "cursor-runner.cjs"),
14070
+ (0, import_node_path38.join)(root, "agents", "cursor-runner.js"),
14071
+ (0, import_node_path38.join)(root, "agents", "cursor-runner.cjs"),
13941
14072
  // If somehow resolved from package root instead of dist/
13942
- (0, import_node_path37.join)(root, "dist", "agents", "cursor-runner.js"),
13943
- (0, import_node_path37.join)(root, "dist", "agents", "cursor-runner.cjs"),
14073
+ (0, import_node_path38.join)(root, "dist", "agents", "cursor-runner.js"),
14074
+ (0, import_node_path38.join)(root, "dist", "agents", "cursor-runner.cjs"),
13944
14075
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
13945
- (0, import_node_path37.join)(root, "cursor-runner.ts"),
13946
- (0, import_node_path37.join)(root, "src", "agents", "cursor-runner.ts")
14076
+ (0, import_node_path38.join)(root, "cursor-runner.ts"),
14077
+ (0, import_node_path38.join)(root, "src", "agents", "cursor-runner.ts")
13947
14078
  ];
13948
14079
  for (const candidate of candidates) {
13949
- if ((0, import_node_fs35.existsSync)(candidate)) return candidate;
14080
+ if ((0, import_node_fs36.existsSync)(candidate)) return candidate;
13950
14081
  }
13951
14082
  return candidates[0];
13952
14083
  }
13953
- var import_node_fs35, import_node_module3, import_node_path37, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
14084
+ var import_node_fs36, import_node_module3, import_node_path38, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
13954
14085
  var init_cursor = __esm({
13955
14086
  "src/agents/cursor.ts"() {
13956
14087
  "use strict";
13957
- import_node_fs35 = require("fs");
14088
+ import_node_fs36 = require("fs");
13958
14089
  import_node_module3 = require("module");
13959
- import_node_path37 = require("path");
14090
+ import_node_path38 = require("path");
13960
14091
  import_node_url2 = require("url");
13961
14092
  import_sdk = require("@cursor/sdk");
13962
14093
  init_run();
@@ -14108,7 +14239,7 @@ async function listOpencodeModels() {
14108
14239
  if (opencode === "opencode") {
14109
14240
  const which = await run("which", ["opencode"], { reject: false });
14110
14241
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
14111
- } else if (!(0, import_node_fs36.existsSync)(opencode)) {
14242
+ } else if (!(0, import_node_fs37.existsSync)(opencode)) {
14112
14243
  return FALLBACK_OPENCODE_MODELS;
14113
14244
  }
14114
14245
  const listed = await run(opencode, ["models"], { reject: false });
@@ -14138,11 +14269,11 @@ function usageFromOpencode(tokens) {
14138
14269
  cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
14139
14270
  };
14140
14271
  }
14141
- var import_node_fs36, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
14272
+ var import_node_fs37, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
14142
14273
  var init_opencode = __esm({
14143
14274
  "src/agents/opencode.ts"() {
14144
14275
  "use strict";
14145
- import_node_fs36 = require("fs");
14276
+ import_node_fs37 = require("fs");
14146
14277
  init_run();
14147
14278
  init_app_settings();
14148
14279
  init_global_workspace();
@@ -14170,7 +14301,7 @@ var init_opencode = __esm({
14170
14301
  async detect() {
14171
14302
  const opencode = resolveAgentExecutable("opencode");
14172
14303
  if (opencode !== "opencode") {
14173
- if (!(0, import_node_fs36.existsSync)(opencode)) {
14304
+ if (!(0, import_node_fs37.existsSync)(opencode)) {
14174
14305
  return {
14175
14306
  agent: "opencode",
14176
14307
  installed: false,
@@ -14889,14 +15020,14 @@ function accessTokenFromCredentialsJson(raw) {
14889
15020
  }
14890
15021
  }
14891
15022
  function claudeCredentialsPath() {
14892
- const root = process.env.CLAUDE_CONFIG_DIR?.trim() || (0, import_node_path38.join)((0, import_node_os13.homedir)(), ".claude");
14893
- return (0, import_node_path38.join)(root, ".credentials.json");
15023
+ const root = process.env.CLAUDE_CONFIG_DIR?.trim() || (0, import_node_path39.join)((0, import_node_os13.homedir)(), ".claude");
15024
+ return (0, import_node_path39.join)(root, ".credentials.json");
14894
15025
  }
14895
15026
  async function readFileAccessToken() {
14896
15027
  const path2 = claudeCredentialsPath();
14897
- if (!(0, import_node_fs37.existsSync)(path2)) return null;
15028
+ if (!(0, import_node_fs38.existsSync)(path2)) return null;
14898
15029
  try {
14899
- return accessTokenFromCredentialsJson((0, import_node_fs37.readFileSync)(path2, "utf8"));
15030
+ return accessTokenFromCredentialsJson((0, import_node_fs38.readFileSync)(path2, "utf8"));
14900
15031
  } catch {
14901
15032
  return null;
14902
15033
  }
@@ -15000,13 +15131,13 @@ async function getClaudePlanUsage(opts = {}) {
15000
15131
  })();
15001
15132
  return inflight;
15002
15133
  }
15003
- var import_node_fs37, import_node_os13, import_node_path38, CLAUDE_OAUTH_USAGE_URL, CLAUDE_USAGE_TTL_MS, CLAUDE_USAGE_ERROR_TTL_MS, CLAUDE_USAGE_STALE_OK_MS, KEYCHAIN_SERVICES, cache, errorUntil, inflight, lastGood, claudeVersion;
15134
+ var import_node_fs38, import_node_os13, import_node_path39, CLAUDE_OAUTH_USAGE_URL, CLAUDE_USAGE_TTL_MS, CLAUDE_USAGE_ERROR_TTL_MS, CLAUDE_USAGE_STALE_OK_MS, KEYCHAIN_SERVICES, cache, errorUntil, inflight, lastGood, claudeVersion;
15004
15135
  var init_claude_usage_client = __esm({
15005
15136
  "src/agents/claude-usage-client.ts"() {
15006
15137
  "use strict";
15007
- import_node_fs37 = require("fs");
15138
+ import_node_fs38 = require("fs");
15008
15139
  import_node_os13 = require("os");
15009
- import_node_path38 = require("path");
15140
+ import_node_path39 = require("path");
15010
15141
  init_run();
15011
15142
  init_fetch();
15012
15143
  init_app_settings();
@@ -15367,17 +15498,79 @@ var init_agents = __esm({
15367
15498
  }
15368
15499
  });
15369
15500
 
15501
+ // src/hook/agent-host-env.ts
15502
+ function isAgentHostEnvKey(key) {
15503
+ if (DROP_EXACT.has(key)) return true;
15504
+ return DROP_PREFIXES.some((prefix) => key.startsWith(prefix));
15505
+ }
15506
+ function stripHostToolingPath(pathValue) {
15507
+ if (!pathValue?.trim()) return "";
15508
+ return pathValue.split(import_node_path40.delimiter).filter((part) => part && !HOST_PATH_NOISE.test(part.replace(/\\/g, "/"))).join(import_node_path40.delimiter);
15509
+ }
15510
+ function sanitizeAgentHostEnv(env, cwd) {
15511
+ for (const key of Object.keys(env)) {
15512
+ if (isAgentHostEnvKey(key)) delete env[key];
15513
+ }
15514
+ env.PATH = stripHostToolingPath(env.PATH);
15515
+ const worktree = cwd?.trim();
15516
+ if (worktree) {
15517
+ env.PWD = worktree;
15518
+ env.INIT_CWD = worktree;
15519
+ }
15520
+ return env;
15521
+ }
15522
+ var import_node_path40, DROP_EXACT, DROP_PREFIXES, HOST_PATH_NOISE;
15523
+ var init_agent_host_env = __esm({
15524
+ "src/hook/agent-host-env.ts"() {
15525
+ "use strict";
15526
+ import_node_path40 = require("path");
15527
+ DROP_EXACT = /* @__PURE__ */ new Set([
15528
+ "NODE_PATH",
15529
+ "NODE_ENV_ELECTRON_VITE",
15530
+ "INIT_CWD",
15531
+ "npm_command",
15532
+ "npm_execpath",
15533
+ "npm_node_execpath",
15534
+ "npm_lifecycle_event",
15535
+ "npm_lifecycle_script",
15536
+ "PNPM_SCRIPT_SRC_DIR",
15537
+ "PNPM_STORE_DIR",
15538
+ "PORT",
15539
+ "SIDEBOARD_ROOT_PATH",
15540
+ "SIDEBOARD_IS_LOCAL",
15541
+ "SIDEBOARD_WORKSPACE_PATH",
15542
+ "SIDEBOARD_WORKSPACE_NAME",
15543
+ "SIDEBOARD_PORT",
15544
+ "CONDUCTOR_ROOT_PATH",
15545
+ "CONDUCTOR_IS_LOCAL",
15546
+ "CONDUCTOR_WORKSPACE_PATH",
15547
+ "CONDUCTOR_WORKSPACE_NAME",
15548
+ "CONDUCTOR_PORT",
15549
+ "CONDUCTOR_DEFAULT_BRANCH",
15550
+ "SIDEBOARD_DEFAULT_BRANCH"
15551
+ ]);
15552
+ DROP_PREFIXES = [
15553
+ "npm_package_",
15554
+ "npm_config_",
15555
+ "PNPM_",
15556
+ "SIDEBOARD_PORT_",
15557
+ "CONDUCTOR_PORT_"
15558
+ ];
15559
+ HOST_PATH_NOISE = /(?:^|\/)node_modules\/\.bin(?:\/|$)|node-gyp-bin|electron-vite/i;
15560
+ }
15561
+ });
15562
+
15370
15563
  // src/hook/worktree-pkg-cache.ts
15371
15564
  function worktreePkgCacheRoot(worktreePath) {
15372
- return (0, import_node_path39.join)(worktreePath, WORKTREE_PKG_CACHE_REL);
15565
+ return (0, import_node_path41.join)(worktreePath, WORKTREE_PKG_CACHE_REL);
15373
15566
  }
15374
15567
  function worktreePkgCacheEnv(worktreePath) {
15375
15568
  const root = worktreePkgCacheRoot(worktreePath);
15376
- const store = (0, import_node_path39.join)(root, "pnpm-store");
15377
- const pnpmCache = (0, import_node_path39.join)(root, "pnpm");
15378
- const npmCache = (0, import_node_path39.join)(root, "npm");
15379
- const nodeGyp = (0, import_node_path39.join)(root, "node-gyp");
15380
- const electron = (0, import_node_path39.join)(root, "electron");
15569
+ const store = (0, import_node_path41.join)(root, "pnpm-store");
15570
+ const pnpmCache = (0, import_node_path41.join)(root, "pnpm");
15571
+ const npmCache = (0, import_node_path41.join)(root, "npm");
15572
+ const nodeGyp = (0, import_node_path41.join)(root, "node-gyp");
15573
+ const electron = (0, import_node_path41.join)(root, "electron");
15381
15574
  return {
15382
15575
  npm_config_store_dir: store,
15383
15576
  PNPM_STORE_DIR: store,
@@ -15399,8 +15592,8 @@ function fillGroup(env, keys, values) {
15399
15592
  }
15400
15593
  }
15401
15594
  function ensureWorktreePkgCacheDirs(worktreePath) {
15402
- if (!(0, import_node_fs38.existsSync)(worktreePath)) return;
15403
- (0, import_node_fs38.mkdirSync)(worktreePkgCacheRoot(worktreePath), { recursive: true });
15595
+ if (!(0, import_node_fs39.existsSync)(worktreePath)) return;
15596
+ (0, import_node_fs39.mkdirSync)(worktreePkgCacheRoot(worktreePath), { recursive: true });
15404
15597
  }
15405
15598
  function applyWorktreePkgCacheEnv(env, worktreePath) {
15406
15599
  const cwd = worktreePath.trim();
@@ -15413,12 +15606,12 @@ function applyWorktreePkgCacheEnv(env, worktreePath) {
15413
15606
  fillGroup(env, ["electron_config_cache"], next);
15414
15607
  ensureWorktreePkgCacheDirs(cwd);
15415
15608
  }
15416
- var import_node_fs38, import_node_path39, WORKTREE_PKG_CACHE_REL;
15609
+ var import_node_fs39, import_node_path41, WORKTREE_PKG_CACHE_REL;
15417
15610
  var init_worktree_pkg_cache = __esm({
15418
15611
  "src/hook/worktree-pkg-cache.ts"() {
15419
15612
  "use strict";
15420
- import_node_fs38 = require("fs");
15421
- import_node_path39 = require("path");
15613
+ import_node_fs39 = require("fs");
15614
+ import_node_path41 = require("path");
15422
15615
  WORKTREE_PKG_CACHE_REL = ".context/.sideboard/pkg-cache";
15423
15616
  }
15424
15617
  });
@@ -15516,26 +15709,54 @@ async function spawnAgentTurn(thread, input, onEvent) {
15516
15709
  assertOrchestratorCapableAgent(thread.agent);
15517
15710
  }
15518
15711
  const adapter = getAdapter(thread.agent);
15519
- const cmd = await adapter.buildTurn(thread, input);
15712
+ const orch = isOrchestratorThread(thread);
15713
+ traceTurn("spawn.buildTurn.start", {
15714
+ threadId: thread.id,
15715
+ agent: thread.agent,
15716
+ orch,
15717
+ cwd: thread.worktreePath
15718
+ });
15719
+ const cmd = await withTimeout(
15720
+ adapter.buildTurn(thread, input),
15721
+ 2e4,
15722
+ "buildTurn"
15723
+ );
15724
+ traceTurn("spawn.buildTurn.done", { file: cmd.file, cwd: cmd.cwd });
15520
15725
  if (cmd.cwd !== thread.worktreePath) {
15521
15726
  throw new Error(
15522
15727
  `Agent cwd must be the thread worktree (got ${cmd.cwd}, expected ${thread.worktreePath})`
15523
15728
  );
15524
15729
  }
15525
15730
  const env = childEnvWithAppSettings(cmd.env);
15731
+ sanitizeAgentHostEnv(env, cmd.cwd);
15732
+ ensureAgentPath(env);
15526
15733
  applyPromptCacheTtlEnv(thread.agent, env);
15527
15734
  applyAgentRunnerHeapEnv(env);
15528
- if (!isOrchestratorThread(thread)) {
15735
+ if (!orch) {
15529
15736
  applyWorktreePkgCacheEnv(env, thread.worktreePath);
15530
15737
  }
15531
15738
  try {
15532
- if (isOrchestratorThread(thread)) {
15533
- mergeAgentGitAuthEnv(env, await resolveAgentGitAuthEnv(env));
15534
- } else {
15535
- mergeAgentGitAuthEnv(env, await originGhRepoEnv(thread.worktreePath, { env }));
15739
+ traceTurn("spawn.gitAuth.start");
15740
+ mergeAgentGitAuthEnv(
15741
+ env,
15742
+ await withTimeout(
15743
+ resolveAgentGitAuthEnv(env, { cwd: thread.worktreePath }),
15744
+ 8e3,
15745
+ "gitAuth"
15746
+ )
15747
+ );
15748
+ if (!orch) {
15749
+ const slug = await withTimeout(
15750
+ resolveGithubRepoSlug(thread.worktreePath),
15751
+ 8e3,
15752
+ "resolveGithubRepoSlug"
15753
+ );
15754
+ if (slug) env.GH_REPO = slug;
15536
15755
  }
15756
+ traceTurn("spawn.gitAuth.done", { ghRepo: env.GH_REPO ?? null });
15537
15757
  } catch (err) {
15538
15758
  const detail = err instanceof Error ? err.message : String(err);
15759
+ traceTurn("spawn.gitAuth.fail", { detail });
15539
15760
  console.warn(`[sideboard] git auth env failed (${thread.worktreePath}): ${detail}`);
15540
15761
  }
15541
15762
  const child = (0, import_execa3.execa)(cmd.file, cmd.args, {
@@ -15548,6 +15769,7 @@ async function spawnAgentTurn(thread, input, onEvent) {
15548
15769
  // so Claude doesn't wait ~3s for an empty pipe.
15549
15770
  stdin: cmd.stdin != null ? "pipe" : "ignore"
15550
15771
  });
15772
+ traceTurn("spawn.execa", { pid: child.pid ?? null, file: cmd.file });
15551
15773
  if (cmd.stdin != null && child.stdin) {
15552
15774
  child.stdin.write(cmd.stdin);
15553
15775
  child.stdin.end();
@@ -15631,10 +15853,12 @@ var init_spawn = __esm({
15631
15853
  init_git_auth_mode();
15632
15854
  init_app_settings();
15633
15855
  init_global_workspace();
15856
+ init_turn_trace();
15634
15857
  init_brightsy();
15635
15858
  init_agents();
15636
15859
  init_orchestrator_capable();
15637
15860
  init_message_parts();
15861
+ init_agent_host_env();
15638
15862
  init_worktree_pkg_cache();
15639
15863
  init_node_launch();
15640
15864
  init_path();
@@ -16622,21 +16846,21 @@ function shouldRefreshReviewRequestTemplate(content) {
16622
16846
  return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
16623
16847
  }
16624
16848
  function readTextIfPresent(abs) {
16625
- if (!(0, import_node_fs39.existsSync)(abs)) return null;
16849
+ if (!(0, import_node_fs40.existsSync)(abs)) return null;
16626
16850
  try {
16627
- const content = (0, import_node_fs39.readFileSync)(abs, "utf8");
16851
+ const content = (0, import_node_fs40.readFileSync)(abs, "utf8");
16628
16852
  return content.trim() ? content : null;
16629
16853
  } catch {
16630
16854
  return null;
16631
16855
  }
16632
16856
  }
16633
16857
  function readLocalGuidelines(worktreePath) {
16634
- const localAbs = (0, import_node_path40.join)(worktreePath, REVIEW_REQUEST_PATH);
16858
+ const localAbs = (0, import_node_path42.join)(worktreePath, REVIEW_REQUEST_PATH);
16635
16859
  const localContent = readTextIfPresent(localAbs);
16636
16860
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
16637
16861
  return { path: REVIEW_REQUEST_PATH, content: localContent };
16638
16862
  }
16639
- const legacyAbs = (0, import_node_path40.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
16863
+ const legacyAbs = (0, import_node_path42.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
16640
16864
  const legacyContent = readTextIfPresent(legacyAbs);
16641
16865
  if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
16642
16866
  return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
@@ -16660,27 +16884,27 @@ function contextGuidelines(content, source) {
16660
16884
  };
16661
16885
  }
16662
16886
  function writeContextGuidelines(worktreePath, content) {
16663
- const abs = (0, import_node_path40.join)(worktreePath, CONTEXT_REVIEW_PATH);
16664
- (0, import_node_fs39.mkdirSync)((0, import_node_path40.dirname)(abs), { recursive: true });
16887
+ const abs = (0, import_node_path42.join)(worktreePath, CONTEXT_REVIEW_PATH);
16888
+ (0, import_node_fs40.mkdirSync)((0, import_node_path42.dirname)(abs), { recursive: true });
16665
16889
  const body = content.endsWith("\n") ? content : `${content}
16666
16890
  `;
16667
- (0, import_node_fs39.writeFileSync)(abs, body, "utf8");
16891
+ (0, import_node_fs40.writeFileSync)(abs, body, "utf8");
16668
16892
  return body;
16669
16893
  }
16670
16894
  function readSideboardReview(worktreePath, repoPath) {
16671
- const fromWorktree = readTextIfPresent((0, import_node_path40.join)(worktreePath, REPO_REVIEW_PATH));
16895
+ const fromWorktree = readTextIfPresent((0, import_node_path42.join)(worktreePath, REPO_REVIEW_PATH));
16672
16896
  if (fromWorktree) return fromWorktree;
16673
16897
  const repo = repoPath?.replace(/\/+$/, "");
16674
16898
  const wt = worktreePath.replace(/\/+$/, "");
16675
16899
  if (!repo || repo === wt) return null;
16676
- return readTextIfPresent((0, import_node_path40.join)(repo, REPO_REVIEW_PATH));
16900
+ return readTextIfPresent((0, import_node_path42.join)(repo, REPO_REVIEW_PATH));
16677
16901
  }
16678
16902
  function ensureReviewGuidelinesFile(worktreePath, repoPath) {
16679
- const skillContent = readTextIfPresent((0, import_node_path40.join)(worktreePath, REVIEW_SKILL_PATH));
16903
+ const skillContent = readTextIfPresent((0, import_node_path42.join)(worktreePath, REVIEW_SKILL_PATH));
16680
16904
  if (skillContent) {
16681
16905
  return { ...skillGuidelines(skillContent, "skill"), wrote: false };
16682
16906
  }
16683
- const contextContent = readTextIfPresent((0, import_node_path40.join)(worktreePath, CONTEXT_REVIEW_PATH));
16907
+ const contextContent = readTextIfPresent((0, import_node_path42.join)(worktreePath, CONTEXT_REVIEW_PATH));
16684
16908
  if (contextContent && !shouldRefreshReviewRequestTemplate(contextContent)) {
16685
16909
  return { ...contextGuidelines(contextContent, "local"), wrote: false };
16686
16910
  }
@@ -16718,7 +16942,7 @@ function buildReviewRequestAttachment(content, opts) {
16718
16942
  };
16719
16943
  }
16720
16944
  function readExistingReviewRequestFile(worktreePath) {
16721
- return readTextIfPresent((0, import_node_path40.join)(worktreePath, REVIEW_SKILL_PATH)) ?? readTextIfPresent((0, import_node_path40.join)(worktreePath, CONTEXT_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path40.join)(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path40.join)(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent((0, import_node_path40.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
16945
+ return readTextIfPresent((0, import_node_path42.join)(worktreePath, REVIEW_SKILL_PATH)) ?? readTextIfPresent((0, import_node_path42.join)(worktreePath, CONTEXT_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path42.join)(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path42.join)(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent((0, import_node_path42.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
16722
16946
  }
16723
16947
  async function requestReview(threadRef, send2) {
16724
16948
  const from = findThreadByRef(threadRef);
@@ -16745,13 +16969,13 @@ async function requestReview(threadRef, send2) {
16745
16969
  const started = await send2(tab.id, REVIEW_REQUEST_PREFILL);
16746
16970
  return { tab: started, from };
16747
16971
  }
16748
- var import_node_crypto9, import_node_fs39, import_node_path40, REPO_REVIEW_PATH, REPO_REVIEW_NAME, CONTEXT_REVIEW_PATH, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
16972
+ var import_node_crypto9, import_node_fs40, import_node_path42, REPO_REVIEW_PATH, REPO_REVIEW_NAME, CONTEXT_REVIEW_PATH, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
16749
16973
  var init_request_review = __esm({
16750
16974
  "src/review/request-review.ts"() {
16751
16975
  "use strict";
16752
16976
  import_node_crypto9 = require("crypto");
16753
- import_node_fs39 = require("fs");
16754
- import_node_path40 = require("path");
16977
+ import_node_fs40 = require("fs");
16978
+ import_node_path42 = require("path");
16755
16979
  init_global_workspace();
16756
16980
  init_chat_tabs();
16757
16981
  init_thread_store();
@@ -16777,9 +17001,9 @@ function matchSimpleGlob(pattern, name) {
16777
17001
  return new RegExp(`^${escaped}$`).test(name);
16778
17002
  }
16779
17003
  function readWorktreeInclude(repoPath) {
16780
- const path2 = (0, import_node_path41.join)(repoPath, ".worktreeinclude");
16781
- if (!(0, import_node_fs40.existsSync)(path2)) return [];
16782
- return (0, import_node_fs40.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
17004
+ const path2 = (0, import_node_path43.join)(repoPath, ".worktreeinclude");
17005
+ if (!(0, import_node_fs41.existsSync)(path2)) return [];
17006
+ return (0, import_node_fs41.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
16783
17007
  }
16784
17008
  function resolveFilesToCopy(repoPath) {
16785
17009
  const fromInclude = readWorktreeInclude(repoPath);
@@ -16789,10 +17013,10 @@ function resolveFilesToCopy(repoPath) {
16789
17013
  if (settings?.fileIncludeGlobs?.length) {
16790
17014
  const matched = [];
16791
17015
  try {
16792
- for (const entry of (0, import_node_fs40.readdirSync)(repoPath, { withFileTypes: true })) {
17016
+ for (const entry of (0, import_node_fs41.readdirSync)(repoPath, { withFileTypes: true })) {
16793
17017
  if (!entry.isFile()) continue;
16794
17018
  for (const glob of settings.fileIncludeGlobs) {
16795
- if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path41.basename)(glob), entry.name)) {
17019
+ if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path43.basename)(glob), entry.name)) {
16796
17020
  matched.push(entry.name);
16797
17021
  break;
16798
17022
  }
@@ -16804,7 +17028,7 @@ function resolveFilesToCopy(repoPath) {
16804
17028
  }
16805
17029
  const defaults = [];
16806
17030
  try {
16807
- for (const entry of (0, import_node_fs40.readdirSync)(repoPath, { withFileTypes: true })) {
17031
+ for (const entry of (0, import_node_fs41.readdirSync)(repoPath, { withFileTypes: true })) {
16808
17032
  if (entry.isFile() && entry.name.startsWith(".env")) {
16809
17033
  defaults.push(entry.name);
16810
17034
  }
@@ -16818,11 +17042,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
16818
17042
  const patterns = resolveFilesToCopy(repoPath);
16819
17043
  const copied = [];
16820
17044
  for (const rel of patterns) {
16821
- const src = (0, import_node_path41.join)(repoPath, rel);
16822
- if (!(0, import_node_fs40.existsSync)(src)) continue;
16823
- const dest = (0, import_node_path41.join)(worktreePath, rel);
16824
- (0, import_node_fs40.mkdirSync)((0, import_node_path41.dirname)(dest), { recursive: true });
16825
- (0, import_node_fs40.copyFileSync)(src, dest);
17045
+ const src = (0, import_node_path43.join)(repoPath, rel);
17046
+ if (!(0, import_node_fs41.existsSync)(src)) continue;
17047
+ const dest = (0, import_node_path43.join)(worktreePath, rel);
17048
+ (0, import_node_fs41.mkdirSync)((0, import_node_path43.dirname)(dest), { recursive: true });
17049
+ (0, import_node_fs41.copyFileSync)(src, dest);
16826
17050
  copied.push(rel);
16827
17051
  }
16828
17052
  return copied;
@@ -16857,7 +17081,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
16857
17081
  const env = stripNestedElectronEnv({
16858
17082
  ...baseEnv ?? process.env
16859
17083
  });
16860
- const name = opts.workspaceName ?? (0, import_node_path41.basename)(opts.worktreePath);
17084
+ const name = opts.workspaceName ?? (0, import_node_path43.basename)(opts.worktreePath);
16861
17085
  const ports = opts.ports ?? [];
16862
17086
  const primary = ports[0];
16863
17087
  env.SIDEBOARD_WORKSPACE_NAME = name;
@@ -17120,13 +17344,13 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
17120
17344
  done: handle.done
17121
17345
  };
17122
17346
  }
17123
- var import_node_fs40, import_node_net, import_node_path41, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
17347
+ var import_node_fs41, import_node_net, import_node_path43, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
17124
17348
  var init_conductor = __esm({
17125
17349
  "src/hook/conductor.ts"() {
17126
17350
  "use strict";
17127
- import_node_fs40 = require("fs");
17351
+ import_node_fs41 = require("fs");
17128
17352
  import_node_net = require("net");
17129
- import_node_path41 = require("path");
17353
+ import_node_path43 = require("path");
17130
17354
  import_execa4 = require("execa");
17131
17355
  import_node_readline3 = require("readline");
17132
17356
  init_settings();
@@ -17154,9 +17378,9 @@ async function findOrphanWorktrees(repoPaths) {
17154
17378
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
17155
17379
  );
17156
17380
  const homeRoot = sideboardWorkspacesDir();
17157
- if ((0, import_node_fs41.existsSync)(homeRoot)) {
17381
+ if ((0, import_node_fs42.existsSync)(homeRoot)) {
17158
17382
  try {
17159
- for (const entry of (0, import_node_fs41.readdirSync)(homeRoot, { withFileTypes: true })) {
17383
+ for (const entry of (0, import_node_fs42.readdirSync)(homeRoot, { withFileTypes: true })) {
17160
17384
  if (!entry.isDirectory()) continue;
17161
17385
  void entry;
17162
17386
  }
@@ -17166,7 +17390,7 @@ async function findOrphanWorktrees(repoPaths) {
17166
17390
  const orphans = [];
17167
17391
  const seen = /* @__PURE__ */ new Set();
17168
17392
  for (const repoPath of repos) {
17169
- if (!repoPath || !(0, import_node_fs41.existsSync)(repoPath)) continue;
17393
+ if (!repoPath || !(0, import_node_fs42.existsSync)(repoPath)) continue;
17170
17394
  try {
17171
17395
  const wts = await listWorktrees(repoPath);
17172
17396
  for (const wt of wts) {
@@ -17177,7 +17401,7 @@ async function findOrphanWorktrees(repoPaths) {
17177
17401
  seen.add(path2);
17178
17402
  let mtimeMs = 0;
17179
17403
  try {
17180
- mtimeMs = (0, import_node_fs41.statSync)(path2).mtimeMs;
17404
+ mtimeMs = (0, import_node_fs42.statSync)(path2).mtimeMs;
17181
17405
  } catch {
17182
17406
  mtimeMs = 0;
17183
17407
  }
@@ -17187,16 +17411,16 @@ async function findOrphanWorktrees(repoPaths) {
17187
17411
  }
17188
17412
  try {
17189
17413
  const root = worktreesRoot(repoPath);
17190
- if ((0, import_node_fs41.existsSync)(root)) {
17191
- for (const entry of (0, import_node_fs41.readdirSync)(root, { withFileTypes: true })) {
17414
+ if ((0, import_node_fs42.existsSync)(root)) {
17415
+ for (const entry of (0, import_node_fs42.readdirSync)(root, { withFileTypes: true })) {
17192
17416
  if (!entry.isDirectory()) continue;
17193
- const path2 = (0, import_node_path42.join)(root, entry.name).replace(/\/$/, "");
17417
+ const path2 = (0, import_node_path44.join)(root, entry.name).replace(/\/$/, "");
17194
17418
  if (known.has(path2) || seen.has(path2)) continue;
17195
- if (!(0, import_node_fs41.existsSync)((0, import_node_path42.join)(path2, ".git"))) continue;
17419
+ if (!(0, import_node_fs42.existsSync)((0, import_node_path44.join)(path2, ".git"))) continue;
17196
17420
  seen.add(path2);
17197
17421
  let mtimeMs = 0;
17198
17422
  try {
17199
- mtimeMs = (0, import_node_fs41.statSync)(path2).mtimeMs;
17423
+ mtimeMs = (0, import_node_fs42.statSync)(path2).mtimeMs;
17200
17424
  } catch {
17201
17425
  mtimeMs = Date.now();
17202
17426
  }
@@ -17257,12 +17481,12 @@ function worktreeCleanupSettings() {
17257
17481
  autoCleanupOrphans: a.autoCleanupOrphans
17258
17482
  };
17259
17483
  }
17260
- var import_node_fs41, import_node_path42;
17484
+ var import_node_fs42, import_node_path44;
17261
17485
  var init_orphan_cleanup = __esm({
17262
17486
  "src/git/orphan-cleanup.ts"() {
17263
17487
  "use strict";
17264
- import_node_fs41 = require("fs");
17265
- import_node_path42 = require("path");
17488
+ import_node_fs42 = require("fs");
17489
+ import_node_path44 = require("path");
17266
17490
  init_worktree();
17267
17491
  init_thread_store();
17268
17492
  init_paths();
@@ -17437,12 +17661,12 @@ async function cloneRepoIntoSideboard(opts) {
17437
17661
  if (!url) throw new Error("Clone URL is required");
17438
17662
  let name = opts.name?.trim();
17439
17663
  if (!name) {
17440
- const leaf = (0, import_node_path43.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
17664
+ const leaf = (0, import_node_path45.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
17441
17665
  name = leaf || "repo";
17442
17666
  }
17443
17667
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
17444
- const dest = (0, import_node_path43.join)(sideboardReposDir(), name);
17445
- if ((0, import_node_fs42.existsSync)(dest)) {
17668
+ const dest = (0, import_node_path45.join)(sideboardReposDir(), name);
17669
+ if ((0, import_node_fs43.existsSync)(dest)) {
17446
17670
  const repoPath2 = await resolveRepoRoot(dest);
17447
17671
  const workspace2 = await ensureWorkspace(repoPath2);
17448
17672
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -17457,12 +17681,12 @@ async function cloneRepoIntoSideboard(opts) {
17457
17681
  const workspace = await ensureWorkspace(repoPath);
17458
17682
  return { repoPath, workspace };
17459
17683
  }
17460
- var import_node_fs42, import_node_path43, import_execa6;
17684
+ var import_node_fs43, import_node_path45, import_execa6;
17461
17685
  var init_clone_repo = __esm({
17462
17686
  "src/git/clone-repo.ts"() {
17463
17687
  "use strict";
17464
- import_node_fs42 = require("fs");
17465
- import_node_path43 = require("path");
17688
+ import_node_fs43 = require("fs");
17689
+ import_node_path45 = require("path");
17466
17690
  import_execa6 = require("execa");
17467
17691
  init_paths();
17468
17692
  init_workspaces();
@@ -17583,24 +17807,24 @@ function jobTreeAlive(pid) {
17583
17807
  return jobAlive(pid) || processGroupAlive(pid);
17584
17808
  }
17585
17809
  function readIntFile(file) {
17586
- if (!(0, import_node_fs43.existsSync)(file)) return null;
17587
- const n = Number.parseInt((0, import_node_fs43.readFileSync)(file, "utf8").trim(), 10);
17810
+ if (!(0, import_node_fs44.existsSync)(file)) return null;
17811
+ const n = Number.parseInt((0, import_node_fs44.readFileSync)(file, "utf8").trim(), 10);
17588
17812
  return Number.isInteger(n) ? n : null;
17589
17813
  }
17590
17814
  function jobDir(root, id, legacy = false) {
17591
- return (0, import_node_path44.join)(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
17815
+ return (0, import_node_path46.join)(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
17592
17816
  }
17593
17817
  function resolveJobDir(root, id) {
17594
17818
  const modern = jobDir(root, id, false);
17595
- if ((0, import_node_fs43.existsSync)(modern)) return modern;
17819
+ if ((0, import_node_fs44.existsSync)(modern)) return modern;
17596
17820
  const legacy = jobDir(root, id, true);
17597
- if ((0, import_node_fs43.existsSync)(legacy)) return legacy;
17821
+ if ((0, import_node_fs44.existsSync)(legacy)) return legacy;
17598
17822
  return modern;
17599
17823
  }
17600
17824
  function listJobIdsIn(root, rel) {
17601
- const dir = (0, import_node_path44.join)(root, rel);
17602
- if (!(0, import_node_fs43.existsSync)(dir)) return [];
17603
- return (0, import_node_fs43.readdirSync)(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && JOB_ID_RE.test(e.name)).map((e) => e.name);
17825
+ const dir = (0, import_node_path46.join)(root, rel);
17826
+ if (!(0, import_node_fs44.existsSync)(dir)) return [];
17827
+ return (0, import_node_fs44.readdirSync)(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && JOB_ID_RE.test(e.name)).map((e) => e.name);
17604
17828
  }
17605
17829
  function listRunningDetachedJobs(worktreePath) {
17606
17830
  const root = worktreePath.trim();
@@ -17612,7 +17836,7 @@ function listRunningDetachedJobs(worktreePath) {
17612
17836
  const running = [];
17613
17837
  for (const id of ids) {
17614
17838
  const dir = resolveJobDir(root, id);
17615
- const pid = readIntFile((0, import_node_path44.join)(dir, "pid"));
17839
+ const pid = readIntFile((0, import_node_path46.join)(dir, "pid"));
17616
17840
  if (jobTreeAlive(pid)) running.push(id);
17617
17841
  }
17618
17842
  return running.sort();
@@ -17625,6 +17849,7 @@ function looksLikeDeferredDonePromise(text7) {
17625
17849
  return /\b(i['’]?ll|i will)\s+let you know\b/i.test(unquoted) || /\blet you know when\b/i.test(unquoted) || /\b(check back|ping me)\s+when\b/i.test(unquoted) || /\bi(?:['’]ll| will)\s+(report|update you)\s+when\b/i.test(unquoted);
17626
17850
  }
17627
17851
  function isJobContinuePrompt(text7) {
17852
+ if (typeof text7 !== "string") return false;
17628
17853
  const t = text7.trim();
17629
17854
  return t.startsWith("Detached job still running:") || t.startsWith("You ended the turn after promising to report later");
17630
17855
  }
@@ -17694,8 +17919,8 @@ function planJobContinue(opts) {
17694
17919
  return { action: "none" };
17695
17920
  }
17696
17921
  function tailProgress(logFile, maxLines = 12) {
17697
- if (!(0, import_node_fs43.existsSync)(logFile)) return "(no log yet)";
17698
- const lines = (0, import_node_fs43.readFileSync)(logFile, "utf8").split("\n");
17922
+ if (!(0, import_node_fs44.existsSync)(logFile)) return "(no log yet)";
17923
+ const lines = (0, import_node_fs44.readFileSync)(logFile, "utf8").split("\n");
17699
17924
  return lines.slice(-maxLines).join("\n");
17700
17925
  }
17701
17926
  function lastProgressLine(progress) {
@@ -17703,8 +17928,8 @@ function lastProgressLine(progress) {
17703
17928
  return last ? last.slice(0, 72) : void 0;
17704
17929
  }
17705
17930
  function readLogLines(file) {
17706
- if (!(0, import_node_fs43.existsSync)(file)) return [];
17707
- const lines = (0, import_node_fs43.readFileSync)(file, "utf8").split("\n");
17931
+ if (!(0, import_node_fs44.existsSync)(file)) return [];
17932
+ const lines = (0, import_node_fs44.readFileSync)(file, "utf8").split("\n");
17708
17933
  if (lines.length && lines[lines.length - 1] === "") lines.pop();
17709
17934
  return lines;
17710
17935
  }
@@ -17715,15 +17940,15 @@ function takeDelta(logFile, cursorFile) {
17715
17940
  return { delta: capJobLogDelta(lines.slice(start).join("\n")), nextCursor: lines.length };
17716
17941
  }
17717
17942
  function snapshotJob(dir) {
17718
- const pid = readIntFile((0, import_node_path44.join)(dir, "pid"));
17943
+ const pid = readIntFile((0, import_node_path46.join)(dir, "pid"));
17719
17944
  const running = jobTreeAlive(pid);
17720
17945
  return {
17721
17946
  pid,
17722
17947
  running,
17723
- exitCode: readIntFile((0, import_node_path44.join)(dir, "exit")),
17724
- log: (0, import_node_path44.join)(dir, "log"),
17725
- cursor: (0, import_node_path44.join)(dir, "present.cursor"),
17726
- progress: tailProgress((0, import_node_path44.join)(dir, "log"))
17948
+ exitCode: readIntFile((0, import_node_path46.join)(dir, "exit")),
17949
+ log: (0, import_node_path46.join)(dir, "log"),
17950
+ cursor: (0, import_node_path46.join)(dir, "present.cursor"),
17951
+ progress: tailProgress((0, import_node_path46.join)(dir, "log"))
17727
17952
  };
17728
17953
  }
17729
17954
  function toResult(id, snap, extra) {
@@ -17732,8 +17957,8 @@ function toResult(id, snap, extra) {
17732
17957
  const stillRunning = snap.running && !ok;
17733
17958
  const { delta, nextCursor } = takeDelta(snap.log, snap.cursor);
17734
17959
  try {
17735
- (0, import_node_fs43.mkdirSync)((0, import_node_path44.dirname)(snap.cursor), { recursive: true });
17736
- (0, import_node_fs43.writeFileSync)(snap.cursor, `${nextCursor}
17960
+ (0, import_node_fs44.mkdirSync)((0, import_node_path46.dirname)(snap.cursor), { recursive: true });
17961
+ (0, import_node_fs44.writeFileSync)(snap.cursor, `${nextCursor}
17737
17962
  `);
17738
17963
  } catch {
17739
17964
  }
@@ -17762,7 +17987,7 @@ async function waitForDetachedJob(cwd, id, opts) {
17762
17987
  const dir = resolveJobDir(root, jobId);
17763
17988
  const timeoutMs = mcpWaitForJobTimeoutMs(opts?.timeoutMs);
17764
17989
  const sleep2 = opts?.sleep ?? sleepMs;
17765
- if (!(0, import_node_fs43.existsSync)(dir)) {
17990
+ if (!(0, import_node_fs44.existsSync)(dir)) {
17766
17991
  return {
17767
17992
  stillRunning: false,
17768
17993
  ok: false,
@@ -17808,10 +18033,10 @@ function killProcessTree(pid, signal) {
17808
18033
  }
17809
18034
  function appendJobLog(logFile, line) {
17810
18035
  try {
17811
- (0, import_node_fs43.mkdirSync)((0, import_node_path44.dirname)(logFile), { recursive: true });
18036
+ (0, import_node_fs44.mkdirSync)((0, import_node_path46.dirname)(logFile), { recursive: true });
17812
18037
  const body = line.endsWith("\n") ? line : `${line}
17813
18038
  `;
17814
- (0, import_node_fs43.appendFileSync)(logFile, body);
18039
+ (0, import_node_fs44.appendFileSync)(logFile, body);
17815
18040
  } catch {
17816
18041
  }
17817
18042
  }
@@ -17821,7 +18046,7 @@ async function stopDetachedJob(cwd, id, opts) {
17821
18046
  const dir = resolveJobDir(root, jobId);
17822
18047
  const sleep2 = opts?.sleep ?? sleepMs;
17823
18048
  const why = opts?.reason?.trim() ?? "";
17824
- if (!(0, import_node_fs43.existsSync)(dir)) {
18049
+ if (!(0, import_node_fs44.existsSync)(dir)) {
17825
18050
  return {
17826
18051
  stillRunning: false,
17827
18052
  ok: false,
@@ -17857,10 +18082,10 @@ async function stopDetachedJob(cwd, id, opts) {
17857
18082
  killProcessTree(targetPid, "SIGKILL");
17858
18083
  await sleep2(100);
17859
18084
  }
17860
- const exitFile = (0, import_node_path44.join)(dir, "exit");
17861
- if (!(0, import_node_fs43.existsSync)(exitFile)) {
18085
+ const exitFile = (0, import_node_path46.join)(dir, "exit");
18086
+ if (!(0, import_node_fs44.existsSync)(exitFile)) {
17862
18087
  try {
17863
- (0, import_node_fs43.writeFileSync)(exitFile, "1\n");
18088
+ (0, import_node_fs44.writeFileSync)(exitFile, "1\n");
17864
18089
  } catch {
17865
18090
  }
17866
18091
  }
@@ -17880,12 +18105,12 @@ async function stopDetachedJob(cwd, id, opts) {
17880
18105
  hint: stopped ? MCP_STOP_JOB_HINT : MCP_WAIT_JOB_STILL_RUNNING_HINT
17881
18106
  };
17882
18107
  }
17883
- var import_node_fs43, import_node_path44, MAX_JOB_CONTINUES, MAX_JOB_DELTA_LINES, MAX_JOB_DELTA_CHARS, DEFERRED_DONE_MAX_CHARS, GH_WATCH_REFRESH, MCP_WAIT_JOB_STILL_RUNNING_HINT, MCP_STOP_JOB_HINT, JOB_ID_RE;
18108
+ var import_node_fs44, import_node_path46, MAX_JOB_CONTINUES, MAX_JOB_DELTA_LINES, MAX_JOB_DELTA_CHARS, DEFERRED_DONE_MAX_CHARS, GH_WATCH_REFRESH, MCP_WAIT_JOB_STILL_RUNNING_HINT, MCP_STOP_JOB_HINT, JOB_ID_RE;
17884
18109
  var init_wait_for_job = __esm({
17885
18110
  "src/mcp/wait-for-job.ts"() {
17886
18111
  "use strict";
17887
- import_node_fs43 = require("fs");
17888
- import_node_path44 = require("path");
18112
+ import_node_fs44 = require("fs");
18113
+ import_node_path46 = require("path");
17889
18114
  init_workspace_scratch();
17890
18115
  init_wait_for_turn();
17891
18116
  MAX_JOB_CONTINUES = 8;
@@ -19430,7 +19655,7 @@ function reuseLiveThread(input, repoPath, match) {
19430
19655
  }
19431
19656
  async function createThread(input, _onSetupLine) {
19432
19657
  const repoPath = await resolveRepoRoot(input.repoPath);
19433
- if (!(0, import_node_fs44.existsSync)(repoPath)) {
19658
+ if (!(0, import_node_fs45.existsSync)(repoPath)) {
19434
19659
  throw new Error(`Repo not found: ${repoPath}`);
19435
19660
  }
19436
19661
  const reused = reuseLiveThread(input, repoPath, {
@@ -19615,11 +19840,11 @@ async function listLinearIssues(agent, repoPath) {
19615
19840
  }
19616
19841
  return adapter.listLinearIssues(repoPath);
19617
19842
  }
19618
- var import_node_fs44;
19843
+ var import_node_fs45;
19619
19844
  var init_create = __esm({
19620
19845
  "src/threads/create.ts"() {
19621
19846
  "use strict";
19622
- import_node_fs44 = require("fs");
19847
+ import_node_fs45 = require("fs");
19623
19848
  init_detect();
19624
19849
  init_worktree();
19625
19850
  init_home_board();
@@ -19771,20 +19996,20 @@ function writeTurnLive(threadId, progress) {
19771
19996
  const path2 = threadLivePath(threadId);
19772
19997
  const tmp = `${path2}.${process.pid}.tmp`;
19773
19998
  try {
19774
- (0, import_node_fs45.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
19775
- (0, import_node_fs45.renameSync)(tmp, path2);
19999
+ (0, import_node_fs46.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
20000
+ (0, import_node_fs46.renameSync)(tmp, path2);
19776
20001
  } catch {
19777
20002
  try {
19778
- (0, import_node_fs45.unlinkSync)(tmp);
20003
+ (0, import_node_fs46.unlinkSync)(tmp);
19779
20004
  } catch {
19780
20005
  }
19781
20006
  }
19782
20007
  }
19783
20008
  function readTurnLive(threadId) {
19784
20009
  const path2 = threadLivePath(threadId);
19785
- if (!(0, import_node_fs45.existsSync)(path2)) return null;
20010
+ if (!(0, import_node_fs46.existsSync)(path2)) return null;
19786
20011
  try {
19787
- const raw = JSON.parse((0, import_node_fs45.readFileSync)(path2, "utf8"));
20012
+ const raw = JSON.parse((0, import_node_fs46.readFileSync)(path2, "utf8"));
19788
20013
  if (!raw || typeof raw.summary !== "string") return null;
19789
20014
  return raw;
19790
20015
  } catch {
@@ -19796,17 +20021,17 @@ function clearTurnLive(threadId) {
19796
20021
  if (buf?.timer) clearTimeout(buf.timer);
19797
20022
  buffers.delete(threadId);
19798
20023
  const path2 = threadLivePath(threadId);
19799
- if (!(0, import_node_fs45.existsSync)(path2)) return;
20024
+ if (!(0, import_node_fs46.existsSync)(path2)) return;
19800
20025
  try {
19801
- (0, import_node_fs45.unlinkSync)(path2);
20026
+ (0, import_node_fs46.unlinkSync)(path2);
19802
20027
  } catch {
19803
20028
  }
19804
20029
  }
19805
- var import_node_fs45, buffers, FLUSH_MS, MAX_PARTS;
20030
+ var import_node_fs46, buffers, FLUSH_MS, MAX_PARTS;
19806
20031
  var init_turn_live = __esm({
19807
20032
  "src/store/turn-live.ts"() {
19808
20033
  "use strict";
19809
- import_node_fs45 = require("fs");
20034
+ import_node_fs46 = require("fs");
19810
20035
  init_message_parts();
19811
20036
  init_paths();
19812
20037
  buffers = /* @__PURE__ */ new Map();
@@ -20050,7 +20275,7 @@ var init_quota_failover = __esm({
20050
20275
  // src/threads/adopt.ts
20051
20276
  function thisModuleFile() {
20052
20277
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
20053
- return cjsFile || process.argv[1] || (0, import_node_path45.join)(process.cwd(), "package.json");
20278
+ return cjsFile || process.argv[1] || (0, import_node_path47.join)(process.cwd(), "package.json");
20054
20279
  }
20055
20280
  function openReadonlySqlite(file) {
20056
20281
  const req = (0, import_node_module4.createRequire)(thisModuleFile());
@@ -20068,21 +20293,21 @@ function mapAgentType(raw) {
20068
20293
  return null;
20069
20294
  }
20070
20295
  function resolveConductorCursorAgentId(workspacePath) {
20071
- if (!workspacePath || !(0, import_node_fs46.existsSync)(CURSOR_SDK_STORE)) return null;
20296
+ if (!workspacePath || !(0, import_node_fs47.existsSync)(CURSOR_SDK_STORE)) return null;
20072
20297
  const normalized = workspacePath.replace(/\/$/, "");
20073
20298
  let best = null;
20074
20299
  let hashes;
20075
20300
  try {
20076
- hashes = (0, import_node_fs46.readdirSync)(CURSOR_SDK_STORE);
20301
+ hashes = (0, import_node_fs47.readdirSync)(CURSOR_SDK_STORE);
20077
20302
  } catch {
20078
20303
  return null;
20079
20304
  }
20080
20305
  for (const hash of hashes) {
20081
- const agentsFile = (0, import_node_path45.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
20082
- if (!(0, import_node_fs46.existsSync)(agentsFile)) continue;
20306
+ const agentsFile = (0, import_node_path47.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
20307
+ if (!(0, import_node_fs47.existsSync)(agentsFile)) continue;
20083
20308
  let text7;
20084
20309
  try {
20085
- text7 = (0, import_node_fs46.readFileSync)(agentsFile, "utf8");
20310
+ text7 = (0, import_node_fs47.readFileSync)(agentsFile, "utf8");
20086
20311
  } catch {
20087
20312
  continue;
20088
20313
  }
@@ -20106,7 +20331,7 @@ function resolveConductorCursorAgentId(workspacePath) {
20106
20331
  return best?.agentId ?? null;
20107
20332
  }
20108
20333
  async function adoptThread(input) {
20109
- if (!(0, import_node_fs46.existsSync)(input.worktreePath)) {
20334
+ if (!(0, import_node_fs47.existsSync)(input.worktreePath)) {
20110
20335
  throw new Error(`Worktree not found: ${input.worktreePath}`);
20111
20336
  }
20112
20337
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -20135,18 +20360,18 @@ function conductorDbPath() {
20135
20360
  return CONDUCTOR_DB;
20136
20361
  }
20137
20362
  function listConductorWorkspaces() {
20138
- if (!(0, import_node_fs46.existsSync)(CONDUCTOR_DB)) {
20363
+ if (!(0, import_node_fs47.existsSync)(CONDUCTOR_DB)) {
20139
20364
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
20140
20365
  }
20141
- const tmp = (0, import_node_fs46.mkdtempSync)((0, import_node_path45.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
20142
- const snapshot = (0, import_node_path45.join)(tmp, "conductor.db");
20366
+ const tmp = (0, import_node_fs47.mkdtempSync)((0, import_node_path47.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
20367
+ const snapshot = (0, import_node_path47.join)(tmp, "conductor.db");
20143
20368
  try {
20144
- (0, import_node_fs46.copyFileSync)(CONDUCTOR_DB, snapshot);
20369
+ (0, import_node_fs47.copyFileSync)(CONDUCTOR_DB, snapshot);
20145
20370
  for (const suffix of ["-wal", "-shm"]) {
20146
20371
  const src = `${CONDUCTOR_DB}${suffix}`;
20147
- if ((0, import_node_fs46.existsSync)(src)) {
20372
+ if ((0, import_node_fs47.existsSync)(src)) {
20148
20373
  try {
20149
- (0, import_node_fs46.copyFileSync)(src, `${snapshot}${suffix}`);
20374
+ (0, import_node_fs47.copyFileSync)(src, `${snapshot}${suffix}`);
20150
20375
  } catch {
20151
20376
  }
20152
20377
  }
@@ -20222,22 +20447,22 @@ function listConductorWorkspaces() {
20222
20447
  db.close();
20223
20448
  }
20224
20449
  } finally {
20225
- (0, import_node_fs46.rmSync)(tmp, { recursive: true, force: true });
20450
+ (0, import_node_fs47.rmSync)(tmp, { recursive: true, force: true });
20226
20451
  }
20227
20452
  }
20228
20453
  function importConductorWorkspace(workspaceId) {
20229
- if (!(0, import_node_fs46.existsSync)(CONDUCTOR_DB)) {
20454
+ if (!(0, import_node_fs47.existsSync)(CONDUCTOR_DB)) {
20230
20455
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
20231
20456
  }
20232
- const tmp = (0, import_node_fs46.mkdtempSync)((0, import_node_path45.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
20233
- const snapshot = (0, import_node_path45.join)(tmp, "conductor.db");
20457
+ const tmp = (0, import_node_fs47.mkdtempSync)((0, import_node_path47.join)((0, import_node_os14.tmpdir)(), "sideboard-conductor-"));
20458
+ const snapshot = (0, import_node_path47.join)(tmp, "conductor.db");
20234
20459
  try {
20235
- (0, import_node_fs46.copyFileSync)(CONDUCTOR_DB, snapshot);
20460
+ (0, import_node_fs47.copyFileSync)(CONDUCTOR_DB, snapshot);
20236
20461
  for (const suffix of ["-wal", "-shm"]) {
20237
20462
  const src = `${CONDUCTOR_DB}${suffix}`;
20238
- if ((0, import_node_fs46.existsSync)(src)) {
20463
+ if ((0, import_node_fs47.existsSync)(src)) {
20239
20464
  try {
20240
- (0, import_node_fs46.copyFileSync)(src, `${snapshot}${suffix}`);
20465
+ (0, import_node_fs47.copyFileSync)(src, `${snapshot}${suffix}`);
20241
20466
  } catch {
20242
20467
  }
20243
20468
  }
@@ -20255,7 +20480,7 @@ function importConductorWorkspace(workspaceId) {
20255
20480
  ).get(workspaceId);
20256
20481
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
20257
20482
  const worktreePath = String(row.workspacePath);
20258
- if (!(0, import_node_fs46.existsSync)(worktreePath)) {
20483
+ if (!(0, import_node_fs47.existsSync)(worktreePath)) {
20259
20484
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
20260
20485
  }
20261
20486
  let sessionId = null;
@@ -20318,31 +20543,31 @@ function importConductorWorkspace(workspaceId) {
20318
20543
  db.close();
20319
20544
  }
20320
20545
  } finally {
20321
- (0, import_node_fs46.rmSync)(tmp, { recursive: true, force: true });
20546
+ (0, import_node_fs47.rmSync)(tmp, { recursive: true, force: true });
20322
20547
  }
20323
20548
  }
20324
20549
  async function importConductorWorkspaceAsync(workspaceId) {
20325
20550
  return importConductorWorkspace(workspaceId);
20326
20551
  }
20327
- var import_node_child_process5, import_node_fs46, import_node_os14, import_node_path45, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
20552
+ var import_node_child_process5, import_node_fs47, import_node_os14, import_node_path47, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
20328
20553
  var init_adopt = __esm({
20329
20554
  "src/threads/adopt.ts"() {
20330
20555
  "use strict";
20331
20556
  import_node_child_process5 = require("child_process");
20332
- import_node_fs46 = require("fs");
20557
+ import_node_fs47 = require("fs");
20333
20558
  import_node_os14 = require("os");
20334
- import_node_path45 = require("path");
20559
+ import_node_path47 = require("path");
20335
20560
  import_node_module4 = require("module");
20336
20561
  init_worktree();
20337
20562
  init_thread_store();
20338
- CONDUCTOR_APP_SUPPORT = (0, import_node_path45.join)(
20563
+ CONDUCTOR_APP_SUPPORT = (0, import_node_path47.join)(
20339
20564
  process.env.HOME ?? "",
20340
20565
  "Library",
20341
20566
  "Application Support",
20342
20567
  "com.conductor.app"
20343
20568
  );
20344
- CONDUCTOR_DB = (0, import_node_path45.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
20345
- CURSOR_SDK_STORE = (0, import_node_path45.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
20569
+ CONDUCTOR_DB = (0, import_node_path47.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
20570
+ CURSOR_SDK_STORE = (0, import_node_path47.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
20346
20571
  }
20347
20572
  });
20348
20573
 
@@ -20409,7 +20634,7 @@ async function openStackLayer(input, _onSetupLine) {
20409
20634
  let createdWorktree = false;
20410
20635
  const trees = await listWorktrees(repoPath);
20411
20636
  const checkedOut = trees.find((w) => w.branch === branchName);
20412
- if (checkedOut?.path && (0, import_node_fs47.existsSync)(checkedOut.path)) {
20637
+ if (checkedOut?.path && (0, import_node_fs48.existsSync)(checkedOut.path)) {
20413
20638
  if (input.reuseExistingWorktree !== false) {
20414
20639
  worktreePath = checkedOut.path;
20415
20640
  } else {
@@ -20551,7 +20776,7 @@ async function initStackFromThread(input, onSetupLine) {
20551
20776
  async function createPrStack(input, onSetupLine) {
20552
20777
  await requireAgent(input.agent);
20553
20778
  const repoPath = await resolveRepoRoot(input.repoPath);
20554
- if (!(0, import_node_fs47.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
20779
+ if (!(0, import_node_fs48.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
20555
20780
  if (!input.branches.length) throw new Error("At least one branch name required");
20556
20781
  const status = await detectGhStack(repoPath);
20557
20782
  if (!status.available) throw new Error(status.reason);
@@ -20618,7 +20843,7 @@ async function createPrStack(input, onSetupLine) {
20618
20843
  }
20619
20844
  }
20620
20845
  const claimed = new Set(threads.map((t) => t.worktreePath));
20621
- if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs47.existsSync)(bootstrap.worktreePath)) {
20846
+ if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs48.existsSync)(bootstrap.worktreePath)) {
20622
20847
  try {
20623
20848
  await removeWorktree(repoPath, bootstrap.worktreePath, {
20624
20849
  deleteBranch: bootstrap.branchName
@@ -20638,11 +20863,11 @@ function stackAgentDefaultsFrom(input) {
20638
20863
  planMode: input.planMode
20639
20864
  };
20640
20865
  }
20641
- var import_node_fs47;
20866
+ var import_node_fs48;
20642
20867
  var init_stack_layers = __esm({
20643
20868
  "src/threads/stack-layers.ts"() {
20644
20869
  "use strict";
20645
- import_node_fs47 = require("fs");
20870
+ import_node_fs48 = require("fs");
20646
20871
  init_detect();
20647
20872
  init_run();
20648
20873
  init_stack();
@@ -20655,7 +20880,7 @@ var init_stack_layers = __esm({
20655
20880
 
20656
20881
  // src/diff/diff.ts
20657
20882
  async function inspectGitWorktree(worktreePath) {
20658
- if (!worktreePath || !(0, import_node_fs48.existsSync)(worktreePath)) return "missing_worktree";
20883
+ if (!worktreePath || !(0, import_node_fs49.existsSync)(worktreePath)) return "missing_worktree";
20659
20884
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
20660
20885
  reject: false
20661
20886
  });
@@ -20663,7 +20888,7 @@ async function inspectGitWorktree(worktreePath) {
20663
20888
  return "ok";
20664
20889
  }
20665
20890
  async function initializeGitRepository(worktreePath) {
20666
- if (!worktreePath || !(0, import_node_fs48.existsSync)(worktreePath)) {
20891
+ if (!worktreePath || !(0, import_node_fs49.existsSync)(worktreePath)) {
20667
20892
  throw new Error("Worktree not found");
20668
20893
  }
20669
20894
  const status = await inspectGitWorktree(worktreePath);
@@ -20797,11 +21022,11 @@ new file mode 100644
20797
21022
  };
20798
21023
  }
20799
21024
  async function untrackedPatch(worktreePath, path2, maxHunk) {
20800
- const abs = (0, import_node_path46.join)(worktreePath, path2);
21025
+ const abs = (0, import_node_path48.join)(worktreePath, path2);
20801
21026
  try {
20802
- const st = (0, import_node_fs48.statSync)(abs);
21027
+ const st = (0, import_node_fs49.statSync)(abs);
20803
21028
  if (st.isFile() && st.size > maxHunk) {
20804
- const buf = (0, import_node_fs48.readFileSync)(abs).subarray(0, maxHunk);
21029
+ const buf = (0, import_node_fs49.readFileSync)(abs).subarray(0, maxHunk);
20805
21030
  return syntheticAddPatch(path2, buf.toString("utf8"), maxHunk);
20806
21031
  }
20807
21032
  } catch {
@@ -21266,6 +21491,15 @@ async function getDiff(worktreePath, repoPath, opts) {
21266
21491
  mergeBase: needsMergeBase ? mergeBase : null
21267
21492
  };
21268
21493
  }
21494
+ function statWorktreePath(worktreePath, relativePath) {
21495
+ assertSafeRelativePath(relativePath);
21496
+ const abs = (0, import_node_path48.join)(worktreePath, relativePath);
21497
+ if (!(0, import_node_fs49.existsSync)(abs)) return "missing";
21498
+ const st = (0, import_node_fs49.statSync)(abs);
21499
+ if (st.isDirectory()) return "dir";
21500
+ if (st.isFile()) return "file";
21501
+ return "missing";
21502
+ }
21269
21503
  async function listWorktreeFiles(worktreePath, opts) {
21270
21504
  const maxFiles = opts?.maxFiles ?? 5e3;
21271
21505
  const tracked = await git(["ls-files", "-z"], worktreePath, { reject: false });
@@ -21290,8 +21524,8 @@ function isImageRelativePath(relativePath) {
21290
21524
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
21291
21525
  assertSafeRelativePath(relativePath);
21292
21526
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
21293
- const abs = (0, import_node_path46.join)(worktreePath, relativePath);
21294
- const st = (0, import_node_fs48.statSync)(abs);
21527
+ const abs = (0, import_node_path48.join)(worktreePath, relativePath);
21528
+ const st = (0, import_node_fs49.statSync)(abs);
21295
21529
  if (!st.isFile()) {
21296
21530
  throw new Error(`Not a file: ${relativePath}`);
21297
21531
  }
@@ -21300,7 +21534,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
21300
21534
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
21301
21535
  );
21302
21536
  }
21303
- const buf = (0, import_node_fs48.readFileSync)(abs);
21537
+ const buf = (0, import_node_fs49.readFileSync)(abs);
21304
21538
  return {
21305
21539
  path: relativePath,
21306
21540
  contentBase64: buf.toString("base64"),
@@ -21310,12 +21544,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
21310
21544
  function readWorktreeFile(worktreePath, relativePath, opts) {
21311
21545
  assertSafeRelativePath(relativePath);
21312
21546
  const maxBytes = opts?.maxBytes ?? 2e5;
21313
- const abs = (0, import_node_path46.join)(worktreePath, relativePath);
21314
- const st = (0, import_node_fs48.statSync)(abs);
21547
+ const abs = (0, import_node_path48.join)(worktreePath, relativePath);
21548
+ const st = (0, import_node_fs49.statSync)(abs);
21315
21549
  if (!st.isFile()) {
21316
21550
  throw new Error(`Not a file: ${relativePath}`);
21317
21551
  }
21318
- const buf = (0, import_node_fs48.readFileSync)(abs);
21552
+ const buf = (0, import_node_fs49.readFileSync)(abs);
21319
21553
  if (isImageRelativePath(relativePath)) {
21320
21554
  const maxImageBytes = Math.max(maxBytes, 15e6);
21321
21555
  const truncated2 = buf.length > maxImageBytes;
@@ -21358,9 +21592,9 @@ function assertSafeRelativePath(relativePath) {
21358
21592
  }
21359
21593
  function writeWorktreeFile(worktreePath, relativePath, content) {
21360
21594
  assertSafeRelativePath(relativePath);
21361
- const abs = (0, import_node_path46.join)(worktreePath, relativePath);
21362
- (0, import_node_fs48.mkdirSync)((0, import_node_path46.dirname)(abs), { recursive: true });
21363
- (0, import_node_fs48.writeFileSync)(abs, content, "utf8");
21595
+ const abs = (0, import_node_path48.join)(worktreePath, relativePath);
21596
+ (0, import_node_fs49.mkdirSync)((0, import_node_path48.dirname)(abs), { recursive: true });
21597
+ (0, import_node_fs49.writeFileSync)(abs, content, "utf8");
21364
21598
  return { path: relativePath };
21365
21599
  }
21366
21600
  async function getWorktreeDirtyStat(worktreePath) {
@@ -21400,12 +21634,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
21400
21634
  truncated: full.files.length > maxFiles
21401
21635
  };
21402
21636
  }
21403
- var import_node_fs48, import_node_path46, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
21637
+ var import_node_fs49, import_node_path48, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
21404
21638
  var init_diff = __esm({
21405
21639
  "src/diff/diff.ts"() {
21406
21640
  "use strict";
21407
- import_node_fs48 = require("fs");
21408
- import_node_path46 = require("path");
21641
+ import_node_fs49 = require("fs");
21642
+ import_node_path48 = require("path");
21409
21643
  init_run();
21410
21644
  init_worktree();
21411
21645
  mergeBaseCache = /* @__PURE__ */ new Map();
@@ -21762,7 +21996,7 @@ function parseFrontmatter(content) {
21762
21996
  }
21763
21997
  function readSkill(skillMd, source) {
21764
21998
  try {
21765
- const content = (0, import_node_fs49.readFileSync)(skillMd, "utf8");
21999
+ const content = (0, import_node_fs50.readFileSync)(skillMd, "utf8");
21766
22000
  const { name: fmName, description } = parseFrontmatter(content);
21767
22001
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
21768
22002
  const name = fmName || dirName;
@@ -21781,19 +22015,19 @@ function readSkill(skillMd, source) {
21781
22015
  }
21782
22016
  }
21783
22017
  function scanSkillsDir(dir, source, out) {
21784
- if (!(0, import_node_fs49.existsSync)(dir)) return;
22018
+ if (!(0, import_node_fs50.existsSync)(dir)) return;
21785
22019
  let entries;
21786
22020
  try {
21787
- entries = (0, import_node_fs49.readdirSync)(dir);
22021
+ entries = (0, import_node_fs50.readdirSync)(dir);
21788
22022
  } catch {
21789
22023
  return;
21790
22024
  }
21791
22025
  for (const entry of entries) {
21792
22026
  if (entry.startsWith(".")) continue;
21793
- const skillMd = (0, import_node_path47.join)(dir, entry, "SKILL.md");
21794
- if (!(0, import_node_fs49.existsSync)(skillMd)) continue;
22027
+ const skillMd = (0, import_node_path49.join)(dir, entry, "SKILL.md");
22028
+ if (!(0, import_node_fs50.existsSync)(skillMd)) continue;
21795
22029
  try {
21796
- if (!(0, import_node_fs49.statSync)(skillMd).isFile()) continue;
22030
+ if (!(0, import_node_fs50.statSync)(skillMd).isFile()) continue;
21797
22031
  } catch {
21798
22032
  continue;
21799
22033
  }
@@ -21802,24 +22036,24 @@ function scanSkillsDir(dir, source, out) {
21802
22036
  }
21803
22037
  }
21804
22038
  function scanClaudePluginSkills(pluginsRoot, out) {
21805
- if (!(0, import_node_fs49.existsSync)(pluginsRoot)) return;
22039
+ if (!(0, import_node_fs50.existsSync)(pluginsRoot)) return;
21806
22040
  const walk = (dir, depth, lookingForSkillsDir) => {
21807
22041
  if (depth > 7) return;
21808
22042
  let entries;
21809
22043
  try {
21810
- entries = (0, import_node_fs49.readdirSync)(dir);
22044
+ entries = (0, import_node_fs50.readdirSync)(dir);
21811
22045
  } catch {
21812
22046
  return;
21813
22047
  }
21814
22048
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
21815
- const skill = readSkill((0, import_node_path47.join)(dir, "SKILL.md"), "cli");
22049
+ const skill = readSkill((0, import_node_path49.join)(dir, "SKILL.md"), "cli");
21816
22050
  if (skill) out.push(skill);
21817
22051
  }
21818
22052
  for (const entry of entries) {
21819
22053
  if (entry === "node_modules" || entry === ".git") continue;
21820
- const full = (0, import_node_path47.join)(dir, entry);
22054
+ const full = (0, import_node_path49.join)(dir, entry);
21821
22055
  try {
21822
- if (!(0, import_node_fs49.statSync)(full).isDirectory()) continue;
22056
+ if (!(0, import_node_fs50.statSync)(full).isDirectory()) continue;
21823
22057
  } catch {
21824
22058
  continue;
21825
22059
  }
@@ -21837,17 +22071,17 @@ function discoverSkills(worktreePath) {
21837
22071
  const home = (0, import_node_os15.homedir)();
21838
22072
  const collected = [];
21839
22073
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
21840
- scanSkillsDir((0, import_node_path47.join)(worktreePath, rel), "workspace", collected);
22074
+ scanSkillsDir((0, import_node_path49.join)(worktreePath, rel), "workspace", collected);
21841
22075
  }
21842
22076
  for (const abs of [
21843
- (0, import_node_path47.join)(home, ".claude/skills"),
21844
- (0, import_node_path47.join)(home, ".cursor/skills"),
21845
- (0, import_node_path47.join)(home, ".sideboard/skills"),
21846
- (0, import_node_path47.join)(home, ".brightsy/skills")
22077
+ (0, import_node_path49.join)(home, ".claude/skills"),
22078
+ (0, import_node_path49.join)(home, ".cursor/skills"),
22079
+ (0, import_node_path49.join)(home, ".sideboard/skills"),
22080
+ (0, import_node_path49.join)(home, ".brightsy/skills")
21847
22081
  ]) {
21848
22082
  scanSkillsDir(abs, "user", collected);
21849
22083
  }
21850
- scanClaudePluginSkills((0, import_node_path47.join)(home, ".claude/plugins"), collected);
22084
+ scanClaudePluginSkills((0, import_node_path49.join)(home, ".claude/plugins"), collected);
21851
22085
  collected.push(...bundledSkills());
21852
22086
  const rank = {
21853
22087
  workspace: 0,
@@ -21873,7 +22107,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
21873
22107
  \u2026(truncated)` : body;
21874
22108
  }
21875
22109
  }
21876
- const raw = (0, import_node_fs49.readFileSync)(skillPath, "utf8");
22110
+ const raw = (0, import_node_fs50.readFileSync)(skillPath, "utf8");
21877
22111
  if (raw.startsWith("---")) {
21878
22112
  const end = raw.indexOf("\n---", 3);
21879
22113
  if (end >= 0) {
@@ -21887,13 +22121,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
21887
22121
 
21888
22122
  \u2026(truncated)` : raw;
21889
22123
  }
21890
- var import_node_fs49, import_node_os15, import_node_path47, BUNDLED_SKILL_PREFIX;
22124
+ var import_node_fs50, import_node_os15, import_node_path49, BUNDLED_SKILL_PREFIX;
21891
22125
  var init_discover = __esm({
21892
22126
  "src/skills/discover.ts"() {
21893
22127
  "use strict";
21894
- import_node_fs49 = require("fs");
22128
+ import_node_fs50 = require("fs");
21895
22129
  import_node_os15 = require("os");
21896
- import_node_path47 = require("path");
22130
+ import_node_path49 = require("path");
21897
22131
  init_long_running();
21898
22132
  BUNDLED_SKILL_PREFIX = "bundled:";
21899
22133
  }
@@ -22042,10 +22276,22 @@ var init_consume_attachments = __esm({
22042
22276
  });
22043
22277
 
22044
22278
  // src/skills/detached-job-path.ts
22279
+ function compiledModuleDir() {
22280
+ const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
22281
+ if (cjsDir) return cjsDir;
22282
+ try {
22283
+ const url = import_meta3.url;
22284
+ if (typeof url === "string" && url.length > 0) {
22285
+ return (0, import_node_path50.dirname)((0, import_node_url3.fileURLToPath)(url));
22286
+ }
22287
+ } catch {
22288
+ }
22289
+ return null;
22290
+ }
22045
22291
  function detachedJobScriptIn(dir) {
22046
22292
  for (const name of DETACHED_JOB_FILENAMES) {
22047
- const script = (0, import_node_path48.join)(dir, "scripts", name);
22048
- if ((0, import_node_fs50.existsSync)(script)) return script;
22293
+ const script = (0, import_node_path50.join)(dir, "scripts", name);
22294
+ if ((0, import_node_fs51.existsSync)(script)) return script;
22049
22295
  }
22050
22296
  return null;
22051
22297
  }
@@ -22057,11 +22303,12 @@ function packagedDetachedJobPath() {
22057
22303
  function resolveDetachedJobScript() {
22058
22304
  const packaged = packagedDetachedJobPath();
22059
22305
  if (packaged) return packaged;
22060
- let dir = (0, import_node_path48.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
22306
+ let dir = compiledModuleDir();
22307
+ if (!dir) return null;
22061
22308
  for (let i = 0; i < 8; i++) {
22062
22309
  const candidate = detachedJobScriptIn(dir);
22063
22310
  if (candidate) return candidate;
22064
- const parent = (0, import_node_path48.dirname)(dir);
22311
+ const parent = (0, import_node_path50.dirname)(dir);
22065
22312
  if (parent === dir) break;
22066
22313
  dir = parent;
22067
22314
  }
@@ -22072,12 +22319,12 @@ function formatDetachedJobInvoke(scriptPath) {
22072
22319
  if (resolved) return `node ${JSON.stringify(resolved)}`;
22073
22320
  return "node scripts/detached-job.cjs";
22074
22321
  }
22075
- var import_node_fs50, import_node_path48, import_node_url3, import_meta3, DETACHED_JOB_FILENAMES;
22322
+ var import_node_fs51, import_node_path50, import_node_url3, import_meta3, DETACHED_JOB_FILENAMES;
22076
22323
  var init_detached_job_path = __esm({
22077
22324
  "src/skills/detached-job-path.ts"() {
22078
22325
  "use strict";
22079
- import_node_fs50 = require("fs");
22080
- import_node_path48 = require("path");
22326
+ import_node_fs51 = require("fs");
22327
+ import_node_path50 = require("path");
22081
22328
  import_node_url3 = require("url");
22082
22329
  init_packaged_runtime();
22083
22330
  import_meta3 = {};
@@ -22259,9 +22506,9 @@ function formatPrGateDirective() {
22259
22506
  }
22260
22507
  function formatProcessGuideDirective(opts) {
22261
22508
  const worktree = opts?.worktreePath?.trim();
22262
- const hasGraphSkill = !!worktree && (0, import_node_fs51.existsSync)((0, import_node_path49.join)(worktree, ".claude/skills/graph-engineering/SKILL.md"));
22263
- const hasReviewSkill = !!worktree && (0, import_node_fs51.existsSync)((0, import_node_path49.join)(worktree, ".claude/skills/review/SKILL.md"));
22264
- const hasInstallSkill = !!worktree && (0, import_node_fs51.existsSync)((0, import_node_path49.join)(worktree, ".claude/skills/worktree-install/SKILL.md"));
22509
+ const hasGraphSkill = !!worktree && (0, import_node_fs52.existsSync)((0, import_node_path51.join)(worktree, ".claude/skills/graph-engineering/SKILL.md"));
22510
+ const hasReviewSkill = !!worktree && (0, import_node_fs52.existsSync)((0, import_node_path51.join)(worktree, ".claude/skills/review/SKILL.md"));
22511
+ const hasInstallSkill = !!worktree && (0, import_node_fs52.existsSync)((0, import_node_path51.join)(worktree, ".claude/skills/worktree-install/SKILL.md"));
22265
22512
  return [
22266
22513
  "Process guides (recurring work only):",
22267
22514
  hasGraphSkill ? "- Migrations, ports, batch fixes, and other fan-out: follow `.claude/skills/graph-engineering/SKILL.md` (`/graph-engineering`). Judge first; state on disk; grow the rulebook; do not patch around it." : null,
@@ -22299,12 +22546,12 @@ function formatArtifactDirective() {
22299
22546
  function formatUiReminder() {
22300
22547
  return "Sideboard UI: markdown table is enough to read data; present_schema if they ask to edit/filter (even after markdown); present_files for the file manager. html fence or present_artifact, not both for the same document. type=log appends (same artifact_id, new lines only). ask_user only for a real multiple-choice (not hellos, \u201Cwhat next?\u201D, or after a review) \u2014 reply in chat. Do not say artifacts/CMS UI are unavailable.";
22301
22548
  }
22302
- var import_node_fs51, import_node_path49, PR_GOAL_RE, GITHUB_TICKET_REF, KEYED_TICKET_REF;
22549
+ var import_node_fs52, import_node_path51, PR_GOAL_RE, GITHUB_TICKET_REF, KEYED_TICKET_REF;
22303
22550
  var init_instructions = __esm({
22304
22551
  "src/agents/instructions.ts"() {
22305
22552
  "use strict";
22306
- import_node_fs51 = require("fs");
22307
- import_node_path49 = require("path");
22553
+ import_node_fs52 = require("fs");
22554
+ import_node_path51 = require("path");
22308
22555
  init_git_auth_mode();
22309
22556
  init_branch_prefix();
22310
22557
  init_worktree_labels();
@@ -22690,40 +22937,40 @@ __export(plan_file_exports, {
22690
22937
  writePlanFile: () => writePlanFile
22691
22938
  });
22692
22939
  function ensureAttachmentsGitignore(worktreePath) {
22693
- const gitignoreAbs = (0, import_node_path50.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
22694
- if ((0, import_node_fs52.existsSync)(gitignoreAbs)) return;
22695
- (0, import_node_fs52.mkdirSync)((0, import_node_path50.dirname)(gitignoreAbs), { recursive: true });
22696
- (0, import_node_fs52.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
22940
+ const gitignoreAbs = (0, import_node_path52.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
22941
+ if ((0, import_node_fs53.existsSync)(gitignoreAbs)) return;
22942
+ (0, import_node_fs53.mkdirSync)((0, import_node_path52.dirname)(gitignoreAbs), { recursive: true });
22943
+ (0, import_node_fs53.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
22697
22944
  }
22698
22945
  function planFileAbs(worktreePath) {
22699
- return (0, import_node_path50.join)(worktreePath, PLAN_FILE_REL);
22946
+ return (0, import_node_path52.join)(worktreePath, PLAN_FILE_REL);
22700
22947
  }
22701
22948
  function readTextIfPresent2(abs) {
22702
- if (!(0, import_node_fs52.existsSync)(abs)) return null;
22949
+ if (!(0, import_node_fs53.existsSync)(abs)) return null;
22703
22950
  try {
22704
- const content = (0, import_node_fs52.readFileSync)(abs, "utf8");
22951
+ const content = (0, import_node_fs53.readFileSync)(abs, "utf8");
22705
22952
  return content.trim() ? content : null;
22706
22953
  } catch {
22707
22954
  return null;
22708
22955
  }
22709
22956
  }
22710
22957
  function readPlanFile(worktreePath) {
22711
- return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path50.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path50.join)(worktreePath, LEGACY_PLAN_FILE_REL));
22958
+ return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path52.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path52.join)(worktreePath, LEGACY_PLAN_FILE_REL));
22712
22959
  }
22713
22960
  function writePlanFile(worktreePath, content) {
22714
22961
  ensureAttachmentsGitignore(worktreePath);
22715
22962
  const abs = planFileAbs(worktreePath);
22716
- (0, import_node_fs52.mkdirSync)((0, import_node_path50.dirname)(abs), { recursive: true });
22963
+ (0, import_node_fs53.mkdirSync)((0, import_node_path52.dirname)(abs), { recursive: true });
22717
22964
  const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
22718
- (0, import_node_fs52.writeFileSync)(abs, body, "utf8");
22965
+ (0, import_node_fs53.writeFileSync)(abs, body, "utf8");
22719
22966
  return PLAN_FILE_REL;
22720
22967
  }
22721
- var import_node_fs52, import_node_path50;
22968
+ var import_node_fs53, import_node_path52;
22722
22969
  var init_plan_file = __esm({
22723
22970
  "src/plan/plan-file.ts"() {
22724
22971
  "use strict";
22725
- import_node_fs52 = require("fs");
22726
- import_node_path50 = require("path");
22972
+ import_node_fs53 = require("fs");
22973
+ import_node_path52 = require("path");
22727
22974
  init_workspace_scratch();
22728
22975
  init_plan_present();
22729
22976
  init_plan_present();
@@ -22785,9 +23032,9 @@ function recoverFinishedCursorRun(opts) {
22785
23032
  return best;
22786
23033
  }
22787
23034
  function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
22788
- if (!(0, import_node_fs53.existsSync)(runsPath)) return null;
23035
+ if (!(0, import_node_fs54.existsSync)(runsPath)) return null;
22789
23036
  try {
22790
- const lines = (0, import_node_fs53.readFileSync)(runsPath, "utf8").split("\n");
23037
+ const lines = (0, import_node_fs54.readFileSync)(runsPath, "utf8").split("\n");
22791
23038
  let best = null;
22792
23039
  for (const line of lines) {
22793
23040
  const trimmed = line.trim();
@@ -22813,11 +23060,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
22813
23060
  return null;
22814
23061
  }
22815
23062
  }
22816
- var import_node_fs53;
23063
+ var import_node_fs54;
22817
23064
  var init_cursor_recover = __esm({
22818
23065
  "src/agents/cursor-recover.ts"() {
22819
23066
  "use strict";
22820
- import_node_fs53 = require("fs");
23067
+ import_node_fs54 = require("fs");
22821
23068
  init_cursor_store();
22822
23069
  }
22823
23070
  });
@@ -22960,17 +23207,18 @@ async function startOrchestration(opts) {
22960
23207
  }
22961
23208
  return updated;
22962
23209
  }
22963
- var import_node_events, import_node_fs54, LIVE_TURN_SPAWN_GRACE_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton;
23210
+ var import_node_events, import_node_fs55, LIVE_TURN_SPAWN_GRACE_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton;
22964
23211
  var init_orchestrator = __esm({
22965
23212
  "src/orchestrator/orchestrator.ts"() {
22966
23213
  "use strict";
22967
23214
  import_node_events = require("events");
22968
23215
  init_outbound_watch();
22969
- import_node_fs54 = require("fs");
23216
+ import_node_fs55 = require("fs");
22970
23217
  init_error_detail();
22971
23218
  init_run();
22972
23219
  init_stale_lock();
22973
23220
  init_spawn();
23221
+ init_turn_trace();
22974
23222
  init_agents();
22975
23223
  init_worktree();
22976
23224
  init_stack();
@@ -23131,7 +23379,7 @@ var init_orchestrator = __esm({
23131
23379
  this.lightReconcileAt.set(repoPath, Date.now());
23132
23380
  for (const thread of listThreads()) {
23133
23381
  if (isGlobalThread(thread) || thread.repoPath !== repoPath) continue;
23134
- if (!(0, import_node_fs54.existsSync)(thread.worktreePath)) {
23382
+ if (!(0, import_node_fs55.existsSync)(thread.worktreePath)) {
23135
23383
  setStatus(thread.id, "broken", "Worktree missing on disk");
23136
23384
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
23137
23385
  }
@@ -23160,7 +23408,7 @@ var init_orchestrator = __esm({
23160
23408
  }
23161
23409
  continue;
23162
23410
  }
23163
- if (!(0, import_node_fs54.existsSync)(thread.worktreePath)) {
23411
+ if (!(0, import_node_fs55.existsSync)(thread.worktreePath)) {
23164
23412
  setStatus(thread.id, "broken", "Worktree missing on disk");
23165
23413
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
23166
23414
  continue;
@@ -23226,7 +23474,7 @@ var init_orchestrator = __esm({
23226
23474
  }
23227
23475
  if (thread.queue.length > 0) {
23228
23476
  this.haltDrain.delete(thread.id);
23229
- void this.drainQueue(thread.id);
23477
+ this.armDrain(thread.id);
23230
23478
  }
23231
23479
  }
23232
23480
  }
@@ -23562,7 +23810,7 @@ var init_orchestrator = __esm({
23562
23810
  this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
23563
23811
  }
23564
23812
  if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
23565
- void this.drainQueue(thread.id);
23813
+ this.armDrain(thread.id);
23566
23814
  }
23567
23815
  return this.requireThread(thread.id);
23568
23816
  });
@@ -23642,9 +23890,15 @@ var init_orchestrator = __esm({
23642
23890
  if (inFlight || foreignLive) {
23643
23891
  this.stop(thread.id, { clearQueue: false, continueQueue: true });
23644
23892
  }
23645
- void this.drainQueue(thread.id);
23893
+ this.armDrain(thread.id);
23646
23894
  return this.requireThread(thread.id);
23647
23895
  }
23896
+ armDrain(threadId) {
23897
+ void this.drainQueue(threadId).catch((err) => {
23898
+ const detail = err instanceof Error ? err.message : String(err);
23899
+ console.error(`[sideboard] drainQueue ${threadId}: ${detail}`);
23900
+ });
23901
+ }
23648
23902
  async drainQueue(threadId) {
23649
23903
  if (this.draining.has(threadId)) return;
23650
23904
  this.draining.add(threadId);
@@ -23716,196 +23970,205 @@ var init_orchestrator = __esm({
23716
23970
  this.emit({ type: "status_changed", threadId, status: "running" });
23717
23971
  this.emit({ type: "turn_started", threadId, prompt });
23718
23972
  try {
23719
- const baseline = await captureTurnBaseline(thread.worktreePath);
23720
- if (baseline) this.turnBaselines.set(threadId, baseline);
23721
- } catch {
23722
- }
23723
- try {
23724
- const compact = await maybeCompactContext(thread);
23725
- if (compact.didCompact) {
23726
- thread = updateThread(threadId, {
23727
- messages: compact.thread.messages,
23728
- sessionId: compact.thread.sessionId
23729
- });
23730
- this.emit({
23731
- type: "context_compacted",
23732
- threadId,
23733
- olderCount: compact.olderCount ?? 0,
23734
- method: compact.method ?? "extractive"
23735
- });
23973
+ try {
23974
+ const baseline = await captureTurnBaseline(thread.worktreePath);
23975
+ if (baseline) this.turnBaselines.set(threadId, baseline);
23976
+ } catch {
23736
23977
  }
23737
- } catch (err) {
23738
- const message = err instanceof Error ? err.message : String(err);
23739
- this.emit({ type: "error", threadId, message: `context compact failed: ${message}` });
23740
- thread = this.requireThread(threadId);
23741
- }
23742
- const autoContinue = isJobContinuePrompt(prompt) || prompt.trim().startsWith("The previous agent process ended before it finished.");
23743
- const parked = takePendingTurnAttachments(thread);
23744
- const sentAttachments = !autoContinue && parked.length > 0 ? parked : void 0;
23745
- appendMessage(threadId, {
23746
- role: "user",
23747
- text: prompt,
23748
- ...sentAttachments ? { attachments: sentAttachments } : {},
23749
- ...autoContinue ? { origin: "continue" } : {},
23750
- ts: (/* @__PURE__ */ new Date()).toISOString()
23751
- });
23752
- thread = this.requireThread(threadId);
23753
- const gitPrompt = expandCanonicalGitRequest(prompt);
23754
- const { agentPrompt: expandedPrompt } = expandComposerPrompt(
23755
- thread.worktreePath,
23756
- gitPrompt,
23757
- {
23758
- attachments: autoContinue ? [] : sentAttachments ?? []
23978
+ try {
23979
+ const compact = await maybeCompactContext(thread);
23980
+ if (compact.didCompact) {
23981
+ thread = updateThread(threadId, {
23982
+ messages: compact.thread.messages,
23983
+ sessionId: compact.thread.sessionId
23984
+ });
23985
+ this.emit({
23986
+ type: "context_compacted",
23987
+ threadId,
23988
+ olderCount: compact.olderCount ?? 0,
23989
+ method: compact.method ?? "extractive"
23990
+ });
23991
+ }
23992
+ } catch (err) {
23993
+ const message = err instanceof Error ? err.message : String(err);
23994
+ this.emit({ type: "error", threadId, message: `context compact failed: ${message}` });
23995
+ thread = this.requireThread(threadId);
23759
23996
  }
23760
- );
23761
- const slackInbound = /^(Slack DM|Slack @mention)(?:\n|$)/.test(
23762
- expandedPrompt.trim()
23763
- );
23764
- const orchestrationReminder = isOrchestratorThread(thread) ? [
23765
- coordinatorTurnReminder({
23766
- parentId: threadId,
23767
- goal: thread.sourceRef || thread.title
23768
- }),
23769
- slackInbound ? [
23770
- "This turn is a Slack DM or @mention. Your reply is posted back in Slack \u2014 keep it concise. Sideboard signs it with this Mac's destination name; do not prefix the name yourself.",
23771
- SLACK_REPLY_FORMATTING
23772
- ].join("\n") : null
23773
- ].filter(Boolean).join("\n") : null;
23774
- const artifactReminder = thread.agent !== "brightsy" ? formatUiReminder() : null;
23775
- const longRunningReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatLongRunningReminder() : null;
23776
- const worktreeReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatWorktreeReminder() : null;
23777
- const optionalServicesReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatOptionalServicesReminder(loadAppSettings().integrations) : null;
23778
- const issueTicket = issueTicketFromThread(thread, resolveEffectiveIssueSource());
23779
- const issueToolsReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatIssueToolsReminder({
23780
- linear: isLinearConnected(),
23781
- abletime: isAbleTimeConnected(),
23782
- github: true,
23783
- ticketId: issueTicket?.id,
23784
- ticketProvider: issueTicket?.provider
23785
- }) : null;
23786
- const viewerContextReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatViewerContextReminder() : null;
23787
- const reviewWriteGateReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) && isReviewWriteGatedThread(
23788
- thread,
23789
- thread.worktreePath ? threadsSharingWorktree(thread.worktreePath) : []
23790
- ) ? formatReviewWriteGateReminder() : null;
23791
- const slackReplyContext = formatSlackRepliesForTurn(
23792
- pendingSlackExternalReplies(thread.messages)
23793
- );
23794
- const turnReminders = [
23795
- worktreeReminder,
23796
- optionalServicesReminder,
23797
- issueToolsReminder,
23798
- reviewWriteGateReminder,
23799
- viewerContextReminder,
23800
- artifactReminder,
23801
- longRunningReminder
23802
- ].filter(Boolean).join("\n\n") || void 0;
23803
- const prGateDirective = thread.agent !== "brightsy" && !isOrchestratorThread(thread) && mentionsPrGoal(prompt) ? formatPrGateDirective() : null;
23804
- const agentPrompt = [
23805
- thread.planMode ? PLAN_MODE_INSTRUCTION : null,
23806
- orchestrationReminder,
23807
- prGateDirective,
23808
- slackReplyContext,
23809
- expandedPrompt
23810
- ].filter(Boolean).join("\n\n");
23811
- if (!autoContinue && sentAttachments) {
23812
- updateThread(threadId, { pendingTurnAttachments: [] });
23813
- }
23814
- const adapter = getAdapter(thread.agent);
23815
- const resolved = await adapter.resolveSessionId(thread.worktreePath, thread.sessionId);
23816
- if (resolved && resolved !== thread.sessionId) {
23817
- updateThread(threadId, { sessionId: resolved });
23818
- }
23819
- const fresh = this.requireThread(threadId);
23820
- if (!fresh.worktreePath?.trim()) {
23821
- throw new Error(
23822
- `Thread ${threadId} has no worktreePath \u2014 refusing to start an agent outside an isolated worktree`
23997
+ const promptText = typeof prompt === "string" ? prompt : "";
23998
+ const autoContinue = isJobContinuePrompt(promptText) || promptText.startsWith("The previous agent process ended before it finished.");
23999
+ const parked = takePendingTurnAttachments(thread);
24000
+ const sentAttachments = !autoContinue && parked.length > 0 ? parked : void 0;
24001
+ appendMessage(threadId, {
24002
+ role: "user",
24003
+ text: promptText,
24004
+ ...sentAttachments ? { attachments: sentAttachments } : {},
24005
+ ...autoContinue ? { origin: "continue" } : {},
24006
+ ts: (/* @__PURE__ */ new Date()).toISOString()
24007
+ });
24008
+ traceTurn("runTurn.afterUserMessage", {
24009
+ threadId,
24010
+ agent: thread.agent,
24011
+ orch: isOrchestratorThread(thread)
24012
+ });
24013
+ thread = this.requireThread(threadId);
24014
+ const gitPrompt = expandCanonicalGitRequest(promptText);
24015
+ const { agentPrompt: expandedPrompt } = expandComposerPrompt(
24016
+ thread.worktreePath,
24017
+ gitPrompt,
24018
+ {
24019
+ attachments: autoContinue ? [] : sentAttachments ?? []
24020
+ }
23823
24021
  );
23824
- }
23825
- const isBrightsy = fresh.agent === "brightsy";
23826
- const isOrchestration = isOrchestratorThread(fresh);
23827
- const { autoRenameBranchEnabled: autoRenameBranchEnabled2, getGithubGitAuthMode: getGithubGitAuthMode2, gitBranchPrefixSetting: gitBranchPrefixSetting2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
23828
- const gitAuthMode = getGithubGitAuthMode2();
23829
- const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
23830
- githubSlug: await resolveGithubRepoSlug(fresh.worktreePath).catch(
23831
- () => null
23832
- ),
23833
- gitAuthMode
23834
- });
23835
- const artifactDirective = isBrightsy ? null : formatArtifactDirective();
23836
- const longRunningDirective = isBrightsy || isOrchestration ? null : formatLongRunningDirective();
23837
- const optionalServicesDirective = isBrightsy || isOrchestration ? null : formatOptionalServicesDirective(loadAppSettings().integrations);
23838
- const freshIssueTicket = issueTicketFromThread(fresh, resolveEffectiveIssueSource());
23839
- const issueToolsDirective = isBrightsy || isOrchestration ? null : formatIssueToolsDirective({
23840
- linear: isLinearConnected(),
23841
- abletime: isAbleTimeConnected(),
23842
- github: true,
23843
- ticketId: freshIssueTicket?.id,
23844
- ticketProvider: freshIssueTicket?.provider
23845
- });
23846
- const reviewWriteGateDirective = isBrightsy || isOrchestration || !isReviewWriteGatedThread(
23847
- fresh,
23848
- fresh.worktreePath ? threadsSharingWorktree(fresh.worktreePath) : []
23849
- ) ? null : formatReviewWriteGateDirective();
23850
- let viewerContextDirective = null;
23851
- if (!isBrightsy && !isOrchestration) {
23852
- try {
23853
- viewerContextDirective = formatViewerContextDirective(
23854
- resolveViewerProfileForRepo(fresh.repoPath || fresh.worktreePath)
23855
- );
23856
- } catch {
23857
- viewerContextDirective = formatViewerContextDirective(
23858
- resolveViewerProfileForRepo()
24022
+ const slackInbound = /^(Slack DM|Slack @mention)(?:\n|$)/.test(
24023
+ expandedPrompt.trim()
24024
+ );
24025
+ const orchestrationReminder = isOrchestratorThread(thread) ? [
24026
+ coordinatorTurnReminder({
24027
+ parentId: threadId,
24028
+ goal: thread.sourceRef || thread.title
24029
+ }),
24030
+ slackInbound ? [
24031
+ "This turn is a Slack DM or @mention. Your reply is posted back in Slack \u2014 keep it concise. Sideboard signs it with this Mac's destination name; do not prefix the name yourself.",
24032
+ SLACK_REPLY_FORMATTING
24033
+ ].join("\n") : null
24034
+ ].filter(Boolean).join("\n") : null;
24035
+ const artifactReminder = thread.agent !== "brightsy" ? formatUiReminder() : null;
24036
+ const longRunningReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatLongRunningReminder() : null;
24037
+ const worktreeReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatWorktreeReminder() : null;
24038
+ const optionalServicesReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatOptionalServicesReminder(loadAppSettings().integrations) : null;
24039
+ const issueTicket = issueTicketFromThread(thread, resolveEffectiveIssueSource());
24040
+ const issueToolsReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatIssueToolsReminder({
24041
+ linear: isLinearConnected(),
24042
+ abletime: isAbleTimeConnected(),
24043
+ github: true,
24044
+ ticketId: issueTicket?.id,
24045
+ ticketProvider: issueTicket?.provider
24046
+ }) : null;
24047
+ const viewerContextReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatViewerContextReminder() : null;
24048
+ const reviewWriteGateReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) && isReviewWriteGatedThread(
24049
+ thread,
24050
+ thread.worktreePath ? threadsSharingWorktree(thread.worktreePath) : []
24051
+ ) ? formatReviewWriteGateReminder() : null;
24052
+ const slackReplyContext = formatSlackRepliesForTurn(
24053
+ pendingSlackExternalReplies(thread.messages)
24054
+ );
24055
+ const turnReminders = [
24056
+ worktreeReminder,
24057
+ optionalServicesReminder,
24058
+ issueToolsReminder,
24059
+ reviewWriteGateReminder,
24060
+ viewerContextReminder,
24061
+ artifactReminder,
24062
+ longRunningReminder
24063
+ ].filter(Boolean).join("\n\n") || void 0;
24064
+ const prGateDirective = thread.agent !== "brightsy" && !isOrchestratorThread(thread) && mentionsPrGoal(promptText) ? formatPrGateDirective() : null;
24065
+ const agentPrompt = [
24066
+ thread.planMode ? PLAN_MODE_INSTRUCTION : null,
24067
+ orchestrationReminder,
24068
+ prGateDirective,
24069
+ slackReplyContext,
24070
+ expandedPrompt
24071
+ ].filter(Boolean).join("\n\n");
24072
+ if (!autoContinue && sentAttachments) {
24073
+ updateThread(threadId, { pendingTurnAttachments: [] });
24074
+ }
24075
+ const adapter = getAdapter(thread.agent);
24076
+ const resolved = await adapter.resolveSessionId(thread.worktreePath, thread.sessionId);
24077
+ if (resolved && resolved !== thread.sessionId) {
24078
+ updateThread(threadId, { sessionId: resolved });
24079
+ }
24080
+ const fresh = this.requireThread(threadId);
24081
+ if (!fresh.worktreePath?.trim()) {
24082
+ throw new Error(
24083
+ `Thread ${threadId} has no worktreePath \u2014 refusing to start an agent outside an isolated worktree`
23859
24084
  );
23860
24085
  }
23861
- }
23862
- const settings = loadWorkspaceSettings(fresh.worktreePath, fresh.repoPath);
23863
- let renameBranchDirective = null;
23864
- if (!isBrightsy && !isOrchestration && autoRenameBranchEnabled2()) {
23865
- const { resolveGitBranchPrefix: resolveGitBranchPrefix2 } = await Promise.resolve().then(() => (init_branch_prefix(), branch_prefix_exports));
23866
- renameBranchDirective = formatRenameBranchDirective(fresh, {
23867
- customPrompt: settings?.prompts?.renameBranch,
23868
- branchPrefix: resolveGitBranchPrefix2({
23869
- setting: gitBranchPrefixSetting2()
23870
- })
24086
+ const isBrightsy = fresh.agent === "brightsy";
24087
+ const isOrchestration = isOrchestratorThread(fresh);
24088
+ const { autoRenameBranchEnabled: autoRenameBranchEnabled2, getGithubGitAuthMode: getGithubGitAuthMode2, gitBranchPrefixSetting: gitBranchPrefixSetting2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
24089
+ const gitAuthMode = getGithubGitAuthMode2();
24090
+ const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
24091
+ githubSlug: await withTimeout(
24092
+ resolveGithubRepoSlug(fresh.worktreePath),
24093
+ 8e3,
24094
+ "resolveGithubRepoSlug"
24095
+ ).catch(() => null),
24096
+ gitAuthMode
23871
24097
  });
23872
- }
23873
- let seed = null;
23874
- if (!fresh.sessionId) {
23875
- const prior = fresh.messages.slice(0, -1);
23876
- seed = isBrightsy ? buildBrightsySessionSeed(prior) : buildSessionSeed(prior);
23877
- }
23878
- let coordinatorDirective = null;
23879
- if (isOrchestration) {
23880
- if (isGlobalThread(fresh)) {
23881
- ensureGlobalCoordinatorCwd({ orchestratorThreadId: fresh.id });
24098
+ const artifactDirective = isBrightsy ? null : formatArtifactDirective();
24099
+ const longRunningDirective = isBrightsy || isOrchestration ? null : formatLongRunningDirective();
24100
+ const optionalServicesDirective = isBrightsy || isOrchestration ? null : formatOptionalServicesDirective(loadAppSettings().integrations);
24101
+ const freshIssueTicket = issueTicketFromThread(fresh, resolveEffectiveIssueSource());
24102
+ const issueToolsDirective = isBrightsy || isOrchestration ? null : formatIssueToolsDirective({
24103
+ linear: isLinearConnected(),
24104
+ abletime: isAbleTimeConnected(),
24105
+ github: true,
24106
+ ticketId: freshIssueTicket?.id,
24107
+ ticketProvider: freshIssueTicket?.provider
24108
+ });
24109
+ const reviewWriteGateDirective = isBrightsy || isOrchestration || !isReviewWriteGatedThread(
24110
+ fresh,
24111
+ fresh.worktreePath ? threadsSharingWorktree(fresh.worktreePath) : []
24112
+ ) ? null : formatReviewWriteGateDirective();
24113
+ let viewerContextDirective = null;
24114
+ if (!isBrightsy && !isOrchestration) {
24115
+ try {
24116
+ viewerContextDirective = formatViewerContextDirective(
24117
+ resolveViewerProfileForRepo(fresh.repoPath || fresh.worktreePath)
24118
+ );
24119
+ } catch {
24120
+ viewerContextDirective = formatViewerContextDirective(
24121
+ resolveViewerProfileForRepo()
24122
+ );
24123
+ }
23882
24124
  }
23883
- if (!fresh.sessionId) {
23884
- const inventory = await enrichWorkspacesWithGithub(this.listWorkspaces());
23885
- coordinatorDirective = coordinatorSystemPrompt({
23886
- goal: fresh.sourceRef || fresh.title || "Orchestration",
23887
- parentId: fresh.id,
23888
- workspaces: inventory,
23889
- audience: /^(Slack DM|Slack @mention)(?:\n|$)/.test(
23890
- expandedPrompt.trim()
23891
- ) ? "slack" : "desktop"
24125
+ const settings = loadWorkspaceSettings(fresh.worktreePath, fresh.repoPath);
24126
+ let renameBranchDirective = null;
24127
+ if (!isBrightsy && !isOrchestration && autoRenameBranchEnabled2()) {
24128
+ const { resolveGitBranchPrefix: resolveGitBranchPrefix2 } = await Promise.resolve().then(() => (init_branch_prefix(), branch_prefix_exports));
24129
+ renameBranchDirective = formatRenameBranchDirective(fresh, {
24130
+ customPrompt: settings?.prompts?.renameBranch,
24131
+ branchPrefix: resolveGitBranchPrefix2({
24132
+ setting: gitBranchPrefixSetting2()
24133
+ })
23892
24134
  });
23893
24135
  }
23894
- }
23895
- const cachedPrefix = fresh.sessionId ? "" : [
23896
- coordinatorDirective,
23897
- worktreeDirective,
23898
- optionalServicesDirective,
23899
- issueToolsDirective,
23900
- reviewWriteGateDirective,
23901
- viewerContextDirective,
23902
- artifactDirective,
23903
- longRunningDirective,
23904
- renameBranchDirective,
23905
- seed
23906
- ].filter(Boolean).join("\n\n---\n\n");
23907
- try {
24136
+ let seed = null;
24137
+ if (!fresh.sessionId) {
24138
+ const prior = fresh.messages.slice(0, -1);
24139
+ seed = isBrightsy ? buildBrightsySessionSeed(prior) : buildSessionSeed(prior);
24140
+ }
24141
+ let coordinatorDirective = null;
24142
+ if (isOrchestration) {
24143
+ if (isGlobalThread(fresh)) {
24144
+ ensureGlobalCoordinatorCwd({ orchestratorThreadId: fresh.id });
24145
+ }
24146
+ if (!fresh.sessionId) {
24147
+ const inventory = await enrichWorkspacesWithGithub(this.listWorkspaces());
24148
+ coordinatorDirective = coordinatorSystemPrompt({
24149
+ goal: fresh.sourceRef || fresh.title || "Orchestration",
24150
+ parentId: fresh.id,
24151
+ workspaces: inventory,
24152
+ audience: /^(Slack DM|Slack @mention)(?:\n|$)/.test(
24153
+ expandedPrompt.trim()
24154
+ ) ? "slack" : "desktop"
24155
+ });
24156
+ }
24157
+ }
24158
+ const cachedPrefix = fresh.sessionId ? "" : [
24159
+ coordinatorDirective,
24160
+ worktreeDirective,
24161
+ optionalServicesDirective,
24162
+ issueToolsDirective,
24163
+ reviewWriteGateDirective,
24164
+ viewerContextDirective,
24165
+ artifactDirective,
24166
+ longRunningDirective,
24167
+ renameBranchDirective,
24168
+ seed
24169
+ ].filter(Boolean).join("\n\n---\n\n");
23908
24170
  const stderrTail = [];
24171
+ traceTurn("runTurn.beforeSpawn", { threadId, agent: fresh.agent });
23909
24172
  const handle = await spawnAgentTurn(
23910
24173
  fresh,
23911
24174
  {
@@ -24705,6 +24968,18 @@ var init_orchestrator = __esm({
24705
24968
  const thread = this.requireThread(threadRef);
24706
24969
  return listWorktreeFiles(thread.worktreePath);
24707
24970
  }
24971
+ async statPath(threadRef, relativePath) {
24972
+ const thread = this.requireThread(threadRef);
24973
+ if (relativePath.includes("..") || relativePath.startsWith("/")) {
24974
+ return "missing";
24975
+ }
24976
+ if (!relativePath || relativePath === ".") return "dir";
24977
+ try {
24978
+ return statWorktreePath(thread.worktreePath, relativePath);
24979
+ } catch {
24980
+ return "missing";
24981
+ }
24982
+ }
24708
24983
  async readFile(threadRef, relativePath) {
24709
24984
  const thread = this.requireThread(threadRef);
24710
24985
  if (relativePath.includes("..") || relativePath.startsWith("/")) {
@@ -25187,7 +25462,7 @@ var init_orchestrator = __esm({
25187
25462
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
25188
25463
  return restored2;
25189
25464
  }
25190
- if (!(0, import_node_fs54.existsSync)(thread.worktreePath)) {
25465
+ if (!(0, import_node_fs55.existsSync)(thread.worktreePath)) {
25191
25466
  if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
25192
25467
  throw new Error(
25193
25468
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
@@ -25967,6 +26242,7 @@ __export(index_exports, {
25967
26242
  maxConcurrentAgents: () => maxConcurrentAgents,
25968
26243
  maybeCompactContext: () => maybeCompactContext,
25969
26244
  mcpAllowTools: () => mcpAllowTools,
26245
+ mcpAllowToolsFromNames: () => mcpAllowToolsFromNames,
25970
26246
  mcpAuthWarnings: () => mcpAuthWarnings,
25971
26247
  mcpStatusThinkingFromClaudeInit: () => mcpStatusThinkingFromClaudeInit,
25972
26248
  mentionsPrGoal: () => mentionsPrGoal,
@@ -26035,6 +26311,7 @@ __export(index_exports, {
26035
26311
  prepareTerminalCommand: () => prepareTerminalCommand,
26036
26312
  prependQueuedItem: () => prependQueuedItem,
26037
26313
  previewLand: () => previewLand,
26314
+ primaryCheckoutFromLinkedWorktree: () => primaryCheckoutFromLinkedWorktree,
26038
26315
  promptMentionsBrightsy: () => promptMentionsBrightsy,
26039
26316
  pushBranch: () => pushBranch,
26040
26317
  readExistingReviewRequestFile: () => readExistingReviewRequestFile,
@@ -26179,6 +26456,7 @@ __export(index_exports, {
26179
26456
  startOrchestration: () => startOrchestration,
26180
26457
  startSlackOAuth: () => startSlackOAuth,
26181
26458
  startSlackRelayServer: () => startSlackRelayServer,
26459
+ statWorktreePath: () => statWorktreePath,
26182
26460
  stripBrightsyNdjsonNoise: () => stripBrightsyNdjsonNoise,
26183
26461
  stripNestedElectronEnv: () => stripNestedElectronEnv,
26184
26462
  submitPrStack: () => submitPrStack,
@@ -28681,7 +28959,7 @@ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
28681
28959
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
28682
28960
  var import_zod9 = require("zod");
28683
28961
  var import_node_crypto15 = require("crypto");
28684
- var import_node_path53 = require("path");
28962
+ var import_node_path55 = require("path");
28685
28963
  init_orchestrator();
28686
28964
  init_worktree();
28687
28965
  init_global_workspace();
@@ -30401,27 +30679,27 @@ init_gh_errors();
30401
30679
  init_git_auth_mode();
30402
30680
 
30403
30681
  // src/board/load-home-board.ts
30404
- var import_node_fs56 = require("fs");
30405
- var import_node_path52 = require("path");
30682
+ var import_node_fs57 = require("fs");
30683
+ var import_node_path54 = require("path");
30406
30684
  init_worktree();
30407
30685
  init_paths();
30408
30686
 
30409
30687
  // src/board/board-pins.ts
30410
30688
  var import_node_crypto14 = require("crypto");
30411
- var import_node_fs55 = require("fs");
30412
- var import_node_path51 = require("path");
30689
+ var import_node_fs56 = require("fs");
30690
+ var import_node_path53 = require("path");
30413
30691
  init_paths();
30414
30692
  init_home_board();
30415
30693
  var FILE = "home-board-pins.json";
30416
30694
  var VERSION = 1;
30417
30695
  function pinsFile() {
30418
- return (0, import_node_path51.join)(appDataDir(), FILE);
30696
+ return (0, import_node_path53.join)(appDataDir(), FILE);
30419
30697
  }
30420
30698
  function readDisk() {
30421
30699
  const path2 = pinsFile();
30422
- if (!(0, import_node_fs55.existsSync)(path2)) return [];
30700
+ if (!(0, import_node_fs56.existsSync)(path2)) return [];
30423
30701
  try {
30424
- const raw = JSON.parse((0, import_node_fs55.readFileSync)(path2, "utf8"));
30702
+ const raw = JSON.parse((0, import_node_fs56.readFileSync)(path2, "utf8"));
30425
30703
  if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
30426
30704
  return raw.items.filter((item) => item?.id && item.kind && item.ref);
30427
30705
  } catch {
@@ -30429,8 +30707,8 @@ function readDisk() {
30429
30707
  }
30430
30708
  }
30431
30709
  function writeDisk(items) {
30432
- (0, import_node_fs55.mkdirSync)(appDataDir(), { recursive: true });
30433
- (0, import_node_fs55.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
30710
+ (0, import_node_fs56.mkdirSync)(appDataDir(), { recursive: true });
30711
+ (0, import_node_fs56.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
30434
30712
  }
30435
30713
  function listBoardPins() {
30436
30714
  return readDisk();
@@ -30482,7 +30760,7 @@ function replaceBoardPins(items) {
30482
30760
  }
30483
30761
  function clearBoardPins() {
30484
30762
  try {
30485
- (0, import_node_fs55.unlinkSync)(pinsFile());
30763
+ (0, import_node_fs56.unlinkSync)(pinsFile());
30486
30764
  } catch {
30487
30765
  }
30488
30766
  }
@@ -30499,7 +30777,7 @@ function homeBoardWorkspaceKey(workspaces) {
30499
30777
  return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
30500
30778
  }
30501
30779
  function cacheFile() {
30502
- return (0, import_node_path52.join)(appDataDir(), "home-board-cache.json");
30780
+ return (0, import_node_path54.join)(appDataDir(), "home-board-cache.json");
30503
30781
  }
30504
30782
  function emptyInputs() {
30505
30783
  return {
@@ -30525,9 +30803,9 @@ function shouldCacheHomeBoardInputs(inputs) {
30525
30803
  }
30526
30804
  function readDiskCache() {
30527
30805
  const path2 = cacheFile();
30528
- if (!(0, import_node_fs56.existsSync)(path2)) return null;
30806
+ if (!(0, import_node_fs57.existsSync)(path2)) return null;
30529
30807
  try {
30530
- const raw = JSON.parse((0, import_node_fs56.readFileSync)(path2, "utf8"));
30808
+ const raw = JSON.parse((0, import_node_fs57.readFileSync)(path2, "utf8"));
30531
30809
  if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
30532
30810
  return null;
30533
30811
  }
@@ -30541,14 +30819,14 @@ function readDiskCache() {
30541
30819
  }
30542
30820
  function writeDiskCache(entry) {
30543
30821
  try {
30544
- (0, import_node_fs56.mkdirSync)(appDataDir(), { recursive: true });
30545
- (0, import_node_fs56.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
30822
+ (0, import_node_fs57.mkdirSync)(appDataDir(), { recursive: true });
30823
+ (0, import_node_fs57.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
30546
30824
  } catch {
30547
30825
  }
30548
30826
  }
30549
30827
  function deleteDiskCache() {
30550
30828
  try {
30551
- (0, import_node_fs56.unlinkSync)(cacheFile());
30829
+ (0, import_node_fs57.unlinkSync)(cacheFile());
30552
30830
  } catch {
30553
30831
  }
30554
30832
  }
@@ -30734,7 +31012,7 @@ function orchCreateThreadAgentNote(input) {
30734
31012
  // src/mcp/server.ts
30735
31013
  var MAX_ORCH_THREADS = 5;
30736
31014
  var CREATE_THREAD_TIMEOUT_MS = 9e4;
30737
- function withTimeout(promise, ms, label) {
31015
+ function withTimeout2(promise, ms, label) {
30738
31016
  return new Promise((resolve, reject) => {
30739
31017
  const timer = setTimeout(() => {
30740
31018
  reject(new Error(`${label} timed out after ${Math.round(ms / 1e3)}s`));
@@ -30788,7 +31066,7 @@ async function createOrchChildThread(orch, args, resolveNewThreadOptions2) {
30788
31066
  const agentNote = orchCreateThreadAgentNote(opts);
30789
31067
  try {
30790
31068
  const priorIds = new Set(orch.getThreads(false).map((t) => t.id));
30791
- const thread = await withTimeout(
31069
+ const thread = await withTimeout2(
30792
31070
  orch.createThread({
30793
31071
  sourceType: args.sourceType,
30794
31072
  sourceRef: args.sourceRef,
@@ -30898,7 +31176,7 @@ async function startMcpServer() {
30898
31176
  async () => {
30899
31177
  const threads = orch.getThreads(true);
30900
31178
  const lines = threads.map((t) => {
30901
- const repo = t.repoPath === GLOBAL_WORKSPACE_ID2 ? "Orchestration" : (0, import_node_path53.basename)(t.repoPath) || t.repoPath;
31179
+ const repo = t.repoPath === GLOBAL_WORKSPACE_ID2 ? "Orchestration" : (0, import_node_path55.basename)(t.repoPath) || t.repoPath;
30902
31180
  const live = orch.threadLooksLive(t) ? readTurnLive(t.id) : null;
30903
31181
  const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
30904
31182
  const preview = lastMessagePreview(t.messages, 80);
@@ -33865,9 +34143,9 @@ var import_node_http4 = require("http");
33865
34143
  var import_ws3 = require("ws");
33866
34144
 
33867
34145
  // src/slack/relay-static.ts
33868
- var import_node_fs57 = require("fs");
34146
+ var import_node_fs58 = require("fs");
33869
34147
  var import_promises = require("fs/promises");
33870
- var import_node_path54 = __toESM(require("path"), 1);
34148
+ var import_node_path56 = __toESM(require("path"), 1);
33871
34149
  var TYPES = {
33872
34150
  ".css": "text/css; charset=utf-8",
33873
34151
  ".html": "text/html; charset=utf-8",
@@ -33898,9 +34176,9 @@ function resolveStaticPath(root, requestUrl) {
33898
34176
  return null;
33899
34177
  }
33900
34178
  if (!pathname.startsWith("/") || pathname.includes("\0")) return null;
33901
- const rootResolved = import_node_path54.default.resolve(root);
33902
- const candidate = import_node_path54.default.resolve(rootResolved, `.${pathname}`);
33903
- if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path54.default.sep)) {
34179
+ const rootResolved = import_node_path56.default.resolve(root);
34180
+ const candidate = import_node_path56.default.resolve(rootResolved, `.${pathname}`);
34181
+ if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path56.default.sep)) {
33904
34182
  return null;
33905
34183
  }
33906
34184
  return candidate;
@@ -33914,7 +34192,7 @@ async function fileSize(file) {
33914
34192
  }
33915
34193
  }
33916
34194
  function sendFile(req, res, file, size) {
33917
- const ext = import_node_path54.default.extname(file).toLowerCase();
34195
+ const ext = import_node_path56.default.extname(file).toLowerCase();
33918
34196
  res.writeHead(200, {
33919
34197
  "Content-Type": TYPES[ext] ?? "application/octet-stream",
33920
34198
  "Content-Length": size,
@@ -33924,7 +34202,7 @@ function sendFile(req, res, file, size) {
33924
34202
  res.end();
33925
34203
  return true;
33926
34204
  }
33927
- (0, import_node_fs57.createReadStream)(file).pipe(res);
34205
+ (0, import_node_fs58.createReadStream)(file).pipe(res);
33928
34206
  return true;
33929
34207
  }
33930
34208
  async function tryServeStatic(req, res, root) {
@@ -33933,7 +34211,7 @@ async function tryServeStatic(req, res, root) {
33933
34211
  if (!candidate) return false;
33934
34212
  const direct = await fileSize(candidate);
33935
34213
  if (direct != null) return sendFile(req, res, candidate, direct);
33936
- const asIndex = import_node_path54.default.join(candidate, "index.html");
34214
+ const asIndex = import_node_path56.default.join(candidate, "index.html");
33937
34215
  const indexSize = await fileSize(asIndex);
33938
34216
  if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
33939
34217
  return false;
@@ -34756,6 +35034,7 @@ init_outbound_watch();
34756
35034
  maxConcurrentAgents,
34757
35035
  maybeCompactContext,
34758
35036
  mcpAllowTools,
35037
+ mcpAllowToolsFromNames,
34759
35038
  mcpAuthWarnings,
34760
35039
  mcpStatusThinkingFromClaudeInit,
34761
35040
  mentionsPrGoal,
@@ -34824,6 +35103,7 @@ init_outbound_watch();
34824
35103
  prepareTerminalCommand,
34825
35104
  prependQueuedItem,
34826
35105
  previewLand,
35106
+ primaryCheckoutFromLinkedWorktree,
34827
35107
  promptMentionsBrightsy,
34828
35108
  pushBranch,
34829
35109
  readExistingReviewRequestFile,
@@ -34968,6 +35248,7 @@ init_outbound_watch();
34968
35248
  startOrchestration,
34969
35249
  startSlackOAuth,
34970
35250
  startSlackRelayServer,
35251
+ statWorktreePath,
34971
35252
  stripBrightsyNdjsonNoise,
34972
35253
  stripNestedElectronEnv,
34973
35254
  submitPrStack,