@sideboard-ai/core 0.1.62 → 0.1.66

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 (41) hide show
  1. package/dist/{agents-QLSFIQAO.js → agents-EWFD765A.js} +23 -7
  2. package/dist/{agents-KF3J3C53.js → agents-MD7SCFYX.js} +23 -7
  3. package/dist/{app-settings-LTSFG7QJ.js → app-settings-GJVZGU3M.js} +13 -3
  4. package/dist/{app-settings-HK4KAM4R.js → app-settings-ONKMFSEJ.js} +13 -3
  5. package/dist/{chunk-RIWUU7FO.js → chunk-5AG5BUQN.js} +61 -3
  6. package/dist/{chunk-27MAWNKY.js → chunk-AKPEXIKK.js} +2 -2
  7. package/dist/{chunk-2MCNURQV.js → chunk-BBEH2CJE.js} +264 -93
  8. package/dist/{chunk-DDN3UF4R.js → chunk-BPOTVI5J.js} +115 -3
  9. package/dist/{chunk-2FEA4LDA.js → chunk-DNPP7QMK.js} +31 -6
  10. package/dist/{chunk-MBAL5FE6.js → chunk-DZYMNW2A.js} +4 -4
  11. package/dist/{chunk-JB2H7E7V.js → chunk-EVD4KNKR.js} +1 -1
  12. package/dist/{chunk-A6FOKNOU.js → chunk-HTOTTJJX.js} +2 -2
  13. package/dist/{chunk-3KKNTHUC.js → chunk-I2KGRAXC.js} +1 -1
  14. package/dist/{chunk-ZF5YJCXO.js → chunk-IFAU2DEY.js} +269 -93
  15. package/dist/{chunk-NVU7EC2E.js → chunk-LRBRQFBU.js} +2 -2
  16. package/dist/{chunk-6CUJQKTJ.js → chunk-MHR4OGZ4.js} +115 -3
  17. package/dist/{chunk-46KMKHSD.js → chunk-PESJDZTB.js} +2 -2
  18. package/dist/{chunk-UGXSSBFJ.js → chunk-R7GUDEPY.js} +1 -1
  19. package/dist/{chunk-73AT5K4A.js → chunk-TXQ6K2GR.js} +61 -3
  20. package/dist/{chunk-DXTGDXO2.js → chunk-YTNLOJPK.js} +31 -6
  21. package/dist/{connected-teams-RSL4VB3X.js → connected-teams-CHXO5FFA.js} +2 -2
  22. package/dist/{connected-teams-MKIYKOYA.js → connected-teams-GJTESSTX.js} +2 -2
  23. package/dist/{coordinator-prompt-LKG3SHMI.js → coordinator-prompt-E5UGSJES.js} +4 -4
  24. package/dist/{coordinator-prompt-N2R6FGZK.js → coordinator-prompt-ILSULI7C.js} +4 -4
  25. package/dist/{global-workspace-LALWQWRJ.js → global-workspace-44UG64NA.js} +5 -6
  26. package/dist/{global-workspace-YOAUQCMA.js → global-workspace-5PM5LA6E.js} +5 -6
  27. package/dist/index.cjs +1308 -925
  28. package/dist/index.d.cts +92 -1
  29. package/dist/index.d.ts +92 -1
  30. package/dist/index.js +746 -715
  31. package/dist/mcp/run-stdio.cjs +1267 -976
  32. package/dist/mcp/run-stdio.js +691 -748
  33. package/dist/{run-HZTBWGQR.js → run-74S2NZWB.js} +1 -1
  34. package/dist/{run-GPSVV5OH.js → run-JLN5JK7Q.js} +1 -1
  35. package/dist/{workspaces-VCAIHVIE.js → workspaces-OVBCSS5Y.js} +6 -7
  36. package/dist/{workspaces-E75POJXP.js → workspaces-RXFXQRRF.js} +6 -7
  37. package/dist/{worktree-MV4WRW6G.js → worktree-K2JB53R5.js} +2 -2
  38. package/dist/{worktree-LZEGVQSN.js → worktree-S2N63FLV.js} +2 -2
  39. package/package.json +1 -1
  40. package/dist/chunk-GI7E5733.js +0 -30
  41. package/dist/chunk-S2LL5HA4.js +0 -33
package/dist/index.cjs CHANGED
@@ -397,6 +397,7 @@ __export(app_settings_exports, {
397
397
  autoRunAfterSetupEnabled: () => autoRunAfterSetupEnabled,
398
398
  brightsyCloudConnectAgent: () => brightsyCloudConnectAgent,
399
399
  brightsyCloudConnectEnabled: () => brightsyCloudConnectEnabled,
400
+ brightsyInjectWorktreeMcpEnabled: () => brightsyInjectWorktreeMcpEnabled,
400
401
  caffeinateWhileCloudConnectEnabled: () => caffeinateWhileCloudConnectEnabled,
401
402
  caffeinateWhileRunningEnabled: () => caffeinateWhileRunningEnabled,
402
403
  childEnvWithAppSettings: () => childEnvWithAppSettings,
@@ -415,17 +416,21 @@ __export(app_settings_exports, {
415
416
  maxConcurrentAgents: () => maxConcurrentAgents,
416
417
  orchestrationQuotaFallbackAgent: () => orchestrationQuotaFallbackAgent,
417
418
  orchestrationQuotaOnLimit: () => orchestrationQuotaOnLimit,
419
+ resolveAgentExecutable: () => resolveAgentExecutable,
418
420
  resolveClaudeExecutable: () => resolveClaudeExecutable,
419
421
  resolveEffectiveIssueSource: () => resolveEffectiveIssueSource,
420
422
  resolveNewThreadOptions: () => resolveNewThreadOptions,
421
423
  resolveThreadDefaults: () => resolveThreadDefaults,
422
424
  saveAppSettings: () => saveAppSettings,
423
425
  updateAdvancedSettings: () => updateAdvancedSettings,
426
+ updateAgentExecutable: () => updateAgentExecutable,
424
427
  updateAppEnvironment: () => updateAppEnvironment,
425
428
  updateBrightsySettings: () => updateBrightsySettings,
426
429
  updateClaudeSettings: () => updateClaudeSettings,
430
+ updateCodexSettings: () => updateCodexSettings,
427
431
  updateDefaultsSettings: () => updateDefaultsSettings,
428
- updateIntegrationsSettings: () => updateIntegrationsSettings
432
+ updateIntegrationsSettings: () => updateIntegrationsSettings,
433
+ updateOpencodeSettings: () => updateOpencodeSettings
429
434
  });
430
435
  function appSettingsPath() {
431
436
  return (0, import_node_path4.join)(appDataDir(), "settings.json");
@@ -446,16 +451,33 @@ function normalizeClaude(raw) {
446
451
  }
447
452
  return out;
448
453
  }
454
+ function normalizeCliExecutable(raw) {
455
+ if (!raw || typeof raw !== "object") return {};
456
+ const source = raw;
457
+ const out = {};
458
+ if (typeof source.executablePath === "string") {
459
+ const path = source.executablePath.trim();
460
+ if (path) out.executablePath = path;
461
+ }
462
+ return out;
463
+ }
449
464
  function normalizeBrightsy(raw) {
450
465
  if (!raw || typeof raw !== "object") return {};
451
466
  const source = raw;
452
467
  const out = {};
468
+ if (typeof source.executablePath === "string") {
469
+ const path = source.executablePath.trim();
470
+ if (path) out.executablePath = path;
471
+ }
453
472
  if (typeof source.cloudConnectEnabled === "boolean") {
454
473
  out.cloudConnectEnabled = source.cloudConnectEnabled;
455
474
  }
456
475
  if (typeof source.cloudConnectAgent === "string" && CLOUD_CONNECT_AGENTS.has(source.cloudConnectAgent)) {
457
476
  out.cloudConnectAgent = source.cloudConnectAgent;
458
477
  }
478
+ if (typeof source.injectWorktreeMcp === "boolean") {
479
+ out.injectWorktreeMcp = source.injectWorktreeMcp;
480
+ }
459
481
  return out;
460
482
  }
461
483
  function normalizeIntegrations(raw) {
@@ -541,6 +563,8 @@ function normalizeAdvanced(raw) {
541
563
  function normalizeSettings(raw) {
542
564
  const env = {};
543
565
  let claude = {};
566
+ let codex = {};
567
+ let opencode = {};
544
568
  let brightsy = {};
545
569
  let integrations = {};
546
570
  let defaults = {};
@@ -559,6 +583,12 @@ function normalizeSettings(raw) {
559
583
  if ("claude" in raw) {
560
584
  claude = normalizeClaude(raw.claude);
561
585
  }
586
+ if ("codex" in raw) {
587
+ codex = normalizeCliExecutable(raw.codex);
588
+ }
589
+ if ("opencode" in raw) {
590
+ opencode = normalizeCliExecutable(raw.opencode);
591
+ }
562
592
  if ("brightsy" in raw) {
563
593
  brightsy = normalizeBrightsy(raw.brightsy);
564
594
  }
@@ -574,7 +604,16 @@ function normalizeSettings(raw) {
574
604
  advanced = normalizeAdvanced(raw.advanced);
575
605
  }
576
606
  }
577
- return { environment: env, claude, brightsy, integrations, defaults, advanced };
607
+ return {
608
+ environment: env,
609
+ claude,
610
+ codex,
611
+ opencode,
612
+ brightsy,
613
+ integrations,
614
+ defaults,
615
+ advanced
616
+ };
578
617
  }
579
618
  function loadAppSettings() {
580
619
  const path = appSettingsPath();
@@ -627,6 +666,13 @@ function updateClaudeSettings(patch) {
627
666
  function updateBrightsySettings(patch) {
628
667
  const current = loadAppSettings();
629
668
  const brightsy = { ...current.brightsy };
669
+ if ("executablePath" in patch) {
670
+ if (patch.executablePath == null || patch.executablePath.trim() === "") {
671
+ delete brightsy.executablePath;
672
+ } else {
673
+ brightsy.executablePath = patch.executablePath.trim();
674
+ }
675
+ }
630
676
  if (typeof patch.cloudConnectEnabled === "boolean") {
631
677
  brightsy.cloudConnectEnabled = patch.cloudConnectEnabled;
632
678
  }
@@ -637,8 +683,35 @@ function updateBrightsySettings(patch) {
637
683
  brightsy.cloudConnectAgent = patch.cloudConnectAgent;
638
684
  }
639
685
  }
686
+ if (typeof patch.injectWorktreeMcp === "boolean") {
687
+ brightsy.injectWorktreeMcp = patch.injectWorktreeMcp;
688
+ }
640
689
  return saveAppSettings({ ...current, brightsy });
641
690
  }
691
+ function updateCodexSettings(patch) {
692
+ const current = loadAppSettings();
693
+ const codex = { ...current.codex };
694
+ if ("executablePath" in patch) {
695
+ if (patch.executablePath == null || patch.executablePath.trim() === "") {
696
+ delete codex.executablePath;
697
+ } else {
698
+ codex.executablePath = patch.executablePath.trim();
699
+ }
700
+ }
701
+ return saveAppSettings({ ...current, codex });
702
+ }
703
+ function updateOpencodeSettings(patch) {
704
+ const current = loadAppSettings();
705
+ const opencode = { ...current.opencode };
706
+ if ("executablePath" in patch) {
707
+ if (patch.executablePath == null || patch.executablePath.trim() === "") {
708
+ delete opencode.executablePath;
709
+ } else {
710
+ opencode.executablePath = patch.executablePath.trim();
711
+ }
712
+ }
713
+ return saveAppSettings({ ...current, opencode });
714
+ }
642
715
  function updateIntegrationsSettings(patch) {
643
716
  const current = loadAppSettings();
644
717
  const integrations = { ...current.integrations };
@@ -746,6 +819,9 @@ function getLinearApiKey(settings = loadAppSettings()) {
746
819
  function brightsyCloudConnectEnabled(settings = loadAppSettings()) {
747
820
  return Boolean(settings.brightsy.cloudConnectEnabled);
748
821
  }
822
+ function brightsyInjectWorktreeMcpEnabled(settings = loadAppSettings()) {
823
+ return Boolean(settings.brightsy.injectWorktreeMcp);
824
+ }
749
825
  function brightsyCloudConnectAgent(settings = loadAppSettings()) {
750
826
  const fallback = settings.brightsy.cloudConnectAgent && CLOUD_CONNECT_AGENTS.has(settings.brightsy.cloudConnectAgent) ? settings.brightsy.cloudConnectAgent : "claude";
751
827
  const preferred = getDefaultAgent(settings);
@@ -840,8 +916,36 @@ function maxConcurrentAgents(settings = loadAppSettings()) {
840
916
  return 3;
841
917
  }
842
918
  function resolveClaudeExecutable(settings = loadAppSettings()) {
843
- const override = settings.claude.executablePath?.trim();
844
- return override || "claude";
919
+ return resolveAgentExecutable("claude", settings);
920
+ }
921
+ function resolveAgentExecutable(agent, settings = loadAppSettings()) {
922
+ const fallback = DEFAULT_CLI_BIN[agent];
923
+ if (agent === "claude") {
924
+ const override2 = settings.claude.executablePath?.trim();
925
+ return override2 || fallback;
926
+ }
927
+ if (agent === "codex") {
928
+ const override2 = settings.codex.executablePath?.trim();
929
+ return override2 || fallback;
930
+ }
931
+ if (agent === "opencode") {
932
+ const override2 = settings.opencode.executablePath?.trim();
933
+ return override2 || fallback;
934
+ }
935
+ const override = settings.brightsy.executablePath?.trim();
936
+ return override || fallback;
937
+ }
938
+ function updateAgentExecutable(agent, executablePath) {
939
+ if (agent === "claude") {
940
+ return updateClaudeSettings({ executablePath });
941
+ }
942
+ if (agent === "codex") {
943
+ return updateCodexSettings({ executablePath });
944
+ }
945
+ if (agent === "opencode") {
946
+ return updateOpencodeSettings({ executablePath });
947
+ }
948
+ return updateBrightsySettings({ executablePath });
845
949
  }
846
950
  function claudeChromeEnabled(settings = loadAppSettings()) {
847
951
  return Boolean(settings.claude.chromeEnabled);
@@ -869,7 +973,7 @@ function childEnvWithAppSettings(extra) {
869
973
  function harnessEnvKey(harness) {
870
974
  return HARNESS_ENV_KEYS[harness];
871
975
  }
872
- var import_node_fs3, import_node_os3, import_node_path4, HARNESS_ENV_KEYS, DEFAULT_AGENTS, CLOUD_CONNECT_AGENTS, ISSUE_SOURCES, EMPTY_SETTINGS;
976
+ var import_node_fs3, import_node_os3, import_node_path4, HARNESS_ENV_KEYS, DEFAULT_AGENTS, CLOUD_CONNECT_AGENTS, ISSUE_SOURCES, EMPTY_SETTINGS, DEFAULT_CLI_BIN;
873
977
  var init_app_settings = __esm({
874
978
  "src/store/app-settings.ts"() {
875
979
  "use strict";
@@ -902,11 +1006,19 @@ var init_app_settings = __esm({
902
1006
  EMPTY_SETTINGS = {
903
1007
  environment: {},
904
1008
  claude: {},
1009
+ codex: {},
1010
+ opencode: {},
905
1011
  brightsy: {},
906
1012
  integrations: {},
907
1013
  defaults: {},
908
1014
  advanced: {}
909
1015
  };
1016
+ DEFAULT_CLI_BIN = {
1017
+ claude: "claude",
1018
+ codex: "codex",
1019
+ opencode: "opencode",
1020
+ brightsy: "brightsy"
1021
+ };
910
1022
  }
911
1023
  });
912
1024
 
@@ -2041,18 +2153,28 @@ var init_gh_errors = __esm({
2041
2153
  });
2042
2154
 
2043
2155
  // src/agents/path.ts
2156
+ function prependPathDir(env, dir) {
2157
+ if (!dir || !(0, import_node_fs5.existsSync)(dir)) return;
2158
+ const current = env.PATH ?? "";
2159
+ const parts = current.split(import_node_path5.delimiter).filter(Boolean);
2160
+ if (parts.includes(dir)) {
2161
+ env.PATH = current;
2162
+ return;
2163
+ }
2164
+ env.PATH = [dir, ...parts].join(import_node_path5.delimiter);
2165
+ }
2044
2166
  function ensureAgentPath(env = process.env) {
2045
2167
  const home = env.HOME || env.USERPROFILE || (0, import_node_os4.homedir)();
2046
2168
  const current = env.PATH ?? "";
2047
2169
  const parts = current.split(import_node_path5.delimiter).filter(Boolean);
2048
2170
  const seen = new Set(parts);
2049
2171
  const extras = [
2050
- ...EXTRA_BIN_DIRS.map((rel) => `${home}/${rel}`),
2172
+ ...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path5.join)(home, rel)),
2051
2173
  "/opt/homebrew/bin",
2052
2174
  "/usr/local/bin"
2053
2175
  ];
2054
2176
  for (const dir of extras.reverse()) {
2055
- if (!dir || seen.has(dir)) continue;
2177
+ if (!dir || seen.has(dir) || !(0, import_node_fs5.existsSync)(dir)) continue;
2056
2178
  parts.unshift(dir);
2057
2179
  seen.add(dir);
2058
2180
  }
@@ -2060,10 +2182,50 @@ function ensureAgentPath(env = process.env) {
2060
2182
  env.PATH = next;
2061
2183
  return next;
2062
2184
  }
2063
- var import_node_os4, import_node_path5, EXTRA_BIN_DIRS;
2185
+ function enrichPathWithNpmGlobalBin(env = process.env) {
2186
+ ensureAgentPath(env);
2187
+ try {
2188
+ const prefix = (0, import_node_child_process.execFileSync)("npm", ["prefix", "-g"], {
2189
+ encoding: "utf8",
2190
+ env: { ...process.env, ...env },
2191
+ timeout: 8e3,
2192
+ stdio: ["ignore", "pipe", "ignore"]
2193
+ }).trim().split(/\r?\n/).find(Boolean);
2194
+ if (prefix) {
2195
+ const binDir = process.platform === "win32" ? prefix : (0, import_node_path5.join)(prefix, "bin");
2196
+ prependPathDir(env, binDir);
2197
+ }
2198
+ } catch {
2199
+ }
2200
+ return env.PATH ?? "";
2201
+ }
2202
+ function posixShellSingleQuote(value) {
2203
+ return `'${value.replace(/'/g, `'\\''`)}'`;
2204
+ }
2205
+ function resolveCommandBinarySync(command, whichPath) {
2206
+ const trimmed = command.trim();
2207
+ if (!trimmed) return trimmed;
2208
+ const match = /^(\S+)(\s[\s\S]*)?$/.exec(trimmed);
2209
+ if (!match) return trimmed;
2210
+ const bin = match[1];
2211
+ const rest = match[2] ?? "";
2212
+ if (bin.includes("/") || bin.includes("\\")) return trimmed;
2213
+ const abs = whichPath?.trim().split(/\r?\n/).find(Boolean);
2214
+ if (!abs) return trimmed;
2215
+ return `${abs}${rest}`;
2216
+ }
2217
+ function withExportedPath(command, pathValue) {
2218
+ const trimmed = command.trim();
2219
+ if (!trimmed) return trimmed;
2220
+ if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
2221
+ return `export PATH=${posixShellSingleQuote(pathValue)}; ${trimmed}`;
2222
+ }
2223
+ var import_node_fs5, import_node_child_process, import_node_os4, import_node_path5, EXTRA_BIN_DIRS;
2064
2224
  var init_path = __esm({
2065
2225
  "src/agents/path.ts"() {
2066
2226
  "use strict";
2227
+ import_node_fs5 = require("fs");
2228
+ import_node_child_process = require("child_process");
2067
2229
  import_node_os4 = require("os");
2068
2230
  import_node_path5 = require("path");
2069
2231
  EXTRA_BIN_DIRS = [
@@ -2071,6 +2233,10 @@ var init_path = __esm({
2071
2233
  ".cargo/bin",
2072
2234
  ".nvm/current/bin",
2073
2235
  ".asdf/shims",
2236
+ ".volta/bin",
2237
+ ".npm-global/bin",
2238
+ // fnm default alias (common when shell init is skipped)
2239
+ ".local/share/fnm/aliases/default/bin",
2074
2240
  // pnpm / npm global bins (where `@brightsy/cli` typically lands)
2075
2241
  "Library/pnpm",
2076
2242
  ".pnpm"
@@ -3158,7 +3324,7 @@ function isLocalPrFetchBranch(ref) {
3158
3324
  async function createThreadWorktree(opts) {
3159
3325
  let branchName = `thread/${opts.slug}`;
3160
3326
  const worktreePath = (0, import_node_path6.join)(worktreesRoot(opts.repoPath), opts.slug);
3161
- if ((0, import_node_fs5.existsSync)(worktreePath)) {
3327
+ if ((0, import_node_fs6.existsSync)(worktreePath)) {
3162
3328
  throw new Error(`Worktree already exists at ${worktreePath}`);
3163
3329
  }
3164
3330
  await ensureGhPreferOrigin(opts.repoPath);
@@ -3228,7 +3394,7 @@ async function createExistingBranchWorktree(opts) {
3228
3394
  const branchName = opts.branchName.trim();
3229
3395
  if (!branchName) throw new Error("branch name required");
3230
3396
  const worktreePath = (0, import_node_path6.join)(worktreesRoot(opts.repoPath), opts.slug);
3231
- if ((0, import_node_fs5.existsSync)(worktreePath)) {
3397
+ if ((0, import_node_fs6.existsSync)(worktreePath)) {
3232
3398
  throw new Error(`Worktree already exists at ${worktreePath}`);
3233
3399
  }
3234
3400
  await ensureGhPreferOrigin(opts.repoPath);
@@ -3489,9 +3655,9 @@ function sameRepoPath(a, b) {
3489
3655
  }
3490
3656
  function listLocalThreadBranchSlugs(repoPath) {
3491
3657
  const refsDir = (0, import_node_path6.join)(repoPath, ".git", "refs", "heads", "thread");
3492
- if (!(0, import_node_fs5.existsSync)(refsDir)) return [];
3658
+ if (!(0, import_node_fs6.existsSync)(refsDir)) return [];
3493
3659
  try {
3494
- return (0, import_node_fs5.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
3660
+ return (0, import_node_fs6.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
3495
3661
  } catch {
3496
3662
  return [];
3497
3663
  }
@@ -3499,8 +3665,8 @@ function listLocalThreadBranchSlugs(repoPath) {
3499
3665
  function collectTakenTeamSlugs(repoPath) {
3500
3666
  const taken = /* @__PURE__ */ new Set();
3501
3667
  const root = worktreesRoot(repoPath);
3502
- if ((0, import_node_fs5.existsSync)(root)) {
3503
- for (const entry of (0, import_node_fs5.readdirSync)(root, { withFileTypes: true })) {
3668
+ if ((0, import_node_fs6.existsSync)(root)) {
3669
+ for (const entry of (0, import_node_fs6.readdirSync)(root, { withFileTypes: true })) {
3504
3670
  if (entry.isDirectory() && entry.name !== ".DS_Store") {
3505
3671
  taken.add(normalizeTakenSlug(entry.name));
3506
3672
  }
@@ -3522,16 +3688,16 @@ function allocateTeamSlug(repoPath) {
3522
3688
  for (let attempt = 0; attempt < 32; attempt++) {
3523
3689
  const team = allocateTeamName(taken);
3524
3690
  const path = (0, import_node_path6.join)(worktreesRoot(repoPath), team.slug);
3525
- if (!(0, import_node_fs5.existsSync)(path)) return team;
3691
+ if (!(0, import_node_fs6.existsSync)(path)) return team;
3526
3692
  taken.add(team.slug);
3527
3693
  }
3528
3694
  throw new Error("No available soccer team worktree directories left");
3529
3695
  }
3530
- var import_node_fs5, import_node_path6;
3696
+ var import_node_fs6, import_node_path6;
3531
3697
  var init_worktree = __esm({
3532
3698
  "src/git/worktree.ts"() {
3533
3699
  "use strict";
3534
- import_node_fs5 = require("fs");
3700
+ import_node_fs6 = require("fs");
3535
3701
  import_node_path6 = require("path");
3536
3702
  init_paths();
3537
3703
  init_thread_store();
@@ -3611,7 +3777,7 @@ function coordinatorTurnReminder(opts) {
3611
3777
  function ensureGlobalCoordinatorCwd(opts) {
3612
3778
  const dir = globalAgentCwd();
3613
3779
  try {
3614
- (0, import_node_fs6.mkdirSync)(dir, { recursive: true });
3780
+ (0, import_node_fs7.mkdirSync)(dir, { recursive: true });
3615
3781
  } catch {
3616
3782
  return dir;
3617
3783
  }
@@ -3619,7 +3785,7 @@ function ensureGlobalCoordinatorCwd(opts) {
3619
3785
  let orchId = opts?.orchestratorThreadId?.trim() || "";
3620
3786
  if (!orchId) {
3621
3787
  try {
3622
- const existing = (0, import_node_fs6.readFileSync)((0, import_node_path7.join)(dir, "AGENTS.md"), "utf8");
3788
+ const existing = (0, import_node_fs7.readFileSync)((0, import_node_path7.join)(dir, "AGENTS.md"), "utf8");
3623
3789
  const m = existing.match(
3624
3790
  /YOUR orchestration thread id is `([0-9a-f-]{36})`/i
3625
3791
  );
@@ -3661,9 +3827,9 @@ function ensureGlobalCoordinatorCwd(opts) {
3661
3827
  "Always ask worktree agents to open draft PRs (`send_to_thread` + `gh pr create --draft -R <origin>`); never open PRs from the orchestrator."
3662
3828
  ].join("\n");
3663
3829
  try {
3664
- (0, import_node_fs6.writeFileSync)((0, import_node_path7.join)(dir, "CLAUDE.md"), `${body}
3830
+ (0, import_node_fs7.writeFileSync)((0, import_node_path7.join)(dir, "CLAUDE.md"), `${body}
3665
3831
  `, "utf8");
3666
- (0, import_node_fs6.writeFileSync)((0, import_node_path7.join)(dir, "AGENTS.md"), `${body}
3832
+ (0, import_node_fs7.writeFileSync)((0, import_node_path7.join)(dir, "AGENTS.md"), `${body}
3667
3833
  `, "utf8");
3668
3834
  } catch {
3669
3835
  }
@@ -3696,11 +3862,11 @@ function coordinatorSystemPrompt(opts) {
3696
3862
  formatWorkspaceInventory(opts.workspaces)
3697
3863
  ].join("\n");
3698
3864
  }
3699
- var import_node_fs6, import_node_path7, COORDINATOR_TOOL_PLAYBOOK;
3865
+ var import_node_fs7, import_node_path7, COORDINATOR_TOOL_PLAYBOOK;
3700
3866
  var init_coordinator_prompt = __esm({
3701
3867
  "src/orchestrator/coordinator-prompt.ts"() {
3702
3868
  "use strict";
3703
- import_node_fs6 = require("fs");
3869
+ import_node_fs7 = require("fs");
3704
3870
  import_node_path7 = require("path");
3705
3871
  init_worktree();
3706
3872
  init_app_settings();
@@ -3937,31 +4103,31 @@ function removedWorkspacesFile() {
3937
4103
  }
3938
4104
  function readAll() {
3939
4105
  const path = workspacesFile();
3940
- if (!(0, import_node_fs7.existsSync)(path)) return [];
4106
+ if (!(0, import_node_fs8.existsSync)(path)) return [];
3941
4107
  try {
3942
- const raw = JSON.parse((0, import_node_fs7.readFileSync)(path, "utf8"));
4108
+ const raw = JSON.parse((0, import_node_fs8.readFileSync)(path, "utf8"));
3943
4109
  return Array.isArray(raw) ? raw : [];
3944
4110
  } catch {
3945
4111
  return [];
3946
4112
  }
3947
4113
  }
3948
4114
  function writeAll(list) {
3949
- (0, import_node_fs7.mkdirSync)(appDataDir(), { recursive: true });
3950
- (0, import_node_fs7.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
4115
+ (0, import_node_fs8.mkdirSync)(appDataDir(), { recursive: true });
4116
+ (0, import_node_fs8.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
3951
4117
  }
3952
4118
  function readRemoved() {
3953
4119
  const path = removedWorkspacesFile();
3954
- if (!(0, import_node_fs7.existsSync)(path)) return /* @__PURE__ */ new Set();
4120
+ if (!(0, import_node_fs8.existsSync)(path)) return /* @__PURE__ */ new Set();
3955
4121
  try {
3956
- const raw = JSON.parse((0, import_node_fs7.readFileSync)(path, "utf8"));
4122
+ const raw = JSON.parse((0, import_node_fs8.readFileSync)(path, "utf8"));
3957
4123
  return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
3958
4124
  } catch {
3959
4125
  return /* @__PURE__ */ new Set();
3960
4126
  }
3961
4127
  }
3962
4128
  function writeRemoved(paths) {
3963
- (0, import_node_fs7.mkdirSync)(appDataDir(), { recursive: true });
3964
- (0, import_node_fs7.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
4129
+ (0, import_node_fs8.mkdirSync)(appDataDir(), { recursive: true });
4130
+ (0, import_node_fs8.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
3965
4131
  }
3966
4132
  function rememberRemoved(repoPath) {
3967
4133
  const next = readRemoved();
@@ -3984,7 +4150,7 @@ function listWorkspaces() {
3984
4150
  async function addWorkspace(repoPath) {
3985
4151
  const root = await resolveRepoRoot(repoPath);
3986
4152
  if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
3987
- if (!(0, import_node_fs7.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
4153
+ if (!(0, import_node_fs8.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
3988
4154
  forgetRemoved(root);
3989
4155
  await ensureGhPreferOrigin(root);
3990
4156
  const current = readAll();
@@ -4014,7 +4180,7 @@ function syncWorkspacesFromThreads(repoPaths) {
4014
4180
  if (!path || path === "/" || isGlobalRepoPath(path) || byPath.has(path) || removed.has(path)) {
4015
4181
  continue;
4016
4182
  }
4017
- if (!(0, import_node_fs7.existsSync)(path)) continue;
4183
+ if (!(0, import_node_fs8.existsSync)(path)) continue;
4018
4184
  const ws = {
4019
4185
  path,
4020
4186
  name: (0, import_node_path8.basename)(path),
@@ -4027,11 +4193,11 @@ function syncWorkspacesFromThreads(repoPaths) {
4027
4193
  if (dirty) writeAll(next);
4028
4194
  return next.sort((a, b) => a.name.localeCompare(b.name));
4029
4195
  }
4030
- var import_node_fs7, import_node_path8;
4196
+ var import_node_fs8, import_node_path8;
4031
4197
  var init_workspaces = __esm({
4032
4198
  "src/store/workspaces.ts"() {
4033
4199
  "use strict";
4034
- import_node_fs7 = require("fs");
4200
+ import_node_fs8 = require("fs");
4035
4201
  import_node_path8 = require("path");
4036
4202
  init_paths();
4037
4203
  init_global_workspace();
@@ -4045,26 +4211,26 @@ function brightsyConfigPath() {
4045
4211
  }
4046
4212
  function loadBrightsyConfig() {
4047
4213
  const path = brightsyConfigPath();
4048
- if (!(0, import_node_fs8.existsSync)(path)) {
4214
+ if (!(0, import_node_fs9.existsSync)(path)) {
4049
4215
  throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
4050
4216
  }
4051
- const raw = JSON.parse((0, import_node_fs8.readFileSync)(path, "utf8"));
4217
+ const raw = JSON.parse((0, import_node_fs9.readFileSync)(path, "utf8"));
4052
4218
  if (!raw.access_token || !raw.account_id) {
4053
4219
  throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
4054
4220
  }
4055
4221
  return raw;
4056
4222
  }
4057
4223
  function saveBrightsyConfig(cfg) {
4058
- (0, import_node_fs8.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
4224
+ (0, import_node_fs9.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
4059
4225
  `, {
4060
4226
  mode: 384
4061
4227
  });
4062
4228
  }
4063
- var import_node_fs8, import_node_os5, import_node_path9;
4229
+ var import_node_fs9, import_node_os5, import_node_path9;
4064
4230
  var init_config = __esm({
4065
4231
  "src/brightsy/config.ts"() {
4066
4232
  "use strict";
4067
- import_node_fs8 = require("fs");
4233
+ import_node_fs9 = require("fs");
4068
4234
  import_node_os5 = require("os");
4069
4235
  import_node_path9 = require("path");
4070
4236
  }
@@ -4173,18 +4339,18 @@ function storePath() {
4173
4339
  }
4174
4340
  function readStore() {
4175
4341
  const path = storePath();
4176
- if (!(0, import_node_fs9.existsSync)(path)) return [];
4342
+ if (!(0, import_node_fs10.existsSync)(path)) return [];
4177
4343
  try {
4178
- const parsed = JSON.parse((0, import_node_fs9.readFileSync)(path, "utf8"));
4344
+ const parsed = JSON.parse((0, import_node_fs10.readFileSync)(path, "utf8"));
4179
4345
  return Array.isArray(parsed.teams) ? parsed.teams : [];
4180
4346
  } catch {
4181
4347
  return [];
4182
4348
  }
4183
4349
  }
4184
4350
  function writeStore(teams) {
4185
- (0, import_node_fs9.mkdirSync)(appDataDir(), { recursive: true });
4351
+ (0, import_node_fs10.mkdirSync)(appDataDir(), { recursive: true });
4186
4352
  const path = storePath();
4187
- (0, import_node_fs9.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
4353
+ (0, import_node_fs10.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
4188
4354
  `, {
4189
4355
  mode: 384
4190
4356
  });
@@ -4346,11 +4512,11 @@ function brightsyMcpServerName(slug) {
4346
4512
  const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
4347
4513
  return `brightsy_${cleaned || "team"}`;
4348
4514
  }
4349
- var import_node_fs9, import_node_path10;
4515
+ var import_node_fs10, import_node_path10;
4350
4516
  var init_connected_teams = __esm({
4351
4517
  "src/brightsy/connected-teams.ts"() {
4352
4518
  "use strict";
4353
- import_node_fs9 = require("fs");
4519
+ import_node_fs10 = require("fs");
4354
4520
  import_node_path10 = require("path");
4355
4521
  init_paths();
4356
4522
  init_accounts();
@@ -4525,6 +4691,11 @@ function normalizeTurnInput(input) {
4525
4691
  if (typeof input === "string") return { prompt: input };
4526
4692
  return { prompt: input.prompt, cachedPrefix: input.cachedPrefix?.trim() || void 0 };
4527
4693
  }
4694
+ function dropCachedPrefixOnResume(input, sessionId) {
4695
+ const turn = normalizeTurnInput(input);
4696
+ if (sessionId) return { prompt: turn.prompt };
4697
+ return turn;
4698
+ }
4528
4699
  function flattenTurnInput(input) {
4529
4700
  const { cachedPrefix, prompt } = normalizeTurnInput(input);
4530
4701
  if (!cachedPrefix) return prompt;
@@ -4713,9 +4884,13 @@ async function fetchTeamChatTargets(team) {
4713
4884
  };
4714
4885
  }
4715
4886
  async function listBrightsyChatTargetsViaCli() {
4716
- const listed = await run("brightsy", ["chat", "--list-targets", "--json"], {
4717
- reject: false
4718
- });
4887
+ const listed = await run(
4888
+ resolveAgentExecutable("brightsy"),
4889
+ ["chat", "--list-targets", "--json"],
4890
+ {
4891
+ reject: false
4892
+ }
4893
+ );
4719
4894
  if (listed.exitCode !== 0 || !listed.stdout.trim()) {
4720
4895
  throw new Error(
4721
4896
  listed.stderr.trim() || "Failed to list Brightsy chat targets \u2014 is `brightsy` installed and logged in?"
@@ -4799,13 +4974,15 @@ async function syncCliForTarget(accountId) {
4799
4974
  }
4800
4975
  applyConnectedTeamToCli(team);
4801
4976
  }
4802
- var brightsyAdapter;
4977
+ var import_node_fs11, brightsyAdapter;
4803
4978
  var init_brightsy = __esm({
4804
4979
  "src/agents/brightsy.ts"() {
4805
4980
  "use strict";
4981
+ import_node_fs11 = require("fs");
4806
4982
  init_run();
4807
4983
  init_connected_teams();
4808
4984
  init_config();
4985
+ init_app_settings();
4809
4986
  init_brightsy_targets();
4810
4987
  init_error_detail();
4811
4988
  init_turn_input();
@@ -4813,18 +4990,32 @@ var init_brightsy = __esm({
4813
4990
  brightsyAdapter = {
4814
4991
  kind: "brightsy",
4815
4992
  async detect() {
4816
- const which = await run("which", ["brightsy"], { reject: false });
4817
- if (which.exitCode !== 0) {
4818
- return {
4819
- agent: "brightsy",
4820
- installed: false,
4821
- authenticated: false,
4822
- linearMcp: false,
4823
- warnings: [],
4824
- reason: "brightsy CLI not found on PATH \u2014 npm i -g @brightsy/cli"
4825
- };
4993
+ const brightsy = resolveAgentExecutable("brightsy");
4994
+ if (brightsy !== "brightsy") {
4995
+ if (!(0, import_node_fs11.existsSync)(brightsy)) {
4996
+ return {
4997
+ agent: "brightsy",
4998
+ installed: false,
4999
+ authenticated: false,
5000
+ linearMcp: false,
5001
+ warnings: [],
5002
+ reason: `Brightsy executable not found: ${brightsy}`
5003
+ };
5004
+ }
5005
+ } else {
5006
+ const which = await run("which", ["brightsy"], { reject: false });
5007
+ if (which.exitCode !== 0) {
5008
+ return {
5009
+ agent: "brightsy",
5010
+ installed: false,
5011
+ authenticated: false,
5012
+ linearMcp: false,
5013
+ warnings: [],
5014
+ reason: "brightsy CLI not found on PATH \u2014 npm i -g @brightsy/cli"
5015
+ };
5016
+ }
4826
5017
  }
4827
- const who = await run("brightsy", ["whoami"], { reject: false });
5018
+ const who = await run(brightsy, ["whoami"], { reject: false });
4828
5019
  const authenticated = who.exitCode === 0 && /logged in as/i.test(who.stdout);
4829
5020
  return {
4830
5021
  agent: "brightsy",
@@ -4849,7 +5040,7 @@ var init_brightsy = __esm({
4849
5040
  target.id
4850
5041
  ];
4851
5042
  return {
4852
- file: "brightsy",
5043
+ file: resolveAgentExecutable("brightsy"),
4853
5044
  args,
4854
5045
  cwd: thread.worktreePath,
4855
5046
  // Piped stdin becomes the message body (avoids ARG_MAX for long seeds).
@@ -4866,7 +5057,11 @@ var init_brightsy = __esm({
4866
5057
  const target = decodeBrightsyTarget(thread.model);
4867
5058
  await syncCliForTarget(target.accountId);
4868
5059
  const args = target.type === "model" ? ["chat", "--model", target.id] : ["chat", "--agent", target.id];
4869
- return { file: "brightsy", args, cwd: thread.worktreePath };
5060
+ return {
5061
+ file: resolveAgentExecutable("brightsy"),
5062
+ args,
5063
+ cwd: thread.worktreePath
5064
+ };
4870
5065
  }
4871
5066
  };
4872
5067
  }
@@ -4918,6 +5113,18 @@ var init_claude_mcp = __esm({
4918
5113
  }
4919
5114
  });
4920
5115
 
5116
+ // src/mcp/profile.ts
5117
+ function sideboardMcpProfile(env = process.env) {
5118
+ return env[SIDEBOARD_MCP_PROFILE_ENV]?.trim().toLowerCase() === "worktree" ? "worktree" : "orchestration";
5119
+ }
5120
+ var SIDEBOARD_MCP_PROFILE_ENV;
5121
+ var init_profile = __esm({
5122
+ "src/mcp/profile.ts"() {
5123
+ "use strict";
5124
+ SIDEBOARD_MCP_PROFILE_ENV = "SIDEBOARD_MCP_PROFILE";
5125
+ }
5126
+ });
5127
+
4921
5128
  // src/agents/node-launch.ts
4922
5129
  function isAsarPath(filePath) {
4923
5130
  return /\.asar([/\\]|$)/.test(filePath);
@@ -4965,6 +5172,38 @@ function isBrightsyConnected() {
4965
5172
  return false;
4966
5173
  }
4967
5174
  }
5175
+ function promptMentionsBrightsy(text) {
5176
+ return BRIGHTSY_WORD.test(text ?? "");
5177
+ }
5178
+ function isBrightsyMcpToolName(name) {
5179
+ const n = name.toLowerCase();
5180
+ return n === "brightsy" || n.startsWith("mcp__brightsy") || n.startsWith("brightsy_");
5181
+ }
5182
+ function toolInputUsesBrightsyDatasource(input) {
5183
+ const ds = input?.datasource;
5184
+ return typeof ds === "string" && ds.toLowerCase() === "brightsy";
5185
+ }
5186
+ function messageUsedBrightsyMcp(msg) {
5187
+ if (msg.role === "user" && promptMentionsBrightsy(msg.text)) return true;
5188
+ for (const part of msg.parts ?? []) {
5189
+ if (part.type !== "tool") continue;
5190
+ if (isBrightsyMcpToolName(part.name)) return true;
5191
+ if (/present_(schema|files)$/i.test(part.name) && toolInputUsesBrightsyDatasource(part.input)) {
5192
+ return true;
5193
+ }
5194
+ }
5195
+ return false;
5196
+ }
5197
+ function threadRequestsBrightsyMcp(thread) {
5198
+ return (thread?.messages ?? []).some(messageUsedBrightsyMcp);
5199
+ }
5200
+ function shouldInjectBrightsyMcp(thread, opts) {
5201
+ if (!(opts?.connected ?? isBrightsyConnected())) return false;
5202
+ if (opts?.orchestrator) return true;
5203
+ const alwaysOn = opts?.alwaysOnWorktree ?? Boolean(loadAppSettings().brightsy?.injectWorktreeMcp);
5204
+ if (alwaysOn) return true;
5205
+ return threadRequestsBrightsyMcp(thread);
5206
+ }
4968
5207
  function mcpLaunch(cmd, name, env) {
4969
5208
  if (cmd === "brightsy-mcp") {
4970
5209
  return { name, command: "brightsy-mcp", ...env ? { env } : {} };
@@ -5010,7 +5249,7 @@ function corePackageDir() {
5010
5249
  }
5011
5250
  function findSideboardMcpJsEntry() {
5012
5251
  const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
5013
- if (override && (0, import_node_fs10.existsSync)(override)) return override;
5252
+ if (override && (0, import_node_fs12.existsSync)(override)) return override;
5014
5253
  let dir = corePackageDir();
5015
5254
  for (let i = 0; i < 10; i++) {
5016
5255
  const candidates = [
@@ -5023,7 +5262,7 @@ function findSideboardMcpJsEntry() {
5023
5262
  (0, import_node_path11.join)(dir, "cli/dist/index.js")
5024
5263
  ];
5025
5264
  for (const p of candidates) {
5026
- if ((0, import_node_fs10.existsSync)(p)) return p;
5265
+ if ((0, import_node_fs12.existsSync)(p)) return p;
5027
5266
  }
5028
5267
  const parent = (0, import_node_path11.dirname)(dir);
5029
5268
  if (parent === dir) break;
@@ -5054,11 +5293,13 @@ async function buildInjectedMcpServers(opts) {
5054
5293
  const servers = [];
5055
5294
  if (opts.includeSideboard) {
5056
5295
  const sideboard = await resolveSideboardMcpServer();
5296
+ const orchId = opts.orchestratorThreadId?.trim();
5297
+ const profile = orchId ? "orchestration" : "worktree";
5057
5298
  sideboard.env = {
5058
5299
  ...sideboard.env ?? {},
5059
- SIDEBOARD_APP_DATA: appDataDir()
5300
+ SIDEBOARD_APP_DATA: appDataDir(),
5301
+ [SIDEBOARD_MCP_PROFILE_ENV]: profile
5060
5302
  };
5061
- const orchId = opts.orchestratorThreadId?.trim();
5062
5303
  if (orchId) {
5063
5304
  sideboard.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID = orchId;
5064
5305
  }
@@ -5133,19 +5374,19 @@ function writeMcpServersConfig(servers) {
5133
5374
  ...s.env ? { env: s.env } : {}
5134
5375
  };
5135
5376
  }
5136
- const dir = (0, import_node_fs10.mkdtempSync)((0, import_node_path11.join)((0, import_node_os6.tmpdir)(), "sideboard-mcp-"));
5377
+ const dir = (0, import_node_fs12.mkdtempSync)((0, import_node_path11.join)((0, import_node_os6.tmpdir)(), "sideboard-mcp-"));
5137
5378
  const cfgPath = (0, import_node_path11.join)(dir, "mcp.json");
5138
- (0, import_node_fs10.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
5379
+ (0, import_node_fs12.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
5139
5380
  return cfgPath;
5140
5381
  }
5141
5382
  async function writeInjectedMcpConfig(opts) {
5142
5383
  return writeMcpServersConfig(await buildInjectedMcpServers(opts));
5143
5384
  }
5144
- var import_node_fs10, import_node_module, import_node_os6, import_node_path11, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, BRIGHTSY_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache;
5385
+ var import_node_fs12, import_node_module, import_node_os6, import_node_path11, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, BRIGHTSY_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
5145
5386
  var init_injected_mcp = __esm({
5146
5387
  "src/agents/injected-mcp.ts"() {
5147
5388
  "use strict";
5148
- import_node_fs10 = require("fs");
5389
+ import_node_fs12 = require("fs");
5149
5390
  import_node_module = require("module");
5150
5391
  import_node_os6 = require("os");
5151
5392
  import_node_path11 = require("path");
@@ -5153,6 +5394,8 @@ var init_injected_mcp = __esm({
5153
5394
  init_run();
5154
5395
  init_config();
5155
5396
  init_connected_teams();
5397
+ init_profile();
5398
+ init_app_settings();
5156
5399
  init_paths();
5157
5400
  init_node_launch();
5158
5401
  import_meta = {};
@@ -5172,6 +5415,7 @@ var init_injected_mcp = __esm({
5172
5415
  "mcp__brightsy__*"
5173
5416
  ];
5174
5417
  brightsyMcpCommandCache = null;
5418
+ BRIGHTSY_WORD = /(?<![a-z0-9_-])brightsy(?![a-z0-9_-])/i;
5175
5419
  }
5176
5420
  });
5177
5421
 
@@ -5326,11 +5570,11 @@ function parseIssuesJson(raw) {
5326
5570
  }
5327
5571
  return [];
5328
5572
  }
5329
- var import_node_fs11, BASE_ALLOWED_TOOLS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
5573
+ var import_node_fs13, BASE_ALLOWED_TOOLS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
5330
5574
  var init_claude = __esm({
5331
5575
  "src/agents/claude.ts"() {
5332
5576
  "use strict";
5333
- import_node_fs11 = require("fs");
5577
+ import_node_fs13 = require("fs");
5334
5578
  init_run();
5335
5579
  init_app_settings();
5336
5580
  init_claude_mcp();
@@ -5359,7 +5603,7 @@ var init_claude = __esm({
5359
5603
  async detect() {
5360
5604
  const claude = resolveClaudeExecutable();
5361
5605
  if (claude !== "claude") {
5362
- if (!(0, import_node_fs11.existsSync)(claude)) {
5606
+ if (!(0, import_node_fs13.existsSync)(claude)) {
5363
5607
  return {
5364
5608
  agent: "claude",
5365
5609
  installed: false,
@@ -5398,9 +5642,8 @@ var init_claude = __esm({
5398
5642
  },
5399
5643
  async buildTurn(thread, input) {
5400
5644
  const claude = resolveClaudeExecutable();
5401
- const turn = normalizeTurnInput(input);
5402
5645
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
5403
- const effective = sessionId ? { prompt: turn.prompt } : turn;
5646
+ const effective = dropCachedPrefixOnResume(input, sessionId);
5404
5647
  const promptText = flattenTurnInput(effective);
5405
5648
  const useStdin = promptText.length > CLAUDE_PROMPT_ARG_MAX;
5406
5649
  if (process.env.SIDEBOARD_DEBUG_CLAUDE_TURN === "1") {
@@ -5413,7 +5656,9 @@ var init_claude = __esm({
5413
5656
  const isOrchestrator = isOrchestratorThread2(thread);
5414
5657
  const injectedServers = await buildInjectedMcpServers({
5415
5658
  includeSideboard: true,
5416
- includeBrightsy: isBrightsyConnected(),
5659
+ includeBrightsy: shouldInjectBrightsyMcp(thread, {
5660
+ orchestrator: isOrchestrator
5661
+ }),
5417
5662
  orchestratorThreadId: isOrchestrator ? thread.id : null
5418
5663
  });
5419
5664
  const injectedBrightsyNames = injectedServers.filter((s) => s.name === "brightsy" || s.name.startsWith("brightsy_")).map((s) => s.name);
@@ -5587,9 +5832,14 @@ async function listCodexModels() {
5587
5832
  if (cachedCodexModels && now - cachedCodexModels.at < CODEX_MODEL_CACHE_MS) {
5588
5833
  return cachedCodexModels.models;
5589
5834
  }
5590
- const which = await run("which", ["codex"], { reject: false });
5591
- if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
5592
- const listed = await run("codex", ["debug", "models"], { reject: false });
5835
+ const codex = resolveAgentExecutable("codex");
5836
+ if (codex === "codex") {
5837
+ const which = await run("which", ["codex"], { reject: false });
5838
+ if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
5839
+ } else if (!(0, import_node_fs14.existsSync)(codex)) {
5840
+ return FALLBACK_CODEX_MODELS;
5841
+ }
5842
+ const listed = await run(codex, ["debug", "models"], { reject: false });
5593
5843
  if (listed.exitCode !== 0 || !listed.stdout.trim()) {
5594
5844
  return cachedCodexModels?.models ?? FALLBACK_CODEX_MODELS;
5595
5845
  }
@@ -5628,8 +5878,8 @@ function codexConfigHasNetworkAccess() {
5628
5878
  (0, import_node_path12.join)((0, import_node_os7.homedir)(), ".config", "codex", "config.toml")
5629
5879
  ];
5630
5880
  for (const path of candidates) {
5631
- if (!(0, import_node_fs12.existsSync)(path)) continue;
5632
- const text = (0, import_node_fs12.readFileSync)(path, "utf8");
5881
+ if (!(0, import_node_fs14.existsSync)(path)) continue;
5882
+ const text = (0, import_node_fs14.readFileSync)(path, "utf8");
5633
5883
  if (/network_access\s*=\s*true/.test(text)) return true;
5634
5884
  }
5635
5885
  return false;
@@ -5662,21 +5912,23 @@ function asRecord(value) {
5662
5912
  }
5663
5913
  function codexLooksAuthenticated() {
5664
5914
  const authPath = (0, import_node_path12.join)((0, import_node_os7.homedir)(), ".codex", "auth.json");
5665
- if (!(0, import_node_fs12.existsSync)(authPath)) return false;
5915
+ if (!(0, import_node_fs14.existsSync)(authPath)) return false;
5666
5916
  try {
5667
- return (0, import_node_fs12.statSync)(authPath).size > 2;
5917
+ return (0, import_node_fs14.statSync)(authPath).size > 2;
5668
5918
  } catch {
5669
5919
  return false;
5670
5920
  }
5671
5921
  }
5672
- var import_node_fs12, import_node_os7, import_node_path12, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
5922
+ var import_node_fs14, import_node_os7, import_node_path12, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
5673
5923
  var init_codex = __esm({
5674
5924
  "src/agents/codex.ts"() {
5675
5925
  "use strict";
5676
- import_node_fs12 = require("fs");
5926
+ import_node_fs14 = require("fs");
5677
5927
  import_node_os7 = require("os");
5678
5928
  import_node_path12 = require("path");
5679
5929
  init_run();
5930
+ init_app_settings();
5931
+ init_global_workspace();
5680
5932
  init_error_detail();
5681
5933
  init_injected_mcp();
5682
5934
  init_turn_input();
@@ -5694,16 +5946,30 @@ var init_codex = __esm({
5694
5946
  codexAdapter = {
5695
5947
  kind: "codex",
5696
5948
  async detect() {
5697
- const which = await run("which", ["codex"], { reject: false, timeoutMs: 3e3 });
5698
- if (which.exitCode !== 0) {
5699
- return {
5700
- agent: "codex",
5701
- installed: false,
5702
- authenticated: false,
5703
- linearMcp: false,
5704
- warnings: [],
5705
- reason: "codex CLI not found on PATH"
5706
- };
5949
+ const codex = resolveAgentExecutable("codex");
5950
+ if (codex !== "codex") {
5951
+ if (!(0, import_node_fs14.existsSync)(codex)) {
5952
+ return {
5953
+ agent: "codex",
5954
+ installed: false,
5955
+ authenticated: false,
5956
+ linearMcp: false,
5957
+ warnings: [],
5958
+ reason: `Codex executable not found: ${codex}`
5959
+ };
5960
+ }
5961
+ } else {
5962
+ const which = await run("which", ["codex"], { reject: false, timeoutMs: 3e3 });
5963
+ if (which.exitCode !== 0) {
5964
+ return {
5965
+ agent: "codex",
5966
+ installed: false,
5967
+ authenticated: false,
5968
+ linearMcp: false,
5969
+ warnings: [],
5970
+ reason: "codex CLI not found on PATH"
5971
+ };
5972
+ }
5707
5973
  }
5708
5974
  const authenticated = codexLooksAuthenticated();
5709
5975
  const linearMcp = false;
@@ -5723,22 +5989,24 @@ var init_codex = __esm({
5723
5989
  };
5724
5990
  },
5725
5991
  async buildTurn(thread, input) {
5726
- const prompt = flattenTurnInput(input);
5727
5992
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
5993
+ const prompt = flattenTurnInput(dropCachedPrefixOnResume(input, sessionId));
5728
5994
  const useStdin = prompt.length > CODEX_PROMPT_ARG_MAX;
5729
5995
  const promptArg = useStdin ? "-" : prompt;
5730
5996
  if (process.env.SIDEBOARD_DEBUG_CODEX_TURN === "1") {
5731
- const { cachedPrefix } = normalizeTurnInput(input);
5732
5997
  console.error(
5733
- `[sideboard/codex] promptChars=${prompt.length} resumed=${Boolean(sessionId)} stdin=${useStdin} hasPrefix=${Boolean(cachedPrefix)}`
5998
+ `[sideboard/codex] promptChars=${prompt.length} resumed=${Boolean(sessionId)} stdin=${useStdin} hasPrefix=${prompt.includes("Current request:")}`
5734
5999
  );
5735
6000
  }
5736
6001
  const mode = permissionMode(thread);
5737
6002
  const model = thread.model?.trim();
6003
+ const isOrchestrator = isOrchestratorThread(thread);
5738
6004
  const injected = await buildInjectedMcpServers({
5739
6005
  includeSideboard: true,
5740
- includeBrightsy: isBrightsyConnected(),
5741
- orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
6006
+ includeBrightsy: shouldInjectBrightsyMcp(thread, {
6007
+ orchestrator: isOrchestrator
6008
+ }),
6009
+ orchestratorThreadId: isOrchestrator ? thread.id : null
5742
6010
  });
5743
6011
  const mcpOverrides = toCodexMcpConfigArgs(injected);
5744
6012
  const execOpts = [
@@ -5758,7 +6026,7 @@ var init_codex = __esm({
5758
6026
  ];
5759
6027
  const args = sessionId ? ["exec", ...execOpts, "resume", sessionId, promptArg] : ["exec", ...execOpts, promptArg];
5760
6028
  return {
5761
- file: "codex",
6029
+ file: resolveAgentExecutable("codex"),
5762
6030
  args,
5763
6031
  cwd: thread.worktreePath,
5764
6032
  stdin: useStdin ? `${prompt}
@@ -5854,16 +6122,17 @@ var init_codex = __esm({
5854
6122
  return cached;
5855
6123
  },
5856
6124
  async buildAttach(thread) {
6125
+ const codex = resolveAgentExecutable("codex");
5857
6126
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
5858
6127
  if (sessionId) {
5859
6128
  return {
5860
- file: "codex",
6129
+ file: codex,
5861
6130
  args: ["exec", "--cd", thread.worktreePath, "resume", sessionId],
5862
6131
  cwd: thread.worktreePath
5863
6132
  };
5864
6133
  }
5865
6134
  return {
5866
- file: "codex",
6135
+ file: codex,
5867
6136
  args: ["--cd", thread.worktreePath],
5868
6137
  cwd: thread.worktreePath
5869
6138
  };
@@ -5871,7 +6140,7 @@ var init_codex = __esm({
5871
6140
  async listLinearIssues(_repoPath) {
5872
6141
  const prompt = "List my assigned Linear issues as JSON array only: id, identifier, title, url, labels.";
5873
6142
  const { stdout, exitCode } = await run(
5874
- "codex",
6143
+ resolveAgentExecutable("codex"),
5875
6144
  [
5876
6145
  "exec",
5877
6146
  "--json",
@@ -6134,21 +6403,22 @@ function cursorRunnerPath() {
6134
6403
  (0, import_node_path13.join)(root, "src", "agents", "cursor-runner.ts")
6135
6404
  ];
6136
6405
  for (const candidate of candidates) {
6137
- if ((0, import_node_fs13.existsSync)(candidate)) return candidate;
6406
+ if ((0, import_node_fs15.existsSync)(candidate)) return candidate;
6138
6407
  }
6139
6408
  return candidates[0];
6140
6409
  }
6141
- var import_node_fs13, import_node_module2, import_node_path13, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
6410
+ var import_node_fs15, import_node_module2, import_node_path13, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
6142
6411
  var init_cursor = __esm({
6143
6412
  "src/agents/cursor.ts"() {
6144
6413
  "use strict";
6145
- import_node_fs13 = require("fs");
6414
+ import_node_fs15 = require("fs");
6146
6415
  import_node_module2 = require("module");
6147
6416
  import_node_path13 = require("path");
6148
6417
  import_node_url2 = require("url");
6149
6418
  import_sdk = require("@cursor/sdk");
6150
6419
  init_run();
6151
6420
  init_app_settings();
6421
+ init_global_workspace();
6152
6422
  init_cursor_events();
6153
6423
  init_injected_mcp();
6154
6424
  init_node_launch();
@@ -6185,13 +6455,16 @@ var init_cursor = __esm({
6185
6455
  };
6186
6456
  },
6187
6457
  async buildTurn(thread, input) {
6188
- const prompt = flattenTurnInput(input);
6189
6458
  const agentId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
6459
+ const prompt = flattenTurnInput(dropCachedPrefixOnResume(input, agentId));
6190
6460
  const apiKey = resolveCursorApiKey() || void 0;
6461
+ const isOrchestrator = isOrchestratorThread(thread);
6191
6462
  const injected = await buildInjectedMcpServers({
6192
6463
  includeSideboard: true,
6193
- includeBrightsy: isBrightsyConnected(),
6194
- orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
6464
+ includeBrightsy: shouldInjectBrightsyMcp(thread, {
6465
+ orchestrator: isOrchestrator
6466
+ }),
6467
+ orchestratorThreadId: isOrchestrator ? thread.id : null
6195
6468
  });
6196
6469
  const mcpServers = toCursorMcpServers(injected);
6197
6470
  const req = {
@@ -6262,9 +6535,14 @@ async function listOpencodeModels() {
6262
6535
  if (cachedOpencodeModels && now - cachedOpencodeModels.at < OPENCODE_MODEL_CACHE_MS) {
6263
6536
  return cachedOpencodeModels.models;
6264
6537
  }
6265
- const which = await run("which", ["opencode"], { reject: false });
6266
- if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
6267
- const listed = await run("opencode", ["models"], { reject: false });
6538
+ const opencode = resolveAgentExecutable("opencode");
6539
+ if (opencode === "opencode") {
6540
+ const which = await run("which", ["opencode"], { reject: false });
6541
+ if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
6542
+ } else if (!(0, import_node_fs16.existsSync)(opencode)) {
6543
+ return FALLBACK_OPENCODE_MODELS;
6544
+ }
6545
+ const listed = await run(opencode, ["models"], { reject: false });
6268
6546
  if (listed.exitCode !== 0 || !listed.stdout.trim()) {
6269
6547
  return cachedOpencodeModels?.models ?? FALLBACK_OPENCODE_MODELS;
6270
6548
  }
@@ -6291,11 +6569,14 @@ function usageFromOpencode(tokens) {
6291
6569
  cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
6292
6570
  };
6293
6571
  }
6294
- var FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
6572
+ var import_node_fs16, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
6295
6573
  var init_opencode = __esm({
6296
6574
  "src/agents/opencode.ts"() {
6297
6575
  "use strict";
6576
+ import_node_fs16 = require("fs");
6298
6577
  init_run();
6578
+ init_app_settings();
6579
+ init_global_workspace();
6299
6580
  init_error_detail();
6300
6581
  init_injected_mcp();
6301
6582
  init_turn_input();
@@ -6316,20 +6597,34 @@ var init_opencode = __esm({
6316
6597
  opencodeAdapter = {
6317
6598
  kind: "opencode",
6318
6599
  async detect() {
6319
- const which = await run("which", ["opencode"], { reject: false });
6320
- if (which.exitCode !== 0) {
6321
- return {
6322
- agent: "opencode",
6323
- installed: false,
6324
- authenticated: false,
6325
- linearMcp: false,
6326
- warnings: [],
6327
- reason: "opencode CLI not found on PATH"
6328
- };
6600
+ const opencode = resolveAgentExecutable("opencode");
6601
+ if (opencode !== "opencode") {
6602
+ if (!(0, import_node_fs16.existsSync)(opencode)) {
6603
+ return {
6604
+ agent: "opencode",
6605
+ installed: false,
6606
+ authenticated: false,
6607
+ linearMcp: false,
6608
+ warnings: [],
6609
+ reason: `OpenCode executable not found: ${opencode}`
6610
+ };
6611
+ }
6612
+ } else {
6613
+ const which = await run("which", ["opencode"], { reject: false });
6614
+ if (which.exitCode !== 0) {
6615
+ return {
6616
+ agent: "opencode",
6617
+ installed: false,
6618
+ authenticated: false,
6619
+ linearMcp: false,
6620
+ warnings: [],
6621
+ reason: "opencode CLI not found on PATH"
6622
+ };
6623
+ }
6329
6624
  }
6330
- const auth = await run("opencode", ["auth", "list"], { reject: false });
6625
+ const auth = await run(opencode, ["auth", "list"], { reject: false });
6331
6626
  const authenticated = auth.exitCode === 0 && auth.stdout.trim().length > 0;
6332
- const mcp = await run("opencode", ["mcp", "list"], { reject: false });
6627
+ const mcp = await run(opencode, ["mcp", "list"], { reject: false });
6333
6628
  const linearMcp = /linear/i.test(mcp.stdout + mcp.stderr);
6334
6629
  return {
6335
6630
  agent: "opencode",
@@ -6341,8 +6636,8 @@ var init_opencode = __esm({
6341
6636
  };
6342
6637
  },
6343
6638
  async buildTurn(thread, input) {
6344
- const prompt = flattenTurnInput(input);
6345
6639
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
6640
+ const prompt = flattenTurnInput(dropCachedPrefixOnResume(input, sessionId));
6346
6641
  const mode = permissionMode(thread);
6347
6642
  const model = thread.model?.trim();
6348
6643
  const args = [
@@ -6358,14 +6653,17 @@ var init_opencode = __esm({
6358
6653
  if (model) {
6359
6654
  args.push("--model", model);
6360
6655
  }
6656
+ const isOrchestrator = isOrchestratorThread(thread);
6361
6657
  const injected = await buildInjectedMcpServers({
6362
6658
  includeSideboard: true,
6363
- includeBrightsy: isBrightsyConnected(),
6364
- orchestratorThreadId: thread.sourceType === "orchestration" ? thread.id : null
6659
+ includeBrightsy: shouldInjectBrightsyMcp(thread, {
6660
+ orchestrator: isOrchestrator
6661
+ }),
6662
+ orchestratorThreadId: isOrchestrator ? thread.id : null
6365
6663
  });
6366
6664
  const mcpContent = injected.length > 0 ? toOpencodeMcpConfigContent(injected) : null;
6367
6665
  return {
6368
- file: "opencode",
6666
+ file: resolveAgentExecutable("opencode"),
6369
6667
  args,
6370
6668
  cwd: thread.worktreePath,
6371
6669
  // `opencode run` treats non-TTY stdin as the message body when no positional
@@ -6441,7 +6739,7 @@ var init_opencode = __esm({
6441
6739
  async resolveSessionId(worktreePath, cached) {
6442
6740
  const cachedId = cached?.trim() || null;
6443
6741
  const listed = await run(
6444
- "opencode",
6742
+ resolveAgentExecutable("opencode"),
6445
6743
  ["session", "list", "--format", "json"],
6446
6744
  { cwd: worktreePath, reject: false }
6447
6745
  );
@@ -6472,7 +6770,7 @@ var init_opencode = __esm({
6472
6770
  const args = ["--dir", thread.worktreePath];
6473
6771
  if (sessionId) args.push("--session", sessionId);
6474
6772
  return {
6475
- file: "opencode",
6773
+ file: resolveAgentExecutable("opencode"),
6476
6774
  args,
6477
6775
  cwd: thread.worktreePath,
6478
6776
  env: {
@@ -6483,7 +6781,7 @@ var init_opencode = __esm({
6483
6781
  async listLinearIssues(_repoPath) {
6484
6782
  const prompt = "List my assigned Linear issues as JSON array only: id, identifier, title, url, labels.";
6485
6783
  const { stdout, exitCode } = await run(
6486
- "opencode",
6784
+ resolveAgentExecutable("opencode"),
6487
6785
  ["run", prompt, "--format", "json"],
6488
6786
  {
6489
6787
  reject: false,
@@ -6716,9 +7014,30 @@ function getAgentSetupInfo(agent) {
6716
7014
  function listAgentSetupInfo() {
6717
7015
  return Object.values(SETUP);
6718
7016
  }
6719
- async function openInSystemTerminal(command) {
6720
- ensureAgentPath();
7017
+ function resolveLoginCommand(agent) {
7018
+ const info = getAgentSetupInfo(agent);
7019
+ if (!info.loginCommand) return null;
7020
+ if (!CLI_LOGIN_AGENTS.has(agent)) return info.loginCommand;
7021
+ const exe = resolveAgentExecutable(agent);
7022
+ return info.loginCommand.replace(/^\S+/, exe);
7023
+ }
7024
+ async function prepareTerminalCommand(command) {
7025
+ enrichPathWithNpmGlobalBin();
6721
7026
  const trimmed = command.trim();
7027
+ if (!trimmed) return trimmed;
7028
+ if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
7029
+ const match = /^(\S+)(\s[\s\S]*)?$/.exec(trimmed);
7030
+ const bin = match?.[1];
7031
+ let whichPath = null;
7032
+ if (bin && !bin.includes("/") && !bin.includes("\\")) {
7033
+ const which = await run("which", [bin], { reject: false, timeoutMs: 3e3 });
7034
+ whichPath = which.exitCode === 0 ? which.stdout.trim() : null;
7035
+ }
7036
+ const resolved = resolveCommandBinarySync(trimmed, whichPath);
7037
+ return withExportedPath(resolved, process.env.PATH ?? "");
7038
+ }
7039
+ async function openInSystemTerminal(command) {
7040
+ const trimmed = (await prepareTerminalCommand(command)).trim();
6722
7041
  if (!trimmed) throw new Error("Command is empty");
6723
7042
  if (process.platform === "darwin") {
6724
7043
  const escaped = trimmed.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
@@ -6779,7 +7098,7 @@ async function installAgent(agent) {
6779
7098
  message: `Opened Terminal to run: ${info.installCommand}`
6780
7099
  };
6781
7100
  }
6782
- ensureAgentPath();
7101
+ enrichPathWithNpmGlobalBin();
6783
7102
  const result = await run("npm", ["install", "-g", info.npmPackage], { reject: false });
6784
7103
  const ok = result.exitCode === 0;
6785
7104
  if (!ok) {
@@ -6805,36 +7124,46 @@ async function installAgent(agent) {
6805
7124
  };
6806
7125
  }
6807
7126
  }
7127
+ enrichPathWithNpmGlobalBin();
7128
+ const cliBin = agent === "cursor" ? null : CLI_BIN[agent];
7129
+ let binPath = null;
7130
+ if (cliBin) {
7131
+ const which = await run("which", [cliBin], { reject: false, timeoutMs: 3e3 });
7132
+ binPath = which.exitCode === 0 ? which.stdout.trim().split(/\r?\n/).find(Boolean) ?? null : null;
7133
+ }
6808
7134
  return {
6809
7135
  ok: true,
6810
7136
  command: info.installCommand,
6811
7137
  exitCode: 0,
6812
7138
  stdout: result.stdout,
6813
7139
  stderr: result.stderr,
6814
- message: `Installed ${info.npmPackage}`
7140
+ message: binPath ? `Installed ${info.npmPackage} \u2192 ${binPath}` : `Installed ${info.npmPackage} (CLI not yet on PATH \u2014 Log in still exports Electron\u2019s PATH into Terminal)`
6815
7141
  };
6816
7142
  }
6817
7143
  async function loginAgent(agent) {
6818
7144
  const info = getAgentSetupInfo(agent);
6819
- if (!info.loginCommand) {
7145
+ const loginCommand = resolveLoginCommand(agent);
7146
+ if (!loginCommand) {
6820
7147
  return {
6821
7148
  ok: true,
6822
7149
  message: info.kind === "bundled-sdk" || info.kind === "api-key" ? info.summary : `No login command for ${agent}`
6823
7150
  };
6824
7151
  }
6825
- await openInSystemTerminal(info.loginCommand);
7152
+ const prepared = await prepareTerminalCommand(loginCommand);
7153
+ await openInSystemTerminal(prepared);
6826
7154
  return {
6827
7155
  ok: true,
6828
7156
  openedTerminal: true,
6829
- command: info.loginCommand,
6830
- message: `Opened Terminal to run: ${info.loginCommand}`
7157
+ command: prepared,
7158
+ message: `Opened Terminal to run: ${prepared}`
6831
7159
  };
6832
7160
  }
6833
- var SETUP;
7161
+ var SETUP, CLI_BIN, CLI_LOGIN_AGENTS;
6834
7162
  var init_install = __esm({
6835
7163
  "src/agents/install.ts"() {
6836
7164
  "use strict";
6837
7165
  init_run();
7166
+ init_app_settings();
6838
7167
  init_path();
6839
7168
  SETUP = {
6840
7169
  claude: {
@@ -6883,6 +7212,18 @@ var init_install = __esm({
6883
7212
  npmPackage: "@brightsy/cli"
6884
7213
  }
6885
7214
  };
7215
+ CLI_BIN = {
7216
+ claude: "claude",
7217
+ codex: "codex",
7218
+ opencode: "opencode",
7219
+ brightsy: "brightsy"
7220
+ };
7221
+ CLI_LOGIN_AGENTS = /* @__PURE__ */ new Set([
7222
+ "claude",
7223
+ "codex",
7224
+ "opencode",
7225
+ "brightsy"
7226
+ ]);
6886
7227
  }
6887
7228
  });
6888
7229
 
@@ -6902,6 +7243,7 @@ __export(agents_exports, {
6902
7243
  cursorSdkMessageToEvents: () => cursorSdkMessageToEvents,
6903
7244
  decodeBrightsyTarget: () => decodeBrightsyTarget,
6904
7245
  encodeBrightsyTarget: () => encodeBrightsyTarget,
7246
+ enrichPathWithNpmGlobalBin: () => enrichPathWithNpmGlobalBin,
6905
7247
  ensureAgentPath: () => ensureAgentPath,
6906
7248
  getAdapter: () => getAdapter,
6907
7249
  getAgentSetupInfo: () => getAgentSetupInfo,
@@ -6921,8 +7263,13 @@ __export(agents_exports, {
6921
7263
  parseCursorRunnerLine: () => parseCursorRunnerLine,
6922
7264
  parseSessionQuotaResetAt: () => parseSessionQuotaResetAt,
6923
7265
  permissionMode: () => permissionMode,
7266
+ posixShellSingleQuote: () => posixShellSingleQuote,
7267
+ prepareTerminalCommand: () => prepareTerminalCommand,
7268
+ resolveCommandBinarySync: () => resolveCommandBinarySync,
6924
7269
  resolveCursorModelId: () => resolveCursorModelId,
6925
- resolveQuotaFallbackAgent: () => resolveQuotaFallbackAgent
7270
+ resolveLoginCommand: () => resolveLoginCommand,
7271
+ resolveQuotaFallbackAgent: () => resolveQuotaFallbackAgent,
7272
+ withExportedPath: () => withExportedPath
6926
7273
  });
6927
7274
  function getAdapter(kind) {
6928
7275
  return adapters[kind];
@@ -7034,17 +7381,17 @@ __export(plan_file_exports, {
7034
7381
  });
7035
7382
  function ensureAttachmentsGitignore2(worktreePath) {
7036
7383
  const gitignoreAbs = (0, import_node_path24.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
7037
- if ((0, import_node_fs26.existsSync)(gitignoreAbs)) return;
7038
- (0, import_node_fs26.mkdirSync)((0, import_node_path24.dirname)(gitignoreAbs), { recursive: true });
7039
- (0, import_node_fs26.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
7384
+ if ((0, import_node_fs29.existsSync)(gitignoreAbs)) return;
7385
+ (0, import_node_fs29.mkdirSync)((0, import_node_path24.dirname)(gitignoreAbs), { recursive: true });
7386
+ (0, import_node_fs29.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
7040
7387
  }
7041
7388
  function planFileAbs(worktreePath) {
7042
7389
  return (0, import_node_path24.join)(worktreePath, PLAN_FILE_REL);
7043
7390
  }
7044
7391
  function readTextIfPresent2(abs) {
7045
- if (!(0, import_node_fs26.existsSync)(abs)) return null;
7392
+ if (!(0, import_node_fs29.existsSync)(abs)) return null;
7046
7393
  try {
7047
- const content = (0, import_node_fs26.readFileSync)(abs, "utf8");
7394
+ const content = (0, import_node_fs29.readFileSync)(abs, "utf8");
7048
7395
  return content.trim() ? content : null;
7049
7396
  } catch {
7050
7397
  return null;
@@ -7056,16 +7403,16 @@ function readPlanFile(worktreePath) {
7056
7403
  function writePlanFile(worktreePath, content) {
7057
7404
  ensureAttachmentsGitignore2(worktreePath);
7058
7405
  const abs = planFileAbs(worktreePath);
7059
- (0, import_node_fs26.mkdirSync)((0, import_node_path24.dirname)(abs), { recursive: true });
7406
+ (0, import_node_fs29.mkdirSync)((0, import_node_path24.dirname)(abs), { recursive: true });
7060
7407
  const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
7061
- (0, import_node_fs26.writeFileSync)(abs, body, "utf8");
7408
+ (0, import_node_fs29.writeFileSync)(abs, body, "utf8");
7062
7409
  return PLAN_FILE_REL;
7063
7410
  }
7064
- var import_node_fs26, import_node_path24;
7411
+ var import_node_fs29, import_node_path24;
7065
7412
  var init_plan_file = __esm({
7066
7413
  "src/plan/plan-file.ts"() {
7067
7414
  "use strict";
7068
- import_node_fs26 = require("fs");
7415
+ import_node_fs29 = require("fs");
7069
7416
  import_node_path24 = require("path");
7070
7417
  init_workspace_scratch();
7071
7418
  init_plan_present();
@@ -7082,9 +7429,9 @@ function recoverFinishedCursorRun(opts) {
7082
7429
  const agentId = opts.agentId.trim();
7083
7430
  if (!agentId) return null;
7084
7431
  const runsPath = (0, import_node_path25.join)(appDataDir(), "cursor-sdk-store", "runs.ndjson");
7085
- if (!(0, import_node_fs27.existsSync)(runsPath)) return null;
7432
+ if (!(0, import_node_fs30.existsSync)(runsPath)) return null;
7086
7433
  try {
7087
- const lines = (0, import_node_fs27.readFileSync)(runsPath, "utf8").split("\n");
7434
+ const lines = (0, import_node_fs30.readFileSync)(runsPath, "utf8").split("\n");
7088
7435
  let best = null;
7089
7436
  for (const line of lines) {
7090
7437
  const trimmed = line.trim();
@@ -7110,11 +7457,11 @@ function recoverFinishedCursorRun(opts) {
7110
7457
  return null;
7111
7458
  }
7112
7459
  }
7113
- var import_node_fs27, import_node_path25;
7460
+ var import_node_fs30, import_node_path25;
7114
7461
  var init_cursor_recover = __esm({
7115
7462
  "src/agents/cursor-recover.ts"() {
7116
7463
  "use strict";
7117
- import_node_fs27 = require("fs");
7464
+ import_node_fs30 = require("fs");
7118
7465
  import_node_path25 = require("path");
7119
7466
  init_paths();
7120
7467
  }
@@ -7188,6 +7535,7 @@ __export(index_exports, {
7188
7535
  REVIEW_REQUEST_PREFILL: () => REVIEW_REQUEST_PREFILL,
7189
7536
  SIDEBOARD_FORCE_STOP: () => SIDEBOARD_FORCE_STOP,
7190
7537
  SIDEBOARD_MCP_ALLOWED_TOOLS: () => SIDEBOARD_MCP_ALLOWED_TOOLS,
7538
+ SIDEBOARD_MCP_PROFILE_ENV: () => SIDEBOARD_MCP_PROFILE_ENV,
7191
7539
  THINKING_EFFORTS: () => THINKING_EFFORTS,
7192
7540
  addPrStackLayer: () => addPrStackLayer,
7193
7541
  addStackLayerFromThread: () => addStackLayerFromThread,
@@ -7219,6 +7567,7 @@ __export(index_exports, {
7219
7567
  brightsyCloudConnectAgent: () => brightsyCloudConnectAgent,
7220
7568
  brightsyCloudConnectEnabled: () => brightsyCloudConnectEnabled,
7221
7569
  brightsyConfigPath: () => brightsyConfigPath,
7570
+ brightsyInjectWorktreeMcpEnabled: () => brightsyInjectWorktreeMcpEnabled,
7222
7571
  brightsyMcpAllowedTools: () => brightsyMcpAllowedTools,
7223
7572
  brightsyMcpServerName: () => brightsyMcpServerName,
7224
7573
  buildCachedUserContent: () => buildCachedUserContent,
@@ -7270,7 +7619,9 @@ __export(index_exports, {
7270
7619
  detectLocalMergeConflicts: () => detectLocalMergeConflicts,
7271
7620
  disconnectBrightsyTeam: () => disconnectBrightsyTeam,
7272
7621
  discoverSkills: () => discoverSkills,
7622
+ dropCachedPrefixOnResume: () => dropCachedPrefixOnResume,
7273
7623
  encodeBrightsyTarget: () => encodeBrightsyTarget,
7624
+ enrichPathWithNpmGlobalBin: () => enrichPathWithNpmGlobalBin,
7274
7625
  enrichWorkspacesWithGithub: () => enrichWorkspacesWithGithub,
7275
7626
  ensureAgentPath: () => ensureAgentPath,
7276
7627
  ensureCloudCoordinator: () => ensureCloudCoordinator,
@@ -7308,6 +7659,7 @@ __export(index_exports, {
7308
7659
  formatTranscriptMarkdown: () => formatTranscriptMarkdown,
7309
7660
  formatWorkspaceInventory: () => formatWorkspaceInventory,
7310
7661
  formatWorktreeDirective: () => formatWorktreeDirective,
7662
+ formatWorktreeReminder: () => formatWorktreeReminder,
7311
7663
  getAdapter: () => getAdapter,
7312
7664
  getAgentSetupInfo: () => getAgentSetupInfo,
7313
7665
  getBrightsySession: () => getBrightsySession,
@@ -7434,7 +7786,10 @@ __export(index_exports, {
7434
7786
  pastedTextStats: () => pastedTextStats,
7435
7787
  permissionMode: () => permissionMode,
7436
7788
  planFileAbs: () => planFileAbs,
7789
+ posixShellSingleQuote: () => posixShellSingleQuote,
7790
+ prepareTerminalCommand: () => prepareTerminalCommand,
7437
7791
  previewLand: () => previewLand,
7792
+ promptMentionsBrightsy: () => promptMentionsBrightsy,
7438
7793
  pushBranch: () => pushBranch,
7439
7794
  readExistingReviewRequestFile: () => readExistingReviewRequestFile,
7440
7795
  readPlanFile: () => readPlanFile,
@@ -7450,7 +7805,9 @@ __export(index_exports, {
7450
7805
  requestReview: () => requestReview,
7451
7806
  requireAgent: () => requireAgent,
7452
7807
  resetGhStackDetectCache: () => resetGhStackDetectCache,
7808
+ resolveAgentExecutable: () => resolveAgentExecutable,
7453
7809
  resolveClaudeExecutable: () => resolveClaudeExecutable,
7810
+ resolveCommandBinarySync: () => resolveCommandBinarySync,
7454
7811
  resolveConductorCursorAgentId: () => resolveConductorCursorAgentId,
7455
7812
  resolveCursorModelId: () => resolveCursorModelId,
7456
7813
  resolveDefaultBranch: () => resolveDefaultBranch,
@@ -7459,6 +7816,7 @@ __export(index_exports, {
7459
7816
  resolveFilesToCopy: () => resolveFilesToCopy,
7460
7817
  resolveGhAuthToken: () => resolveGhAuthToken,
7461
7818
  resolveGithubRepoSlug: () => resolveGithubRepoSlug,
7819
+ resolveLoginCommand: () => resolveLoginCommand,
7462
7820
  resolveNewThreadOptions: () => resolveNewThreadOptions,
7463
7821
  resolvePlanMarkdown: () => resolvePlanMarkdown,
7464
7822
  resolvePrSelector: () => resolvePrSelector,
@@ -7480,9 +7838,11 @@ __export(index_exports, {
7480
7838
  settingsSourceLabel: () => settingsSourceLabel,
7481
7839
  shouldAttachPastedText: () => shouldAttachPastedText,
7482
7840
  shouldCompactContext: () => shouldCompactContext,
7841
+ shouldInjectBrightsyMcp: () => shouldInjectBrightsyMcp,
7483
7842
  shouldRefreshReviewRequestTemplate: () => shouldRefreshReviewRequestTemplate,
7484
7843
  shouldRunWorktreeCleanup: () => shouldRunWorktreeCleanup,
7485
7844
  sideboardHomeDir: () => sideboardHomeDir,
7845
+ sideboardMcpProfile: () => sideboardMcpProfile,
7486
7846
  sideboardReposDir: () => sideboardReposDir,
7487
7847
  sideboardWorkspacesDir: () => sideboardWorkspacesDir,
7488
7848
  slugify: () => slugify,
@@ -7510,6 +7870,7 @@ __export(index_exports, {
7510
7870
  threadDisplayLabel: () => threadDisplayLabel,
7511
7871
  threadFilePath: () => threadFilePath,
7512
7872
  threadLockPath: () => threadLockPath,
7873
+ threadRequestsBrightsyMcp: () => threadRequestsBrightsyMcp,
7513
7874
  threadsDir: () => threadsDir,
7514
7875
  threadsSharingWorktree: () => threadsSharingWorktree,
7515
7876
  toolDescription: () => toolDescription,
@@ -7517,14 +7878,18 @@ __export(index_exports, {
7517
7878
  toolFilePath: () => toolFilePath,
7518
7879
  totalTokens: () => totalTokens,
7519
7880
  updateAdvancedSettings: () => updateAdvancedSettings,
7881
+ updateAgentExecutable: () => updateAgentExecutable,
7520
7882
  updateAppEnvironment: () => updateAppEnvironment,
7521
7883
  updateBrightsySettings: () => updateBrightsySettings,
7522
7884
  updateClaudeSettings: () => updateClaudeSettings,
7885
+ updateCodexSettings: () => updateCodexSettings,
7523
7886
  updateDefaultsSettings: () => updateDefaultsSettings,
7524
7887
  updateIntegrationsSettings: () => updateIntegrationsSettings,
7888
+ updateOpencodeSettings: () => updateOpencodeSettings,
7525
7889
  updateThread: () => updateThread,
7526
7890
  validateLinearApiKey: () => validateLinearApiKey,
7527
7891
  withAgentInstructions: () => withAgentInstructions,
7892
+ withExportedPath: () => withExportedPath,
7528
7893
  withThreadLock: () => withThreadLock,
7529
7894
  workspaceSettingsSourceLabel: () => workspaceSettingsSourceLabel,
7530
7895
  worktreeCleanupSettings: () => worktreeCleanupSettings,
@@ -8101,7 +8466,7 @@ async function spawnAgentTurn(thread, input, onEvent) {
8101
8466
  init_claude_mcp();
8102
8467
 
8103
8468
  // src/agents/instructions.ts
8104
- var import_node_fs14 = require("fs");
8469
+ var import_node_fs17 = require("fs");
8105
8470
  var import_node_path14 = require("path");
8106
8471
  init_worktree_labels();
8107
8472
  function normPath2(p) {
@@ -8201,6 +8566,9 @@ function formatWorktreeDirective(thread, opts) {
8201
8566
  );
8202
8567
  return lines.join("\n");
8203
8568
  }
8569
+ function formatWorktreeReminder() {
8570
+ return "Sideboard worktree: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout.";
8571
+ }
8204
8572
  function formatArtifactDirective() {
8205
8573
  return [
8206
8574
  "Sideboard side column (desktop UI):",
@@ -8242,10 +8610,10 @@ function loadAgentInstructions(worktreePath, agent) {
8242
8610
  for (const rel of candidates) {
8243
8611
  if (seen.has(rel)) continue;
8244
8612
  const abs = (0, import_node_path14.join)(worktreePath, rel);
8245
- if (!(0, import_node_fs14.existsSync)(abs)) continue;
8613
+ if (!(0, import_node_fs17.existsSync)(abs)) continue;
8246
8614
  try {
8247
- if (!(0, import_node_fs14.statSync)(abs).isFile()) continue;
8248
- let content = (0, import_node_fs14.readFileSync)(abs, "utf8");
8615
+ if (!(0, import_node_fs17.statSync)(abs).isFile()) continue;
8616
+ let content = (0, import_node_fs17.readFileSync)(abs, "utf8");
8249
8617
  if (!content.trim()) continue;
8250
8618
  if (content.length > MAX_CHARS_PER_FILE) {
8251
8619
  content = `${content.slice(0, MAX_CHARS_PER_FILE)}
@@ -8290,11 +8658,13 @@ init_turn_input();
8290
8658
  init_agents();
8291
8659
  async function detectAgents() {
8292
8660
  ensureAgentPath();
8661
+ enrichPathWithNpmGlobalBin();
8293
8662
  return Promise.all(allAdapters().map((a) => a.detect()));
8294
8663
  }
8295
8664
  var REQUIRE_AGENT_TIMEOUT_MS = 8e3;
8296
8665
  async function requireAgent(agent, opts) {
8297
8666
  ensureAgentPath();
8667
+ enrichPathWithNpmGlobalBin();
8298
8668
  const status = await Promise.race([
8299
8669
  getAdapter(agent).detect(),
8300
8670
  new Promise((_, reject) => {
@@ -8322,7 +8692,7 @@ async function requireAgent(agent, opts) {
8322
8692
  init_settings();
8323
8693
 
8324
8694
  // src/hook/conductor.ts
8325
- var import_node_fs15 = require("fs");
8695
+ var import_node_fs18 = require("fs");
8326
8696
  var import_node_net = require("net");
8327
8697
  var import_node_path15 = require("path");
8328
8698
  var import_execa3 = require("execa");
@@ -8335,8 +8705,8 @@ function matchSimpleGlob(pattern, name) {
8335
8705
  }
8336
8706
  function readWorktreeInclude(repoPath) {
8337
8707
  const path = (0, import_node_path15.join)(repoPath, ".worktreeinclude");
8338
- if (!(0, import_node_fs15.existsSync)(path)) return [];
8339
- return (0, import_node_fs15.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
8708
+ if (!(0, import_node_fs18.existsSync)(path)) return [];
8709
+ return (0, import_node_fs18.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
8340
8710
  }
8341
8711
  function resolveFilesToCopy(repoPath) {
8342
8712
  const fromInclude = readWorktreeInclude(repoPath);
@@ -8346,7 +8716,7 @@ function resolveFilesToCopy(repoPath) {
8346
8716
  if (settings?.fileIncludeGlobs?.length) {
8347
8717
  const matched = [];
8348
8718
  try {
8349
- for (const entry of (0, import_node_fs15.readdirSync)(repoPath, { withFileTypes: true })) {
8719
+ for (const entry of (0, import_node_fs18.readdirSync)(repoPath, { withFileTypes: true })) {
8350
8720
  if (!entry.isFile()) continue;
8351
8721
  for (const glob of settings.fileIncludeGlobs) {
8352
8722
  if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path15.basename)(glob), entry.name)) {
@@ -8361,7 +8731,7 @@ function resolveFilesToCopy(repoPath) {
8361
8731
  }
8362
8732
  const defaults = [];
8363
8733
  try {
8364
- for (const entry of (0, import_node_fs15.readdirSync)(repoPath, { withFileTypes: true })) {
8734
+ for (const entry of (0, import_node_fs18.readdirSync)(repoPath, { withFileTypes: true })) {
8365
8735
  if (entry.isFile() && entry.name.startsWith(".env")) {
8366
8736
  defaults.push(entry.name);
8367
8737
  }
@@ -8376,10 +8746,10 @@ function copyConfiguredFiles(repoPath, worktreePath) {
8376
8746
  const copied = [];
8377
8747
  for (const rel of patterns) {
8378
8748
  const src = (0, import_node_path15.join)(repoPath, rel);
8379
- if (!(0, import_node_fs15.existsSync)(src)) continue;
8749
+ if (!(0, import_node_fs18.existsSync)(src)) continue;
8380
8750
  const dest = (0, import_node_path15.join)(worktreePath, rel);
8381
- (0, import_node_fs15.mkdirSync)((0, import_node_path15.dirname)(dest), { recursive: true });
8382
- (0, import_node_fs15.copyFileSync)(src, dest);
8751
+ (0, import_node_fs18.mkdirSync)((0, import_node_path15.dirname)(dest), { recursive: true });
8752
+ (0, import_node_fs18.copyFileSync)(src, dest);
8383
8753
  copied.push(rel);
8384
8754
  }
8385
8755
  return copied;
@@ -8632,15 +9002,15 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
8632
9002
  }
8633
9003
 
8634
9004
  // src/hook/cursor-worktrees.ts
8635
- var import_node_fs16 = require("fs");
9005
+ var import_node_fs19 = require("fs");
8636
9006
  var import_node_path16 = require("path");
8637
9007
  var import_execa4 = require("execa");
8638
9008
  var import_node_readline3 = require("readline");
8639
9009
  function loadCursorWorktreesJson(rootPath) {
8640
9010
  const path = (0, import_node_path16.join)(rootPath, ".cursor", "worktrees.json");
8641
- if (!(0, import_node_fs16.existsSync)(path)) return null;
9011
+ if (!(0, import_node_fs19.existsSync)(path)) return null;
8642
9012
  try {
8643
- return JSON.parse((0, import_node_fs16.readFileSync)(path, "utf8"));
9013
+ return JSON.parse((0, import_node_fs19.readFileSync)(path, "utf8"));
8644
9014
  } catch {
8645
9015
  return null;
8646
9016
  }
@@ -8705,12 +9075,12 @@ function hasCursorWorktreeSetup(worktreePath, repoPath) {
8705
9075
  }
8706
9076
 
8707
9077
  // src/diff/diff.ts
8708
- var import_node_fs17 = require("fs");
9078
+ var import_node_fs20 = require("fs");
8709
9079
  var import_node_path17 = require("path");
8710
9080
  init_run();
8711
9081
  init_worktree();
8712
9082
  async function inspectGitWorktree(worktreePath) {
8713
- if (!worktreePath || !(0, import_node_fs17.existsSync)(worktreePath)) return "missing_worktree";
9083
+ if (!worktreePath || !(0, import_node_fs20.existsSync)(worktreePath)) return "missing_worktree";
8714
9084
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
8715
9085
  reject: false
8716
9086
  });
@@ -8718,7 +9088,7 @@ async function inspectGitWorktree(worktreePath) {
8718
9088
  return "ok";
8719
9089
  }
8720
9090
  async function initializeGitRepository(worktreePath) {
8721
- if (!worktreePath || !(0, import_node_fs17.existsSync)(worktreePath)) {
9091
+ if (!worktreePath || !(0, import_node_fs20.existsSync)(worktreePath)) {
8722
9092
  throw new Error("Worktree not found");
8723
9093
  }
8724
9094
  const status = await inspectGitWorktree(worktreePath);
@@ -9156,7 +9526,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
9156
9526
  assertSafeRelativePath(relativePath);
9157
9527
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
9158
9528
  const abs = (0, import_node_path17.join)(worktreePath, relativePath);
9159
- const st = (0, import_node_fs17.statSync)(abs);
9529
+ const st = (0, import_node_fs20.statSync)(abs);
9160
9530
  if (!st.isFile()) {
9161
9531
  throw new Error(`Not a file: ${relativePath}`);
9162
9532
  }
@@ -9165,7 +9535,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
9165
9535
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
9166
9536
  );
9167
9537
  }
9168
- const buf = (0, import_node_fs17.readFileSync)(abs);
9538
+ const buf = (0, import_node_fs20.readFileSync)(abs);
9169
9539
  return {
9170
9540
  path: relativePath,
9171
9541
  contentBase64: buf.toString("base64"),
@@ -9176,11 +9546,11 @@ function readWorktreeFile(worktreePath, relativePath, opts) {
9176
9546
  assertSafeRelativePath(relativePath);
9177
9547
  const maxBytes = opts?.maxBytes ?? 2e5;
9178
9548
  const abs = (0, import_node_path17.join)(worktreePath, relativePath);
9179
- const st = (0, import_node_fs17.statSync)(abs);
9549
+ const st = (0, import_node_fs20.statSync)(abs);
9180
9550
  if (!st.isFile()) {
9181
9551
  throw new Error(`Not a file: ${relativePath}`);
9182
9552
  }
9183
- const buf = (0, import_node_fs17.readFileSync)(abs);
9553
+ const buf = (0, import_node_fs20.readFileSync)(abs);
9184
9554
  if (isImageRelativePath(relativePath)) {
9185
9555
  const maxImageBytes = Math.max(maxBytes, 15e6);
9186
9556
  const truncated2 = buf.length > maxImageBytes;
@@ -9224,8 +9594,8 @@ function assertSafeRelativePath(relativePath) {
9224
9594
  function writeWorktreeFile(worktreePath, relativePath, content) {
9225
9595
  assertSafeRelativePath(relativePath);
9226
9596
  const abs = (0, import_node_path17.join)(worktreePath, relativePath);
9227
- (0, import_node_fs17.mkdirSync)((0, import_node_path17.dirname)(abs), { recursive: true });
9228
- (0, import_node_fs17.writeFileSync)(abs, content, "utf8");
9597
+ (0, import_node_fs20.mkdirSync)((0, import_node_path17.dirname)(abs), { recursive: true });
9598
+ (0, import_node_fs20.writeFileSync)(abs, content, "utf8");
9229
9599
  return { path: relativePath };
9230
9600
  }
9231
9601
  async function getDiffSummary(worktreePath, repoPath, opts) {
@@ -9244,7 +9614,7 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
9244
9614
  }
9245
9615
 
9246
9616
  // src/skills/discover.ts
9247
- var import_node_fs18 = require("fs");
9617
+ var import_node_fs21 = require("fs");
9248
9618
  var import_node_os8 = require("os");
9249
9619
  var import_node_path18 = require("path");
9250
9620
  function toCommand(name) {
@@ -9278,7 +9648,7 @@ function parseFrontmatter(content) {
9278
9648
  }
9279
9649
  function readSkill(skillMd, source) {
9280
9650
  try {
9281
- const content = (0, import_node_fs18.readFileSync)(skillMd, "utf8");
9651
+ const content = (0, import_node_fs21.readFileSync)(skillMd, "utf8");
9282
9652
  const { name: fmName, description } = parseFrontmatter(content);
9283
9653
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
9284
9654
  const name = fmName || dirName;
@@ -9297,19 +9667,19 @@ function readSkill(skillMd, source) {
9297
9667
  }
9298
9668
  }
9299
9669
  function scanSkillsDir(dir, source, out) {
9300
- if (!(0, import_node_fs18.existsSync)(dir)) return;
9670
+ if (!(0, import_node_fs21.existsSync)(dir)) return;
9301
9671
  let entries;
9302
9672
  try {
9303
- entries = (0, import_node_fs18.readdirSync)(dir);
9673
+ entries = (0, import_node_fs21.readdirSync)(dir);
9304
9674
  } catch {
9305
9675
  return;
9306
9676
  }
9307
9677
  for (const entry of entries) {
9308
9678
  if (entry.startsWith(".")) continue;
9309
9679
  const skillMd = (0, import_node_path18.join)(dir, entry, "SKILL.md");
9310
- if (!(0, import_node_fs18.existsSync)(skillMd)) continue;
9680
+ if (!(0, import_node_fs21.existsSync)(skillMd)) continue;
9311
9681
  try {
9312
- if (!(0, import_node_fs18.statSync)(skillMd).isFile()) continue;
9682
+ if (!(0, import_node_fs21.statSync)(skillMd).isFile()) continue;
9313
9683
  } catch {
9314
9684
  continue;
9315
9685
  }
@@ -9318,12 +9688,12 @@ function scanSkillsDir(dir, source, out) {
9318
9688
  }
9319
9689
  }
9320
9690
  function scanClaudePluginSkills(pluginsRoot, out) {
9321
- if (!(0, import_node_fs18.existsSync)(pluginsRoot)) return;
9691
+ if (!(0, import_node_fs21.existsSync)(pluginsRoot)) return;
9322
9692
  const walk = (dir, depth, lookingForSkillsDir) => {
9323
9693
  if (depth > 7) return;
9324
9694
  let entries;
9325
9695
  try {
9326
- entries = (0, import_node_fs18.readdirSync)(dir);
9696
+ entries = (0, import_node_fs21.readdirSync)(dir);
9327
9697
  } catch {
9328
9698
  return;
9329
9699
  }
@@ -9335,7 +9705,7 @@ function scanClaudePluginSkills(pluginsRoot, out) {
9335
9705
  if (entry === "node_modules" || entry === ".git") continue;
9336
9706
  const full = (0, import_node_path18.join)(dir, entry);
9337
9707
  try {
9338
- if (!(0, import_node_fs18.statSync)(full).isDirectory()) continue;
9708
+ if (!(0, import_node_fs21.statSync)(full).isDirectory()) continue;
9339
9709
  } catch {
9340
9710
  continue;
9341
9711
  }
@@ -9375,7 +9745,7 @@ function discoverSkills(worktreePath) {
9375
9745
  return [...byCommand.values()].sort((a, b) => a.command.localeCompare(b.command));
9376
9746
  }
9377
9747
  function readSkillBody(skillPath, maxChars = 12e3) {
9378
- const raw = (0, import_node_fs18.readFileSync)(skillPath, "utf8");
9748
+ const raw = (0, import_node_fs21.readFileSync)(skillPath, "utf8");
9379
9749
  if (raw.startsWith("---")) {
9380
9750
  const end = raw.indexOf("\n---", 3);
9381
9751
  if (end >= 0) {
@@ -9516,7 +9886,7 @@ function buildDiffCommentAttachment(input) {
9516
9886
  }
9517
9887
 
9518
9888
  // src/composer/stage-files.ts
9519
- var import_node_fs19 = require("fs");
9889
+ var import_node_fs22 = require("fs");
9520
9890
  var import_node_path19 = require("path");
9521
9891
  var import_node_crypto2 = require("crypto");
9522
9892
  init_workspace_scratch();
@@ -9554,21 +9924,21 @@ function imageMimeType(filePath) {
9554
9924
  }
9555
9925
  function ensureAttachmentsDir(worktreePath) {
9556
9926
  const dir = (0, import_node_path19.join)(worktreePath, ATTACHMENTS_DIR);
9557
- (0, import_node_fs19.mkdirSync)(dir, { recursive: true });
9927
+ (0, import_node_fs22.mkdirSync)(dir, { recursive: true });
9558
9928
  const gi = (0, import_node_path19.join)(dir, ".gitignore");
9559
- if (!(0, import_node_fs19.existsSync)(gi)) {
9560
- (0, import_node_fs19.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
9929
+ if (!(0, import_node_fs22.existsSync)(gi)) {
9930
+ (0, import_node_fs22.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
9561
9931
  }
9562
9932
  return dir;
9563
9933
  }
9564
9934
  function uniqueAttachmentName(dir, originalName) {
9565
9935
  const safe = originalName.replace(/[/\\]/g, "_") || "file";
9566
- if (!(0, import_node_fs19.existsSync)((0, import_node_path19.join)(dir, safe))) return safe;
9936
+ if (!(0, import_node_fs22.existsSync)((0, import_node_path19.join)(dir, safe))) return safe;
9567
9937
  const ext = (0, import_node_path19.extname)(safe);
9568
9938
  const stem = ext ? safe.slice(0, -ext.length) : safe;
9569
9939
  for (let i = 1; i < 1e4; i++) {
9570
9940
  const candidate = `${stem}-${i}${ext}`;
9571
- if (!(0, import_node_fs19.existsSync)((0, import_node_path19.join)(dir, candidate))) return candidate;
9941
+ if (!(0, import_node_fs22.existsSync)((0, import_node_path19.join)(dir, candidate))) return candidate;
9572
9942
  }
9573
9943
  return `${stem}-${(0, import_node_crypto2.randomUUID)()}${ext}`;
9574
9944
  }
@@ -9622,7 +9992,7 @@ function attachmentFromBuffer(name, buf, opts) {
9622
9992
  function attachmentFromAbsolutePath(absolutePath) {
9623
9993
  const name = (0, import_node_path19.basename)(absolutePath);
9624
9994
  try {
9625
- const st = (0, import_node_fs19.statSync)(absolutePath);
9995
+ const st = (0, import_node_fs22.statSync)(absolutePath);
9626
9996
  if (!st.isFile()) {
9627
9997
  return {
9628
9998
  id: (0, import_node_crypto2.randomUUID)(),
@@ -9631,7 +10001,7 @@ function attachmentFromAbsolutePath(absolutePath) {
9631
10001
  content: `(not a file: ${absolutePath})`
9632
10002
  };
9633
10003
  }
9634
- const buf = (0, import_node_fs19.readFileSync)(absolutePath);
10004
+ const buf = (0, import_node_fs22.readFileSync)(absolutePath);
9635
10005
  return attachmentFromBuffer(name, buf, { sourceLabel: absolutePath });
9636
10006
  } catch (err) {
9637
10007
  return {
@@ -9649,13 +10019,13 @@ function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
9649
10019
  for (const abs of absolutePaths) {
9650
10020
  const originalName = (0, import_node_path19.basename)(abs);
9651
10021
  try {
9652
- const st = (0, import_node_fs19.statSync)(abs);
10022
+ const st = (0, import_node_fs22.statSync)(abs);
9653
10023
  if (!st.isFile()) continue;
9654
10024
  const name = uniqueAttachmentName(dir, originalName);
9655
10025
  const destAbs = (0, import_node_path19.join)(dir, name);
9656
- (0, import_node_fs19.copyFileSync)(abs, destAbs);
10026
+ (0, import_node_fs22.copyFileSync)(abs, destAbs);
9657
10027
  const rel = `${ATTACHMENTS_DIR}/${name}`;
9658
- const buf = (0, import_node_fs19.readFileSync)(destAbs);
10028
+ const buf = (0, import_node_fs22.readFileSync)(destAbs);
9659
10029
  out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
9660
10030
  } catch (err) {
9661
10031
  out.push({
@@ -9678,7 +10048,7 @@ function stageBuffersAsAttachments(worktreePath, buffers) {
9678
10048
  const buf = Buffer.from(item.dataBase64, "base64");
9679
10049
  const name = uniqueAttachmentName(dir, originalName);
9680
10050
  const destAbs = (0, import_node_path19.join)(dir, name);
9681
- (0, import_node_fs19.writeFileSync)(destAbs, buf);
10051
+ (0, import_node_fs22.writeFileSync)(destAbs, buf);
9682
10052
  const rel = `${ATTACHMENTS_DIR}/${name}`;
9683
10053
  out.push(attachmentFromBuffer(name, buf, { path: rel }));
9684
10054
  } catch (err) {
@@ -9723,9 +10093,9 @@ function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
9723
10093
  const name = (0, import_node_path19.basename)(rel);
9724
10094
  try {
9725
10095
  const abs = (0, import_node_path19.join)(worktreePath, rel);
9726
- const st = (0, import_node_fs19.statSync)(abs);
10096
+ const st = (0, import_node_fs22.statSync)(abs);
9727
10097
  if (!st.isFile()) continue;
9728
- const buf = (0, import_node_fs19.readFileSync)(abs);
10098
+ const buf = (0, import_node_fs22.readFileSync)(abs);
9729
10099
  out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
9730
10100
  } catch (err) {
9731
10101
  out.push({
@@ -10213,7 +10583,7 @@ async function confirmLand(thread, opts) {
10213
10583
  }
10214
10584
 
10215
10585
  // src/threads/create.ts
10216
- var import_node_fs20 = require("fs");
10586
+ var import_node_fs23 = require("fs");
10217
10587
  init_worktree();
10218
10588
  init_app_settings();
10219
10589
  init_thread_store();
@@ -10227,7 +10597,7 @@ async function createThread(input, _onSetupLine) {
10227
10597
  });
10228
10598
  await requireAgent(resolved.agent);
10229
10599
  const repoPath = await resolveRepoRoot(input.repoPath);
10230
- if (!(0, import_node_fs20.existsSync)(repoPath)) {
10600
+ if (!(0, import_node_fs23.existsSync)(repoPath)) {
10231
10601
  throw new Error(`Repo not found: ${repoPath}`);
10232
10602
  }
10233
10603
  let sourceRef = input.sourceRef;
@@ -10454,7 +10824,7 @@ async function forkThreadWorktree(input, onSetupLine) {
10454
10824
  }
10455
10825
 
10456
10826
  // src/threads/stack-layers.ts
10457
- var import_node_fs21 = require("fs");
10827
+ var import_node_fs24 = require("fs");
10458
10828
  init_run();
10459
10829
  init_stack();
10460
10830
  init_worktree();
@@ -10522,7 +10892,7 @@ async function openStackLayer(input, _onSetupLine) {
10522
10892
  let createdWorktree = false;
10523
10893
  const trees = await listWorktrees(repoPath);
10524
10894
  const checkedOut = trees.find((w) => w.branch === branchName);
10525
- if (checkedOut?.path && (0, import_node_fs21.existsSync)(checkedOut.path)) {
10895
+ if (checkedOut?.path && (0, import_node_fs24.existsSync)(checkedOut.path)) {
10526
10896
  if (input.reuseExistingWorktree !== false) {
10527
10897
  worktreePath = checkedOut.path;
10528
10898
  } else {
@@ -10664,7 +11034,7 @@ async function initStackFromThread(input, onSetupLine) {
10664
11034
  async function createPrStack(input, onSetupLine) {
10665
11035
  await requireAgent(input.agent);
10666
11036
  const repoPath = await resolveRepoRoot(input.repoPath);
10667
- if (!(0, import_node_fs21.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
11037
+ if (!(0, import_node_fs24.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
10668
11038
  if (!input.branches.length) throw new Error("At least one branch name required");
10669
11039
  const status = await detectGhStack(repoPath);
10670
11040
  if (!status.available) throw new Error(status.reason);
@@ -10731,7 +11101,7 @@ async function createPrStack(input, onSetupLine) {
10731
11101
  }
10732
11102
  }
10733
11103
  const claimed = new Set(threads.map((t) => t.worktreePath));
10734
- if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs21.existsSync)(bootstrap.worktreePath)) {
11104
+ if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs24.existsSync)(bootstrap.worktreePath)) {
10735
11105
  try {
10736
11106
  await removeWorktree(repoPath, bootstrap.worktreePath, {
10737
11107
  deleteBranch: bootstrap.branchName
@@ -10753,8 +11123,8 @@ function stackAgentDefaultsFrom(input) {
10753
11123
  }
10754
11124
 
10755
11125
  // src/threads/adopt.ts
10756
- var import_node_child_process = require("child_process");
10757
- var import_node_fs22 = require("fs");
11126
+ var import_node_child_process2 = require("child_process");
11127
+ var import_node_fs25 = require("fs");
10758
11128
  var import_node_os9 = require("os");
10759
11129
  var import_node_path20 = require("path");
10760
11130
  var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
@@ -10779,21 +11149,21 @@ function mapAgentType(raw) {
10779
11149
  return null;
10780
11150
  }
10781
11151
  function resolveConductorCursorAgentId(workspacePath) {
10782
- if (!workspacePath || !(0, import_node_fs22.existsSync)(CURSOR_SDK_STORE)) return null;
11152
+ if (!workspacePath || !(0, import_node_fs25.existsSync)(CURSOR_SDK_STORE)) return null;
10783
11153
  const normalized = workspacePath.replace(/\/$/, "");
10784
11154
  let best = null;
10785
11155
  let hashes;
10786
11156
  try {
10787
- hashes = (0, import_node_fs22.readdirSync)(CURSOR_SDK_STORE);
11157
+ hashes = (0, import_node_fs25.readdirSync)(CURSOR_SDK_STORE);
10788
11158
  } catch {
10789
11159
  return null;
10790
11160
  }
10791
11161
  for (const hash of hashes) {
10792
11162
  const agentsFile = (0, import_node_path20.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
10793
- if (!(0, import_node_fs22.existsSync)(agentsFile)) continue;
11163
+ if (!(0, import_node_fs25.existsSync)(agentsFile)) continue;
10794
11164
  let text;
10795
11165
  try {
10796
- text = (0, import_node_fs22.readFileSync)(agentsFile, "utf8");
11166
+ text = (0, import_node_fs25.readFileSync)(agentsFile, "utf8");
10797
11167
  } catch {
10798
11168
  continue;
10799
11169
  }
@@ -10817,7 +11187,7 @@ function resolveConductorCursorAgentId(workspacePath) {
10817
11187
  return best?.agentId ?? null;
10818
11188
  }
10819
11189
  async function adoptThread(input) {
10820
- if (!(0, import_node_fs22.existsSync)(input.worktreePath)) {
11190
+ if (!(0, import_node_fs25.existsSync)(input.worktreePath)) {
10821
11191
  throw new Error(`Worktree not found: ${input.worktreePath}`);
10822
11192
  }
10823
11193
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -10844,18 +11214,18 @@ function conductorDbPath() {
10844
11214
  return CONDUCTOR_DB;
10845
11215
  }
10846
11216
  function listConductorWorkspaces() {
10847
- if (!(0, import_node_fs22.existsSync)(CONDUCTOR_DB)) {
11217
+ if (!(0, import_node_fs25.existsSync)(CONDUCTOR_DB)) {
10848
11218
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
10849
11219
  }
10850
- const tmp = (0, import_node_fs22.mkdtempSync)((0, import_node_path20.join)((0, import_node_os9.tmpdir)(), "sideboard-conductor-"));
11220
+ const tmp = (0, import_node_fs25.mkdtempSync)((0, import_node_path20.join)((0, import_node_os9.tmpdir)(), "sideboard-conductor-"));
10851
11221
  const snapshot = (0, import_node_path20.join)(tmp, "conductor.db");
10852
11222
  try {
10853
- (0, import_node_fs22.copyFileSync)(CONDUCTOR_DB, snapshot);
11223
+ (0, import_node_fs25.copyFileSync)(CONDUCTOR_DB, snapshot);
10854
11224
  for (const suffix of ["-wal", "-shm"]) {
10855
11225
  const src = `${CONDUCTOR_DB}${suffix}`;
10856
- if ((0, import_node_fs22.existsSync)(src)) {
11226
+ if ((0, import_node_fs25.existsSync)(src)) {
10857
11227
  try {
10858
- (0, import_node_fs22.copyFileSync)(src, `${snapshot}${suffix}`);
11228
+ (0, import_node_fs25.copyFileSync)(src, `${snapshot}${suffix}`);
10859
11229
  } catch {
10860
11230
  }
10861
11231
  }
@@ -10931,22 +11301,22 @@ function listConductorWorkspaces() {
10931
11301
  db.close();
10932
11302
  }
10933
11303
  } finally {
10934
- (0, import_node_fs22.rmSync)(tmp, { recursive: true, force: true });
11304
+ (0, import_node_fs25.rmSync)(tmp, { recursive: true, force: true });
10935
11305
  }
10936
11306
  }
10937
11307
  function importConductorWorkspace(workspaceId) {
10938
- if (!(0, import_node_fs22.existsSync)(CONDUCTOR_DB)) {
11308
+ if (!(0, import_node_fs25.existsSync)(CONDUCTOR_DB)) {
10939
11309
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
10940
11310
  }
10941
- const tmp = (0, import_node_fs22.mkdtempSync)((0, import_node_path20.join)((0, import_node_os9.tmpdir)(), "sideboard-conductor-"));
11311
+ const tmp = (0, import_node_fs25.mkdtempSync)((0, import_node_path20.join)((0, import_node_os9.tmpdir)(), "sideboard-conductor-"));
10942
11312
  const snapshot = (0, import_node_path20.join)(tmp, "conductor.db");
10943
11313
  try {
10944
- (0, import_node_fs22.copyFileSync)(CONDUCTOR_DB, snapshot);
11314
+ (0, import_node_fs25.copyFileSync)(CONDUCTOR_DB, snapshot);
10945
11315
  for (const suffix of ["-wal", "-shm"]) {
10946
11316
  const src = `${CONDUCTOR_DB}${suffix}`;
10947
- if ((0, import_node_fs22.existsSync)(src)) {
11317
+ if ((0, import_node_fs25.existsSync)(src)) {
10948
11318
  try {
10949
- (0, import_node_fs22.copyFileSync)(src, `${snapshot}${suffix}`);
11319
+ (0, import_node_fs25.copyFileSync)(src, `${snapshot}${suffix}`);
10950
11320
  } catch {
10951
11321
  }
10952
11322
  }
@@ -10964,7 +11334,7 @@ function importConductorWorkspace(workspaceId) {
10964
11334
  ).get(workspaceId);
10965
11335
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
10966
11336
  const worktreePath = String(row.workspacePath);
10967
- if (!(0, import_node_fs22.existsSync)(worktreePath)) {
11337
+ if (!(0, import_node_fs25.existsSync)(worktreePath)) {
10968
11338
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
10969
11339
  }
10970
11340
  let sessionId = null;
@@ -11004,7 +11374,7 @@ function importConductorWorkspace(workspaceId) {
11004
11374
  }
11005
11375
  let repoPath = worktreePath;
11006
11376
  try {
11007
- repoPath = (0, import_node_child_process.execFileSync)("git", ["rev-parse", "--show-toplevel"], {
11377
+ repoPath = (0, import_node_child_process2.execFileSync)("git", ["rev-parse", "--show-toplevel"], {
11008
11378
  cwd: worktreePath,
11009
11379
  encoding: "utf8"
11010
11380
  }).trim();
@@ -11027,7 +11397,7 @@ function importConductorWorkspace(workspaceId) {
11027
11397
  db.close();
11028
11398
  }
11029
11399
  } finally {
11030
- (0, import_node_fs22.rmSync)(tmp, { recursive: true, force: true });
11400
+ (0, import_node_fs25.rmSync)(tmp, { recursive: true, force: true });
11031
11401
  }
11032
11402
  }
11033
11403
  async function importConductorWorkspaceAsync(workspaceId) {
@@ -11036,7 +11406,7 @@ async function importConductorWorkspaceAsync(workspaceId) {
11036
11406
 
11037
11407
  // src/orchestrator/orchestrator.ts
11038
11408
  var import_node_events = require("events");
11039
- var import_node_fs28 = require("fs");
11409
+ var import_node_fs31 = require("fs");
11040
11410
  init_error_detail();
11041
11411
  init_agents();
11042
11412
  init_worktree();
@@ -11057,7 +11427,7 @@ function shouldAutoArchiveOnPrMerge(opts) {
11057
11427
  }
11058
11428
 
11059
11429
  // src/git/orphan-cleanup.ts
11060
- var import_node_fs23 = require("fs");
11430
+ var import_node_fs26 = require("fs");
11061
11431
  var import_node_path21 = require("path");
11062
11432
  init_worktree();
11063
11433
  init_thread_store();
@@ -11073,9 +11443,9 @@ async function findOrphanWorktrees(repoPaths) {
11073
11443
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
11074
11444
  );
11075
11445
  const homeRoot = sideboardWorkspacesDir();
11076
- if ((0, import_node_fs23.existsSync)(homeRoot)) {
11446
+ if ((0, import_node_fs26.existsSync)(homeRoot)) {
11077
11447
  try {
11078
- for (const entry of (0, import_node_fs23.readdirSync)(homeRoot, { withFileTypes: true })) {
11448
+ for (const entry of (0, import_node_fs26.readdirSync)(homeRoot, { withFileTypes: true })) {
11079
11449
  if (!entry.isDirectory()) continue;
11080
11450
  void entry;
11081
11451
  }
@@ -11085,7 +11455,7 @@ async function findOrphanWorktrees(repoPaths) {
11085
11455
  const orphans = [];
11086
11456
  const seen = /* @__PURE__ */ new Set();
11087
11457
  for (const repoPath of repos) {
11088
- if (!repoPath || !(0, import_node_fs23.existsSync)(repoPath)) continue;
11458
+ if (!repoPath || !(0, import_node_fs26.existsSync)(repoPath)) continue;
11089
11459
  try {
11090
11460
  const wts = await listWorktrees(repoPath);
11091
11461
  for (const wt of wts) {
@@ -11096,7 +11466,7 @@ async function findOrphanWorktrees(repoPaths) {
11096
11466
  seen.add(path);
11097
11467
  let mtimeMs = 0;
11098
11468
  try {
11099
- mtimeMs = (0, import_node_fs23.statSync)(path).mtimeMs;
11469
+ mtimeMs = (0, import_node_fs26.statSync)(path).mtimeMs;
11100
11470
  } catch {
11101
11471
  mtimeMs = 0;
11102
11472
  }
@@ -11106,16 +11476,16 @@ async function findOrphanWorktrees(repoPaths) {
11106
11476
  }
11107
11477
  try {
11108
11478
  const root = worktreesRoot(repoPath);
11109
- if ((0, import_node_fs23.existsSync)(root)) {
11110
- for (const entry of (0, import_node_fs23.readdirSync)(root, { withFileTypes: true })) {
11479
+ if ((0, import_node_fs26.existsSync)(root)) {
11480
+ for (const entry of (0, import_node_fs26.readdirSync)(root, { withFileTypes: true })) {
11111
11481
  if (!entry.isDirectory()) continue;
11112
11482
  const path = (0, import_node_path21.join)(root, entry.name).replace(/\/$/, "");
11113
11483
  if (known.has(path) || seen.has(path)) continue;
11114
- if (!(0, import_node_fs23.existsSync)((0, import_node_path21.join)(path, ".git"))) continue;
11484
+ if (!(0, import_node_fs26.existsSync)((0, import_node_path21.join)(path, ".git"))) continue;
11115
11485
  seen.add(path);
11116
11486
  let mtimeMs = 0;
11117
11487
  try {
11118
- mtimeMs = (0, import_node_fs23.statSync)(path).mtimeMs;
11488
+ mtimeMs = (0, import_node_fs26.statSync)(path).mtimeMs;
11119
11489
  } catch {
11120
11490
  mtimeMs = Date.now();
11121
11491
  }
@@ -11261,7 +11631,7 @@ async function applyThreadIntoMain(thread, opts) {
11261
11631
  }
11262
11632
 
11263
11633
  // src/git/clone-repo.ts
11264
- var import_node_fs24 = require("fs");
11634
+ var import_node_fs27 = require("fs");
11265
11635
  var import_node_path22 = require("path");
11266
11636
  var import_execa6 = require("execa");
11267
11637
  init_paths();
@@ -11277,7 +11647,7 @@ async function cloneRepoIntoSideboard(opts) {
11277
11647
  }
11278
11648
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
11279
11649
  const dest = (0, import_node_path22.join)(sideboardReposDir(), name);
11280
- if ((0, import_node_fs24.existsSync)(dest)) {
11650
+ if ((0, import_node_fs27.existsSync)(dest)) {
11281
11651
  const repoPath2 = await resolveRepoRoot(dest);
11282
11652
  const workspace2 = await ensureWorkspace(repoPath2);
11283
11653
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -11299,7 +11669,7 @@ init_orchestrator_capable();
11299
11669
 
11300
11670
  // src/review/request-review.ts
11301
11671
  var import_node_crypto5 = require("crypto");
11302
- var import_node_fs25 = require("fs");
11672
+ var import_node_fs28 = require("fs");
11303
11673
  var import_node_path23 = require("path");
11304
11674
  init_global_workspace();
11305
11675
  init_thread_store();
@@ -11444,9 +11814,9 @@ function shouldRefreshReviewRequestTemplate(content) {
11444
11814
  return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
11445
11815
  }
11446
11816
  function readTextIfPresent(abs) {
11447
- if (!(0, import_node_fs25.existsSync)(abs)) return null;
11817
+ if (!(0, import_node_fs28.existsSync)(abs)) return null;
11448
11818
  try {
11449
- const content = (0, import_node_fs25.readFileSync)(abs, "utf8");
11819
+ const content = (0, import_node_fs28.readFileSync)(abs, "utf8");
11450
11820
  return content.trim() ? content : null;
11451
11821
  } catch {
11452
11822
  return null;
@@ -11454,9 +11824,9 @@ function readTextIfPresent(abs) {
11454
11824
  }
11455
11825
  function ensureAttachmentsGitignore(worktreePath) {
11456
11826
  const gitignoreAbs = (0, import_node_path23.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
11457
- if ((0, import_node_fs25.existsSync)(gitignoreAbs)) return;
11458
- (0, import_node_fs25.mkdirSync)((0, import_node_path23.dirname)(gitignoreAbs), { recursive: true });
11459
- (0, import_node_fs25.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
11827
+ if ((0, import_node_fs28.existsSync)(gitignoreAbs)) return;
11828
+ (0, import_node_fs28.mkdirSync)((0, import_node_path23.dirname)(gitignoreAbs), { recursive: true });
11829
+ (0, import_node_fs28.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
11460
11830
  }
11461
11831
  function resolveReviewGuidelines(worktreePath) {
11462
11832
  const repoAbs = (0, import_node_path23.join)(worktreePath, REPO_REVIEW_PATH);
@@ -11490,8 +11860,8 @@ function resolveReviewGuidelines(worktreePath) {
11490
11860
  };
11491
11861
  }
11492
11862
  ensureAttachmentsGitignore(worktreePath);
11493
- (0, import_node_fs25.mkdirSync)((0, import_node_path23.dirname)(localAbs), { recursive: true });
11494
- (0, import_node_fs25.writeFileSync)(localAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
11863
+ (0, import_node_fs28.mkdirSync)((0, import_node_path23.dirname)(localAbs), { recursive: true });
11864
+ (0, import_node_fs28.writeFileSync)(localAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
11495
11865
  return {
11496
11866
  path: REVIEW_REQUEST_PATH,
11497
11867
  name: REVIEW_REQUEST_NAME,
@@ -11513,7 +11883,7 @@ function ensureReviewRequestFile(worktreePath) {
11513
11883
  const localAbs = (0, import_node_path23.join)(worktreePath, REVIEW_REQUEST_PATH);
11514
11884
  const localContent = readTextIfPresent(localAbs) ?? readTextIfPresent((0, import_node_path23.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
11515
11885
  if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
11516
- const path = (0, import_node_fs25.existsSync)(localAbs) ? REVIEW_REQUEST_PATH : LEGACY_REVIEW_REQUEST_PATH;
11886
+ const path = (0, import_node_fs28.existsSync)(localAbs) ? REVIEW_REQUEST_PATH : LEGACY_REVIEW_REQUEST_PATH;
11517
11887
  return {
11518
11888
  path,
11519
11889
  name: REVIEW_REQUEST_NAME,
@@ -11521,8 +11891,8 @@ function ensureReviewRequestFile(worktreePath) {
11521
11891
  source: "local"
11522
11892
  };
11523
11893
  }
11524
- (0, import_node_fs25.mkdirSync)((0, import_node_path23.dirname)(repoAbs), { recursive: true });
11525
- (0, import_node_fs25.writeFileSync)(repoAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
11894
+ (0, import_node_fs28.mkdirSync)((0, import_node_path23.dirname)(repoAbs), { recursive: true });
11895
+ (0, import_node_fs28.writeFileSync)(repoAbs, REVIEW_REQUEST_TEMPLATE, "utf8");
11526
11896
  return {
11527
11897
  path: REPO_REVIEW_PATH,
11528
11898
  name: REPO_REVIEW_NAME,
@@ -11802,7 +12172,7 @@ var Orchestrator = class {
11802
12172
  }
11803
12173
  continue;
11804
12174
  }
11805
- if (!(0, import_node_fs28.existsSync)(thread.worktreePath)) {
12175
+ if (!(0, import_node_fs31.existsSync)(thread.worktreePath)) {
11806
12176
  setStatus(thread.id, "broken", "Worktree missing on disk");
11807
12177
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
11808
12178
  continue;
@@ -12219,13 +12589,14 @@ var Orchestrator = class {
12219
12589
  "Files column: MCP present_files (brightsy account storage or memory).",
12220
12590
  "Do not say artifacts/CMS UI are unavailable."
12221
12591
  ].join(" ") : null;
12592
+ const worktreeReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatWorktreeReminder() : null;
12222
12593
  const agentPrompt = [
12223
12594
  thread.planMode ? PLAN_MODE_INSTRUCTION : null,
12224
12595
  orchestrationReminder,
12596
+ worktreeReminder,
12225
12597
  artifactReminder,
12226
12598
  expandedPrompt
12227
12599
  ].filter(Boolean).join("\n\n");
12228
- const instructionFiles = loadAgentInstructions(thread.worktreePath, thread.agent);
12229
12600
  if (thread.attachments.length > 0) {
12230
12601
  updateThread(threadId, { attachments: [] });
12231
12602
  }
@@ -12253,7 +12624,6 @@ var Orchestrator = class {
12253
12624
  const renameBranchDirective = !isBrightsy && !isOrchestration && autoRenameBranchEnabled2() ? formatRenameBranchDirective(fresh, {
12254
12625
  customPrompt: settings?.prompts?.renameBranch
12255
12626
  }) : null;
12256
- const instructions = fresh.agent === "claude" || isBrightsy ? null : formatAgentInstructions(instructionFiles);
12257
12627
  let seed = null;
12258
12628
  if (!fresh.sessionId) {
12259
12629
  const prior = fresh.messages.slice(0, -1);
@@ -12274,12 +12644,12 @@ var Orchestrator = class {
12274
12644
  });
12275
12645
  }
12276
12646
  }
12277
- const cachedPrefix = [
12647
+ const cachedPrefix = fresh.sessionId ? "" : [
12278
12648
  coordinatorDirective,
12279
12649
  worktreeDirective,
12280
12650
  artifactDirective,
12281
12651
  renameBranchDirective,
12282
- ...fresh.agent === "claude" && fresh.sessionId ? [] : [instructions, seed]
12652
+ seed
12283
12653
  ].filter(Boolean).join("\n\n---\n\n");
12284
12654
  try {
12285
12655
  const stderrTail = [];
@@ -12366,15 +12736,11 @@ var Orchestrator = class {
12366
12736
  const retryThread = this.requireThread(threadId);
12367
12737
  const prior = retryThread.messages.slice(0, -1);
12368
12738
  const retrySeed = buildSessionSeed(prior);
12369
- const retryInstructions = retryThread.agent === "claude" ? null : formatAgentInstructions(
12370
- loadAgentInstructions(retryThread.worktreePath, retryThread.agent)
12371
- );
12372
12739
  const retryPrefix = [
12373
12740
  coordinatorDirective,
12374
12741
  worktreeDirective,
12375
12742
  artifactDirective,
12376
12743
  renameBranchDirective,
12377
- retryInstructions,
12378
12744
  retrySeed
12379
12745
  ].filter(Boolean).join("\n\n---\n\n");
12380
12746
  const retryHandle = await spawnAgentTurn(
@@ -13209,7 +13575,7 @@ var Orchestrator = class {
13209
13575
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
13210
13576
  return restored2;
13211
13577
  }
13212
- if (!(0, import_node_fs28.existsSync)(thread.worktreePath)) {
13578
+ if (!(0, import_node_fs31.existsSync)(thread.worktreePath)) {
13213
13579
  const { createThreadWorktree: createThreadWorktree2 } = await Promise.resolve().then(() => (init_worktree(), worktree_exports));
13214
13580
  const { execa: execa7 } = await import("execa");
13215
13581
  const slug = thread.worktreePath.split("/").pop();
@@ -13465,6 +13831,7 @@ function mcpArchiveBlockedReason(thread) {
13465
13831
  }
13466
13832
 
13467
13833
  // src/mcp/server.ts
13834
+ init_profile();
13468
13835
  var MAX_ORCH_THREADS = 5;
13469
13836
  var CREATE_THREAD_TIMEOUT_MS = 9e4;
13470
13837
  function withTimeout(promise, ms, label) {
@@ -13578,14 +13945,13 @@ async function startMcpServer() {
13578
13945
  ),
13579
13946
  artifact_id: import_zod.z.string().optional().describe("Stable id when updating the same artifact across turns")
13580
13947
  },
13581
- async ({ title, type, content, artifact_id }) => {
13948
+ async ({ title, type, artifact_id }) => {
13582
13949
  const id = artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
13583
13950
  const payload = {
13584
13951
  ok: true,
13585
13952
  artifact_id: id,
13586
13953
  title,
13587
13954
  type,
13588
- content,
13589
13955
  message: "Artifact accepted. Sideboard desktop opens it in the side column beside chat."
13590
13956
  };
13591
13957
  return { content: [{ type: "text", text: JSON.stringify(payload) }] };
@@ -13638,7 +14004,6 @@ async function startMcpServer() {
13638
14004
  ok: true,
13639
14005
  path,
13640
14006
  title: title?.trim() || "Plan",
13641
- content,
13642
14007
  message: "Plan saved to .context/attachments/plan.md and shown in Sideboard chat for approval."
13643
14008
  };
13644
14009
  return { content: [{ type: "text", text: JSON.stringify(payload) }] };
@@ -13668,9 +14033,6 @@ async function startMcpServer() {
13668
14033
  datasource: args.datasource ?? (args.resource ? "inline" : "brightsy"),
13669
14034
  resource_id: args.resource_id,
13670
14035
  record_id: args.record_id,
13671
- resource: args.resource,
13672
- record: args.record,
13673
- records: args.records,
13674
14036
  message: "Schema pane accepted. Sideboard desktop opens the CMS column beside chat."
13675
14037
  };
13676
14038
  return { content: [{ type: "text", text: JSON.stringify(payload) }] };
@@ -13698,744 +14060,747 @@ async function startMcpServer() {
13698
14060
  return { content: [{ type: "text", text: JSON.stringify(payload) }] };
13699
14061
  }
13700
14062
  );
13701
- const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
13702
- const accountDefaults = resolveThreadDefaults2();
13703
- const accountDefaultsHint = `Account defaults: agent=${accountDefaults.agent}, model=${accountDefaults.model?.trim() || "Auto"}, effort=${accountDefaults.effort}`;
13704
- server.tool(
13705
- "create_thread",
13706
- `Create a new worktree thread (chat) from branch, pr, or ticket. Pass repoPath from list_workspaces. From an orchestration chat, omit parentThreadId (Sideboard binds the child to this chat) or pass the exact id from the turn reminder \u2014 never invent a uuid. Prefer omitting agent/model so Sideboard applies ${accountDefaultsHint}. Then use send_to_thread to chat.`,
13707
- {
13708
- sourceType: import_zod.z.enum(["branch", "pr", "ticket"]),
13709
- sourceRef: import_zod.z.string(),
13710
- agent: import_zod.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]).optional().describe(`Omit to use Account default agent (${accountDefaults.agent})`),
13711
- model: import_zod.z.string().nullable().optional().describe(
13712
- `Usually omit to use Account default model (${accountDefaults.model?.trim() || "Auto"}). Pass null only to force Auto / agent-default.`
13713
- ),
13714
- repoPath: import_zod.z.string(),
13715
- title: import_zod.z.string().optional(),
13716
- parentThreadId: import_zod.z.string().optional().describe(
13717
- "Orchestration: omit (preferred) or pass YOUR chat id from the turn reminder / AGENTS.md. Do not invent uuids."
13718
- )
13719
- },
13720
- async (args) => {
13721
- const envParentId = process.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || "";
13722
- let parentId = args.parentThreadId?.trim() || "";
13723
- let parent = parentId ? orch.getThread(parentId) : null;
13724
- let parentCorrectedFrom;
13725
- if (envParentId) {
13726
- const envParent = orch.getThread(envParentId);
13727
- if (envParent) {
13728
- if (parentId && parentId !== envParentId) parentCorrectedFrom = parentId;
13729
- else if (!parentId) parentCorrectedFrom = void 0;
13730
- parentId = envParentId;
13731
- parent = envParent;
14063
+ if (sideboardMcpProfile() !== "worktree") {
14064
+ const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
14065
+ const accountDefaults = resolveThreadDefaults2();
14066
+ const accountDefaultsHint = `Account defaults: agent=${accountDefaults.agent}, model=${accountDefaults.model?.trim() || "Auto"}, effort=${accountDefaults.effort}`;
14067
+ server.tool(
14068
+ "create_thread",
14069
+ `Create a new worktree thread (chat) from branch, pr, or ticket. Pass repoPath from list_workspaces. From an orchestration chat, omit parentThreadId (Sideboard binds the child to this chat) or pass the exact id from the turn reminder \u2014 never invent a uuid. Prefer omitting agent/model so Sideboard applies ${accountDefaultsHint}. Then use send_to_thread to chat.`,
14070
+ {
14071
+ sourceType: import_zod.z.enum(["branch", "pr", "ticket"]),
14072
+ sourceRef: import_zod.z.string(),
14073
+ agent: import_zod.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]).optional().describe(`Omit to use Account default agent (${accountDefaults.agent})`),
14074
+ model: import_zod.z.string().nullable().optional().describe(
14075
+ `Usually omit to use Account default model (${accountDefaults.model?.trim() || "Auto"}). Pass null only to force Auto / agent-default.`
14076
+ ),
14077
+ repoPath: import_zod.z.string(),
14078
+ title: import_zod.z.string().optional(),
14079
+ parentThreadId: import_zod.z.string().optional().describe(
14080
+ "Orchestration: omit (preferred) or pass YOUR chat id from the turn reminder / AGENTS.md. Do not invent uuids."
14081
+ )
14082
+ },
14083
+ async (args) => {
14084
+ const envParentId = process.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || "";
14085
+ let parentId = args.parentThreadId?.trim() || "";
14086
+ let parent = parentId ? orch.getThread(parentId) : null;
14087
+ let parentCorrectedFrom;
14088
+ if (envParentId) {
14089
+ const envParent = orch.getThread(envParentId);
14090
+ if (envParent) {
14091
+ if (parentId && parentId !== envParentId) parentCorrectedFrom = parentId;
14092
+ else if (!parentId) parentCorrectedFrom = void 0;
14093
+ parentId = envParentId;
14094
+ parent = envParent;
14095
+ }
13732
14096
  }
13733
- }
13734
- if (parentId && !parent) {
13735
- parentCorrectedFrom = parentId;
13736
- parentId = "";
13737
- parent = null;
13738
- }
13739
- if (parentId) {
13740
- const children = orch.getThreads(false).filter((t) => t.parentThreadId === parentId);
13741
- if (children.length >= MAX_ORCH_THREADS) {
14097
+ if (parentId && !parent) {
14098
+ parentCorrectedFrom = parentId;
14099
+ parentId = "";
14100
+ parent = null;
14101
+ }
14102
+ if (parentId) {
14103
+ const children = orch.getThreads(false).filter((t) => t.parentThreadId === parentId);
14104
+ if (children.length >= MAX_ORCH_THREADS) {
14105
+ return {
14106
+ content: [
14107
+ {
14108
+ type: "text",
14109
+ text: `Thread-creation cap (${MAX_ORCH_THREADS}) reached for this orchestration session`
14110
+ }
14111
+ ],
14112
+ isError: true
14113
+ };
14114
+ }
14115
+ }
14116
+ let agentArg = args.agent;
14117
+ let agentCoercedFrom;
14118
+ const resolvedProbe = resolveNewThreadOptions2({ agent: agentArg }).agent;
14119
+ if (resolvedProbe === "codex") {
14120
+ agentCoercedFrom = agentArg ?? "codex";
14121
+ const accountAgent = resolveNewThreadOptions2({}).agent;
14122
+ agentArg = accountAgent !== "codex" ? accountAgent : "cursor";
14123
+ }
14124
+ const opts = resolveNewThreadOptions2({
14125
+ agent: agentArg,
14126
+ model: args.model
14127
+ });
14128
+ try {
14129
+ const thread = await withTimeout(
14130
+ orch.createThread({
14131
+ sourceType: args.sourceType,
14132
+ sourceRef: args.sourceRef,
14133
+ agent: opts.agent,
14134
+ model: opts.model,
14135
+ effort: opts.effort,
14136
+ fast: opts.fast,
14137
+ repoPath: args.repoPath,
14138
+ title: args.title,
14139
+ parentThreadId: parentId || null
14140
+ }),
14141
+ CREATE_THREAD_TIMEOUT_MS,
14142
+ "create_thread"
14143
+ );
14144
+ const parentNote = parentCorrectedFrom ? parentId ? `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; nested under ${parentId}` : `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; created without parent` : void 0;
14145
+ return {
14146
+ content: [
14147
+ {
14148
+ type: "text",
14149
+ text: JSON.stringify({
14150
+ id: thread.id,
14151
+ title: thread.title,
14152
+ branchName: thread.branchName,
14153
+ worktreePath: thread.worktreePath,
14154
+ agent: thread.agent,
14155
+ model: thread.model,
14156
+ status: thread.status,
14157
+ link: `sideboard://thread/${thread.id}`,
14158
+ parentThreadId: thread.parentThreadId,
14159
+ ...agentCoercedFrom ? {
14160
+ agentCoercedFrom,
14161
+ note: `Avoid nested Codex under a Codex orchestrator \u2014 used Account default agent=${thread.agent}`
14162
+ } : {},
14163
+ ...parentCorrectedFrom ? { parentCorrectedFrom, parentNote } : {}
14164
+ })
14165
+ }
14166
+ ]
14167
+ };
14168
+ } catch (err) {
14169
+ const message = err instanceof Error ? err.message : String(err);
13742
14170
  return {
13743
14171
  content: [
13744
14172
  {
13745
14173
  type: "text",
13746
- text: `Thread-creation cap (${MAX_ORCH_THREADS}) reached for this orchestration session`
14174
+ text: `create_thread failed: ${message}`
13747
14175
  }
13748
14176
  ],
13749
14177
  isError: true
13750
14178
  };
13751
14179
  }
13752
14180
  }
13753
- let agentArg = args.agent;
13754
- let agentCoercedFrom;
13755
- const resolvedProbe = resolveNewThreadOptions2({ agent: agentArg }).agent;
13756
- if (resolvedProbe === "codex") {
13757
- agentCoercedFrom = agentArg ?? "codex";
13758
- const accountAgent = resolveNewThreadOptions2({}).agent;
13759
- agentArg = accountAgent !== "codex" ? accountAgent : "cursor";
13760
- }
13761
- const opts = resolveNewThreadOptions2({
13762
- agent: agentArg,
13763
- model: args.model
13764
- });
13765
- try {
13766
- const thread = await withTimeout(
13767
- orch.createThread({
13768
- sourceType: args.sourceType,
13769
- sourceRef: args.sourceRef,
13770
- agent: opts.agent,
13771
- model: opts.model,
13772
- effort: opts.effort,
13773
- fast: opts.fast,
13774
- repoPath: args.repoPath,
13775
- title: args.title,
13776
- parentThreadId: parentId || null
13777
- }),
13778
- CREATE_THREAD_TIMEOUT_MS,
13779
- "create_thread"
13780
- );
13781
- const parentNote = parentCorrectedFrom ? parentId ? `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; nested under ${parentId}` : `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; created without parent` : void 0;
14181
+ );
14182
+ server.tool(
14183
+ "send_to_thread",
14184
+ "Queue a prompt on a worktree thread chat (runs under concurrency cap). Use after create_thread to start or continue a conversation. Set force_stop=true to interrupt an in-flight/queued turn (kill + clear queue) before queueing this prompt \u2014 use when the thread is mid-turn or has stale queued prompts you need to replace.",
14185
+ {
14186
+ ref: import_zod.z.string(),
14187
+ prompt: import_zod.z.string(),
14188
+ force_stop: import_zod.z.boolean().optional()
14189
+ },
14190
+ async ({ ref, prompt, force_stop }) => {
14191
+ if (force_stop) {
14192
+ const existing = orch.getThread(ref);
14193
+ if (existing) {
14194
+ orch.stop(ref, { clearQueue: true });
14195
+ }
14196
+ }
14197
+ const thread = await orch.send(ref, prompt);
13782
14198
  return {
13783
14199
  content: [
13784
14200
  {
13785
14201
  type: "text",
13786
14202
  text: JSON.stringify({
13787
14203
  id: thread.id,
13788
- title: thread.title,
13789
- branchName: thread.branchName,
13790
- worktreePath: thread.worktreePath,
13791
- agent: thread.agent,
13792
- model: thread.model,
13793
14204
  status: thread.status,
13794
- link: `sideboard://thread/${thread.id}`,
13795
- parentThreadId: thread.parentThreadId,
13796
- ...agentCoercedFrom ? {
13797
- agentCoercedFrom,
13798
- note: `Avoid nested Codex under a Codex orchestrator \u2014 used Account default agent=${thread.agent}`
13799
- } : {},
13800
- ...parentCorrectedFrom ? { parentCorrectedFrom, parentNote } : {}
14205
+ queueLength: thread.queue.length,
14206
+ forceStopped: Boolean(force_stop)
13801
14207
  })
13802
14208
  }
13803
14209
  ]
13804
14210
  };
13805
- } catch (err) {
13806
- const message = err instanceof Error ? err.message : String(err);
14211
+ }
14212
+ );
14213
+ server.tool(
14214
+ "wait_for_turn",
14215
+ "Block until the thread finishes its current/queued turn (avoids polling). Use after send_to_thread to read the agent reply.",
14216
+ {
14217
+ ref: import_zod.z.string(),
14218
+ timeoutMs: import_zod.z.number().optional()
14219
+ },
14220
+ async ({ ref, timeoutMs }) => {
14221
+ const thread = await orch.waitForTurn(ref, timeoutMs ?? 6e5);
14222
+ const result = orch.getTurnResult(thread.id);
13807
14223
  return {
13808
14224
  content: [
13809
14225
  {
13810
14226
  type: "text",
13811
- text: `create_thread failed: ${message}`
14227
+ text: JSON.stringify({
14228
+ id: thread.id,
14229
+ status: result.status,
14230
+ text: result.text
14231
+ })
13812
14232
  }
13813
- ],
13814
- isError: true
14233
+ ]
13815
14234
  };
13816
14235
  }
13817
- }
13818
- );
13819
- server.tool(
13820
- "send_to_thread",
13821
- "Queue a prompt on a worktree thread chat (runs under concurrency cap). Use after create_thread to start or continue a conversation. Set force_stop=true to interrupt an in-flight/queued turn (kill + clear queue) before queueing this prompt \u2014 use when the thread is mid-turn or has stale queued prompts you need to replace.",
13822
- {
13823
- ref: import_zod.z.string(),
13824
- prompt: import_zod.z.string(),
13825
- force_stop: import_zod.z.boolean().optional()
13826
- },
13827
- async ({ ref, prompt, force_stop }) => {
13828
- if (force_stop) {
13829
- const existing = orch.getThread(ref);
13830
- if (existing) {
13831
- orch.stop(ref, { clearQueue: true });
13832
- }
14236
+ );
14237
+ server.tool(
14238
+ "get_turn_result",
14239
+ "Final assistant message only (not full transcript)",
14240
+ { ref: import_zod.z.string() },
14241
+ async ({ ref }) => {
14242
+ const result = orch.getTurnResult(ref);
14243
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
13833
14244
  }
13834
- const thread = await orch.send(ref, prompt);
13835
- return {
13836
- content: [
13837
- {
13838
- type: "text",
13839
- text: JSON.stringify({
13840
- id: thread.id,
13841
- status: thread.status,
13842
- queueLength: thread.queue.length,
13843
- forceStopped: Boolean(force_stop)
13844
- })
13845
- }
13846
- ]
13847
- };
13848
- }
13849
- );
13850
- server.tool(
13851
- "wait_for_turn",
13852
- "Block until the thread finishes its current/queued turn (avoids polling). Use after send_to_thread to read the agent reply.",
13853
- {
13854
- ref: import_zod.z.string(),
13855
- timeoutMs: import_zod.z.number().optional()
13856
- },
13857
- async ({ ref, timeoutMs }) => {
13858
- const thread = await orch.waitForTurn(ref, timeoutMs ?? 6e5);
13859
- const result = orch.getTurnResult(thread.id);
13860
- return {
13861
- content: [
13862
- {
13863
- type: "text",
13864
- text: JSON.stringify({
13865
- id: thread.id,
13866
- status: result.status,
13867
- text: result.text
13868
- })
13869
- }
13870
- ]
13871
- };
13872
- }
13873
- );
13874
- server.tool(
13875
- "get_turn_result",
13876
- "Final assistant message only (not full transcript)",
13877
- { ref: import_zod.z.string() },
13878
- async ({ ref }) => {
13879
- const result = orch.getTurnResult(ref);
13880
- return { content: [{ type: "text", text: JSON.stringify(result) }] };
13881
- }
13882
- );
13883
- server.tool(
13884
- "stop_thread",
13885
- "Force-stop a thread: kill any in-flight agent turn AND clear queued prompts so drainQueue cannot continue. Does not archive the worktree. Optional force defaults to true.",
13886
- {
13887
- ref: import_zod.z.string(),
13888
- force: import_zod.z.boolean().optional()
13889
- },
13890
- async ({ ref, force }) => {
13891
- const t = orch.getThread(ref);
13892
- if (!t) {
14245
+ );
14246
+ server.tool(
14247
+ "stop_thread",
14248
+ "Force-stop a thread: kill any in-flight agent turn AND clear queued prompts so drainQueue cannot continue. Does not archive the worktree. Optional force defaults to true.",
14249
+ {
14250
+ ref: import_zod.z.string(),
14251
+ force: import_zod.z.boolean().optional()
14252
+ },
14253
+ async ({ ref, force }) => {
14254
+ const t = orch.getThread(ref);
14255
+ if (!t) {
14256
+ return {
14257
+ content: [{ type: "text", text: `Thread not found: ${ref}` }],
14258
+ isError: true
14259
+ };
14260
+ }
14261
+ const clearQueue = force !== false;
14262
+ const hadQueued = t.queue.length > 0;
14263
+ const stopped = orch.stop(ref, { clearQueue });
13893
14264
  return {
13894
- content: [{ type: "text", text: `Thread not found: ${ref}` }],
13895
- isError: true
14265
+ content: [
14266
+ {
14267
+ type: "text",
14268
+ text: JSON.stringify({
14269
+ id: stopped.id,
14270
+ status: stopped.status,
14271
+ clearedQueue: clearQueue && hadQueued
14272
+ })
14273
+ }
14274
+ ]
13896
14275
  };
13897
14276
  }
13898
- const clearQueue = force !== false;
13899
- const hadQueued = t.queue.length > 0;
13900
- const stopped = orch.stop(ref, { clearQueue });
13901
- return {
13902
- content: [
13903
- {
13904
- type: "text",
13905
- text: JSON.stringify({
13906
- id: stopped.id,
13907
- status: stopped.status,
13908
- clearedQueue: clearQueue && hadQueued
13909
- })
13910
- }
13911
- ]
13912
- };
13913
- }
13914
- );
13915
- server.tool(
13916
- "archive_thread",
13917
- "Archive a thread (stops agent/dev, runs archive script, removes worktree when last chat tab). Cannot archive the cloud coordinator \u2014 use the Sideboard UI for that.",
13918
- { ref: import_zod.z.string() },
13919
- async ({ ref }) => {
13920
- const t = orch.getThread(ref);
13921
- if (!t) {
14277
+ );
14278
+ server.tool(
14279
+ "archive_thread",
14280
+ "Archive a thread (stops agent/dev, runs archive script, removes worktree when last chat tab). Cannot archive the cloud coordinator \u2014 use the Sideboard UI for that.",
14281
+ { ref: import_zod.z.string() },
14282
+ async ({ ref }) => {
14283
+ const t = orch.getThread(ref);
14284
+ if (!t) {
14285
+ return {
14286
+ content: [{ type: "text", text: `Thread not found: ${ref}` }],
14287
+ isError: true
14288
+ };
14289
+ }
14290
+ const blocked = mcpArchiveBlockedReason(t);
14291
+ if (blocked) {
14292
+ return {
14293
+ content: [{ type: "text", text: blocked }],
14294
+ isError: true
14295
+ };
14296
+ }
14297
+ const archived = await orch.archive(ref);
13922
14298
  return {
13923
- content: [{ type: "text", text: `Thread not found: ${ref}` }],
13924
- isError: true
14299
+ content: [
14300
+ {
14301
+ type: "text",
14302
+ text: JSON.stringify({
14303
+ id: archived.id,
14304
+ status: archived.status
14305
+ })
14306
+ }
14307
+ ]
13925
14308
  };
13926
14309
  }
13927
- const blocked = mcpArchiveBlockedReason(t);
13928
- if (blocked) {
13929
- return {
13930
- content: [{ type: "text", text: blocked }],
13931
- isError: true
13932
- };
14310
+ );
14311
+ server.tool(
14312
+ "restore_thread",
14313
+ "Restore an archived thread (recreates worktree from branch when needed)",
14314
+ { ref: import_zod.z.string() },
14315
+ async ({ ref }) => {
14316
+ try {
14317
+ const restored = await orch.restore(ref);
14318
+ return {
14319
+ content: [
14320
+ {
14321
+ type: "text",
14322
+ text: JSON.stringify({
14323
+ id: restored.id,
14324
+ status: restored.status,
14325
+ worktreePath: restored.worktreePath
14326
+ })
14327
+ }
14328
+ ]
14329
+ };
14330
+ } catch (err) {
14331
+ const message = err instanceof Error ? err.message : String(err);
14332
+ return { content: [{ type: "text", text: message }], isError: true };
14333
+ }
13933
14334
  }
13934
- const archived = await orch.archive(ref);
13935
- return {
13936
- content: [
13937
- {
13938
- type: "text",
13939
- text: JSON.stringify({
13940
- id: archived.id,
13941
- status: archived.status
13942
- })
13943
- }
13944
- ]
13945
- };
13946
- }
13947
- );
13948
- server.tool(
13949
- "restore_thread",
13950
- "Restore an archived thread (recreates worktree from branch when needed)",
13951
- { ref: import_zod.z.string() },
13952
- async ({ ref }) => {
13953
- try {
13954
- const restored = await orch.restore(ref);
14335
+ );
14336
+ server.tool(
14337
+ "get_diff",
14338
+ "Compact diff summary (capped hunks, paginated)",
14339
+ {
14340
+ ref: import_zod.z.string(),
14341
+ maxFiles: import_zod.z.number().optional()
14342
+ },
14343
+ async ({ ref, maxFiles }) => {
14344
+ const summary = await orch.diffSummary(ref);
13955
14345
  return {
13956
14346
  content: [
13957
14347
  {
13958
14348
  type: "text",
13959
14349
  text: JSON.stringify({
13960
- id: restored.id,
13961
- status: restored.status,
13962
- worktreePath: restored.worktreePath
14350
+ ...summary,
14351
+ files: summary.files.slice(0, maxFiles ?? 10)
13963
14352
  })
13964
14353
  }
13965
14354
  ]
13966
14355
  };
13967
- } catch (err) {
13968
- const message = err instanceof Error ? err.message : String(err);
13969
- return { content: [{ type: "text", text: message }], isError: true };
13970
14356
  }
13971
- }
13972
- );
13973
- server.tool(
13974
- "get_diff",
13975
- "Compact diff summary (capped hunks, paginated)",
13976
- {
13977
- ref: import_zod.z.string(),
13978
- maxFiles: import_zod.z.number().optional()
13979
- },
13980
- async ({ ref, maxFiles }) => {
13981
- const summary = await orch.diffSummary(ref);
13982
- return {
13983
- content: [
13984
- {
13985
- type: "text",
13986
- text: JSON.stringify({
13987
- ...summary,
13988
- files: summary.files.slice(0, maxFiles ?? 10)
13989
- })
14357
+ );
14358
+ server.tool(
14359
+ "request_review",
14360
+ 'Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, attaches .sideboard/review.md when present (else local Review request.md / stock template), and sends "Review changes in this workspace." Expect Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn / get_turn_result on the returned review tab id.',
14361
+ { ref: import_zod.z.string().describe("Worktree thread id/ref to review") },
14362
+ async ({ ref }) => {
14363
+ try {
14364
+ const tab = await orch.requestReview(ref);
14365
+ const from = orch.getThread(ref);
14366
+ return {
14367
+ content: [
14368
+ {
14369
+ type: "text",
14370
+ text: JSON.stringify({
14371
+ id: tab.id,
14372
+ title: tab.title,
14373
+ status: tab.status,
14374
+ fromThreadId: from?.id ?? ref,
14375
+ link: `sideboard://thread/${tab.id}`
14376
+ })
14377
+ }
14378
+ ]
14379
+ };
14380
+ } catch (err) {
14381
+ const message = err instanceof Error ? err.message : String(err);
14382
+ return { content: [{ type: "text", text: message }], isError: true };
14383
+ }
14384
+ }
14385
+ );
14386
+ const agentEnum = import_zod.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]);
14387
+ server.tool(
14388
+ "list_models",
14389
+ "List models for an agent. Prefer Auto: do not call this unless you have a reason to pin a specific model (user request, cost/latency, capability). Omit agent to list all.",
14390
+ {
14391
+ agent: agentEnum.optional().describe("Limit to one agent; omit for all")
14392
+ },
14393
+ async ({ agent }) => {
14394
+ try {
14395
+ const catalogs = await listModelsForAgent(agent);
14396
+ return {
14397
+ content: [{ type: "text", text: JSON.stringify(catalogs, null, 2) }]
14398
+ };
14399
+ } catch (err) {
14400
+ const message = err instanceof Error ? err.message : String(err);
14401
+ return { content: [{ type: "text", text: message }], isError: true };
14402
+ }
14403
+ }
14404
+ );
14405
+ server.tool(
14406
+ "fork_worktree",
14407
+ "Fork a worktree agent chat into a NEW git worktree + chat (desktop \u201CFork to new workspace\u201D). Seeds a transcript (through through_index, default all). Optional agent override. Leave model unset for Auto (default) \u2014 only pass model when you have a reason. Not for the orchestrator. Then send_to_thread / wait_for_turn on the returned id.",
14408
+ {
14409
+ ref: import_zod.z.string().describe("Worktree thread id/ref to fork"),
14410
+ through_index: import_zod.z.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
14411
+ agent: agentEnum.optional().describe("Agent for the forked chat (default: same as source)"),
14412
+ model: import_zod.z.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
14413
+ title: import_zod.z.string().optional()
14414
+ },
14415
+ async ({ ref, through_index, agent, model, title }) => {
14416
+ try {
14417
+ const source = orch.getThread(ref);
14418
+ if (source) await orch.reconcile(source.repoPath, { drainQueues: false });
14419
+ const thread = await orch.forkThreadWorktree({
14420
+ threadId: ref,
14421
+ throughIndex: through_index,
14422
+ agent,
14423
+ model,
14424
+ title
14425
+ });
14426
+ return {
14427
+ content: [
14428
+ {
14429
+ type: "text",
14430
+ text: JSON.stringify({
14431
+ id: thread.id,
14432
+ title: thread.title,
14433
+ status: thread.status,
14434
+ agent: thread.agent,
14435
+ model: thread.model,
14436
+ branchName: thread.branchName,
14437
+ worktreePath: thread.worktreePath,
14438
+ fromThreadId: source?.id ?? ref,
14439
+ link: `sideboard://thread/${thread.id}`
14440
+ })
14441
+ }
14442
+ ]
14443
+ };
14444
+ } catch (err) {
14445
+ const message = err instanceof Error ? err.message : String(err);
14446
+ return { content: [{ type: "text", text: message }], isError: true };
14447
+ }
14448
+ }
14449
+ );
14450
+ server.tool(
14451
+ "fork_chat",
14452
+ "Fork a chat into a NEW tab on the SAME workspace: worktree agent \u2192 same worktree tab; Global orchestration chat \u2192 new orchestration chat (same synthetic home). Seeds a transcript; optional agent override. Leave model unset for Auto unless you have a reason. Orchestration forks require an MCP-capable agent (claude, cursor, codex, opencode \u2014 not brightsy). Remote coordinators use this to continue an orchestration chat on another agent after session limits. Then send_to_thread / wait_for_turn on the returned id. Use fork_worktree only for worktree agents that need a new git worktree.",
14453
+ {
14454
+ ref: import_zod.z.string().describe("Thread id/ref to fork (worktree agent or orchestration chat)"),
14455
+ through_index: import_zod.z.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
14456
+ agent: agentEnum.optional().describe("Agent for the forked chat (default: same as source)"),
14457
+ model: import_zod.z.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
14458
+ title: import_zod.z.string().optional()
14459
+ },
14460
+ async ({ ref, through_index, agent, model, title }) => {
14461
+ try {
14462
+ const source = orch.getThread(ref);
14463
+ if (!source) {
14464
+ return {
14465
+ content: [{ type: "text", text: `Thread not found: ${ref}` }],
14466
+ isError: true
14467
+ };
13990
14468
  }
13991
- ]
13992
- };
13993
- }
13994
- );
13995
- server.tool(
13996
- "request_review",
13997
- 'Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, attaches .sideboard/review.md when present (else local Review request.md / stock template), and sends "Review changes in this workspace." Expect Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn / get_turn_result on the returned review tab id.',
13998
- { ref: import_zod.z.string().describe("Worktree thread id/ref to review") },
13999
- async ({ ref }) => {
14000
- try {
14001
- const tab = await orch.requestReview(ref);
14002
- const from = orch.getThread(ref);
14469
+ const tab = orch.forkChatTab({
14470
+ threadId: source.id,
14471
+ throughIndex: through_index,
14472
+ agent,
14473
+ model,
14474
+ title
14475
+ });
14476
+ return {
14477
+ content: [
14478
+ {
14479
+ type: "text",
14480
+ text: JSON.stringify({
14481
+ id: tab.id,
14482
+ title: tab.title,
14483
+ status: tab.status,
14484
+ agent: tab.agent,
14485
+ model: tab.model,
14486
+ sourceType: tab.sourceType,
14487
+ worktreePath: tab.worktreePath,
14488
+ fromThreadId: source.id,
14489
+ link: `sideboard://thread/${tab.id}`
14490
+ })
14491
+ }
14492
+ ]
14493
+ };
14494
+ } catch (err) {
14495
+ const message = err instanceof Error ? err.message : String(err);
14496
+ return { content: [{ type: "text", text: message }], isError: true };
14497
+ }
14498
+ }
14499
+ );
14500
+ server.tool(
14501
+ "run_dev_script",
14502
+ "Start a .sideboard/.conductor run script for a thread (default script if name omitted); returns port",
14503
+ {
14504
+ ref: import_zod.z.string(),
14505
+ name: import_zod.z.string().optional()
14506
+ },
14507
+ async ({ ref, name }) => {
14508
+ const result = await orch.startDev(ref, name);
14003
14509
  return {
14004
14510
  content: [
14005
14511
  {
14006
14512
  type: "text",
14007
14513
  text: JSON.stringify({
14008
- id: tab.id,
14009
- title: tab.title,
14010
- status: tab.status,
14011
- fromThreadId: from?.id ?? ref,
14012
- link: `sideboard://thread/${tab.id}`
14514
+ port: result.port,
14515
+ scriptName: result.scriptName,
14516
+ ports: result.ports,
14517
+ url: `http://localhost:${result.port}`
14013
14518
  })
14014
14519
  }
14015
14520
  ]
14016
14521
  };
14017
- } catch (err) {
14018
- const message = err instanceof Error ? err.message : String(err);
14019
- return { content: [{ type: "text", text: message }], isError: true };
14020
14522
  }
14021
- }
14022
- );
14023
- const agentEnum = import_zod.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]);
14024
- server.tool(
14025
- "list_models",
14026
- "List models for an agent. Prefer Auto: do not call this unless you have a reason to pin a specific model (user request, cost/latency, capability). Omit agent to list all.",
14027
- {
14028
- agent: agentEnum.optional().describe("Limit to one agent; omit for all")
14029
- },
14030
- async ({ agent }) => {
14031
- try {
14032
- const catalogs = await listModelsForAgent(agent);
14523
+ );
14524
+ server.tool(
14525
+ "list_run_scripts",
14526
+ "List named run scripts available for a thread",
14527
+ { ref: import_zod.z.string() },
14528
+ async ({ ref }) => {
14529
+ const scripts = orch.listThreadRunScripts(ref);
14530
+ const active = orch.getActiveRuns(ref);
14033
14531
  return {
14034
- content: [{ type: "text", text: JSON.stringify(catalogs, null, 2) }]
14532
+ content: [
14533
+ {
14534
+ type: "text",
14535
+ text: JSON.stringify({ scripts, active }, null, 2)
14536
+ }
14537
+ ]
14035
14538
  };
14036
- } catch (err) {
14037
- const message = err instanceof Error ? err.message : String(err);
14038
- return { content: [{ type: "text", text: message }], isError: true };
14039
14539
  }
14040
- }
14041
- );
14042
- server.tool(
14043
- "fork_worktree",
14044
- "Fork a worktree agent chat into a NEW git worktree + chat (desktop \u201CFork to new workspace\u201D). Seeds a transcript (through through_index, default all). Optional agent override. Leave model unset for Auto (default) \u2014 only pass model when you have a reason. Not for the orchestrator. Then send_to_thread / wait_for_turn on the returned id.",
14045
- {
14046
- ref: import_zod.z.string().describe("Worktree thread id/ref to fork"),
14047
- through_index: import_zod.z.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
14048
- agent: agentEnum.optional().describe("Agent for the forked chat (default: same as source)"),
14049
- model: import_zod.z.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
14050
- title: import_zod.z.string().optional()
14051
- },
14052
- async ({ ref, through_index, agent, model, title }) => {
14053
- try {
14054
- const source = orch.getThread(ref);
14055
- if (source) await orch.reconcile(source.repoPath, { drainQueues: false });
14056
- const thread = await orch.forkThreadWorktree({
14057
- threadId: ref,
14058
- throughIndex: through_index,
14059
- agent,
14060
- model,
14061
- title
14540
+ );
14541
+ server.tool(
14542
+ "stop_dev_script",
14543
+ "Stop a running script for a thread (all scripts if name omitted)",
14544
+ {
14545
+ ref: import_zod.z.string(),
14546
+ name: import_zod.z.string().optional()
14547
+ },
14548
+ async ({ ref, name }) => {
14549
+ orch.stopDev(ref, name);
14550
+ return { content: [{ type: "text", text: "ok" }] };
14551
+ }
14552
+ );
14553
+ server.tool(
14554
+ "run_setup",
14555
+ "Re-run workspace setup (Sideboard/Conductor settings or .cursor/worktrees.json)",
14556
+ { ref: import_zod.z.string() },
14557
+ async ({ ref }) => {
14558
+ const result = await orch.runSetup(ref);
14559
+ return {
14560
+ content: [{ type: "text", text: JSON.stringify(result) }]
14561
+ };
14562
+ }
14563
+ );
14564
+ server.tool(
14565
+ "add_workspace",
14566
+ "Register a git repo as a Sideboard workspace",
14567
+ { repoPath: import_zod.z.string() },
14568
+ async ({ repoPath }) => {
14569
+ const ws = await orch.addWorkspace(repoPath);
14570
+ return { content: [{ type: "text", text: JSON.stringify(ws) }] };
14571
+ }
14572
+ );
14573
+ server.tool(
14574
+ "remove_workspace",
14575
+ "Unregister a Sideboard workspace (does not archive threads)",
14576
+ { repoPath: import_zod.z.string() },
14577
+ async ({ repoPath }) => {
14578
+ orch.removeWorkspace(repoPath);
14579
+ return { content: [{ type: "text", text: "ok" }] };
14580
+ }
14581
+ );
14582
+ server.tool(
14583
+ "fanout",
14584
+ "Best-of-n: create one thread per agent with the same prompt (parallel attempts)",
14585
+ {
14586
+ prompt: import_zod.z.string(),
14587
+ agents: import_zod.z.array(import_zod.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"])),
14588
+ repoPath: import_zod.z.string(),
14589
+ sourceType: import_zod.z.enum(["branch", "pr", "ticket"]).optional(),
14590
+ sourceRef: import_zod.z.string().optional(),
14591
+ title: import_zod.z.string().optional()
14592
+ },
14593
+ async (args) => {
14594
+ const threads = await orch.bestOfN(args);
14595
+ return {
14596
+ content: [
14597
+ {
14598
+ type: "text",
14599
+ text: JSON.stringify(
14600
+ threads.map((t) => ({
14601
+ id: t.id,
14602
+ agent: t.agent,
14603
+ branchName: t.branchName,
14604
+ worktreePath: t.worktreePath
14605
+ })),
14606
+ null,
14607
+ 2
14608
+ )
14609
+ }
14610
+ ]
14611
+ };
14612
+ }
14613
+ );
14614
+ server.tool(
14615
+ "list_branches",
14616
+ "List git branches in a registered workspace. Pass repoPath from list_workspaces (unmerged into the default branch by default \u2014 for create_thread sourceType=branch).",
14617
+ {
14618
+ repoPath: import_zod.z.string(),
14619
+ unmergedOnly: import_zod.z.boolean().optional()
14620
+ },
14621
+ async ({ repoPath, unmergedOnly }) => {
14622
+ const root = await resolveRepoRoot(repoPath);
14623
+ const branches = await listBranches(root, {
14624
+ unmergedOnly: unmergedOnly !== false
14062
14625
  });
14063
14626
  return {
14064
14627
  content: [
14065
14628
  {
14066
14629
  type: "text",
14067
- text: JSON.stringify({
14068
- id: thread.id,
14069
- title: thread.title,
14070
- status: thread.status,
14071
- agent: thread.agent,
14072
- model: thread.model,
14073
- branchName: thread.branchName,
14074
- worktreePath: thread.worktreePath,
14075
- fromThreadId: source?.id ?? ref,
14076
- link: `sideboard://thread/${thread.id}`
14077
- })
14630
+ text: branches.map((b) => `${b.current ? "*" : " "} ${b.name}`).join("\n")
14078
14631
  }
14079
14632
  ]
14080
14633
  };
14081
- } catch (err) {
14082
- const message = err instanceof Error ? err.message : String(err);
14083
- return { content: [{ type: "text", text: message }], isError: true };
14084
14634
  }
14085
- }
14086
- );
14087
- server.tool(
14088
- "fork_chat",
14089
- "Fork a chat into a NEW tab on the SAME workspace: worktree agent \u2192 same worktree tab; Global orchestration chat \u2192 new orchestration chat (same synthetic home). Seeds a transcript; optional agent override. Leave model unset for Auto unless you have a reason. Orchestration forks require an MCP-capable agent (claude, cursor, codex, opencode \u2014 not brightsy). Remote coordinators use this to continue an orchestration chat on another agent after session limits. Then send_to_thread / wait_for_turn on the returned id. Use fork_worktree only for worktree agents that need a new git worktree.",
14090
- {
14091
- ref: import_zod.z.string().describe("Thread id/ref to fork (worktree agent or orchestration chat)"),
14092
- through_index: import_zod.z.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
14093
- agent: agentEnum.optional().describe("Agent for the forked chat (default: same as source)"),
14094
- model: import_zod.z.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
14095
- title: import_zod.z.string().optional()
14096
- },
14097
- async ({ ref, through_index, agent, model, title }) => {
14098
- try {
14099
- const source = orch.getThread(ref);
14100
- if (!source) {
14101
- return {
14102
- content: [{ type: "text", text: `Thread not found: ${ref}` }],
14103
- isError: true
14104
- };
14105
- }
14106
- const tab = orch.forkChatTab({
14107
- threadId: source.id,
14108
- throughIndex: through_index,
14109
- agent,
14110
- model,
14111
- title
14635
+ );
14636
+ server.tool(
14637
+ "list_prs",
14638
+ "List open GitHub PRs for a registered workspace. Pass repoPath from list_workspaces (uses gh against that repo remote). Then create_thread with sourceType=pr.",
14639
+ { repoPath: import_zod.z.string() },
14640
+ async ({ repoPath }) => {
14641
+ const root = await resolveRepoRoot(repoPath);
14642
+ const prs = await listPrs(root);
14643
+ return {
14644
+ content: [
14645
+ {
14646
+ type: "text",
14647
+ text: prs.map(
14648
+ (p) => `#${p.number} ${p.title} (${p.headRefName})${p.isCrossRepository ? " [fork]" : ""}`
14649
+ ).join("\n")
14650
+ }
14651
+ ]
14652
+ };
14653
+ }
14654
+ );
14655
+ server.tool(
14656
+ "get_pr_stack",
14657
+ "Load the GitHub PR stack for a thread worktree (`gh stack view --json`). Returns null JSON when the branch is not stacked. Prefer this before mergePr on stacked PRs.",
14658
+ { ref: import_zod.z.string() },
14659
+ async ({ ref }) => {
14660
+ const stack = await orch.getPrStack(ref);
14661
+ return {
14662
+ content: [{ type: "text", text: JSON.stringify(stack, null, 2) }]
14663
+ };
14664
+ }
14665
+ );
14666
+ server.tool(
14667
+ "open_pr_stack_layers",
14668
+ "Materialize one worktree+thread per stack layer (or a single 1-based layer). Pass a thread ref already on the stack.",
14669
+ {
14670
+ ref: import_zod.z.string(),
14671
+ layer: import_zod.z.number().int().positive().optional()
14672
+ },
14673
+ async ({ ref, layer }) => {
14674
+ const result = await orch.openPrStackLayers(ref, { layer });
14675
+ return {
14676
+ content: [
14677
+ {
14678
+ type: "text",
14679
+ text: JSON.stringify(
14680
+ {
14681
+ stackNumber: result.stack.stackNumber,
14682
+ trunk: result.stack.trunk,
14683
+ threads: result.threads.map((t) => ({
14684
+ id: t.id,
14685
+ title: t.title,
14686
+ branchName: t.branchName,
14687
+ stackLayer: t.stackLayer,
14688
+ worktreePath: t.worktreePath,
14689
+ prUrl: t.prUrl,
14690
+ link: `sideboard://thread/${t.id}`
14691
+ }))
14692
+ },
14693
+ null,
14694
+ 2
14695
+ )
14696
+ }
14697
+ ]
14698
+ };
14699
+ }
14700
+ );
14701
+ server.tool(
14702
+ "add_stack_layer",
14703
+ "Add a branch on top of the current stack (`gh stack add`) and open a worktree+thread for it.",
14704
+ {
14705
+ ref: import_zod.z.string(),
14706
+ branchName: import_zod.z.string(),
14707
+ title: import_zod.z.string().optional()
14708
+ },
14709
+ async ({ ref, branchName, title }) => {
14710
+ const result = await orch.addStackLayer(ref, branchName, { title });
14711
+ return {
14712
+ content: [
14713
+ {
14714
+ type: "text",
14715
+ text: JSON.stringify(
14716
+ {
14717
+ id: result.thread.id,
14718
+ title: result.thread.title,
14719
+ branchName: result.thread.branchName,
14720
+ stackLayer: result.thread.stackLayer,
14721
+ worktreePath: result.thread.worktreePath,
14722
+ link: `sideboard://thread/${result.thread.id}`
14723
+ },
14724
+ null,
14725
+ 2
14726
+ )
14727
+ }
14728
+ ]
14729
+ };
14730
+ }
14731
+ );
14732
+ server.tool(
14733
+ "create_pr_stack",
14734
+ "Create a new GitHub PR stack with one Sideboard worktree per layer (bottom\u2192top branch names). Requires `gh extension install github/gh-stack`.",
14735
+ {
14736
+ repoPath: import_zod.z.string(),
14737
+ branches: import_zod.z.array(import_zod.z.string()).min(1),
14738
+ agent: import_zod.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]),
14739
+ base: import_zod.z.string().optional(),
14740
+ title: import_zod.z.string().optional()
14741
+ },
14742
+ async (args) => {
14743
+ const result = await orch.createPrStack({
14744
+ repoPath: args.repoPath,
14745
+ branches: args.branches,
14746
+ agent: args.agent,
14747
+ base: args.base,
14748
+ title: args.title
14112
14749
  });
14113
14750
  return {
14114
14751
  content: [
14115
14752
  {
14116
14753
  type: "text",
14117
- text: JSON.stringify({
14118
- id: tab.id,
14119
- title: tab.title,
14120
- status: tab.status,
14121
- agent: tab.agent,
14122
- model: tab.model,
14123
- sourceType: tab.sourceType,
14124
- worktreePath: tab.worktreePath,
14125
- fromThreadId: source.id,
14126
- link: `sideboard://thread/${tab.id}`
14127
- })
14754
+ text: JSON.stringify(
14755
+ {
14756
+ stackNumber: result.stack.stackNumber,
14757
+ trunk: result.stack.trunk,
14758
+ threads: result.threads.map((t) => ({
14759
+ id: t.id,
14760
+ title: t.title,
14761
+ branchName: t.branchName,
14762
+ stackLayer: t.stackLayer,
14763
+ worktreePath: t.worktreePath,
14764
+ link: `sideboard://thread/${t.id}`
14765
+ }))
14766
+ },
14767
+ null,
14768
+ 2
14769
+ )
14128
14770
  }
14129
14771
  ]
14130
14772
  };
14131
- } catch (err) {
14132
- const message = err instanceof Error ? err.message : String(err);
14133
- return { content: [{ type: "text", text: message }], isError: true };
14134
14773
  }
14135
- }
14136
- );
14137
- server.tool(
14138
- "run_dev_script",
14139
- "Start a .sideboard/.conductor run script for a thread (default script if name omitted); returns port",
14140
- {
14141
- ref: import_zod.z.string(),
14142
- name: import_zod.z.string().optional()
14143
- },
14144
- async ({ ref, name }) => {
14145
- const result = await orch.startDev(ref, name);
14146
- return {
14147
- content: [
14148
- {
14149
- type: "text",
14150
- text: JSON.stringify({
14151
- port: result.port,
14152
- scriptName: result.scriptName,
14153
- ports: result.ports,
14154
- url: `http://localhost:${result.port}`
14155
- })
14156
- }
14157
- ]
14158
- };
14159
- }
14160
- );
14161
- server.tool(
14162
- "list_run_scripts",
14163
- "List named run scripts available for a thread",
14164
- { ref: import_zod.z.string() },
14165
- async ({ ref }) => {
14166
- const scripts = orch.listThreadRunScripts(ref);
14167
- const active = orch.getActiveRuns(ref);
14168
- return {
14169
- content: [
14170
- {
14171
- type: "text",
14172
- text: JSON.stringify({ scripts, active }, null, 2)
14173
- }
14174
- ]
14175
- };
14176
- }
14177
- );
14178
- server.tool(
14179
- "stop_dev_script",
14180
- "Stop a running script for a thread (all scripts if name omitted)",
14181
- {
14182
- ref: import_zod.z.string(),
14183
- name: import_zod.z.string().optional()
14184
- },
14185
- async ({ ref, name }) => {
14186
- orch.stopDev(ref, name);
14187
- return { content: [{ type: "text", text: "ok" }] };
14188
- }
14189
- );
14190
- server.tool(
14191
- "run_setup",
14192
- "Re-run workspace setup (Sideboard/Conductor settings or .cursor/worktrees.json)",
14193
- { ref: import_zod.z.string() },
14194
- async ({ ref }) => {
14195
- const result = await orch.runSetup(ref);
14196
- return {
14197
- content: [{ type: "text", text: JSON.stringify(result) }]
14198
- };
14199
- }
14200
- );
14201
- server.tool(
14202
- "add_workspace",
14203
- "Register a git repo as a Sideboard workspace",
14204
- { repoPath: import_zod.z.string() },
14205
- async ({ repoPath }) => {
14206
- const ws = await orch.addWorkspace(repoPath);
14207
- return { content: [{ type: "text", text: JSON.stringify(ws) }] };
14208
- }
14209
- );
14210
- server.tool(
14211
- "remove_workspace",
14212
- "Unregister a Sideboard workspace (does not archive threads)",
14213
- { repoPath: import_zod.z.string() },
14214
- async ({ repoPath }) => {
14215
- orch.removeWorkspace(repoPath);
14216
- return { content: [{ type: "text", text: "ok" }] };
14217
- }
14218
- );
14219
- server.tool(
14220
- "fanout",
14221
- "Best-of-n: create one thread per agent with the same prompt (parallel attempts)",
14222
- {
14223
- prompt: import_zod.z.string(),
14224
- agents: import_zod.z.array(import_zod.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"])),
14225
- repoPath: import_zod.z.string(),
14226
- sourceType: import_zod.z.enum(["branch", "pr", "ticket"]).optional(),
14227
- sourceRef: import_zod.z.string().optional(),
14228
- title: import_zod.z.string().optional()
14229
- },
14230
- async (args) => {
14231
- const threads = await orch.bestOfN(args);
14232
- return {
14233
- content: [
14234
- {
14235
- type: "text",
14236
- text: JSON.stringify(
14237
- threads.map((t) => ({
14238
- id: t.id,
14239
- agent: t.agent,
14240
- branchName: t.branchName,
14241
- worktreePath: t.worktreePath
14242
- })),
14243
- null,
14244
- 2
14245
- )
14246
- }
14247
- ]
14248
- };
14249
- }
14250
- );
14251
- server.tool(
14252
- "list_branches",
14253
- "List git branches in a registered workspace. Pass repoPath from list_workspaces (unmerged into the default branch by default \u2014 for create_thread sourceType=branch).",
14254
- {
14255
- repoPath: import_zod.z.string(),
14256
- unmergedOnly: import_zod.z.boolean().optional()
14257
- },
14258
- async ({ repoPath, unmergedOnly }) => {
14259
- const root = await resolveRepoRoot(repoPath);
14260
- const branches = await listBranches(root, {
14261
- unmergedOnly: unmergedOnly !== false
14262
- });
14263
- return {
14264
- content: [
14265
- {
14266
- type: "text",
14267
- text: branches.map((b) => `${b.current ? "*" : " "} ${b.name}`).join("\n")
14268
- }
14269
- ]
14270
- };
14271
- }
14272
- );
14273
- server.tool(
14274
- "list_prs",
14275
- "List open GitHub PRs for a registered workspace. Pass repoPath from list_workspaces (uses gh against that repo remote). Then create_thread with sourceType=pr.",
14276
- { repoPath: import_zod.z.string() },
14277
- async ({ repoPath }) => {
14278
- const root = await resolveRepoRoot(repoPath);
14279
- const prs = await listPrs(root);
14280
- return {
14281
- content: [
14282
- {
14283
- type: "text",
14284
- text: prs.map(
14285
- (p) => `#${p.number} ${p.title} (${p.headRefName})${p.isCrossRepository ? " [fork]" : ""}`
14286
- ).join("\n")
14287
- }
14288
- ]
14289
- };
14290
- }
14291
- );
14292
- server.tool(
14293
- "get_pr_stack",
14294
- "Load the GitHub PR stack for a thread worktree (`gh stack view --json`). Returns null JSON when the branch is not stacked. Prefer this before mergePr on stacked PRs.",
14295
- { ref: import_zod.z.string() },
14296
- async ({ ref }) => {
14297
- const stack = await orch.getPrStack(ref);
14298
- return {
14299
- content: [{ type: "text", text: JSON.stringify(stack, null, 2) }]
14300
- };
14301
- }
14302
- );
14303
- server.tool(
14304
- "open_pr_stack_layers",
14305
- "Materialize one worktree+thread per stack layer (or a single 1-based layer). Pass a thread ref already on the stack.",
14306
- {
14307
- ref: import_zod.z.string(),
14308
- layer: import_zod.z.number().int().positive().optional()
14309
- },
14310
- async ({ ref, layer }) => {
14311
- const result = await orch.openPrStackLayers(ref, { layer });
14312
- return {
14313
- content: [
14314
- {
14315
- type: "text",
14316
- text: JSON.stringify(
14317
- {
14318
- stackNumber: result.stack.stackNumber,
14319
- trunk: result.stack.trunk,
14320
- threads: result.threads.map((t) => ({
14321
- id: t.id,
14322
- title: t.title,
14323
- branchName: t.branchName,
14324
- stackLayer: t.stackLayer,
14325
- worktreePath: t.worktreePath,
14326
- prUrl: t.prUrl,
14327
- link: `sideboard://thread/${t.id}`
14328
- }))
14329
- },
14330
- null,
14331
- 2
14332
- )
14333
- }
14334
- ]
14335
- };
14336
- }
14337
- );
14338
- server.tool(
14339
- "add_stack_layer",
14340
- "Add a branch on top of the current stack (`gh stack add`) and open a worktree+thread for it.",
14341
- {
14342
- ref: import_zod.z.string(),
14343
- branchName: import_zod.z.string(),
14344
- title: import_zod.z.string().optional()
14345
- },
14346
- async ({ ref, branchName, title }) => {
14347
- const result = await orch.addStackLayer(ref, branchName, { title });
14348
- return {
14349
- content: [
14350
- {
14351
- type: "text",
14352
- text: JSON.stringify(
14353
- {
14354
- id: result.thread.id,
14355
- title: result.thread.title,
14356
- branchName: result.thread.branchName,
14357
- stackLayer: result.thread.stackLayer,
14358
- worktreePath: result.thread.worktreePath,
14359
- link: `sideboard://thread/${result.thread.id}`
14360
- },
14361
- null,
14362
- 2
14363
- )
14364
- }
14365
- ]
14366
- };
14367
- }
14368
- );
14369
- server.tool(
14370
- "create_pr_stack",
14371
- "Create a new GitHub PR stack with one Sideboard worktree per layer (bottom\u2192top branch names). Requires `gh extension install github/gh-stack`.",
14372
- {
14373
- repoPath: import_zod.z.string(),
14374
- branches: import_zod.z.array(import_zod.z.string()).min(1),
14375
- agent: import_zod.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]),
14376
- base: import_zod.z.string().optional(),
14377
- title: import_zod.z.string().optional()
14378
- },
14379
- async (args) => {
14380
- const result = await orch.createPrStack({
14381
- repoPath: args.repoPath,
14382
- branches: args.branches,
14383
- agent: args.agent,
14384
- base: args.base,
14385
- title: args.title
14386
- });
14387
- return {
14388
- content: [
14389
- {
14390
- type: "text",
14391
- text: JSON.stringify(
14392
- {
14393
- stackNumber: result.stack.stackNumber,
14394
- trunk: result.stack.trunk,
14395
- threads: result.threads.map((t) => ({
14396
- id: t.id,
14397
- title: t.title,
14398
- branchName: t.branchName,
14399
- stackLayer: t.stackLayer,
14400
- worktreePath: t.worktreePath,
14401
- link: `sideboard://thread/${t.id}`
14402
- }))
14403
- },
14404
- null,
14405
- 2
14406
- )
14407
- }
14408
- ]
14409
- };
14410
- }
14411
- );
14412
- server.tool(
14413
- "list_issues",
14414
- "List issues from Sideboard Account connections (Linear API or GitHub Issues; Linear\u2192GitHub fallback when Linear is not connected). Pass repoPath from list_workspaces \u2014 GitHub Issues are scoped to that repo. Then create_thread with sourceType=ticket.",
14415
- { repoPath: import_zod.z.string() },
14416
- async ({ repoPath }) => {
14417
- const root = await resolveRepoRoot(repoPath);
14418
- const result = await listIssues(root);
14419
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
14420
- }
14421
- );
14422
- server.tool(
14423
- "list_linear_issues",
14424
- "Deprecated: prefer list_issues. Lists assigned Linear issues via the chosen agent MCP connector",
14425
- {
14426
- agent: import_zod.z.enum(["claude", "codex", "opencode"]),
14427
- repoPath: import_zod.z.string()
14428
- },
14429
- async ({ agent, repoPath }) => {
14430
- const issues = await listLinearIssues(agent, repoPath);
14431
- return { content: [{ type: "text", text: JSON.stringify(issues, null, 2) }] };
14432
- }
14433
- );
14774
+ );
14775
+ server.tool(
14776
+ "list_issues",
14777
+ "List issues from Sideboard Account connections (Linear API or GitHub Issues; Linear\u2192GitHub fallback when Linear is not connected). Pass repoPath from list_workspaces \u2014 GitHub Issues are scoped to that repo. Then create_thread with sourceType=ticket.",
14778
+ { repoPath: import_zod.z.string() },
14779
+ async ({ repoPath }) => {
14780
+ const root = await resolveRepoRoot(repoPath);
14781
+ const result = await listIssues(root);
14782
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
14783
+ }
14784
+ );
14785
+ server.tool(
14786
+ "list_linear_issues",
14787
+ "Deprecated: prefer list_issues. Lists assigned Linear issues via the chosen agent MCP connector",
14788
+ {
14789
+ agent: import_zod.z.enum(["claude", "codex", "opencode"]),
14790
+ repoPath: import_zod.z.string()
14791
+ },
14792
+ async ({ agent, repoPath }) => {
14793
+ const issues = await listLinearIssues(agent, repoPath);
14794
+ return { content: [{ type: "text", text: JSON.stringify(issues, null, 2) }] };
14795
+ }
14796
+ );
14797
+ }
14434
14798
  const transport = new import_stdio.StdioServerTransport();
14435
14799
  await server.connect(transport);
14436
14800
  }
14437
14801
 
14438
14802
  // src/index.ts
14803
+ init_profile();
14439
14804
  init_config();
14440
14805
 
14441
14806
  // src/brightsy/api.ts
@@ -14812,6 +15177,7 @@ init_injected_mcp();
14812
15177
  REVIEW_REQUEST_PREFILL,
14813
15178
  SIDEBOARD_FORCE_STOP,
14814
15179
  SIDEBOARD_MCP_ALLOWED_TOOLS,
15180
+ SIDEBOARD_MCP_PROFILE_ENV,
14815
15181
  THINKING_EFFORTS,
14816
15182
  addPrStackLayer,
14817
15183
  addStackLayerFromThread,
@@ -14843,6 +15209,7 @@ init_injected_mcp();
14843
15209
  brightsyCloudConnectAgent,
14844
15210
  brightsyCloudConnectEnabled,
14845
15211
  brightsyConfigPath,
15212
+ brightsyInjectWorktreeMcpEnabled,
14846
15213
  brightsyMcpAllowedTools,
14847
15214
  brightsyMcpServerName,
14848
15215
  buildCachedUserContent,
@@ -14894,7 +15261,9 @@ init_injected_mcp();
14894
15261
  detectLocalMergeConflicts,
14895
15262
  disconnectBrightsyTeam,
14896
15263
  discoverSkills,
15264
+ dropCachedPrefixOnResume,
14897
15265
  encodeBrightsyTarget,
15266
+ enrichPathWithNpmGlobalBin,
14898
15267
  enrichWorkspacesWithGithub,
14899
15268
  ensureAgentPath,
14900
15269
  ensureCloudCoordinator,
@@ -14932,6 +15301,7 @@ init_injected_mcp();
14932
15301
  formatTranscriptMarkdown,
14933
15302
  formatWorkspaceInventory,
14934
15303
  formatWorktreeDirective,
15304
+ formatWorktreeReminder,
14935
15305
  getAdapter,
14936
15306
  getAgentSetupInfo,
14937
15307
  getBrightsySession,
@@ -15058,7 +15428,10 @@ init_injected_mcp();
15058
15428
  pastedTextStats,
15059
15429
  permissionMode,
15060
15430
  planFileAbs,
15431
+ posixShellSingleQuote,
15432
+ prepareTerminalCommand,
15061
15433
  previewLand,
15434
+ promptMentionsBrightsy,
15062
15435
  pushBranch,
15063
15436
  readExistingReviewRequestFile,
15064
15437
  readPlanFile,
@@ -15074,7 +15447,9 @@ init_injected_mcp();
15074
15447
  requestReview,
15075
15448
  requireAgent,
15076
15449
  resetGhStackDetectCache,
15450
+ resolveAgentExecutable,
15077
15451
  resolveClaudeExecutable,
15452
+ resolveCommandBinarySync,
15078
15453
  resolveConductorCursorAgentId,
15079
15454
  resolveCursorModelId,
15080
15455
  resolveDefaultBranch,
@@ -15083,6 +15458,7 @@ init_injected_mcp();
15083
15458
  resolveFilesToCopy,
15084
15459
  resolveGhAuthToken,
15085
15460
  resolveGithubRepoSlug,
15461
+ resolveLoginCommand,
15086
15462
  resolveNewThreadOptions,
15087
15463
  resolvePlanMarkdown,
15088
15464
  resolvePrSelector,
@@ -15104,9 +15480,11 @@ init_injected_mcp();
15104
15480
  settingsSourceLabel,
15105
15481
  shouldAttachPastedText,
15106
15482
  shouldCompactContext,
15483
+ shouldInjectBrightsyMcp,
15107
15484
  shouldRefreshReviewRequestTemplate,
15108
15485
  shouldRunWorktreeCleanup,
15109
15486
  sideboardHomeDir,
15487
+ sideboardMcpProfile,
15110
15488
  sideboardReposDir,
15111
15489
  sideboardWorkspacesDir,
15112
15490
  slugify,
@@ -15134,6 +15512,7 @@ init_injected_mcp();
15134
15512
  threadDisplayLabel,
15135
15513
  threadFilePath,
15136
15514
  threadLockPath,
15515
+ threadRequestsBrightsyMcp,
15137
15516
  threadsDir,
15138
15517
  threadsSharingWorktree,
15139
15518
  toolDescription,
@@ -15141,14 +15520,18 @@ init_injected_mcp();
15141
15520
  toolFilePath,
15142
15521
  totalTokens,
15143
15522
  updateAdvancedSettings,
15523
+ updateAgentExecutable,
15144
15524
  updateAppEnvironment,
15145
15525
  updateBrightsySettings,
15146
15526
  updateClaudeSettings,
15527
+ updateCodexSettings,
15147
15528
  updateDefaultsSettings,
15148
15529
  updateIntegrationsSettings,
15530
+ updateOpencodeSettings,
15149
15531
  updateThread,
15150
15532
  validateLinearApiKey,
15151
15533
  withAgentInstructions,
15534
+ withExportedPath,
15152
15535
  withThreadLock,
15153
15536
  workspaceSettingsSourceLabel,
15154
15537
  worktreeCleanupSettings,