@sideboard-ai/core 0.1.211 → 0.1.213

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 (31) hide show
  1. package/dist/{agents-GQANI7M5.js → agents-HETHRRZJ.js} +4 -4
  2. package/dist/{agents-A2U3K7VK.js → agents-WBDDLRBY.js} +4 -4
  3. package/dist/{chunk-JJ3ONQ4Q.js → chunk-3IMSQNTS.js} +12 -2
  4. package/dist/{chunk-IA5IPGZI.js → chunk-7MTVRNP4.js} +3 -3
  5. package/dist/{chunk-KZUA4QG2.js → chunk-C32SBNA3.js} +198 -97
  6. package/dist/{chunk-ERNK7AWM.js → chunk-D2IKXMF3.js} +196 -96
  7. package/dist/{chunk-IRCAWYTN.js → chunk-DFTVZEZY.js} +3 -3
  8. package/dist/{chunk-2PE6SZCM.js → chunk-FNGXKY5W.js} +2 -2
  9. package/dist/{chunk-GHKFSBES.js → chunk-HY2GFZ5S.js} +12 -2
  10. package/dist/{chunk-WNVQJZ7P.js → chunk-KFD2OXCE.js} +2 -2
  11. package/dist/{chunk-NRKDRQM3.js → chunk-NI243N27.js} +1 -1
  12. package/dist/{chunk-VPQXJYIW.js → chunk-XYKVRRC2.js} +1 -1
  13. package/dist/{coordinator-prompt-LMTMWCPN.js → coordinator-prompt-FQX6ALAI.js} +3 -3
  14. package/dist/{coordinator-prompt-EHRDZ2ZU.js → coordinator-prompt-LE2GQZ2X.js} +3 -3
  15. package/dist/{global-workspace-NG2TBUI5.js → global-workspace-6P236KKG.js} +3 -3
  16. package/dist/{global-workspace-RHABXQWB.js → global-workspace-KT3FRHZL.js} +3 -3
  17. package/dist/index.cjs +210 -88
  18. package/dist/index.d.cts +61 -6
  19. package/dist/index.d.ts +61 -6
  20. package/dist/index.js +11 -5
  21. package/dist/mcp/run-stdio.cjs +204 -88
  22. package/dist/mcp/run-stdio.js +5 -5
  23. package/dist/{orchestrator-NZO4PVFH.js → orchestrator-MI7A5DQZ.js} +7 -5
  24. package/dist/{orchestrator-QMGH4V4K.js → orchestrator-WVZPTHBV.js} +7 -5
  25. package/dist/{thread-store-MSMBQ3V4.js → thread-store-KDPPXJJ3.js} +3 -1
  26. package/dist/{thread-store-4M6WETL6.js → thread-store-N6WQIWZ4.js} +3 -1
  27. package/dist/{workspaces-VIUUE4RT.js → workspaces-KM7KTLVO.js} +3 -3
  28. package/dist/{workspaces-FRR6Y4BY.js → workspaces-R5LJCJRB.js} +3 -3
  29. package/dist/{worktree-GKUOHXXB.js → worktree-MDMTCAHX.js} +2 -2
  30. package/dist/{worktree-3MEG62KB.js → worktree-VXRI7LYM.js} +2 -2
  31. package/package.json +1 -1
@@ -24,7 +24,7 @@ import {
24
24
  resolveQuotaFallbackAgent,
25
25
  stripBrightsyNdjsonNoise,
26
26
  toolDescription
27
- } from "./chunk-IRCAWYTN.js";
27
+ } from "./chunk-DFTVZEZY.js";
28
28
  import {
29
29
  SLACK_REPLY_FORMATTING,
30
30
  addWorkspace,
@@ -47,7 +47,7 @@ import {
47
47
  stageAbsolutePathsAsAttachments,
48
48
  stageBuffersAsAttachments,
49
49
  syncWorkspacesFromThreads
50
- } from "./chunk-2PE6SZCM.js";
50
+ } from "./chunk-FNGXKY5W.js";
51
51
  import {
52
52
  addPrStackLayer,
53
53
  allocateTeamName,
@@ -97,7 +97,7 @@ import {
97
97
  worktreeDisplayLabelForGroup,
98
98
  worktreeNameFromPath,
99
99
  worktreeSlugForTicket
100
- } from "./chunk-NRKDRQM3.js";
100
+ } from "./chunk-NI243N27.js";
101
101
  import {
102
102
  ATTACHMENTS_DIR,
103
103
  DETACHED_JOBS_DIR,
@@ -189,7 +189,7 @@ import {
189
189
  updateThread,
190
190
  withThreadLock,
191
191
  writeThread
192
- } from "./chunk-JJ3ONQ4Q.js";
192
+ } from "./chunk-3IMSQNTS.js";
193
193
  import {
194
194
  appDataDir,
195
195
  findConventionSetup,
@@ -483,7 +483,7 @@ async function continueSourceThread(threadId, prompt) {
483
483
  await continueOnReply(threadId, prompt);
484
484
  return;
485
485
  }
486
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-QMGH4V4K.js");
486
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-WVZPTHBV.js");
487
487
  await getOrchestrator2().send(threadId, prompt);
488
488
  } catch {
489
489
  }
@@ -817,9 +817,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
817
817
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
818
818
  );
819
819
  }
820
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-NG2TBUI5.js");
820
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-6P236KKG.js");
821
821
  if (isGlobalThread2(thread)) {
822
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-LMTMWCPN.js");
822
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-FQX6ALAI.js");
823
823
  ensureGlobalCoordinatorCwd2(
824
824
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
825
825
  );
@@ -2377,6 +2377,29 @@ ${line}` : line;
2377
2377
  }
2378
2378
  var memory = /* @__PURE__ */ new Map();
2379
2379
  var persistTimers = /* @__PURE__ */ new Map();
2380
+ function fromSnapshot(snap) {
2381
+ return {
2382
+ chunks: snap.output ? [snap.output] : [],
2383
+ length: snap.output.length,
2384
+ running: snap.running,
2385
+ exitCode: snap.exitCode,
2386
+ source: snap.source
2387
+ };
2388
+ }
2389
+ function materialize(mem) {
2390
+ let output = mem.chunks.join("\n");
2391
+ if (output.length > MAX_SETUP_LOG_CHARS) {
2392
+ output = appendSetupOutput("", output);
2393
+ mem.chunks = [output];
2394
+ mem.length = output.length;
2395
+ }
2396
+ return {
2397
+ output,
2398
+ running: mem.running,
2399
+ exitCode: mem.exitCode,
2400
+ source: mem.source
2401
+ };
2402
+ }
2380
2403
  function setupLogPath(threadId) {
2381
2404
  return join7(threadsDir(), `${threadId}.setup.log.json`);
2382
2405
  }
@@ -2395,20 +2418,22 @@ function mergeSetupOutput(prev, incoming) {
2395
2418
  if (incoming.startsWith(prev) || incoming.endsWith(prev)) return incoming;
2396
2419
  return incoming.length >= prev.length ? incoming : prev;
2397
2420
  }
2398
- function clone(snap) {
2399
- return { ...snap };
2400
- }
2421
+ var PERSIST_DEBOUNCE_MS = 500;
2401
2422
  function persistNow(threadId) {
2402
2423
  const timer = persistTimers.get(threadId);
2403
2424
  if (timer) {
2404
2425
  clearTimeout(timer);
2405
2426
  persistTimers.delete(threadId);
2406
2427
  }
2407
- const snap = memory.get(threadId);
2408
- if (!snap) return;
2428
+ const mem = memory.get(threadId);
2429
+ if (!mem) return;
2409
2430
  try {
2410
- writeFileSync2(setupLogPath(threadId), `${JSON.stringify(snap)}
2411
- `, "utf8");
2431
+ writeFileSync2(
2432
+ setupLogPath(threadId),
2433
+ `${JSON.stringify(materialize(mem))}
2434
+ `,
2435
+ "utf8"
2436
+ );
2412
2437
  } catch {
2413
2438
  }
2414
2439
  }
@@ -2419,7 +2444,7 @@ function schedulePersist(threadId) {
2419
2444
  setTimeout(() => {
2420
2445
  persistTimers.delete(threadId);
2421
2446
  persistNow(threadId);
2422
- }, 100)
2447
+ }, PERSIST_DEBOUNCE_MS)
2423
2448
  );
2424
2449
  }
2425
2450
  function loadFromDisk(threadId) {
@@ -2437,49 +2462,50 @@ function loadFromDisk(threadId) {
2437
2462
  return null;
2438
2463
  }
2439
2464
  }
2465
+ function memFor(threadId) {
2466
+ const cached = memory.get(threadId);
2467
+ if (cached) return cached;
2468
+ const mem = fromSnapshot(loadFromDisk(threadId) ?? emptySetupLog());
2469
+ memory.set(threadId, mem);
2470
+ return mem;
2471
+ }
2440
2472
  function readSetupLog(threadId) {
2441
2473
  const cached = memory.get(threadId);
2442
- if (cached) return clone(cached);
2474
+ if (cached) return materialize(cached);
2443
2475
  const disk = loadFromDisk(threadId);
2444
2476
  if (disk) {
2445
- memory.set(threadId, disk);
2446
- return clone(disk);
2477
+ memory.set(threadId, fromSnapshot(disk));
2478
+ return disk;
2447
2479
  }
2448
2480
  return emptySetupLog();
2449
2481
  }
2450
2482
  function beginSetupLog(threadId) {
2451
- const snap = {
2452
- output: "",
2483
+ const mem = {
2484
+ chunks: [],
2485
+ length: 0,
2453
2486
  running: true,
2454
2487
  exitCode: null,
2455
2488
  source: null
2456
2489
  };
2457
- memory.set(threadId, snap);
2490
+ memory.set(threadId, mem);
2458
2491
  persistNow(threadId);
2459
- return clone(snap);
2492
+ return materialize(mem);
2460
2493
  }
2461
2494
  function appendSetupLog(threadId, line) {
2462
- const current = memory.get(threadId) ?? readSetupLog(threadId);
2463
- const snap = {
2464
- ...current,
2465
- output: appendSetupOutput(current.output, line),
2466
- running: true
2467
- };
2468
- memory.set(threadId, snap);
2495
+ const mem = memFor(threadId);
2496
+ mem.chunks.push(line);
2497
+ mem.length += line.length + 1;
2498
+ mem.running = true;
2499
+ if (mem.length > MAX_SETUP_LOG_CHARS * 2) materialize(mem);
2469
2500
  schedulePersist(threadId);
2470
- return clone(snap);
2471
2501
  }
2472
2502
  function finishSetupLog(threadId, exitCode, source) {
2473
- const current = memory.get(threadId) ?? readSetupLog(threadId);
2474
- const snap = {
2475
- ...current,
2476
- running: false,
2477
- exitCode,
2478
- source: source ?? current.source
2479
- };
2480
- memory.set(threadId, snap);
2503
+ const mem = memFor(threadId);
2504
+ mem.running = false;
2505
+ mem.exitCode = exitCode;
2506
+ mem.source = source ?? mem.source;
2481
2507
  persistNow(threadId);
2482
- return clone(snap);
2508
+ return materialize(mem);
2483
2509
  }
2484
2510
 
2485
2511
  // src/git/orphan-cleanup.ts
@@ -4039,7 +4065,7 @@ async function createThread(input, _onSetupLine) {
4039
4065
  return readThread(thread.id) ?? thread;
4040
4066
  }
4041
4067
  async function listLinearIssues(agent, repoPath) {
4042
- const { getAdapter: getAdapter2 } = await import("./agents-GQANI7M5.js");
4068
+ const { getAdapter: getAdapter2 } = await import("./agents-HETHRRZJ.js");
4043
4069
  await requireAgent(agent, { requireLinear: true });
4044
4070
  const adapter = getAdapter2(agent);
4045
4071
  if (!adapter.listLinearIssues) {
@@ -4071,6 +4097,33 @@ function shouldRemoveWorktreeOnTeardown(thread) {
4071
4097
  return !isCowboyThread(thread) && !isPrimaryCheckoutThread(thread);
4072
4098
  }
4073
4099
 
4100
+ // src/util/line-coalescer.ts
4101
+ function createLineCoalescer(onChunk, opts) {
4102
+ const delayMs = opts?.delayMs ?? 50;
4103
+ const maxLines = opts?.maxLines ?? 200;
4104
+ let buffer = [];
4105
+ let timer = null;
4106
+ const flush2 = () => {
4107
+ if (timer) {
4108
+ clearTimeout(timer);
4109
+ timer = null;
4110
+ }
4111
+ if (buffer.length === 0) return;
4112
+ const chunk = buffer.join("\n");
4113
+ buffer = [];
4114
+ onChunk(chunk);
4115
+ };
4116
+ const push = (line) => {
4117
+ buffer.push(line);
4118
+ if (buffer.length >= maxLines) {
4119
+ flush2();
4120
+ return;
4121
+ }
4122
+ if (!timer) timer = setTimeout(flush2, delayMs);
4123
+ };
4124
+ return { push, flush: flush2 };
4125
+ }
4126
+
4074
4127
  // src/store/turn-live.ts
4075
4128
  import {
4076
4129
  existsSync as existsSync11,
@@ -4485,7 +4538,7 @@ async function adoptThread(input) {
4485
4538
  messages: input.messages ?? []
4486
4539
  });
4487
4540
  writeThread(thread);
4488
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-FRR6Y4BY.js");
4541
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-R5LJCJRB.js");
4489
4542
  await ensureWorkspace2(repoPath);
4490
4543
  const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-X54WSOXM.js");
4491
4544
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
@@ -5705,6 +5758,29 @@ function writeWorktreeFile(worktreePath, relativePath, content) {
5705
5758
  writeFileSync6(abs, content, "utf8");
5706
5759
  return { path: relativePath };
5707
5760
  }
5761
+ async function getWorktreeDirtyStat(worktreePath) {
5762
+ const status = await inspectGitWorktree(worktreePath);
5763
+ if (status !== "ok") {
5764
+ return { additions: 0, deletions: 0, dirty: false };
5765
+ }
5766
+ const head = await git(["rev-parse", "--verify", "HEAD"], worktreePath, {
5767
+ reject: false,
5768
+ timeoutMs: 4e3
5769
+ });
5770
+ if (head.exitCode !== 0) {
5771
+ return { additions: 0, deletions: 0, dirty: await isDirty(worktreePath) };
5772
+ }
5773
+ const [num, dirty] = await Promise.all([
5774
+ gitDiff(["--numstat", "HEAD"], worktreePath, { timeoutMs: 4e3 }),
5775
+ isDirty(worktreePath)
5776
+ ]);
5777
+ const counts = statFromNumstat(num.stdout);
5778
+ return {
5779
+ additions: counts.additions,
5780
+ deletions: counts.deletions,
5781
+ dirty: dirty || counts.additions > 0 || counts.deletions > 0
5782
+ };
5783
+ }
5708
5784
  async function getDiffSummary(worktreePath, repoPath, opts) {
5709
5785
  const full = await getDiff(worktreePath, repoPath, {
5710
5786
  maxHunkChars: opts?.maxHunkChars ?? 2e3,
@@ -6251,9 +6327,7 @@ function consumeComposerAttachments(thread) {
6251
6327
  };
6252
6328
  }
6253
6329
  function takePendingTurnAttachments(thread) {
6254
- const pending = thread.pendingTurnAttachments ?? [];
6255
- if (pending.length > 0) return [...pending];
6256
- return thread.attachments.length > 0 ? [...thread.attachments] : [];
6330
+ return [...thread.pendingTurnAttachments ?? []];
6257
6331
  }
6258
6332
  function alignQueueAttachments(queueLength, existing) {
6259
6333
  const next = (existing ?? []).slice(0, queueLength).map((slot) => [...slot ?? []]);
@@ -7123,7 +7197,7 @@ function formatScheduledPrompt(name, prompt) {
7123
7197
  ${prompt}`;
7124
7198
  }
7125
7199
  async function defaultDeps() {
7126
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-QMGH4V4K.js");
7200
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-WVZPTHBV.js");
7127
7201
  const orch = getOrchestrator2();
7128
7202
  return {
7129
7203
  findThread: (id) => findThreadByRef(id),
@@ -7254,6 +7328,7 @@ function resolveOrchChildFollowUp(requested) {
7254
7328
  return followUpBehavior();
7255
7329
  }
7256
7330
  var STALE_AGENT_PID_WAIT_MS = 2500;
7331
+ var LIGHT_RECONCILE_THROTTLE_MS = 1e4;
7257
7332
  function writeLiveStatus(threadId, status, lastError) {
7258
7333
  const latest = readThread(threadId);
7259
7334
  if (!latest || latest.status === "archived") return latest;
@@ -7268,6 +7343,8 @@ var Orchestrator = class {
7268
7343
  startingTurns = /* @__PURE__ */ new Set();
7269
7344
  /** Last sync thread-file read for false-stop heal (throttled per thread). */
7270
7345
  lastReconcileHealAt = /* @__PURE__ */ new Map();
7346
+ /** Per-repo timestamp of the last `reconcile(repo, { light: true })`. */
7347
+ lightReconcileAt = /* @__PURE__ */ new Map();
7271
7348
  /**
7272
7349
  * Threads intentionally force-stopped. Prevents runTurn from re-asserting
7273
7350
  * `running` after spawn, and from overwriting `stopped` with idle/error when
@@ -7353,6 +7430,20 @@ var Orchestrator = class {
7353
7430
  async reconcile(repoPath, opts) {
7354
7431
  const reclaimStaleTurns = opts?.reclaimStaleTurns === true;
7355
7432
  const drainQueues = opts?.drainQueues !== false;
7433
+ if (opts?.light && repoPath) {
7434
+ const last = this.lightReconcileAt.get(repoPath) ?? 0;
7435
+ if (Date.now() - last < LIGHT_RECONCILE_THROTTLE_MS) return;
7436
+ this.lightReconcileAt.set(repoPath, Date.now());
7437
+ for (const thread of listThreads()) {
7438
+ if (isGlobalThread(thread) || thread.repoPath !== repoPath) continue;
7439
+ if (!existsSync19(thread.worktreePath)) {
7440
+ setStatus(thread.id, "broken", "Worktree missing on disk");
7441
+ this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
7442
+ }
7443
+ }
7444
+ await this.reconcileOrphans([repoPath]);
7445
+ return;
7446
+ }
7356
7447
  healOrchestrationSoccerTitles();
7357
7448
  for (const thread of listThreads({ includeArchived: true })) {
7358
7449
  if (thread.status === "archived") continue;
@@ -7385,6 +7476,21 @@ var Orchestrator = class {
7385
7476
  }
7386
7477
  }
7387
7478
  const repoPaths = (repoPath ? [repoPath] : [...new Set(listThreads({ includeArchived: true }).map((t) => t.repoPath))]).filter((p) => !isGlobalRepoPath(p));
7479
+ await this.reconcileOrphans(repoPaths);
7480
+ try {
7481
+ if (shouldRunHistoryCleanup()) {
7482
+ cleanupArchivedHistory();
7483
+ }
7484
+ } catch {
7485
+ }
7486
+ if (drainQueues) {
7487
+ this.adoptPersistedQueues();
7488
+ }
7489
+ this.schedulePendingQuotaResumes();
7490
+ armSchedules();
7491
+ }
7492
+ /** Surface (and, when enabled, clean up) worktrees git knows about but no thread owns. */
7493
+ async reconcileOrphans(repoPaths) {
7388
7494
  try {
7389
7495
  const orphans = await findOrphanWorktrees(repoPaths);
7390
7496
  if (orphans.length) {
@@ -7399,17 +7505,6 @@ var Orchestrator = class {
7399
7505
  }
7400
7506
  } catch {
7401
7507
  }
7402
- try {
7403
- if (shouldRunHistoryCleanup()) {
7404
- cleanupArchivedHistory();
7405
- }
7406
- } catch {
7407
- }
7408
- if (drainQueues) {
7409
- this.adoptPersistedQueues();
7410
- }
7411
- this.schedulePendingQuotaResumes();
7412
- armSchedules();
7413
7508
  }
7414
7509
  /**
7415
7510
  * Adopt queues persisted by another process (MCP stdio / CLI) into this
@@ -7643,7 +7738,7 @@ var Orchestrator = class {
7643
7738
  return listThreads({ includeArchived });
7644
7739
  }
7645
7740
  getThread(idOrRef) {
7646
- return findThreadByRef(idOrRef) ?? readThread(idOrRef);
7741
+ return readThread(idOrRef) ?? findThreadByRef(idOrRef);
7647
7742
  }
7648
7743
  async createThread(input) {
7649
7744
  const prior = new Set(
@@ -7814,9 +7909,11 @@ var Orchestrator = class {
7814
7909
  const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id);
7815
7910
  updateThread(thread.id, {
7816
7911
  ...removed,
7817
- // Old sends parked on pendingTurnAttachments; drop that bag when the
7818
- // follow-up that owned it is gone so a later turn cannot inherit it.
7819
- ...stillQueued ? {} : { pendingTurnAttachments: [] },
7912
+ // Follow-up files live on queueAttachments. pendingTurnAttachments is
7913
+ // the in-flight / just-dequeued snapshot — do not wipe it when a
7914
+ // later follow-up is removed. Only drop a leftover bag when nothing
7915
+ // is running and the queue is empty (legacy sends that never drained).
7916
+ ...stillQueued || inFlight ? {} : { pendingTurnAttachments: [] },
7820
7917
  status: !stillQueued && !inFlight && current.status === "queued" ? "idle" : current.status
7821
7918
  });
7822
7919
  this.emit({ type: "queue_changed", threadId: thread.id, queue: removed.queue });
@@ -7898,7 +7995,9 @@ var Orchestrator = class {
7898
7995
  updateThread(threadId, {
7899
7996
  queue: shifted.queue,
7900
7997
  queueAttachments: shifted.queueAttachments,
7901
- ...shifted.attachments.length > 0 ? { pendingTurnAttachments: shifted.attachments } : {}
7998
+ // Always write the snapshot, including [] for text-only, so
7999
+ // takePending cannot fall back to leftover pending or composer files.
8000
+ pendingTurnAttachments: shifted.attachments
7902
8001
  });
7903
8002
  this.emit({ type: "queue_changed", threadId, queue: shifted.queue });
7904
8003
  await this.runTurn(threadId, shifted.prompt);
@@ -7946,7 +8045,6 @@ var Orchestrator = class {
7946
8045
  thread = this.requireThread(threadId);
7947
8046
  }
7948
8047
  const autoContinue = isJobContinuePrompt(prompt) || prompt.trim().startsWith("The previous agent process ended before it finished.");
7949
- const parkedSnapshot = thread.pendingTurnAttachments ?? [];
7950
8048
  const parked = takePendingTurnAttachments(thread);
7951
8049
  const sentAttachments = !autoContinue && parked.length > 0 ? parked : void 0;
7952
8050
  appendMessage(threadId, {
@@ -7962,7 +8060,7 @@ var Orchestrator = class {
7962
8060
  thread.worktreePath,
7963
8061
  gitPrompt,
7964
8062
  {
7965
- attachments: autoContinue ? [] : sentAttachments ?? thread.attachments
8063
+ attachments: autoContinue ? [] : sentAttachments ?? []
7966
8064
  }
7967
8065
  );
7968
8066
  const slackInbound = /^(Slack DM|Slack @mention)(?:\n|$)/.test(
@@ -8016,10 +8114,7 @@ var Orchestrator = class {
8016
8114
  expandedPrompt
8017
8115
  ].filter(Boolean).join("\n\n");
8018
8116
  if (!autoContinue && sentAttachments) {
8019
- updateThread(
8020
- threadId,
8021
- parkedSnapshot.length > 0 ? { pendingTurnAttachments: [] } : { attachments: [], pendingTurnAttachments: [] }
8022
- );
8117
+ updateThread(threadId, { pendingTurnAttachments: [] });
8023
8118
  }
8024
8119
  const adapter = getAdapter(thread.agent);
8025
8120
  const resolved = await adapter.resolveSessionId(thread.worktreePath, thread.sessionId);
@@ -8499,17 +8594,18 @@ var Orchestrator = class {
8499
8594
  }
8500
8595
  }
8501
8596
  }
8597
+ const runOutput = createLineCoalescer((chunk) => {
8598
+ this.emit({
8599
+ type: "run_output",
8600
+ threadId: thread.id,
8601
+ scriptName: resolvedName,
8602
+ line: chunk
8603
+ });
8604
+ });
8502
8605
  const handle = await startDevServer(
8503
8606
  thread.repoPath,
8504
8607
  thread.worktreePath,
8505
- (line) => {
8506
- this.emit({
8507
- type: "run_output",
8508
- threadId: thread.id,
8509
- scriptName: resolvedName,
8510
- line
8511
- });
8512
- },
8608
+ runOutput.push,
8513
8609
  { scriptName: resolvedName }
8514
8610
  );
8515
8611
  if (!handle) {
@@ -8555,6 +8651,7 @@ var Orchestrator = class {
8555
8651
  scriptName: resolvedName
8556
8652
  });
8557
8653
  void handle.done.then(() => {
8654
+ runOutput.flush();
8558
8655
  this.processes.delete(runKey);
8559
8656
  if (isDefault) this.processes.delete(worktreeDevProcessKey(thread.worktreePath));
8560
8657
  const latest = mergeWorktreeActiveRuns(threadsSharingWorktree(thread.worktreePath));
@@ -8640,9 +8737,14 @@ var Orchestrator = class {
8640
8737
  (t) => this.processes.has(`${t.id}:setup`)
8641
8738
  );
8642
8739
  }
8643
- writeSetupLog(threadId, worktreePath, fn) {
8740
+ /**
8741
+ * The worktree-keyed log is canonical (`resolveWorktreeSetupLog` prefers it
8742
+ * whenever it has output/running/exitCode); per-chat keys only exist for
8743
+ * records that predate it. Writing one key halves the sync persists during
8744
+ * `pnpm install`.
8745
+ */
8746
+ writeSetupLog(worktreePath, fn) {
8644
8747
  fn(setupLogKeyForWorktree(worktreePath));
8645
- fn(threadId);
8646
8748
  }
8647
8749
  async runSetup(threadRef, opts) {
8648
8750
  const thread = this.requireThread(threadRef);
@@ -8657,14 +8759,18 @@ var Orchestrator = class {
8657
8759
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
8658
8760
  kill: () => abort.abort()
8659
8761
  });
8660
- this.writeSetupLog(thread.id, thread.worktreePath, beginSetupLog);
8762
+ this.writeSetupLog(thread.worktreePath, beginSetupLog);
8661
8763
  this.emit({ type: "setup_started", threadId: thread.id });
8764
+ const output = createLineCoalescer((chunk) => {
8765
+ this.writeSetupLog(thread.worktreePath, (logKey) => appendSetupLog(logKey, chunk));
8766
+ this.emit({ type: "setup_output", threadId: thread.id, line: chunk });
8767
+ });
8662
8768
  let finished = false;
8663
8769
  const finish = (exitCode, source) => {
8664
8770
  if (finished) return;
8665
8771
  finished = true;
8772
+ output.flush();
8666
8773
  this.writeSetupLog(
8667
- thread.id,
8668
8774
  thread.worktreePath,
8669
8775
  (logKey) => finishSetupLog(logKey, exitCode, source)
8670
8776
  );
@@ -8674,24 +8780,12 @@ var Orchestrator = class {
8674
8780
  const setup = await runWorkspaceSetup(
8675
8781
  thread.repoPath,
8676
8782
  thread.worktreePath,
8677
- (line) => {
8678
- this.writeSetupLog(
8679
- thread.id,
8680
- thread.worktreePath,
8681
- (logKey) => appendSetupLog(logKey, line)
8682
- );
8683
- this.emit({ type: "setup_output", threadId: thread.id, line });
8684
- },
8783
+ output.push,
8685
8784
  { signal: abort.signal }
8686
8785
  );
8687
8786
  if (!setup.ran) {
8688
8787
  const line = "No setup script in .sideboard/settings.toml, .conductor/settings.toml, .cursor/worktrees.json, or script/setup (bin/setup, scripts/setup)";
8689
- this.writeSetupLog(
8690
- thread.id,
8691
- thread.worktreePath,
8692
- (logKey) => appendSetupLog(logKey, line)
8693
- );
8694
- this.emit({ type: "setup_output", threadId: thread.id, line });
8788
+ output.push(line);
8695
8789
  finish(null, null);
8696
8790
  throw new Error(line);
8697
8791
  }
@@ -8897,6 +8991,11 @@ var Orchestrator = class {
8897
8991
  lastTurnBase: this.turnBaselines.get(thread.id) ?? null
8898
8992
  });
8899
8993
  }
8994
+ async worktreeDirtyStat(threadRef) {
8995
+ const thread = this.requireThread(threadRef);
8996
+ this.assertNotGlobal(thread, "Diff");
8997
+ return getWorktreeDirtyStat(thread.worktreePath);
8998
+ }
8900
8999
  async diffSummary(threadRef) {
8901
9000
  const thread = this.requireThread(threadRef);
8902
9001
  this.assertNotGlobal(thread, "Diff");
@@ -9345,7 +9444,7 @@ var Orchestrator = class {
9345
9444
  this.enforceHistoryRetention();
9346
9445
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
9347
9446
  try {
9348
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-FRR6Y4BY.js");
9447
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-R5LJCJRB.js");
9349
9448
  await ensureWorkspace2(thread.repoPath);
9350
9449
  } catch {
9351
9450
  }
@@ -9399,7 +9498,7 @@ var Orchestrator = class {
9399
9498
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
9400
9499
  );
9401
9500
  }
9402
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-GKUOHXXB.js");
9501
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-MDMTCAHX.js");
9403
9502
  const slug = thread.worktreePath.split("/").pop();
9404
9503
  const dest = thread.worktreePath;
9405
9504
  await withRepoGitLock(thread.repoPath, async () => {
@@ -9509,7 +9608,7 @@ async function startOrchestration(opts) {
9509
9608
  sourceRef: "default",
9510
9609
  ...createOpts
9511
9610
  }).catch(async () => {
9512
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-GKUOHXXB.js");
9611
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-MDMTCAHX.js");
9513
9612
  const repo = await resolveRepoRoot2(repoPath);
9514
9613
  const def = await resolveDefaultBranch2(repo);
9515
9614
  return orch.createThread({
@@ -9519,7 +9618,7 @@ async function startOrchestration(opts) {
9519
9618
  repoPath: repo
9520
9619
  });
9521
9620
  });
9522
- const { updateThread: upd } = await import("./thread-store-4M6WETL6.js");
9621
+ const { updateThread: upd } = await import("./thread-store-N6WQIWZ4.js");
9523
9622
  const updated = upd(thread.id, {
9524
9623
  sourceType: "orchestration",
9525
9624
  sourceRef: goal
@@ -9725,6 +9824,7 @@ export {
9725
9824
  readWorktreeFileForUpload,
9726
9825
  readWorktreeFile,
9727
9826
  writeWorktreeFile,
9827
+ getWorktreeDirtyStat,
9728
9828
  getDiffSummary,
9729
9829
  previewLand,
9730
9830
  confirmLand,
@@ -9778,6 +9878,7 @@ export {
9778
9878
  waitForPidExit,
9779
9879
  resolveSendFollowUp,
9780
9880
  resolveOrchChildFollowUp,
9881
+ LIGHT_RECONCILE_THROTTLE_MS,
9781
9882
  Orchestrator,
9782
9883
  getOrchestrator,
9783
9884
  startOrchestration,