@sideboard-ai/core 0.1.152 → 0.1.153

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 (61) hide show
  1. package/dist/{abletime-223A3LY6.js → abletime-H7LPGIP2.js} +3 -3
  2. package/dist/{abletime-CLC5UJC2.js → abletime-JSTJLXAW.js} +3 -3
  3. package/dist/agents/cursor-runner.js +2 -2
  4. package/dist/{agents-CUKWIM34.js → agents-V24DYZI4.js} +8 -9
  5. package/dist/{agents-VHXCBBBD.js → agents-YVW75KBO.js} +8 -9
  6. package/dist/{app-settings-3CHCNIMD.js → app-settings-H3INSR67.js} +38 -4
  7. package/dist/{app-settings-J3JBCUOT.js → app-settings-VRQI3FIE.js} +38 -4
  8. package/dist/{caffeinate-hold-NBRUWYXO.js → caffeinate-hold-DBKMRZZO.js} +2 -2
  9. package/dist/{caffeinate-hold-X3JNPR42.js → caffeinate-hold-SK2QISPE.js} +2 -2
  10. package/dist/chunk-2F63IMCL.js +959 -0
  11. package/dist/{chunk-7BQNSUR2.js → chunk-2NRNP7QP.js} +357 -185
  12. package/dist/{chunk-4XNSGDXE.js → chunk-3BWVOUQG.js} +244 -1
  13. package/dist/{chunk-EY6QXPPO.js → chunk-4THE3EY7.js} +6 -6
  14. package/dist/{chunk-TUGKX5BD.js → chunk-7UURXPKD.js} +1 -1
  15. package/dist/{chunk-DCOZABNT.js → chunk-AO35MGOE.js} +1 -1
  16. package/dist/{chunk-3JBMACYX.js → chunk-CJQLPPEJ.js} +387 -15
  17. package/dist/{chunk-CZD4NRDZ.js → chunk-D7EGJ3EI.js} +244 -1
  18. package/dist/{chunk-QZQEXME2.js → chunk-EFVFB2AH.js} +1 -1
  19. package/dist/{chunk-B7XK37WZ.js → chunk-FDCFXMDG.js} +1 -1
  20. package/dist/{chunk-WLV7TRMR.js → chunk-JOK4XWBG.js} +1 -1
  21. package/dist/{chunk-BD2ICC4D.js → chunk-JTJHOYCU.js} +1 -1
  22. package/dist/{chunk-6X7Z34XE.js → chunk-KMNODRWF.js} +397 -173
  23. package/dist/{chunk-GE7M3QTE.js → chunk-LQMFCS54.js} +387 -15
  24. package/dist/{chunk-G7SIQFBQ.js → chunk-LZ6QMEQC.js} +1 -1
  25. package/dist/{chunk-EUXOHTUK.js → chunk-LZQULFIT.js} +1 -1
  26. package/dist/{chunk-KLBOWJ74.js → chunk-OCQPTUR7.js} +1 -1
  27. package/dist/{chunk-GFQ57XAX.js → chunk-QZEZXYVV.js} +13 -13
  28. package/dist/chunk-RNC3GR6L.js +905 -0
  29. package/dist/{chunk-VHX673DI.js → chunk-WLPXZFRE.js} +1 -1
  30. package/dist/{chunk-7F4XE6UG.js → chunk-XD2BAANL.js} +5 -5
  31. package/dist/{connected-teams-XO766HB4.js → connected-teams-DBWAMP7G.js} +2 -2
  32. package/dist/{connected-teams-I2WZZZFA.js → connected-teams-WGONUQOF.js} +2 -2
  33. package/dist/{coordinator-prompt-WGFRYCHE.js → coordinator-prompt-7FHKCWXB.js} +5 -5
  34. package/dist/{coordinator-prompt-TBX4MOFM.js → coordinator-prompt-KX2FVVYT.js} +5 -5
  35. package/dist/{cursor-recover-NOQYOFRF.js → cursor-recover-L5MD6MBO.js} +1 -1
  36. package/dist/{cursor-recover-QSLWEZNA.js → cursor-recover-NDMLLNYX.js} +2 -2
  37. package/dist/{global-workspace-IY5QAV5C.js → global-workspace-2BRRKSDN.js} +5 -6
  38. package/dist/{global-workspace-BHLUJ46D.js → global-workspace-4LHCZ2DC.js} +5 -6
  39. package/dist/index.cjs +1875 -765
  40. package/dist/index.d.cts +195 -11
  41. package/dist/index.d.ts +195 -11
  42. package/dist/index.js +298 -108
  43. package/dist/mcp/run-stdio.cjs +1743 -1228
  44. package/dist/mcp/run-stdio.js +232 -80
  45. package/dist/{orchestrator-NUA6SEV7.js → orchestrator-5PSHBLP6.js} +10 -12
  46. package/dist/{orchestrator-256DFPSX.js → orchestrator-ZSSU3FKW.js} +9 -11
  47. package/dist/{paths-UMEDHOS5.js → paths-53TLA7VQ.js} +1 -1
  48. package/dist/{paths-QCI3MTO5.js → paths-RRCLNSJB.js} +1 -1
  49. package/dist/{thread-store-WGASXXXR.js → thread-store-KBFBHT5G.js} +2 -2
  50. package/dist/{thread-store-57ZLHR3A.js → thread-store-MVQU6HPJ.js} +2 -2
  51. package/dist/{workspaces-4FSXVIZM.js → workspaces-5UNDTN4G.js} +5 -7
  52. package/dist/{workspaces-NECIQTAO.js → workspaces-MQYNZXUK.js} +5 -7
  53. package/dist/{worktree-HTUM35NT.js → worktree-PEWDAX5O.js} +4 -4
  54. package/dist/{worktree-DPIREDFR.js → worktree-T4SWFSTT.js} +4 -4
  55. package/package.json +1 -1
  56. package/dist/chunk-2U6QF3PT.js +0 -211
  57. package/dist/chunk-67TIJ7S5.js +0 -122
  58. package/dist/chunk-7TIUOYBK.js +0 -213
  59. package/dist/chunk-G4MTYUWS.js +0 -592
  60. package/dist/chunk-K2ANSHUO.js +0 -120
  61. package/dist/chunk-SN6CMKF6.js +0 -538
@@ -33,18 +33,27 @@ import {
33
33
  summarizeTurnStderr,
34
34
  toolDescription,
35
35
  turnFailChatText
36
- } from "./chunk-EY6QXPPO.js";
36
+ } from "./chunk-4THE3EY7.js";
37
37
  import {
38
- addWorkspace,
39
- ensureWorkspace,
40
- removeWorkspace,
41
- syncWorkspacesFromThreads
42
- } from "./chunk-67TIJ7S5.js";
38
+ extractPresentedPlan,
39
+ readPlanFile,
40
+ writePlanFile
41
+ } from "./chunk-2SDMENAL.js";
42
+ import {
43
+ releaseCaffeinateHoldForThread
44
+ } from "./chunk-OCQPTUR7.js";
43
45
  import {
46
+ SLACK_REPLY_FORMATTING,
47
+ addWorkspace,
44
48
  assertOrchestratorCapableAgent,
45
49
  attachmentsFromWorktreePaths,
46
50
  coerceOrchestratorAgent,
51
+ coordinatorSystemPrompt,
52
+ coordinatorTurnReminder,
47
53
  createGlobalChat,
54
+ enrichWorkspacesWithGithub,
55
+ ensureGlobalCoordinatorCwd,
56
+ ensureWorkspace,
48
57
  healOrchestrationSoccerTitles,
49
58
  isCloudCoordinatorThread,
50
59
  isGlobalRepoPath,
@@ -54,24 +63,11 @@ import {
54
63
  isSlackCoordinatorThread,
55
64
  orchestratorSessionPoisonedByBuiltins,
56
65
  persistPendingFileAttachments,
66
+ removeWorkspace,
57
67
  stageAbsolutePathsAsAttachments,
58
- stageBuffersAsAttachments
59
- } from "./chunk-SN6CMKF6.js";
60
- import {
61
- extractPresentedPlan,
62
- readPlanFile,
63
- writePlanFile
64
- } from "./chunk-2SDMENAL.js";
65
- import {
66
- releaseCaffeinateHoldForThread
67
- } from "./chunk-KLBOWJ74.js";
68
- import {
69
- SLACK_REPLY_FORMATTING,
70
- coordinatorSystemPrompt,
71
- coordinatorTurnReminder,
72
- enrichWorkspacesWithGithub,
73
- ensureGlobalCoordinatorCwd
74
- } from "./chunk-7TIUOYBK.js";
68
+ stageBuffersAsAttachments,
69
+ syncWorkspacesFromThreads
70
+ } from "./chunk-RNC3GR6L.js";
75
71
  import {
76
72
  addPrStackLayer,
77
73
  allocateTeamName,
@@ -119,7 +115,7 @@ import {
119
115
  withRepoGitLock,
120
116
  worktreeDisplayLabelForGroup,
121
117
  worktreeNameFromPath
122
- } from "./chunk-3JBMACYX.js";
118
+ } from "./chunk-CJQLPPEJ.js";
123
119
  import {
124
120
  ATTACHMENTS_DIR,
125
121
  LEGACY_ATTACHMENTS_DIR
@@ -135,7 +131,7 @@ import {
135
131
  updateThread,
136
132
  withThreadLock,
137
133
  writeThread
138
- } from "./chunk-EUXOHTUK.js";
134
+ } from "./chunk-LZQULFIT.js";
139
135
  import {
140
136
  ensureWorktreeSideboardIgnored
141
137
  } from "./chunk-SYFVUF2C.js";
@@ -162,7 +158,7 @@ import {
162
158
  stripNestedElectronEnv,
163
159
  updateAdvancedSettings,
164
160
  writeSecureJson
165
- } from "./chunk-CZD4NRDZ.js";
161
+ } from "./chunk-D7EGJ3EI.js";
166
162
  import {
167
163
  writePrivateFile
168
164
  } from "./chunk-NSTQ6QKD.js";
@@ -175,9 +171,10 @@ import {
175
171
  sideboardReposDir,
176
172
  sideboardWorkspacesDir,
177
173
  threadLivePath,
174
+ threadsDir,
178
175
  workspaceSettingsSourceLabel,
179
176
  worktreesRoot
180
- } from "./chunk-BD2ICC4D.js";
177
+ } from "./chunk-JTJHOYCU.js";
181
178
 
182
179
  // src/orchestrator/orchestrator.ts
183
180
  import { EventEmitter } from "events";
@@ -395,7 +392,7 @@ async function continueSourceThread(threadId, prompt) {
395
392
  await continueOnReply(threadId, prompt);
396
393
  return;
397
394
  }
398
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-256DFPSX.js");
395
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-ZSSU3FKW.js");
399
396
  await getOrchestrator2().send(threadId, prompt);
400
397
  } catch {
401
398
  }
@@ -655,7 +652,7 @@ async function pollSlackOutboundWatches(opts) {
655
652
  }
656
653
 
657
654
  // src/orchestrator/orchestrator.ts
658
- import { existsSync as existsSync16 } from "fs";
655
+ import { existsSync as existsSync17 } from "fs";
659
656
 
660
657
  // src/agents/spawn.ts
661
658
  import { createInterface } from "readline";
@@ -736,9 +733,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
736
733
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
737
734
  );
738
735
  }
739
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-BHLUJ46D.js");
736
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-4LHCZ2DC.js");
740
737
  if (isGlobalThread2(thread)) {
741
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-TBX4MOFM.js");
738
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-KX2FVVYT.js");
742
739
  ensureGlobalCoordinatorCwd2(
743
740
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
744
741
  );
@@ -1940,6 +1937,8 @@ async function attachAbort(handle, signal) {
1940
1937
  async function runSetupScript(repoPath, worktreePath, onLine, opts) {
1941
1938
  const settings = loadWorkspaceSettings(worktreePath, repoPath);
1942
1939
  if (!settings?.setup) return { ran: false, exitCode: null, source: null };
1940
+ const source = workspaceSettingsSourceLabel(worktreePath, repoPath);
1941
+ onLine?.(`[setup] ${source ?? "settings.toml"}`);
1943
1942
  const handle = await spawnWorkspaceScript(settings.setup, {
1944
1943
  worktreePath,
1945
1944
  repoPath,
@@ -1950,7 +1949,7 @@ async function runSetupScript(repoPath, worktreePath, onLine, opts) {
1950
1949
  return {
1951
1950
  ran: true,
1952
1951
  exitCode,
1953
- source: workspaceSettingsSourceLabel(worktreePath, repoPath),
1952
+ source,
1954
1953
  kill: handle.kill
1955
1954
  };
1956
1955
  }
@@ -2079,9 +2078,114 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
2079
2078
  };
2080
2079
  }
2081
2080
 
2082
- // src/git/orphan-cleanup.ts
2083
- import { existsSync as existsSync5, readdirSync as readdirSync2, statSync } from "fs";
2081
+ // src/store/setup-log.ts
2082
+ import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
2084
2083
  import { join as join6 } from "path";
2084
+ var EMPTY = {
2085
+ output: "",
2086
+ running: false,
2087
+ exitCode: null,
2088
+ source: null
2089
+ };
2090
+ var memory = /* @__PURE__ */ new Map();
2091
+ var persistTimers = /* @__PURE__ */ new Map();
2092
+ function setupLogPath(threadId) {
2093
+ return join6(threadsDir(), `${threadId}.setup.log.json`);
2094
+ }
2095
+ function emptySetupLog() {
2096
+ return { ...EMPTY };
2097
+ }
2098
+ function clone(snap) {
2099
+ return { ...snap };
2100
+ }
2101
+ function persistNow(threadId) {
2102
+ const timer = persistTimers.get(threadId);
2103
+ if (timer) {
2104
+ clearTimeout(timer);
2105
+ persistTimers.delete(threadId);
2106
+ }
2107
+ const snap = memory.get(threadId);
2108
+ if (!snap) return;
2109
+ try {
2110
+ writeFileSync2(setupLogPath(threadId), `${JSON.stringify(snap)}
2111
+ `, "utf8");
2112
+ } catch {
2113
+ }
2114
+ }
2115
+ function schedulePersist(threadId) {
2116
+ if (persistTimers.has(threadId)) return;
2117
+ persistTimers.set(
2118
+ threadId,
2119
+ setTimeout(() => {
2120
+ persistTimers.delete(threadId);
2121
+ persistNow(threadId);
2122
+ }, 100)
2123
+ );
2124
+ }
2125
+ function loadFromDisk(threadId) {
2126
+ const path = setupLogPath(threadId);
2127
+ if (!existsSync5(path)) return null;
2128
+ try {
2129
+ const raw = JSON.parse(readFileSync5(path, "utf8"));
2130
+ return {
2131
+ output: typeof raw.output === "string" ? raw.output : "",
2132
+ running: Boolean(raw.running),
2133
+ exitCode: typeof raw.exitCode === "number" ? raw.exitCode : null,
2134
+ source: typeof raw.source === "string" ? raw.source : null
2135
+ };
2136
+ } catch {
2137
+ return null;
2138
+ }
2139
+ }
2140
+ function readSetupLog(threadId) {
2141
+ const cached = memory.get(threadId);
2142
+ if (cached) return clone(cached);
2143
+ const disk = loadFromDisk(threadId);
2144
+ if (disk) {
2145
+ memory.set(threadId, disk);
2146
+ return clone(disk);
2147
+ }
2148
+ return emptySetupLog();
2149
+ }
2150
+ function beginSetupLog(threadId) {
2151
+ const snap = {
2152
+ output: "",
2153
+ running: true,
2154
+ exitCode: null,
2155
+ source: null
2156
+ };
2157
+ memory.set(threadId, snap);
2158
+ persistNow(threadId);
2159
+ return clone(snap);
2160
+ }
2161
+ function appendSetupLog(threadId, line) {
2162
+ const current = memory.get(threadId) ?? readSetupLog(threadId);
2163
+ const snap = {
2164
+ ...current,
2165
+ output: current.output ? `${current.output}
2166
+ ${line}` : line,
2167
+ running: true
2168
+ };
2169
+ memory.set(threadId, snap);
2170
+ schedulePersist(threadId);
2171
+ return clone(snap);
2172
+ }
2173
+ function finishSetupLog(threadId, exitCode, source) {
2174
+ const current = memory.get(threadId) ?? readSetupLog(threadId);
2175
+ const snap = {
2176
+ ...current,
2177
+ running: false,
2178
+ exitCode,
2179
+ source: source ?? current.source
2180
+ };
2181
+ memory.set(threadId, snap);
2182
+ persistNow(threadId);
2183
+ return clone(snap);
2184
+ }
2185
+
2186
+ // src/git/orphan-cleanup.ts
2187
+ import { existsSync as existsSync6, readdirSync as readdirSync2, statSync } from "fs";
2188
+ import { join as join7 } from "path";
2085
2189
  function isSideboardWorktreePath(path) {
2086
2190
  return path.includes("/.sideboard/worktrees/") || path.includes("/sideboard/workspaces/");
2087
2191
  }
@@ -2092,7 +2196,7 @@ async function findOrphanWorktrees(repoPaths) {
2092
2196
  repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
2093
2197
  );
2094
2198
  const homeRoot = sideboardWorkspacesDir();
2095
- if (existsSync5(homeRoot)) {
2199
+ if (existsSync6(homeRoot)) {
2096
2200
  try {
2097
2201
  for (const entry of readdirSync2(homeRoot, { withFileTypes: true })) {
2098
2202
  if (!entry.isDirectory()) continue;
@@ -2104,7 +2208,7 @@ async function findOrphanWorktrees(repoPaths) {
2104
2208
  const orphans = [];
2105
2209
  const seen = /* @__PURE__ */ new Set();
2106
2210
  for (const repoPath of repos) {
2107
- if (!repoPath || !existsSync5(repoPath)) continue;
2211
+ if (!repoPath || !existsSync6(repoPath)) continue;
2108
2212
  try {
2109
2213
  const wts = await listWorktrees(repoPath);
2110
2214
  for (const wt of wts) {
@@ -2125,12 +2229,12 @@ async function findOrphanWorktrees(repoPaths) {
2125
2229
  }
2126
2230
  try {
2127
2231
  const root = worktreesRoot(repoPath);
2128
- if (existsSync5(root)) {
2232
+ if (existsSync6(root)) {
2129
2233
  for (const entry of readdirSync2(root, { withFileTypes: true })) {
2130
2234
  if (!entry.isDirectory()) continue;
2131
- const path = join6(root, entry.name).replace(/\/$/, "");
2235
+ const path = join7(root, entry.name).replace(/\/$/, "");
2132
2236
  if (known.has(path) || seen.has(path)) continue;
2133
- if (!existsSync5(join6(path, ".git"))) continue;
2237
+ if (!existsSync6(join7(path, ".git"))) continue;
2134
2238
  seen.add(path);
2135
2239
  let mtimeMs = 0;
2136
2240
  try {
@@ -2270,8 +2374,8 @@ async function applyThreadIntoMain(thread, opts) {
2270
2374
  }
2271
2375
 
2272
2376
  // src/git/clone-repo.ts
2273
- import { existsSync as existsSync6 } from "fs";
2274
- import { basename as basename2, join as join7 } from "path";
2377
+ import { existsSync as existsSync7 } from "fs";
2378
+ import { basename as basename2, join as join8 } from "path";
2275
2379
  import { execa as execa4 } from "execa";
2276
2380
  async function cloneRepoIntoSideboard(opts) {
2277
2381
  const url = opts.url.trim();
@@ -2282,8 +2386,8 @@ async function cloneRepoIntoSideboard(opts) {
2282
2386
  name = leaf || "repo";
2283
2387
  }
2284
2388
  name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
2285
- const dest = join7(sideboardReposDir(), name);
2286
- if (existsSync6(dest)) {
2389
+ const dest = join8(sideboardReposDir(), name);
2390
+ if (existsSync7(dest)) {
2287
2391
  const repoPath2 = await resolveRepoRoot(dest);
2288
2392
  const workspace2 = await ensureWorkspace(repoPath2);
2289
2393
  return { repoPath: repoPath2, workspace: workspace2 };
@@ -2300,14 +2404,14 @@ async function cloneRepoIntoSideboard(opts) {
2300
2404
  }
2301
2405
 
2302
2406
  // src/store/desktop-host.ts
2303
- import { readFileSync as readFileSync5, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
2304
- import { join as join8 } from "path";
2407
+ import { readFileSync as readFileSync6, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
2408
+ import { join as join9 } from "path";
2305
2409
  function desktopHostPidPath() {
2306
- return join8(appDataDir(), "desktop-host.pid");
2410
+ return join9(appDataDir(), "desktop-host.pid");
2307
2411
  }
2308
2412
  function readDesktopHostPid() {
2309
2413
  try {
2310
- const pid = Number.parseInt(readFileSync5(desktopHostPidPath(), "utf8").trim(), 10);
2414
+ const pid = Number.parseInt(readFileSync6(desktopHostPidPath(), "utf8").trim(), 10);
2311
2415
  if (!Number.isFinite(pid) || pid <= 0) return null;
2312
2416
  return pid;
2313
2417
  } catch {
@@ -2374,7 +2478,7 @@ function notifyParentOfChildHalt(child, status, send) {
2374
2478
  }
2375
2479
 
2376
2480
  // src/threads/create.ts
2377
- import { existsSync as existsSync7 } from "fs";
2481
+ import { existsSync as existsSync8 } from "fs";
2378
2482
 
2379
2483
  // src/detect/detect.ts
2380
2484
  var REQUIRE_AGENT_TIMEOUT_MS = 8e3;
@@ -2540,12 +2644,19 @@ function urlsMatch(a, b) {
2540
2644
  const norm = (u) => u.trim().replace(/\/+$/, "").toLowerCase();
2541
2645
  return Boolean(a && b && norm(a) === norm(b));
2542
2646
  }
2647
+ function threadPrUrlMatchesNumber(thread, number) {
2648
+ if (!Number.isFinite(number) || number < 1) return false;
2649
+ const url = (thread.prUrl ?? "").trim();
2650
+ if (!url) return false;
2651
+ return new RegExp(`/pull/${number}(?:/|$|[?#])`, "i").test(url);
2652
+ }
2543
2653
  function threadMatchesPr(thread, pr) {
2544
2654
  const num = String(pr.number);
2545
2655
  if (thread.sourceType === "pr" && normalizeIssueKey(thread.sourceRef ?? "") === num) {
2546
2656
  return true;
2547
2657
  }
2548
2658
  if (thread.prUrl && pr.url && urlsMatch(thread.prUrl, pr.url)) return true;
2659
+ if (threadPrUrlMatchesNumber(thread, pr.number)) return true;
2549
2660
  const head = pr.headRefName.trim().toLowerCase();
2550
2661
  if (!head) return false;
2551
2662
  const branch = (thread.branchName ?? "").trim().toLowerCase();
@@ -2598,19 +2709,32 @@ function findLiveThreadForCreate(input, threads) {
2598
2709
  (t) => threadMatchesPr(t, {
2599
2710
  number: Number.isFinite(number) ? number : -1,
2600
2711
  title: input.title ?? "",
2601
- url: "",
2602
- headRefName: ""
2712
+ url: input.prUrl ?? "",
2713
+ headRefName: input.headRefName ?? ""
2603
2714
  })
2604
2715
  );
2605
2716
  }
2606
2717
  if (input.sourceType === "branch") {
2607
2718
  if (isDefaultBranchCreateRef(input.sourceRef)) return void 0;
2608
- return live.find(
2719
+ const byBranch = live.find(
2609
2720
  (t) => threadMatchesBranch(t, {
2610
2721
  ref: input.sourceRef,
2611
2722
  repoPath: input.repoPath
2612
2723
  })
2613
2724
  );
2725
+ if (byBranch) return byBranch;
2726
+ if (input.prUrl || input.headRefName) {
2727
+ const number = Number(normalizeIssueKey(input.sourceRef));
2728
+ return live.find(
2729
+ (t) => threadMatchesPr(t, {
2730
+ number: Number.isFinite(number) ? number : -1,
2731
+ title: input.title ?? "",
2732
+ url: input.prUrl ?? "",
2733
+ headRefName: input.headRefName ?? input.sourceRef
2734
+ })
2735
+ );
2736
+ }
2737
+ return void 0;
2614
2738
  }
2615
2739
  return void 0;
2616
2740
  }
@@ -2836,42 +2960,53 @@ function assembleHomeBoard(input) {
2836
2960
  }
2837
2961
  return { columns, hidden, totals };
2838
2962
  }
2839
- var HOME_BOARD_AGENT_HINT = "Home is a Kanban of worktrees (one card per checkout; sibling chat tabs nest as inner cards). create_thread reuses a live worktree for the same ticket, PR, or named branch \u2014 do not recreate it. Columns are the path to merge: New (no PR) \u2192 Draft (draft PR) \u2192 Review (open PR) \u2192 Merged. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. Orchestration chats stay in the sidebar. Do not invent status.";
2963
+ var HOME_BOARD_AGENT_HINT = "Home is a Kanban of worktrees (one card per checkout; sibling chat tabs nest as inner cards). Do not create a second worktree for a ticket, PR, or named branch that already has a live checkout \u2014 create_thread / start_board_card return that thread (alreadyStarted). Creating from the default branch still opens a new isolated worktree. Columns are the path to merge: New (no PR) \u2192 Draft (draft PR) \u2192 Review (open PR) \u2192 Merged. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. Orchestration chats stay in the sidebar. Do not invent status.";
2840
2964
 
2841
2965
  // src/threads/create.ts
2842
2966
  function persistCreateAttachments(worktreePath, attachments) {
2843
2967
  return persistPendingFileAttachments(worktreePath, attachments ?? []);
2844
2968
  }
2969
+ function liveThreadsForCreate() {
2970
+ return listThreads({ includeArchived: false }).map((t) => ({
2971
+ ...t,
2972
+ repoPath: canonicalizeRepoPath(t.repoPath)
2973
+ }));
2974
+ }
2975
+ function reuseLiveThread(input, repoPath, match) {
2976
+ if (input.reuseExisting === false) return void 0;
2977
+ const existing = findLiveThreadForCreate(
2978
+ {
2979
+ sourceType: match.sourceType,
2980
+ sourceRef: match.sourceRef,
2981
+ repoPath,
2982
+ title: match.title ?? input.title,
2983
+ cowboy: input.cowboy,
2984
+ prUrl: match.prUrl,
2985
+ headRefName: match.headRefName
2986
+ },
2987
+ liveThreadsForCreate()
2988
+ );
2989
+ if (!existing) return void 0;
2990
+ const thread = readThread(existing.id) ?? existing;
2991
+ if (!input.attachments?.length) return thread;
2992
+ return updateThread(thread.id, {
2993
+ attachments: persistCreateAttachments(thread.worktreePath, [
2994
+ ...thread.attachments,
2995
+ ...input.attachments
2996
+ ])
2997
+ });
2998
+ }
2845
2999
  async function createThread(input, _onSetupLine) {
2846
3000
  const repoPath = await resolveRepoRoot(input.repoPath);
2847
- if (!existsSync7(repoPath)) {
3001
+ if (!existsSync8(repoPath)) {
2848
3002
  throw new Error(`Repo not found: ${repoPath}`);
2849
3003
  }
2850
- if (input.reuseExisting !== false) {
2851
- const existing = findLiveThreadForCreate(
2852
- {
2853
- sourceType: input.sourceType,
2854
- sourceRef: input.sourceRef,
2855
- repoPath,
2856
- title: input.title,
2857
- cowboy: input.cowboy
2858
- },
2859
- listThreads({ includeArchived: false }).map((t) => ({
2860
- ...t,
2861
- repoPath: canonicalizeRepoPath(t.repoPath)
2862
- }))
2863
- );
2864
- if (existing) {
2865
- const thread2 = readThread(existing.id) ?? existing;
2866
- if (!input.attachments?.length) return thread2;
2867
- return updateThread(thread2.id, {
2868
- attachments: persistCreateAttachments(thread2.worktreePath, [
2869
- ...thread2.attachments,
2870
- ...input.attachments
2871
- ])
2872
- });
2873
- }
2874
- }
3004
+ const reused = reuseLiveThread(input, repoPath, {
3005
+ sourceType: input.sourceType,
3006
+ sourceRef: input.sourceRef,
3007
+ title: input.title
3008
+ });
3009
+ if (reused) return reused;
2875
3010
  const resolved = resolveNewThreadOptions({
2876
3011
  agent: input.agent,
2877
3012
  model: input.model,
@@ -2880,7 +3015,7 @@ async function createThread(input, _onSetupLine) {
2880
3015
  });
2881
3016
  await requireAgent(resolved.agent);
2882
3017
  if (input.cowboy) {
2883
- const { cowboyModeEnabled } = await import("./app-settings-J3JBCUOT.js");
3018
+ const { cowboyModeEnabled } = await import("./app-settings-VRQI3FIE.js");
2884
3019
  if (!cowboyModeEnabled()) {
2885
3020
  throw new Error(
2886
3021
  "Cowboy mode is off. Enable it in Settings \u2192 Advanced."
@@ -2938,7 +3073,7 @@ async function createThread(input, _onSetupLine) {
2938
3073
  let sourceIsFork = false;
2939
3074
  if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
2940
3075
  if (isAbleTimeConnected() && getIssueSource() === "abletime") {
2941
- const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-CLC5UJC2.js");
3076
+ const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-JSTJLXAW.js");
2942
3077
  const task = await ensureAbleTimeTask({
2943
3078
  title: title?.trim() || "Untitled work",
2944
3079
  description: input.prompt?.trim() || void 0
@@ -2948,6 +3083,12 @@ async function createThread(input, _onSetupLine) {
2948
3083
  persistedSourceRef = task.identifier;
2949
3084
  title = title?.trim() || task.title;
2950
3085
  attachments = [...attachments, issueAttachmentForAbleTimeTask(task)];
3086
+ const reusedTicket = reuseLiveThread(
3087
+ { ...input, sourceType: "ticket", sourceRef, title, attachments },
3088
+ repoPath,
3089
+ { sourceType: "ticket", sourceRef, title }
3090
+ );
3091
+ if (reusedTicket) return reusedTicket;
2951
3092
  }
2952
3093
  }
2953
3094
  let prUrl = null;
@@ -2957,6 +3098,14 @@ async function createThread(input, _onSetupLine) {
2957
3098
  if (!Number.isFinite(num)) throw new Error(`Invalid PR number: ${input.sourceRef}`);
2958
3099
  const pr = await getPr(repoPath, num);
2959
3100
  if (!pr) throw new Error(`PR #${num} not found`);
3101
+ const reusedPr = reuseLiveThread(input, repoPath, {
3102
+ sourceType: "pr",
3103
+ sourceRef: String(pr.number),
3104
+ title: input.title ?? pr.title,
3105
+ prUrl: pr.url,
3106
+ headRefName: pr.headRefName
3107
+ });
3108
+ if (reusedPr) return reusedPr;
2960
3109
  sourceIsFork = pr.isCrossRepository;
2961
3110
  prUrl = pr.url;
2962
3111
  const localFetchBranch = `sideboard-pr-${pr.number}`;
@@ -2969,9 +3118,19 @@ async function createThread(input, _onSetupLine) {
2969
3118
  sourceRef = await resolveDefaultBranch(repoPath);
2970
3119
  } else {
2971
3120
  const existing = await getPrForHeadBranch(repoPath, sourceRef);
2972
- if (existing?.url) {
2973
- prUrl = existing.url;
2974
- prTitle = existing.title;
3121
+ if (existing) {
3122
+ const reusedPr = reuseLiveThread(input, repoPath, {
3123
+ sourceType: "pr",
3124
+ sourceRef: String(existing.number),
3125
+ title: input.title ?? existing.title,
3126
+ prUrl: existing.url,
3127
+ headRefName: existing.headRefName
3128
+ });
3129
+ if (reusedPr) return reusedPr;
3130
+ if (existing.url) {
3131
+ prUrl = existing.url;
3132
+ prTitle = existing.title;
3133
+ }
2975
3134
  }
2976
3135
  }
2977
3136
  } else if (sourceType === "adopt") {
@@ -3010,15 +3169,6 @@ async function createThread(input, _onSetupLine) {
3010
3169
  await ensureWorkspace(repoPath);
3011
3170
  return readThread(thread.id) ?? thread;
3012
3171
  }
3013
- async function listLinearIssues(agent, repoPath) {
3014
- const { getAdapter: getAdapter2 } = await import("./agents-CUKWIM34.js");
3015
- await requireAgent(agent, { requireLinear: true });
3016
- const adapter = getAdapter2(agent);
3017
- if (!adapter.listLinearIssues) {
3018
- throw new Error(`${agent} does not support Linear issue listing`);
3019
- }
3020
- return adapter.listLinearIssues(repoPath);
3021
- }
3022
3172
 
3023
3173
  // src/threads/cowboy.ts
3024
3174
  function isCowboyThread(thread) {
@@ -3034,11 +3184,11 @@ function shouldRemoveWorktreeOnTeardown(thread) {
3034
3184
 
3035
3185
  // src/store/turn-live.ts
3036
3186
  import {
3037
- existsSync as existsSync8,
3187
+ existsSync as existsSync9,
3038
3188
  renameSync,
3039
3189
  unlinkSync as unlinkSync2,
3040
- writeFileSync as writeFileSync3,
3041
- readFileSync as readFileSync6
3190
+ writeFileSync as writeFileSync4,
3191
+ readFileSync as readFileSync7
3042
3192
  } from "fs";
3043
3193
  var buffers = /* @__PURE__ */ new Map();
3044
3194
  var FLUSH_MS = 800;
@@ -3115,7 +3265,7 @@ function writeTurnLive(threadId, progress) {
3115
3265
  const path = threadLivePath(threadId);
3116
3266
  const tmp = `${path}.${process.pid}.tmp`;
3117
3267
  try {
3118
- writeFileSync3(tmp, JSON.stringify(progress), "utf8");
3268
+ writeFileSync4(tmp, JSON.stringify(progress), "utf8");
3119
3269
  renameSync(tmp, path);
3120
3270
  } catch {
3121
3271
  try {
@@ -3126,9 +3276,9 @@ function writeTurnLive(threadId, progress) {
3126
3276
  }
3127
3277
  function readTurnLive(threadId) {
3128
3278
  const path = threadLivePath(threadId);
3129
- if (!existsSync8(path)) return null;
3279
+ if (!existsSync9(path)) return null;
3130
3280
  try {
3131
- const raw = JSON.parse(readFileSync6(path, "utf8"));
3281
+ const raw = JSON.parse(readFileSync7(path, "utf8"));
3132
3282
  if (!raw || typeof raw.summary !== "string") return null;
3133
3283
  return raw;
3134
3284
  } catch {
@@ -3140,7 +3290,7 @@ function clearTurnLive(threadId) {
3140
3290
  if (buf?.timer) clearTimeout(buf.timer);
3141
3291
  buffers.delete(threadId);
3142
3292
  const path = threadLivePath(threadId);
3143
- if (!existsSync8(path)) return;
3293
+ if (!existsSync9(path)) return;
3144
3294
  try {
3145
3295
  unlinkSync2(path);
3146
3296
  } catch {
@@ -3324,26 +3474,26 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
3324
3474
  import { execFileSync } from "child_process";
3325
3475
  import {
3326
3476
  copyFileSync as copyFileSync2,
3327
- existsSync as existsSync9,
3477
+ existsSync as existsSync10,
3328
3478
  mkdtempSync,
3329
3479
  readdirSync as readdirSync3,
3330
- readFileSync as readFileSync7,
3480
+ readFileSync as readFileSync8,
3331
3481
  rmSync
3332
3482
  } from "fs";
3333
3483
  import { tmpdir } from "os";
3334
- import { join as join9 } from "path";
3484
+ import { join as join10 } from "path";
3335
3485
  import { createRequire } from "module";
3336
- var CONDUCTOR_APP_SUPPORT = join9(
3486
+ var CONDUCTOR_APP_SUPPORT = join10(
3337
3487
  process.env.HOME ?? "",
3338
3488
  "Library",
3339
3489
  "Application Support",
3340
3490
  "com.conductor.app"
3341
3491
  );
3342
- var CONDUCTOR_DB = join9(CONDUCTOR_APP_SUPPORT, "conductor.db");
3343
- var CURSOR_SDK_STORE = join9(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
3492
+ var CONDUCTOR_DB = join10(CONDUCTOR_APP_SUPPORT, "conductor.db");
3493
+ var CURSOR_SDK_STORE = join10(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
3344
3494
  function thisModuleFile() {
3345
3495
  const cjsFile = typeof __filename !== "undefined" ? __filename : "";
3346
- return cjsFile || process.argv[1] || join9(process.cwd(), "package.json");
3496
+ return cjsFile || process.argv[1] || join10(process.cwd(), "package.json");
3347
3497
  }
3348
3498
  function openReadonlySqlite(file) {
3349
3499
  const req = createRequire(thisModuleFile());
@@ -3361,7 +3511,7 @@ function mapAgentType(raw) {
3361
3511
  return null;
3362
3512
  }
3363
3513
  function resolveConductorCursorAgentId(workspacePath) {
3364
- if (!workspacePath || !existsSync9(CURSOR_SDK_STORE)) return null;
3514
+ if (!workspacePath || !existsSync10(CURSOR_SDK_STORE)) return null;
3365
3515
  const normalized = workspacePath.replace(/\/$/, "");
3366
3516
  let best = null;
3367
3517
  let hashes;
@@ -3371,11 +3521,11 @@ function resolveConductorCursorAgentId(workspacePath) {
3371
3521
  return null;
3372
3522
  }
3373
3523
  for (const hash of hashes) {
3374
- const agentsFile = join9(CURSOR_SDK_STORE, hash, "agents.ndjson");
3375
- if (!existsSync9(agentsFile)) continue;
3524
+ const agentsFile = join10(CURSOR_SDK_STORE, hash, "agents.ndjson");
3525
+ if (!existsSync10(agentsFile)) continue;
3376
3526
  let text;
3377
3527
  try {
3378
- text = readFileSync7(agentsFile, "utf8");
3528
+ text = readFileSync8(agentsFile, "utf8");
3379
3529
  } catch {
3380
3530
  continue;
3381
3531
  }
@@ -3399,7 +3549,7 @@ function resolveConductorCursorAgentId(workspacePath) {
3399
3549
  return best?.agentId ?? null;
3400
3550
  }
3401
3551
  async function adoptThread(input) {
3402
- if (!existsSync9(input.worktreePath)) {
3552
+ if (!existsSync10(input.worktreePath)) {
3403
3553
  throw new Error(`Worktree not found: ${input.worktreePath}`);
3404
3554
  }
3405
3555
  const repoPath = await resolveRepoRoot(input.worktreePath);
@@ -3418,23 +3568,23 @@ async function adoptThread(input) {
3418
3568
  messages: input.messages ?? []
3419
3569
  });
3420
3570
  writeThread(thread);
3421
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-NECIQTAO.js");
3571
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-MQYNZXUK.js");
3422
3572
  await ensureWorkspace2(repoPath);
3423
3573
  const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-N5X5I422.js");
3424
3574
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
3425
3575
  return thread;
3426
3576
  }
3427
3577
  function listConductorWorkspaces() {
3428
- if (!existsSync9(CONDUCTOR_DB)) {
3578
+ if (!existsSync10(CONDUCTOR_DB)) {
3429
3579
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
3430
3580
  }
3431
- const tmp = mkdtempSync(join9(tmpdir(), "sideboard-conductor-"));
3432
- const snapshot = join9(tmp, "conductor.db");
3581
+ const tmp = mkdtempSync(join10(tmpdir(), "sideboard-conductor-"));
3582
+ const snapshot = join10(tmp, "conductor.db");
3433
3583
  try {
3434
3584
  copyFileSync2(CONDUCTOR_DB, snapshot);
3435
3585
  for (const suffix of ["-wal", "-shm"]) {
3436
3586
  const src = `${CONDUCTOR_DB}${suffix}`;
3437
- if (existsSync9(src)) {
3587
+ if (existsSync10(src)) {
3438
3588
  try {
3439
3589
  copyFileSync2(src, `${snapshot}${suffix}`);
3440
3590
  } catch {
@@ -3516,16 +3666,16 @@ function listConductorWorkspaces() {
3516
3666
  }
3517
3667
  }
3518
3668
  function importConductorWorkspace(workspaceId) {
3519
- if (!existsSync9(CONDUCTOR_DB)) {
3669
+ if (!existsSync10(CONDUCTOR_DB)) {
3520
3670
  throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
3521
3671
  }
3522
- const tmp = mkdtempSync(join9(tmpdir(), "sideboard-conductor-"));
3523
- const snapshot = join9(tmp, "conductor.db");
3672
+ const tmp = mkdtempSync(join10(tmpdir(), "sideboard-conductor-"));
3673
+ const snapshot = join10(tmp, "conductor.db");
3524
3674
  try {
3525
3675
  copyFileSync2(CONDUCTOR_DB, snapshot);
3526
3676
  for (const suffix of ["-wal", "-shm"]) {
3527
3677
  const src = `${CONDUCTOR_DB}${suffix}`;
3528
- if (existsSync9(src)) {
3678
+ if (existsSync10(src)) {
3529
3679
  try {
3530
3680
  copyFileSync2(src, `${snapshot}${suffix}`);
3531
3681
  } catch {
@@ -3545,7 +3695,7 @@ function importConductorWorkspace(workspaceId) {
3545
3695
  ).get(workspaceId);
3546
3696
  if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
3547
3697
  const worktreePath = String(row.workspacePath);
3548
- if (!existsSync9(worktreePath)) {
3698
+ if (!existsSync10(worktreePath)) {
3549
3699
  throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
3550
3700
  }
3551
3701
  let sessionId = null;
@@ -3616,7 +3766,7 @@ async function importConductorWorkspaceAsync(workspaceId) {
3616
3766
  }
3617
3767
 
3618
3768
  // src/threads/stack-layers.ts
3619
- import { existsSync as existsSync10 } from "fs";
3769
+ import { existsSync as existsSync11 } from "fs";
3620
3770
  function stackIdFrom(stack) {
3621
3771
  if (stack.stackNumber != null) return `gh-stack-${stack.stackNumber}`;
3622
3772
  const key = stack.layers.map((l) => l.branchName).join("|");
@@ -3679,7 +3829,7 @@ async function openStackLayer(input, _onSetupLine) {
3679
3829
  let createdWorktree = false;
3680
3830
  const trees = await listWorktrees(repoPath);
3681
3831
  const checkedOut = trees.find((w) => w.branch === branchName);
3682
- if (checkedOut?.path && existsSync10(checkedOut.path)) {
3832
+ if (checkedOut?.path && existsSync11(checkedOut.path)) {
3683
3833
  if (input.reuseExistingWorktree !== false) {
3684
3834
  worktreePath = checkedOut.path;
3685
3835
  } else {
@@ -3821,7 +3971,7 @@ async function initStackFromThread(input, onSetupLine) {
3821
3971
  async function createPrStack(input, onSetupLine) {
3822
3972
  await requireAgent(input.agent);
3823
3973
  const repoPath = await resolveRepoRoot(input.repoPath);
3824
- if (!existsSync10(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
3974
+ if (!existsSync11(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
3825
3975
  if (!input.branches.length) throw new Error("At least one branch name required");
3826
3976
  const status = await detectGhStack(repoPath);
3827
3977
  if (!status.available) throw new Error(status.reason);
@@ -3888,7 +4038,7 @@ async function createPrStack(input, onSetupLine) {
3888
4038
  }
3889
4039
  }
3890
4040
  const claimed = new Set(threads.map((t) => t.worktreePath));
3891
- if (!claimed.has(bootstrap.worktreePath) && existsSync10(bootstrap.worktreePath)) {
4041
+ if (!claimed.has(bootstrap.worktreePath) && existsSync11(bootstrap.worktreePath)) {
3892
4042
  try {
3893
4043
  await removeWorktree(repoPath, bootstrap.worktreePath, {
3894
4044
  deleteBranch: bootstrap.branchName
@@ -3900,10 +4050,10 @@ async function createPrStack(input, onSetupLine) {
3900
4050
  }
3901
4051
 
3902
4052
  // src/diff/diff.ts
3903
- import { existsSync as existsSync11, mkdirSync as mkdirSync3, readFileSync as readFileSync8, statSync as statSync2, writeFileSync as writeFileSync4 } from "fs";
3904
- import { dirname as dirname3, join as join10 } from "path";
4053
+ import { existsSync as existsSync12, mkdirSync as mkdirSync3, readFileSync as readFileSync9, statSync as statSync2, writeFileSync as writeFileSync5 } from "fs";
4054
+ import { dirname as dirname3, join as join11 } from "path";
3905
4055
  async function inspectGitWorktree(worktreePath) {
3906
- if (!worktreePath || !existsSync11(worktreePath)) return "missing_worktree";
4056
+ if (!worktreePath || !existsSync12(worktreePath)) return "missing_worktree";
3907
4057
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
3908
4058
  reject: false
3909
4059
  });
@@ -3911,7 +4061,7 @@ async function inspectGitWorktree(worktreePath) {
3911
4061
  return "ok";
3912
4062
  }
3913
4063
  async function initializeGitRepository(worktreePath) {
3914
- if (!worktreePath || !existsSync11(worktreePath)) {
4064
+ if (!worktreePath || !existsSync12(worktreePath)) {
3915
4065
  throw new Error("Worktree not found");
3916
4066
  }
3917
4067
  const status = await inspectGitWorktree(worktreePath);
@@ -4047,11 +4197,11 @@ new file mode 100644
4047
4197
  };
4048
4198
  }
4049
4199
  async function untrackedPatch(worktreePath, path, maxHunk) {
4050
- const abs = join10(worktreePath, path);
4200
+ const abs = join11(worktreePath, path);
4051
4201
  try {
4052
4202
  const st = statSync2(abs);
4053
4203
  if (st.isFile() && st.size > maxHunk) {
4054
- const buf = readFileSync8(abs).subarray(0, maxHunk);
4204
+ const buf = readFileSync9(abs).subarray(0, maxHunk);
4055
4205
  return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
4056
4206
  }
4057
4207
  } catch {
@@ -4552,7 +4702,7 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
4552
4702
  function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
4553
4703
  assertSafeRelativePath(relativePath);
4554
4704
  const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
4555
- const abs = join10(worktreePath, relativePath);
4705
+ const abs = join11(worktreePath, relativePath);
4556
4706
  const st = statSync2(abs);
4557
4707
  if (!st.isFile()) {
4558
4708
  throw new Error(`Not a file: ${relativePath}`);
@@ -4562,7 +4712,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
4562
4712
  `File too large to upload (${st.size} bytes; max ${maxBytes})`
4563
4713
  );
4564
4714
  }
4565
- const buf = readFileSync8(abs);
4715
+ const buf = readFileSync9(abs);
4566
4716
  return {
4567
4717
  path: relativePath,
4568
4718
  contentBase64: buf.toString("base64"),
@@ -4572,12 +4722,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
4572
4722
  function readWorktreeFile(worktreePath, relativePath, opts) {
4573
4723
  assertSafeRelativePath(relativePath);
4574
4724
  const maxBytes = opts?.maxBytes ?? 2e5;
4575
- const abs = join10(worktreePath, relativePath);
4725
+ const abs = join11(worktreePath, relativePath);
4576
4726
  const st = statSync2(abs);
4577
4727
  if (!st.isFile()) {
4578
4728
  throw new Error(`Not a file: ${relativePath}`);
4579
4729
  }
4580
- const buf = readFileSync8(abs);
4730
+ const buf = readFileSync9(abs);
4581
4731
  if (isImageRelativePath(relativePath)) {
4582
4732
  const maxImageBytes = Math.max(maxBytes, 15e6);
4583
4733
  const truncated2 = buf.length > maxImageBytes;
@@ -4620,9 +4770,9 @@ function assertSafeRelativePath(relativePath) {
4620
4770
  }
4621
4771
  function writeWorktreeFile(worktreePath, relativePath, content) {
4622
4772
  assertSafeRelativePath(relativePath);
4623
- const abs = join10(worktreePath, relativePath);
4773
+ const abs = join11(worktreePath, relativePath);
4624
4774
  mkdirSync3(dirname3(abs), { recursive: true });
4625
- writeFileSync4(abs, content, "utf8");
4775
+ writeFileSync5(abs, content, "utf8");
4626
4776
  return { path: relativePath };
4627
4777
  }
4628
4778
  async function getDiffSummary(worktreePath, repoPath, opts) {
@@ -4747,9 +4897,9 @@ async function confirmLand(thread, opts) {
4747
4897
  }
4748
4898
 
4749
4899
  // src/skills/discover.ts
4750
- import { existsSync as existsSync12, readdirSync as readdirSync4, readFileSync as readFileSync9, statSync as statSync3 } from "fs";
4900
+ import { existsSync as existsSync13, readdirSync as readdirSync4, readFileSync as readFileSync10, statSync as statSync3 } from "fs";
4751
4901
  import { homedir } from "os";
4752
- import { join as join11 } from "path";
4902
+ import { join as join12 } from "path";
4753
4903
 
4754
4904
  // src/skills/bundled/long-running.ts
4755
4905
  var LONG_RUNNING_SKILL_COMMAND = "long-running";
@@ -4878,7 +5028,7 @@ function parseFrontmatter(content) {
4878
5028
  }
4879
5029
  function readSkill(skillMd, source) {
4880
5030
  try {
4881
- const content = readFileSync9(skillMd, "utf8");
5031
+ const content = readFileSync10(skillMd, "utf8");
4882
5032
  const { name: fmName, description } = parseFrontmatter(content);
4883
5033
  const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
4884
5034
  const name = fmName || dirName;
@@ -4897,7 +5047,7 @@ function readSkill(skillMd, source) {
4897
5047
  }
4898
5048
  }
4899
5049
  function scanSkillsDir(dir, source, out) {
4900
- if (!existsSync12(dir)) return;
5050
+ if (!existsSync13(dir)) return;
4901
5051
  let entries;
4902
5052
  try {
4903
5053
  entries = readdirSync4(dir);
@@ -4906,8 +5056,8 @@ function scanSkillsDir(dir, source, out) {
4906
5056
  }
4907
5057
  for (const entry of entries) {
4908
5058
  if (entry.startsWith(".")) continue;
4909
- const skillMd = join11(dir, entry, "SKILL.md");
4910
- if (!existsSync12(skillMd)) continue;
5059
+ const skillMd = join12(dir, entry, "SKILL.md");
5060
+ if (!existsSync13(skillMd)) continue;
4911
5061
  try {
4912
5062
  if (!statSync3(skillMd).isFile()) continue;
4913
5063
  } catch {
@@ -4918,7 +5068,7 @@ function scanSkillsDir(dir, source, out) {
4918
5068
  }
4919
5069
  }
4920
5070
  function scanClaudePluginSkills(pluginsRoot, out) {
4921
- if (!existsSync12(pluginsRoot)) return;
5071
+ if (!existsSync13(pluginsRoot)) return;
4922
5072
  const walk = (dir, depth, lookingForSkillsDir) => {
4923
5073
  if (depth > 7) return;
4924
5074
  let entries;
@@ -4928,12 +5078,12 @@ function scanClaudePluginSkills(pluginsRoot, out) {
4928
5078
  return;
4929
5079
  }
4930
5080
  if (lookingForSkillsDir && entries.includes("SKILL.md")) {
4931
- const skill = readSkill(join11(dir, "SKILL.md"), "cli");
5081
+ const skill = readSkill(join12(dir, "SKILL.md"), "cli");
4932
5082
  if (skill) out.push(skill);
4933
5083
  }
4934
5084
  for (const entry of entries) {
4935
5085
  if (entry === "node_modules" || entry === ".git") continue;
4936
- const full = join11(dir, entry);
5086
+ const full = join12(dir, entry);
4937
5087
  try {
4938
5088
  if (!statSync3(full).isDirectory()) continue;
4939
5089
  } catch {
@@ -4953,17 +5103,17 @@ function discoverSkills(worktreePath) {
4953
5103
  const home = homedir();
4954
5104
  const collected = [];
4955
5105
  for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
4956
- scanSkillsDir(join11(worktreePath, rel), "workspace", collected);
5106
+ scanSkillsDir(join12(worktreePath, rel), "workspace", collected);
4957
5107
  }
4958
5108
  for (const abs of [
4959
- join11(home, ".claude/skills"),
4960
- join11(home, ".cursor/skills"),
4961
- join11(home, ".sideboard/skills"),
4962
- join11(home, ".brightsy/skills")
5109
+ join12(home, ".claude/skills"),
5110
+ join12(home, ".cursor/skills"),
5111
+ join12(home, ".sideboard/skills"),
5112
+ join12(home, ".brightsy/skills")
4963
5113
  ]) {
4964
5114
  scanSkillsDir(abs, "user", collected);
4965
5115
  }
4966
- scanClaudePluginSkills(join11(home, ".claude/plugins"), collected);
5116
+ scanClaudePluginSkills(join12(home, ".claude/plugins"), collected);
4967
5117
  collected.push(...bundledSkills());
4968
5118
  const rank = {
4969
5119
  workspace: 0,
@@ -4989,7 +5139,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
4989
5139
  \u2026(truncated)` : body;
4990
5140
  }
4991
5141
  }
4992
- const raw = readFileSync9(skillPath, "utf8");
5142
+ const raw = readFileSync10(skillPath, "utf8");
4993
5143
  if (raw.startsWith("---")) {
4994
5144
  const end = raw.indexOf("\n---", 3);
4995
5145
  if (end >= 0) {
@@ -5082,26 +5232,26 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
5082
5232
  }
5083
5233
 
5084
5234
  // src/agents/instructions.ts
5085
- import { existsSync as existsSync14, readFileSync as readFileSync10, statSync as statSync4 } from "fs";
5086
- import { join as join13 } from "path";
5235
+ import { existsSync as existsSync15, readFileSync as readFileSync11, statSync as statSync4 } from "fs";
5236
+ import { join as join14 } from "path";
5087
5237
 
5088
5238
  // src/skills/detached-job-path.ts
5089
- import { existsSync as existsSync13 } from "fs";
5090
- import { dirname as dirname4, join as join12 } from "path";
5239
+ import { existsSync as existsSync14 } from "fs";
5240
+ import { dirname as dirname4, join as join13 } from "path";
5091
5241
  import { fileURLToPath } from "url";
5092
5242
  function packagedDetachedJobPath() {
5093
5243
  const dir = packagedMcpDir();
5094
5244
  if (!dir) return null;
5095
- const script = join12(dir, "scripts", "detached-job.js");
5096
- return existsSync13(script) ? script : null;
5245
+ const script = join13(dir, "scripts", "detached-job.js");
5246
+ return existsSync14(script) ? script : null;
5097
5247
  }
5098
5248
  function resolveDetachedJobScript() {
5099
5249
  const packaged = packagedDetachedJobPath();
5100
5250
  if (packaged) return packaged;
5101
5251
  let dir = dirname4(fileURLToPath(import.meta.url));
5102
5252
  for (let i = 0; i < 8; i++) {
5103
- const candidate = join12(dir, "scripts", "detached-job.js");
5104
- if (existsSync13(candidate)) return candidate;
5253
+ const candidate = join13(dir, "scripts", "detached-job.js");
5254
+ if (existsSync14(candidate)) return candidate;
5105
5255
  const parent = dirname4(dir);
5106
5256
  if (parent === dir) break;
5107
5257
  dir = parent;
@@ -5403,8 +5553,8 @@ async function syncThreadBranchFromGit(threadId) {
5403
5553
 
5404
5554
  // src/store/schedules.ts
5405
5555
  import { randomUUID as randomUUID4 } from "crypto";
5406
- import { existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
5407
- import { join as join14 } from "path";
5556
+ import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
5557
+ import { join as join15 } from "path";
5408
5558
  import { Cron } from "croner";
5409
5559
  var DURATION_RE = /^(\d+)(s|m|h|d)$/i;
5410
5560
  var UNIT_MS = {
@@ -5414,7 +5564,7 @@ var UNIT_MS = {
5414
5564
  d: 864e5
5415
5565
  };
5416
5566
  function schedulesPath() {
5417
- return join14(appDataDir(), "schedules.json");
5567
+ return join15(appDataDir(), "schedules.json");
5418
5568
  }
5419
5569
  function parseDurationMs(every) {
5420
5570
  const m = every.trim().match(DURATION_RE);
@@ -5514,9 +5664,9 @@ function normalizeTask(raw) {
5514
5664
  }
5515
5665
  function readAll() {
5516
5666
  const path = schedulesPath();
5517
- if (!existsSync15(path)) return [];
5667
+ if (!existsSync16(path)) return [];
5518
5668
  try {
5519
- const parsed = JSON.parse(readFileSync11(path, "utf8"));
5669
+ const parsed = JSON.parse(readFileSync12(path, "utf8"));
5520
5670
  if (!Array.isArray(parsed)) return [];
5521
5671
  return parsed.map((row) => {
5522
5672
  try {
@@ -5639,7 +5789,7 @@ function formatScheduledPrompt(name, prompt) {
5639
5789
  ${prompt}`;
5640
5790
  }
5641
5791
  async function defaultDeps() {
5642
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-256DFPSX.js");
5792
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-ZSSU3FKW.js");
5643
5793
  const orch = getOrchestrator2();
5644
5794
  return {
5645
5795
  findThread: (id) => findThreadByRef(id),
@@ -5879,7 +6029,7 @@ var Orchestrator = class {
5879
6029
  }
5880
6030
  continue;
5881
6031
  }
5882
- if (!existsSync16(thread.worktreePath)) {
6032
+ if (!existsSync17(thread.worktreePath)) {
5883
6033
  setStatus(thread.id, "broken", "Worktree missing on disk");
5884
6034
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
5885
6035
  continue;
@@ -5898,7 +6048,7 @@ var Orchestrator = class {
5898
6048
  orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
5899
6049
  });
5900
6050
  }
5901
- const { autoCleanupOrphansEnabled } = await import("./app-settings-J3JBCUOT.js");
6051
+ const { autoCleanupOrphansEnabled } = await import("./app-settings-VRQI3FIE.js");
5902
6052
  if (autoCleanupOrphansEnabled() && shouldRunWorktreeCleanup() && orphans.length > 0) {
5903
6053
  await cleanupOrphanWorktrees({ repoPaths });
5904
6054
  }
@@ -6138,7 +6288,7 @@ var Orchestrator = class {
6138
6288
  }
6139
6289
  await setup;
6140
6290
  if (skipSetup) return;
6141
- const { autoRunAfterSetupEnabled } = await import("./app-settings-J3JBCUOT.js");
6291
+ const { autoRunAfterSetupEnabled } = await import("./app-settings-VRQI3FIE.js");
6142
6292
  if (autoRunAfterSetupEnabled()) {
6143
6293
  try {
6144
6294
  await this.startDev(threadId);
@@ -6446,7 +6596,7 @@ var Orchestrator = class {
6446
6596
  }
6447
6597
  const isBrightsy = fresh.agent === "brightsy";
6448
6598
  const isOrchestration = isOrchestratorThread(fresh);
6449
- const { autoRenameBranchEnabled, getGithubGitAuthMode } = await import("./app-settings-J3JBCUOT.js");
6599
+ const { autoRenameBranchEnabled, getGithubGitAuthMode } = await import("./app-settings-VRQI3FIE.js");
6450
6600
  const gitAuthMode = getGithubGitAuthMode();
6451
6601
  const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
6452
6602
  githubSlug: await resolveGithubRepoSlug(fresh.worktreePath).catch(
@@ -6552,7 +6702,7 @@ var Orchestrator = class {
6552
6702
  if (!this.stoppedTurns.has(threadId) && this.requireThread(threadId).agent === "cursor" && exitCode !== 0 && !assistantText && parts.length === 0) {
6553
6703
  const sessionId = result.sessionId || this.requireThread(threadId).sessionId || "";
6554
6704
  if (sessionId) {
6555
- const { recoverFinishedCursorRun } = await import("./cursor-recover-NOQYOFRF.js");
6705
+ const { recoverFinishedCursorRun } = await import("./cursor-recover-L5MD6MBO.js");
6556
6706
  for (let i = 0; i < 8; i++) {
6557
6707
  const recovered = recoverFinishedCursorRun({
6558
6708
  agentId: sessionId,
@@ -6942,6 +7092,15 @@ var Orchestrator = class {
6942
7092
  getActiveRuns(threadRef) {
6943
7093
  return this.requireThread(threadRef).activeRuns ?? [];
6944
7094
  }
7095
+ getSetupLog(threadRef) {
7096
+ const thread = this.getThread(threadRef);
7097
+ if (!thread) return readSetupLog(threadRef);
7098
+ const snap = readSetupLog(thread.id);
7099
+ if (snap.running && !this.processes.has(`${thread.id}:setup`)) {
7100
+ return { ...snap, running: false };
7101
+ }
7102
+ return snap;
7103
+ }
6945
7104
  async runSetup(threadRef) {
6946
7105
  const thread = this.requireThread(threadRef);
6947
7106
  this.assertNotGlobal(thread, "Setup");
@@ -6955,20 +7114,31 @@ var Orchestrator = class {
6955
7114
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
6956
7115
  kill: () => abort.abort()
6957
7116
  });
7117
+ beginSetupLog(thread.id);
6958
7118
  this.emit({ type: "setup_started", threadId: thread.id });
7119
+ let finished = false;
7120
+ const finish = (exitCode, source) => {
7121
+ if (finished) return;
7122
+ finished = true;
7123
+ finishSetupLog(thread.id, exitCode, source);
7124
+ this.emit({ type: "setup_finished", threadId: thread.id, exitCode });
7125
+ };
6959
7126
  try {
6960
7127
  const setup = await runWorkspaceSetup(
6961
7128
  thread.repoPath,
6962
7129
  thread.worktreePath,
6963
7130
  (line) => {
7131
+ appendSetupLog(thread.id, line);
6964
7132
  this.emit({ type: "setup_output", threadId: thread.id, line });
6965
7133
  },
6966
7134
  { signal: abort.signal }
6967
7135
  );
6968
7136
  if (!setup.ran) {
6969
- throw new Error(
6970
- "No setup script in .sideboard/settings.toml, .conductor/settings.toml, .cursor/worktrees.json, or script/setup (bin/setup, scripts/setup)"
6971
- );
7137
+ const line = "No setup script in .sideboard/settings.toml, .conductor/settings.toml, .cursor/worktrees.json, or script/setup (bin/setup, scripts/setup)";
7138
+ appendSetupLog(thread.id, line);
7139
+ this.emit({ type: "setup_output", threadId: thread.id, line });
7140
+ finish(null, null);
7141
+ throw new Error(line);
6972
7142
  }
6973
7143
  if (setup.exitCode !== 0 && setup.exitCode !== null) {
6974
7144
  const live = readThread(thread.id);
@@ -6981,8 +7151,11 @@ var Orchestrator = class {
6981
7151
  });
6982
7152
  }
6983
7153
  }
6984
- this.emit({ type: "setup_finished", threadId: thread.id, exitCode: setup.exitCode });
7154
+ finish(setup.exitCode, setup.source);
6985
7155
  return { exitCode: setup.exitCode, source: setup.source };
7156
+ } catch (err) {
7157
+ finish(null, null);
7158
+ throw err;
6986
7159
  } finally {
6987
7160
  this.processes.delete(key);
6988
7161
  }
@@ -7309,7 +7482,7 @@ var Orchestrator = class {
7309
7482
  updateThread(thread.id, { title: meta.title });
7310
7483
  }
7311
7484
  }
7312
- const { autoArchiveOnMergeEnabled } = await import("./app-settings-J3JBCUOT.js");
7485
+ const { autoArchiveOnMergeEnabled } = await import("./app-settings-VRQI3FIE.js");
7313
7486
  const latest = this.requireThread(thread.id);
7314
7487
  if (!shouldAutoArchiveOnPrMerge({
7315
7488
  previousPrState: prevState || null,
@@ -7626,7 +7799,7 @@ var Orchestrator = class {
7626
7799
  this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
7627
7800
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
7628
7801
  try {
7629
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-NECIQTAO.js");
7802
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-MQYNZXUK.js");
7630
7803
  await ensureWorkspace2(thread.repoPath);
7631
7804
  } catch {
7632
7805
  }
@@ -7653,7 +7826,7 @@ var Orchestrator = class {
7653
7826
  await runArchiveScript(thread.repoPath, thread.worktreePath);
7654
7827
  } catch {
7655
7828
  }
7656
- const { deleteBranchOnPurgeEnabled } = await import("./app-settings-J3JBCUOT.js");
7829
+ const { deleteBranchOnPurgeEnabled } = await import("./app-settings-VRQI3FIE.js");
7657
7830
  const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled();
7658
7831
  await removeWorktree(thread.repoPath, thread.worktreePath, {
7659
7832
  deleteBranch: deleteBranch ? thread.branchName : void 0
@@ -7668,19 +7841,19 @@ var Orchestrator = class {
7668
7841
  throw new Error("Thread is not archived");
7669
7842
  }
7670
7843
  if (isGlobalThread(thread)) {
7671
- const { globalAgentCwd } = await import("./paths-QCI3MTO5.js");
7844
+ const { globalAgentCwd } = await import("./paths-RRCLNSJB.js");
7672
7845
  updateThread(thread.id, { worktreePath: globalAgentCwd() });
7673
7846
  const restored2 = setStatus(thread.id, "idle");
7674
7847
  this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
7675
7848
  return restored2;
7676
7849
  }
7677
- if (!existsSync16(thread.worktreePath)) {
7850
+ if (!existsSync17(thread.worktreePath)) {
7678
7851
  if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
7679
7852
  throw new Error(
7680
7853
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
7681
7854
  );
7682
7855
  }
7683
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-HTUM35NT.js");
7856
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-PEWDAX5O.js");
7684
7857
  const slug = thread.worktreePath.split("/").pop();
7685
7858
  const dest = thread.worktreePath;
7686
7859
  await withRepoGitLock(thread.repoPath, async () => {
@@ -7790,7 +7963,7 @@ async function startOrchestration(opts) {
7790
7963
  sourceRef: "default",
7791
7964
  ...createOpts
7792
7965
  }).catch(async () => {
7793
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-HTUM35NT.js");
7966
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-PEWDAX5O.js");
7794
7967
  const repo = await resolveRepoRoot2(repoPath);
7795
7968
  const def = await resolveDefaultBranch2(repo);
7796
7969
  return orch.createThread({
@@ -7800,7 +7973,7 @@ async function startOrchestration(opts) {
7800
7973
  repoPath: repo
7801
7974
  });
7802
7975
  });
7803
- const { updateThread: upd } = await import("./thread-store-57ZLHR3A.js");
7976
+ const { updateThread: upd } = await import("./thread-store-MVQU6HPJ.js");
7804
7977
  const updated = upd(thread.id, {
7805
7978
  sourceType: "orchestration",
7806
7979
  sourceRef: goal
@@ -7833,7 +8006,6 @@ export {
7833
8006
  findBoardPr,
7834
8007
  assembleHomeBoard,
7835
8008
  HOME_BOARD_AGENT_HINT,
7836
- listLinearIssues,
7837
8009
  readTurnLive,
7838
8010
  resolveScheduleThreadId,
7839
8011
  listSchedules,