@sideboard-ai/core 0.1.193 → 0.1.195

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 (51) hide show
  1. package/dist/{abletime-UX53JTIH.js → abletime-HR6P4GJH.js} +3 -3
  2. package/dist/{abletime-QHKWGTBY.js → abletime-JINF5KJV.js} +3 -3
  3. package/dist/agents/cursor-runner.js +2 -2
  4. package/dist/{agents-MN4GSQTL.js → agents-OXDDPH2O.js} +16 -17
  5. package/dist/{agents-OK5VD25T.js → agents-WQL7SZY6.js} +6 -7
  6. package/dist/{app-settings-LO7UFHQ6.js → app-settings-5KHVKJKO.js} +2 -2
  7. package/dist/{app-settings-QYLNKRK4.js → app-settings-J775CYOO.js} +2 -2
  8. package/dist/{branch-prefix-EVW2KHGQ.js → branch-prefix-7DTIUJT2.js} +1 -1
  9. package/dist/{branch-prefix-7F37FIPX.js → branch-prefix-N3KTCRCE.js} +1 -1
  10. package/dist/{chunk-MQC2VA5U.js → chunk-2X6RGKLI.js} +13 -13
  11. package/dist/{chunk-EBPBGQ4P.js → chunk-6H2XPPPR.js} +9 -9
  12. package/dist/{chunk-HIX2VDRE.js → chunk-6YTI2HBG.js} +6 -8
  13. package/dist/{chunk-KORE4WOF.js → chunk-AH6WIBLY.js} +1 -1
  14. package/dist/{chunk-XPKKCFRT.js → chunk-DP4TKAMZ.js} +864 -7
  15. package/dist/{chunk-O4BMPY5Y.js → chunk-E37JHCO3.js} +1 -1
  16. package/dist/{chunk-JTWKGOFI.js → chunk-FJZWM2ON.js} +1 -1
  17. package/dist/{chunk-3DX2T2KR.js → chunk-GFH3QVAV.js} +188 -95
  18. package/dist/{chunk-EQXXGOMD.js → chunk-HAVI6AY3.js} +197 -104
  19. package/dist/{chunk-4OVCJPVI.js → chunk-HZTHWU6A.js} +6 -8
  20. package/dist/{chunk-4QJRH5DL.js → chunk-KTHRWHA3.js} +1 -1
  21. package/dist/{chunk-BIKCWYRP.js → chunk-S4QCBBXS.js} +873 -16
  22. package/dist/{chunk-BWRS6GAS.js → chunk-S5GLSRLP.js} +1 -1
  23. package/dist/{chunk-PE337IM2.js → chunk-SALM35KD.js} +7 -7
  24. package/dist/{chunk-7SNJMKD6.js → chunk-WDRMZKVB.js} +1 -1
  25. package/dist/{connected-teams-SYQQGCXD.js → connected-teams-WK47ATT7.js} +2 -2
  26. package/dist/{coordinator-prompt-WB65HIZ3.js → coordinator-prompt-IX66YUJ2.js} +5 -6
  27. package/dist/{coordinator-prompt-GXJIPWNA.js → coordinator-prompt-LYKS3YNG.js} +4 -5
  28. package/dist/{global-workspace-MMK5UFUZ.js → global-workspace-4QX6UEOY.js} +5 -6
  29. package/dist/{global-workspace-BZ6V6TEX.js → global-workspace-SNJ2Z6SL.js} +4 -5
  30. package/dist/index.cjs +1051 -971
  31. package/dist/index.d.cts +7 -5
  32. package/dist/index.d.ts +7 -5
  33. package/dist/index.js +95 -54
  34. package/dist/mcp/run-stdio.cjs +218 -140
  35. package/dist/mcp/run-stdio.js +67 -26
  36. package/dist/{orchestrator-4KI6VIFG.js → orchestrator-6ESBGMDN.js} +9 -10
  37. package/dist/{orchestrator-SFOT6Q6F.js → orchestrator-EHRFN3Q6.js} +8 -9
  38. package/dist/{workspaces-KPJS7GLY.js → workspaces-URMUVGAQ.js} +5 -6
  39. package/dist/{workspaces-ACMZMKPD.js → workspaces-UTOYGBYB.js} +4 -5
  40. package/dist/{worktree-6IEVF3GN.js → worktree-R43JOR4V.js} +12 -14
  41. package/dist/{worktree-UW6DNBIE.js → worktree-RM6UWNGZ.js} +17 -19
  42. package/package.json +1 -1
  43. package/dist/chunk-64QSHOKV.js +0 -869
  44. package/dist/chunk-ILWQT2UN.js +0 -55
  45. package/dist/chunk-PBEPPXMY.js +0 -57
  46. package/dist/chunk-RCWHL4TK.js +0 -866
  47. package/dist/github-DWROJOB7.js +0 -11
  48. package/dist/github-IIF7AQNO.js +0 -9
  49. package/dist/worktree-labels-3XDS6O3U.js +0 -22
  50. package/dist/worktree-labels-PEDOJBMD.js +0 -24
  51. package/dist/{chunk-7AJ7OZZF.js → chunk-NLHFAMC2.js} +3 -3
@@ -2986,18 +2986,6 @@ var init_teams = __esm({
2986
2986
  });
2987
2987
 
2988
2988
  // src/git/worktree-labels.ts
2989
- var worktree_labels_exports = {};
2990
- __export(worktree_labels_exports, {
2991
- branchDisplayLabel: () => branchDisplayLabel,
2992
- isPlaceholderBranch: () => isPlaceholderBranch,
2993
- normalizeWorktreePath: () => normalizeWorktreePath,
2994
- threadDisplayLabel: () => threadDisplayLabel,
2995
- ticketSlugForBranch: () => ticketSlugForBranch,
2996
- worktreeDisplayLabel: () => worktreeDisplayLabel,
2997
- worktreeDisplayLabelForGroup: () => worktreeDisplayLabelForGroup,
2998
- worktreeNameFromPath: () => worktreeNameFromPath,
2999
- worktreeSlugForTicket: () => worktreeSlugForTicket
3000
- });
3001
2989
  function normalizeWorktreePath(worktreePath) {
3002
2990
  const trimmed = (worktreePath ?? "").replace(/\/+$/, "") || "/";
3003
2991
  const absolute = trimmed.startsWith("/");
@@ -3465,7 +3453,7 @@ function sanitizeGitBranchPrefix(raw) {
3465
3453
  return slug || null;
3466
3454
  }
3467
3455
  function resolveGitBranchPrefix(opts) {
3468
- return sanitizeGitBranchPrefix(opts.setting) ?? sanitizeGitBranchPrefix(opts.githubLogin);
3456
+ return sanitizeGitBranchPrefix(opts.setting);
3469
3457
  }
3470
3458
  function examplePrefixedBranch(prefix, ticket) {
3471
3459
  const head = sanitizeGitBranchPrefix(prefix);
@@ -13034,6 +13022,59 @@ var init_context_compact = __esm({
13034
13022
  }
13035
13023
  });
13036
13024
 
13025
+ // src/threads/worktree-runtime.ts
13026
+ function worktreeProcessPrefix(worktreePath) {
13027
+ return `wt:${normalizeWorktreePath(worktreePath)}`;
13028
+ }
13029
+ function worktreeSetupProcessKey(worktreePath) {
13030
+ return `${worktreeProcessPrefix(worktreePath)}:setup`;
13031
+ }
13032
+ function worktreeRunProcessKey(worktreePath, scriptName) {
13033
+ return `${worktreeProcessPrefix(worktreePath)}:run:${scriptName}`;
13034
+ }
13035
+ function worktreeDevProcessKey(worktreePath) {
13036
+ return `${worktreeProcessPrefix(worktreePath)}:dev`;
13037
+ }
13038
+ function isWorktreeRunProcessKey(key, worktreePath) {
13039
+ const prefix = worktreeProcessPrefix(worktreePath);
13040
+ return key.startsWith(`${prefix}:run:`) || key === `${prefix}:dev`;
13041
+ }
13042
+ function pickRichestSetupLog(snaps) {
13043
+ let best;
13044
+ for (const snap of snaps) {
13045
+ if (!snap.output && !snap.running && snap.exitCode == null) continue;
13046
+ if (!best) {
13047
+ best = snap;
13048
+ continue;
13049
+ }
13050
+ if (snap.running && !best.running) {
13051
+ best = snap;
13052
+ continue;
13053
+ }
13054
+ if (snap.running === best.running && snap.output.length > best.output.length) {
13055
+ best = snap;
13056
+ }
13057
+ }
13058
+ return best;
13059
+ }
13060
+ function mergeWorktreeActiveRuns(threads) {
13061
+ const byName = /* @__PURE__ */ new Map();
13062
+ let devPort = null;
13063
+ for (const thread of threads) {
13064
+ if (thread.devPort != null && devPort == null) devPort = thread.devPort;
13065
+ for (const run2 of thread.activeRuns ?? []) {
13066
+ if (!byName.has(run2.scriptName)) byName.set(run2.scriptName, run2);
13067
+ }
13068
+ }
13069
+ return { activeRuns: [...byName.values()], devPort };
13070
+ }
13071
+ var init_worktree_runtime = __esm({
13072
+ "src/threads/worktree-runtime.ts"() {
13073
+ "use strict";
13074
+ init_worktree_labels();
13075
+ }
13076
+ });
13077
+
13037
13078
  // src/threads/chat-tabs.ts
13038
13079
  function sameWorktreePath(a, b) {
13039
13080
  return normalizeWorktreePath(a) === normalizeWorktreePath(b);
@@ -13130,7 +13171,8 @@ function createChatTab(input) {
13130
13171
  planMode: from.planMode,
13131
13172
  autonomy: input.autonomy ?? from.autonomy,
13132
13173
  attachments: input.attachments ?? [],
13133
- status: "idle"
13174
+ status: "idle",
13175
+ ...mergeWorktreeActiveRuns(threadsSharingWorktree(binding.worktreePath))
13134
13176
  });
13135
13177
  writeThread(thread);
13136
13178
  return thread;
@@ -13164,6 +13206,7 @@ var init_chat_tabs = __esm({
13164
13206
  init_global_workspace();
13165
13207
  init_orchestrator_capable();
13166
13208
  init_thread_store();
13209
+ init_worktree_runtime();
13167
13210
  init_worktree_labels();
13168
13211
  }
13169
13212
  });
@@ -13832,6 +13875,10 @@ var init_conductor = __esm({
13832
13875
  function setupLogPath(threadId) {
13833
13876
  return (0, import_node_path36.join)(threadsDir(), `${threadId}.setup.log.json`);
13834
13877
  }
13878
+ function setupLogKeyForWorktree(worktreePath) {
13879
+ const norm = normalizeWorktreePath(worktreePath);
13880
+ return `wt-${(0, import_node_crypto8.createHash)("sha1").update(norm).digest("hex").slice(0, 16)}`;
13881
+ }
13835
13882
  function emptySetupLog() {
13836
13883
  return { ...EMPTY };
13837
13884
  }
@@ -13922,12 +13969,14 @@ function finishSetupLog(threadId, exitCode, source) {
13922
13969
  persistNow(threadId);
13923
13970
  return clone(snap);
13924
13971
  }
13925
- var import_node_fs36, import_node_path36, EMPTY, memory, persistTimers;
13972
+ var import_node_crypto8, import_node_fs36, import_node_path36, EMPTY, memory, persistTimers;
13926
13973
  var init_setup_log = __esm({
13927
13974
  "src/store/setup-log.ts"() {
13928
13975
  "use strict";
13976
+ import_node_crypto8 = require("crypto");
13929
13977
  import_node_fs36 = require("fs");
13930
13978
  import_node_path36 = require("path");
13979
+ init_worktree_labels();
13931
13980
  init_paths();
13932
13981
  EMPTY = {
13933
13982
  output: "",
@@ -16396,7 +16445,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
16396
16445
  `- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
16397
16446
  ].join("\n");
16398
16447
  return {
16399
- id: (0, import_node_crypto8.randomUUID)(),
16448
+ id: (0, import_node_crypto9.randomUUID)(),
16400
16449
  name: "Orchestration quota handoff.md",
16401
16450
  kind: "transcript",
16402
16451
  content: body
@@ -16417,11 +16466,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
16417
16466
  sourceType: "orchestration"
16418
16467
  });
16419
16468
  }
16420
- var import_node_crypto8, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
16469
+ var import_node_crypto9, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
16421
16470
  var init_quota_failover = __esm({
16422
16471
  "src/orchestrator/quota-failover.ts"() {
16423
16472
  "use strict";
16424
- import_node_crypto8 = require("crypto");
16473
+ import_node_crypto9 = require("crypto");
16425
16474
  init_session_quota();
16426
16475
  init_app_settings();
16427
16476
  init_global_workspace();
@@ -19179,7 +19228,7 @@ function buildTask(input, now) {
19179
19228
  const ts = nowIso2(now);
19180
19229
  const agent = input.agent ? coerceOrchestratorAgent(input.agent) : null;
19181
19230
  return {
19182
- id: (0, import_node_crypto9.randomUUID)(),
19231
+ id: (0, import_node_crypto10.randomUUID)(),
19183
19232
  name: input.name?.trim() || defaultScheduleName(prompt),
19184
19233
  prompt,
19185
19234
  enabled: input.enabled !== false,
@@ -19266,11 +19315,11 @@ function recordScheduleRun(id, result) {
19266
19315
  writeAll2(rows);
19267
19316
  return next;
19268
19317
  }
19269
- var import_node_crypto9, import_node_fs51, import_node_path48, import_croner, DURATION_RE, UNIT_MS;
19318
+ var import_node_crypto10, import_node_fs51, import_node_path48, import_croner, DURATION_RE, UNIT_MS;
19270
19319
  var init_schedules = __esm({
19271
19320
  "src/store/schedules.ts"() {
19272
19321
  "use strict";
19273
- import_node_crypto9 = require("crypto");
19322
+ import_node_crypto10 = require("crypto");
19274
19323
  import_node_fs51 = require("fs");
19275
19324
  import_node_path48 = require("path");
19276
19325
  import_croner = require("croner");
@@ -19412,64 +19461,6 @@ var init_schedule_runner = __esm({
19412
19461
  }
19413
19462
  });
19414
19463
 
19415
- // src/integrations/github.ts
19416
- var github_exports = {};
19417
- __export(github_exports, {
19418
- getGitHubStatus: () => getGitHubStatus,
19419
- refreshGitHubAuth: () => refreshGitHubAuth
19420
- });
19421
- async function getGitHubStatus() {
19422
- const which = await run("which", ["gh"], { reject: false });
19423
- if (which.exitCode !== 0 || !which.stdout.trim()) {
19424
- return {
19425
- connected: false,
19426
- login: null,
19427
- hosts: [],
19428
- reason: "gh CLI not found on PATH"
19429
- };
19430
- }
19431
- const loginResult = await run(
19432
- "gh",
19433
- ["api", "user", "--jq", ".login"],
19434
- { reject: false }
19435
- );
19436
- if (loginResult.exitCode === 0 && loginResult.stdout.trim()) {
19437
- return {
19438
- connected: true,
19439
- login: loginResult.stdout.trim(),
19440
- hosts: ["github.com"],
19441
- reason: null
19442
- };
19443
- }
19444
- const status = await run("gh", ["auth", "status"], { reject: false });
19445
- const text7 = `${status.stdout}
19446
- ${status.stderr}`;
19447
- const loginMatch = text7.match(/Logged in to ([^\s]+) account (\S+)/i) ?? text7.match(/Logged in to ([^\s]+) as (\S+)/i);
19448
- if (loginMatch) {
19449
- return {
19450
- connected: true,
19451
- login: loginMatch[2].replace(/['"]/g, ""),
19452
- hosts: [loginMatch[1]],
19453
- reason: null
19454
- };
19455
- }
19456
- return {
19457
- connected: false,
19458
- login: null,
19459
- hosts: [],
19460
- reason: status.stderr.trim() || status.stdout.trim() || "Not logged in to GitHub (run: gh auth login)"
19461
- };
19462
- }
19463
- async function refreshGitHubAuth() {
19464
- return getGitHubStatus();
19465
- }
19466
- var init_github = __esm({
19467
- "src/integrations/github.ts"() {
19468
- "use strict";
19469
- init_run();
19470
- }
19471
- });
19472
-
19473
19464
  // src/agents/cursor-store.ts
19474
19465
  function cursorSdkStoreDir(threadId) {
19475
19466
  const root = (0, import_node_path49.join)(appDataDir(), CURSOR_SDK_STORE_DIR);
@@ -19736,6 +19727,7 @@ var init_orchestrator = __esm({
19736
19727
  init_setup_last_error();
19737
19728
  init_request_review();
19738
19729
  init_fork_worktree();
19730
+ init_worktree_runtime();
19739
19731
  init_quota_failover();
19740
19732
  init_adopt();
19741
19733
  init_stack_layers();
@@ -20534,21 +20526,11 @@ var init_orchestrator = __esm({
20534
20526
  const settings = loadWorkspaceSettings(fresh.worktreePath, fresh.repoPath);
20535
20527
  let renameBranchDirective = null;
20536
20528
  if (!isBrightsy && !isOrchestration && autoRenameBranchEnabled2()) {
20537
- const { isPlaceholderBranch: isPlaceholderBranch2 } = await Promise.resolve().then(() => (init_worktree_labels(), worktree_labels_exports));
20538
- let githubLogin = null;
20539
- if (isPlaceholderBranch2(fresh.branchName, fresh.worktreePath) && !gitBranchPrefixSetting2()) {
20540
- try {
20541
- const { getGitHubStatus: getGitHubStatus2 } = await Promise.resolve().then(() => (init_github(), github_exports));
20542
- githubLogin = (await getGitHubStatus2()).login;
20543
- } catch {
20544
- }
20545
- }
20546
20529
  const { resolveGitBranchPrefix: resolveGitBranchPrefix2 } = await Promise.resolve().then(() => (init_branch_prefix(), branch_prefix_exports));
20547
20530
  renameBranchDirective = formatRenameBranchDirective(fresh, {
20548
20531
  customPrompt: settings?.prompts?.renameBranch,
20549
20532
  branchPrefix: resolveGitBranchPrefix2({
20550
- setting: gitBranchPrefixSetting2(),
20551
- githubLogin
20533
+ setting: gitBranchPrefixSetting2()
20552
20534
  })
20553
20535
  });
20554
20536
  }
@@ -20911,22 +20893,25 @@ var init_orchestrator = __esm({
20911
20893
  "No run script found for this worktree. Add [scripts.run.*] in the worktree\u2019s .sideboard/settings.toml or .conductor/settings.toml (or settings.local.toml on the main repo)."
20912
20894
  );
20913
20895
  }
20914
- const runKey = `${thread.id}:run:${resolvedName}`;
20915
- const existing = this.processes.get(runKey);
20916
- const active = (thread.activeRuns ?? []).find((r) => r.scriptName === resolvedName);
20896
+ const siblings = threadsSharingWorktree(thread.worktreePath);
20897
+ const shared = mergeWorktreeActiveRuns(siblings);
20898
+ const runKey = worktreeRunProcessKey(thread.worktreePath, resolvedName);
20899
+ const existing = this.processes.get(runKey) ?? siblings.map((t) => this.processes.get(`${t.id}:run:${resolvedName}`)).find(Boolean);
20900
+ const active = shared.activeRuns.find((r) => r.scriptName === resolvedName);
20917
20901
  if (existing && active) {
20918
20902
  return { port: active.port, scriptName: resolvedName, ports: active.ports };
20919
20903
  }
20920
20904
  if (!scriptName) {
20921
- const legacy = this.processes.get(`${thread.id}:dev`);
20922
- if (legacy && thread.devPort) {
20923
- return { port: thread.devPort, scriptName: resolvedName, ports: [thread.devPort] };
20905
+ const legacy = this.processes.get(worktreeDevProcessKey(thread.worktreePath)) ?? siblings.map((t) => this.processes.get(`${t.id}:dev`)).find(Boolean);
20906
+ if (legacy && shared.devPort) {
20907
+ return { port: shared.devPort, scriptName: resolvedName, ports: [shared.devPort] };
20924
20908
  }
20925
20909
  }
20926
20910
  const mode = getRunMode(thread.worktreePath, thread.repoPath);
20927
20911
  if (mode === "nonconcurrent") {
20912
+ const here = normalizeWorktreePath(thread.worktreePath);
20928
20913
  for (const t of listThreads()) {
20929
- if (t.id === thread.id) continue;
20914
+ if (normalizeWorktreePath(t.worktreePath) === here) continue;
20930
20915
  const runs = t.activeRuns ?? [];
20931
20916
  if (runs.length > 0 || t.devPort) {
20932
20917
  throw new Error(
@@ -20961,7 +20946,7 @@ var init_orchestrator = __esm({
20961
20946
  });
20962
20947
  const isDefault = scripts.find((s) => s.default)?.name === resolvedName || !scripts.some((s) => s.default) && (resolvedName === "dev" || resolvedName === scripts[0]?.name);
20963
20948
  if (isDefault) {
20964
- this.processes.set(`${thread.id}:dev`, {
20949
+ this.processes.set(worktreeDevProcessKey(thread.worktreePath), {
20965
20950
  kind: "dev",
20966
20951
  pid: handle.pid,
20967
20952
  startedAt,
@@ -20976,13 +20961,14 @@ var init_orchestrator = __esm({
20976
20961
  startedAt
20977
20962
  };
20978
20963
  const nextRuns = [
20979
- ...(thread.activeRuns ?? []).filter((r) => r.scriptName !== resolvedName),
20964
+ ...shared.activeRuns.filter((r) => r.scriptName !== resolvedName),
20980
20965
  run2
20981
20966
  ];
20982
- updateThread(thread.id, {
20983
- activeRuns: nextRuns,
20984
- devPort: isDefault ? handle.port : thread.devPort
20985
- });
20967
+ this.syncWorktreeRuns(
20968
+ thread.worktreePath,
20969
+ nextRuns,
20970
+ isDefault ? handle.port : shared.devPort
20971
+ );
20986
20972
  this.emit({
20987
20973
  type: "dev_server_started",
20988
20974
  threadId: thread.id,
@@ -20991,15 +20977,14 @@ var init_orchestrator = __esm({
20991
20977
  });
20992
20978
  void handle.done.then(() => {
20993
20979
  this.processes.delete(runKey);
20994
- if (isDefault) this.processes.delete(`${thread.id}:dev`);
20995
- const latest = readThread(thread.id);
20996
- const remaining = (latest?.activeRuns ?? []).filter(
20997
- (r) => r.scriptName !== resolvedName
20980
+ if (isDefault) this.processes.delete(worktreeDevProcessKey(thread.worktreePath));
20981
+ const latest = mergeWorktreeActiveRuns(threadsSharingWorktree(thread.worktreePath));
20982
+ const remaining = latest.activeRuns.filter((r) => r.scriptName !== resolvedName);
20983
+ this.syncWorktreeRuns(
20984
+ thread.worktreePath,
20985
+ remaining,
20986
+ isDefault ? null : latest.devPort
20998
20987
  );
20999
- updateThread(thread.id, {
21000
- activeRuns: remaining,
21001
- devPort: isDefault ? null : latest?.devPort ?? null
21002
- });
21003
20988
  this.emit({
21004
20989
  type: "dev_server_stopped",
21005
20990
  threadId: thread.id,
@@ -21010,51 +20995,82 @@ var init_orchestrator = __esm({
21010
20995
  }
21011
20996
  stopDev(threadRef, scriptName) {
21012
20997
  const thread = this.requireThread(threadRef);
20998
+ const siblings = threadsSharingWorktree(thread.worktreePath);
20999
+ const shared = mergeWorktreeActiveRuns(siblings);
21013
21000
  if (scriptName) {
21014
- const runKey = `${thread.id}:run:${scriptName}`;
21015
- const proc = this.processes.get(runKey);
21016
- if (proc) proc.kill();
21017
- this.processes.delete(runKey);
21018
- const remaining = (thread.activeRuns ?? []).filter((r) => r.scriptName !== scriptName);
21019
- const isPrimary = thread.devPort != null && thread.activeRuns?.find((r) => r.scriptName === scriptName)?.port === thread.devPort;
21020
- updateThread(thread.id, {
21021
- activeRuns: remaining,
21022
- devPort: isPrimary ? null : thread.devPort
21023
- });
21001
+ const keys = [
21002
+ worktreeRunProcessKey(thread.worktreePath, scriptName),
21003
+ ...siblings.map((t) => `${t.id}:run:${scriptName}`)
21004
+ ];
21005
+ for (const key of keys) {
21006
+ const proc = this.processes.get(key);
21007
+ if (proc) proc.kill();
21008
+ this.processes.delete(key);
21009
+ }
21010
+ const remaining = shared.activeRuns.filter((r) => r.scriptName !== scriptName);
21011
+ const isPrimary = shared.devPort != null && shared.activeRuns.find((r) => r.scriptName === scriptName)?.port === shared.devPort;
21012
+ this.syncWorktreeRuns(
21013
+ thread.worktreePath,
21014
+ remaining,
21015
+ isPrimary ? null : shared.devPort
21016
+ );
21024
21017
  this.emit({ type: "dev_server_stopped", threadId: thread.id, scriptName });
21025
21018
  return;
21026
21019
  }
21027
21020
  for (const [key, proc] of [...this.processes.entries()]) {
21028
- if (key.startsWith(`${thread.id}:run:`) || key === `${thread.id}:dev`) {
21021
+ if (isWorktreeRunProcessKey(key, thread.worktreePath) || siblings.some((t) => key.startsWith(`${t.id}:run:`) || key === `${t.id}:dev`)) {
21029
21022
  proc.kill();
21030
21023
  this.processes.delete(key);
21031
21024
  }
21032
21025
  }
21033
- updateThread(thread.id, { activeRuns: [], devPort: null });
21026
+ this.syncWorktreeRuns(thread.worktreePath, [], null);
21034
21027
  this.emit({ type: "dev_server_stopped", threadId: thread.id });
21035
21028
  }
21029
+ syncWorktreeRuns(worktreePath, activeRuns, devPort) {
21030
+ for (const sibling of threadsSharingWorktree(worktreePath)) {
21031
+ updateThread(sibling.id, { activeRuns, devPort });
21032
+ }
21033
+ }
21036
21034
  listThreadRunScripts(threadRef) {
21037
21035
  const thread = this.requireThread(threadRef);
21038
21036
  return listRunScripts(thread.worktreePath, thread.repoPath);
21039
21037
  }
21040
21038
  getActiveRuns(threadRef) {
21041
- return this.requireThread(threadRef).activeRuns ?? [];
21039
+ const thread = this.requireThread(threadRef);
21040
+ return mergeWorktreeActiveRuns(threadsSharingWorktree(thread.worktreePath)).activeRuns;
21042
21041
  }
21043
21042
  getSetupLog(threadRef) {
21044
21043
  const thread = this.getThread(threadRef);
21045
21044
  if (!thread) return readSetupLog(threadRef);
21046
- const snap = readSetupLog(thread.id);
21047
- if (snap.running && !this.processes.has(`${thread.id}:setup`)) {
21045
+ const siblingIds = [
21046
+ thread.id,
21047
+ ...threadsSharingWorktree(thread.worktreePath).map((t) => t.id)
21048
+ ];
21049
+ const snap = pickRichestSetupLog([
21050
+ readSetupLog(setupLogKeyForWorktree(thread.worktreePath)),
21051
+ ...[...new Set(siblingIds)].map((id) => readSetupLog(id))
21052
+ ]) ?? readSetupLog(thread.id);
21053
+ if (snap.running && !this.hasWorktreeSetupProcess(thread.worktreePath)) {
21048
21054
  return { ...snap, running: false };
21049
21055
  }
21050
21056
  return snap;
21051
21057
  }
21058
+ hasWorktreeSetupProcess(worktreePath) {
21059
+ if (this.processes.has(worktreeSetupProcessKey(worktreePath))) return true;
21060
+ return threadsSharingWorktree(worktreePath).some(
21061
+ (t) => this.processes.has(`${t.id}:setup`)
21062
+ );
21063
+ }
21064
+ writeSetupLog(threadId, worktreePath, fn) {
21065
+ fn(setupLogKeyForWorktree(worktreePath));
21066
+ fn(threadId);
21067
+ }
21052
21068
  async runSetup(threadRef, opts) {
21053
21069
  const thread = this.requireThread(threadRef);
21054
21070
  this.assertNotGlobal(thread, "Setup");
21055
- const key = `${thread.id}:setup`;
21056
- if (this.processes.has(key)) {
21057
- throw new Error("Setup already running for this thread");
21071
+ const key = worktreeSetupProcessKey(thread.worktreePath);
21072
+ if (this.hasWorktreeSetupProcess(thread.worktreePath)) {
21073
+ throw new Error("Setup already running for this worktree");
21058
21074
  }
21059
21075
  const abort = new AbortController();
21060
21076
  this.processes.set(key, {
@@ -21062,13 +21078,17 @@ var init_orchestrator = __esm({
21062
21078
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
21063
21079
  kill: () => abort.abort()
21064
21080
  });
21065
- beginSetupLog(thread.id);
21081
+ this.writeSetupLog(thread.id, thread.worktreePath, beginSetupLog);
21066
21082
  this.emit({ type: "setup_started", threadId: thread.id });
21067
21083
  let finished = false;
21068
21084
  const finish = (exitCode, source) => {
21069
21085
  if (finished) return;
21070
21086
  finished = true;
21071
- finishSetupLog(thread.id, exitCode, source);
21087
+ this.writeSetupLog(
21088
+ thread.id,
21089
+ thread.worktreePath,
21090
+ (logKey) => finishSetupLog(logKey, exitCode, source)
21091
+ );
21072
21092
  this.emit({ type: "setup_finished", threadId: thread.id, exitCode });
21073
21093
  };
21074
21094
  try {
@@ -21076,14 +21096,22 @@ var init_orchestrator = __esm({
21076
21096
  thread.repoPath,
21077
21097
  thread.worktreePath,
21078
21098
  (line) => {
21079
- appendSetupLog(thread.id, line);
21099
+ this.writeSetupLog(
21100
+ thread.id,
21101
+ thread.worktreePath,
21102
+ (logKey) => appendSetupLog(logKey, line)
21103
+ );
21080
21104
  this.emit({ type: "setup_output", threadId: thread.id, line });
21081
21105
  },
21082
21106
  { signal: abort.signal }
21083
21107
  );
21084
21108
  if (!setup.ran) {
21085
21109
  const line = "No setup script in .sideboard/settings.toml, .conductor/settings.toml, .cursor/worktrees.json, or script/setup (bin/setup, scripts/setup)";
21086
- appendSetupLog(thread.id, line);
21110
+ this.writeSetupLog(
21111
+ thread.id,
21112
+ thread.worktreePath,
21113
+ (logKey) => appendSetupLog(logKey, line)
21114
+ );
21087
21115
  this.emit({ type: "setup_output", threadId: thread.id, line });
21088
21116
  finish(null, null);
21089
21117
  throw new Error(line);
@@ -21111,8 +21139,14 @@ var init_orchestrator = __esm({
21111
21139
  }
21112
21140
  cancelSetup(threadRef) {
21113
21141
  const thread = this.requireThread(threadRef);
21114
- const proc = this.processes.get(`${thread.id}:setup`);
21115
- if (proc) proc.kill();
21142
+ const keys = [
21143
+ worktreeSetupProcessKey(thread.worktreePath),
21144
+ ...threadsSharingWorktree(thread.worktreePath).map((t) => `${t.id}:setup`)
21145
+ ];
21146
+ for (const key of [...new Set(keys)]) {
21147
+ const proc = this.processes.get(key);
21148
+ if (proc) proc.kill();
21149
+ }
21116
21150
  }
21117
21151
  async applyIntoMain(threadRef, opts) {
21118
21152
  const thread = this.requireThread(threadRef);
@@ -21862,7 +21896,7 @@ init_system_ca();
21862
21896
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
21863
21897
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
21864
21898
  var import_zod9 = require("zod");
21865
- var import_node_crypto12 = require("crypto");
21899
+ var import_node_crypto13 = require("crypto");
21866
21900
  var import_node_path52 = require("path");
21867
21901
  init_orchestrator();
21868
21902
  init_worktree();
@@ -22289,7 +22323,7 @@ async function createGitHubIssue(input, opts) {
22289
22323
  init_fetch();
22290
22324
 
22291
22325
  // src/integrations/linear-oauth.ts
22292
- var import_node_crypto10 = require("crypto");
22326
+ var import_node_crypto11 = require("crypto");
22293
22327
  var import_node_http = require("http");
22294
22328
  init_app_settings();
22295
22329
  init_fetch();
@@ -25272,7 +25306,7 @@ init_worktree();
25272
25306
  init_paths();
25273
25307
 
25274
25308
  // src/board/board-pins.ts
25275
- var import_node_crypto11 = require("crypto");
25309
+ var import_node_crypto12 = require("crypto");
25276
25310
  var import_node_fs54 = require("fs");
25277
25311
  var import_node_path50 = require("path");
25278
25312
  init_paths();
@@ -25487,7 +25521,51 @@ async function getHomeBoardInputs(workspaces, opts) {
25487
25521
 
25488
25522
  // src/mcp/server.ts
25489
25523
  init_home_board();
25490
- init_github();
25524
+
25525
+ // src/integrations/github.ts
25526
+ init_run();
25527
+ async function getGitHubStatus() {
25528
+ const which = await run("which", ["gh"], { reject: false });
25529
+ if (which.exitCode !== 0 || !which.stdout.trim()) {
25530
+ return {
25531
+ connected: false,
25532
+ login: null,
25533
+ hosts: [],
25534
+ reason: "gh CLI not found on PATH"
25535
+ };
25536
+ }
25537
+ const loginResult = await run(
25538
+ "gh",
25539
+ ["api", "user", "--jq", ".login"],
25540
+ { reject: false }
25541
+ );
25542
+ if (loginResult.exitCode === 0 && loginResult.stdout.trim()) {
25543
+ return {
25544
+ connected: true,
25545
+ login: loginResult.stdout.trim(),
25546
+ hosts: ["github.com"],
25547
+ reason: null
25548
+ };
25549
+ }
25550
+ const status = await run("gh", ["auth", "status"], { reject: false });
25551
+ const text7 = `${status.stdout}
25552
+ ${status.stderr}`;
25553
+ const loginMatch = text7.match(/Logged in to ([^\s]+) account (\S+)/i) ?? text7.match(/Logged in to ([^\s]+) as (\S+)/i);
25554
+ if (loginMatch) {
25555
+ return {
25556
+ connected: true,
25557
+ login: loginMatch[2].replace(/['"]/g, ""),
25558
+ hosts: [loginMatch[1]],
25559
+ reason: null
25560
+ };
25561
+ }
25562
+ return {
25563
+ connected: false,
25564
+ login: null,
25565
+ hosts: [],
25566
+ reason: status.stderr.trim() || status.stdout.trim() || "Not logged in to GitHub (run: gh auth login)"
25567
+ };
25568
+ }
25491
25569
 
25492
25570
  // src/mcp/create-thread-agent.ts
25493
25571
  init_cursor();
@@ -26077,7 +26155,7 @@ async function startMcpServer() {
26077
26155
  const ident = issue?.identifier ?? ref.trim();
26078
26156
  const attachments = issue ? [
26079
26157
  {
26080
- id: (0, import_node_crypto12.randomUUID)(),
26158
+ id: (0, import_node_crypto13.randomUUID)(),
26081
26159
  name: issue.identifier,
26082
26160
  kind: "issue",
26083
26161
  content: [