@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
@@ -841,6 +841,7 @@ __export(thread_store_exports, {
841
841
  findThreadByRef: () => findThreadByRef,
842
842
  invalidateThreadListCache: () => invalidateThreadListCache,
843
843
  invalidateThreadRecord: () => invalidateThreadRecord,
844
+ isSelfWrittenRecord: () => isSelfWrittenRecord,
844
845
  isThreadRecordFile: () => isThreadRecordFile,
845
846
  listThreads: () => listThreads,
846
847
  normalizeThread: () => normalizeThread,
@@ -970,6 +971,7 @@ function forgetThread(id) {
970
971
  const cache = cacheForDir();
971
972
  cache.byId.delete(id);
972
973
  cache.mtimeMs.delete(id);
974
+ selfWriteMtimes.delete(id);
973
975
  }
974
976
  function invalidateThreadListCache() {
975
977
  listCache = null;
@@ -999,14 +1001,21 @@ function writeThread(thread, opts) {
999
1001
  const next = opts?.touch === false ? { ...thread } : { ...thread, updatedAt: nowIso() };
1000
1002
  (0, import_node_fs8.writeFileSync)(tmp, JSON.stringify(next, null, 2), "utf8");
1001
1003
  (0, import_node_fs8.renameSync)(tmp, path);
1002
- rememberThread(next, fileMtimeMs(path) ?? Date.now());
1004
+ const mtimeMs = fileMtimeMs(path) ?? Date.now();
1005
+ rememberThread(next, mtimeMs);
1006
+ selfWriteMtimes.set(thread.id, mtimeMs);
1007
+ }
1008
+ function isSelfWrittenRecord(id) {
1009
+ const ours = selfWriteMtimes.get(id);
1010
+ if (ours == null) return false;
1011
+ return fileMtimeMs(threadFilePath(id)) === ours;
1003
1012
  }
1004
1013
  function idPath(id) {
1005
1014
  return id;
1006
1015
  }
1007
1016
  function isThreadRecordFile(nameOrPath) {
1008
1017
  const name = (0, import_node_path9.basename)(nameOrPath);
1009
- return name.endsWith(".json") && !name.endsWith(".live.json");
1018
+ return name.endsWith(".json") && !name.endsWith(".live.json") && !name.endsWith(".setup.log.json");
1010
1019
  }
1011
1020
  function listThreads(opts) {
1012
1021
  const cache = cacheForDir();
@@ -1072,7 +1081,7 @@ function findThreadByRef(ref) {
1072
1081
  (t) => t.id === ref || t.id.startsWith(ref) || t.branchName === ref || t.title === ref
1073
1082
  ) ?? null;
1074
1083
  }
1075
- var import_node_crypto2, import_node_fs8, import_node_path9, import_proper_lockfile, listCache;
1084
+ var import_node_crypto2, import_node_fs8, import_node_path9, import_proper_lockfile, listCache, selfWriteMtimes;
1076
1085
  var init_thread_store = __esm({
1077
1086
  "src/store/thread-store.ts"() {
1078
1087
  "use strict";
@@ -1084,6 +1093,7 @@ var init_thread_store = __esm({
1084
1093
  init_cursor_store();
1085
1094
  init_paths();
1086
1095
  listCache = null;
1096
+ selfWriteMtimes = /* @__PURE__ */ new Map();
1087
1097
  }
1088
1098
  });
1089
1099
 
@@ -14372,6 +14382,29 @@ ${line}` : line;
14372
14382
  const nl = cut.indexOf("\n");
14373
14383
  return nl >= 0 && nl < cut.length - 1 ? cut.slice(nl + 1) : cut;
14374
14384
  }
14385
+ function fromSnapshot(snap) {
14386
+ return {
14387
+ chunks: snap.output ? [snap.output] : [],
14388
+ length: snap.output.length,
14389
+ running: snap.running,
14390
+ exitCode: snap.exitCode,
14391
+ source: snap.source
14392
+ };
14393
+ }
14394
+ function materialize(mem) {
14395
+ let output = mem.chunks.join("\n");
14396
+ if (output.length > MAX_SETUP_LOG_CHARS) {
14397
+ output = appendSetupOutput("", output);
14398
+ mem.chunks = [output];
14399
+ mem.length = output.length;
14400
+ }
14401
+ return {
14402
+ output,
14403
+ running: mem.running,
14404
+ exitCode: mem.exitCode,
14405
+ source: mem.source
14406
+ };
14407
+ }
14375
14408
  function setupLogPath(threadId) {
14376
14409
  return (0, import_node_path38.join)(threadsDir(), `${threadId}.setup.log.json`);
14377
14410
  }
@@ -14382,20 +14415,21 @@ function setupLogKeyForWorktree(worktreePath) {
14382
14415
  function emptySetupLog() {
14383
14416
  return { ...EMPTY };
14384
14417
  }
14385
- function clone(snap) {
14386
- return { ...snap };
14387
- }
14388
14418
  function persistNow(threadId) {
14389
14419
  const timer = persistTimers.get(threadId);
14390
14420
  if (timer) {
14391
14421
  clearTimeout(timer);
14392
14422
  persistTimers.delete(threadId);
14393
14423
  }
14394
- const snap = memory.get(threadId);
14395
- if (!snap) return;
14424
+ const mem = memory.get(threadId);
14425
+ if (!mem) return;
14396
14426
  try {
14397
- (0, import_node_fs37.writeFileSync)(setupLogPath(threadId), `${JSON.stringify(snap)}
14398
- `, "utf8");
14427
+ (0, import_node_fs37.writeFileSync)(
14428
+ setupLogPath(threadId),
14429
+ `${JSON.stringify(materialize(mem))}
14430
+ `,
14431
+ "utf8"
14432
+ );
14399
14433
  } catch {
14400
14434
  }
14401
14435
  }
@@ -14406,7 +14440,7 @@ function schedulePersist(threadId) {
14406
14440
  setTimeout(() => {
14407
14441
  persistTimers.delete(threadId);
14408
14442
  persistNow(threadId);
14409
- }, 100)
14443
+ }, PERSIST_DEBOUNCE_MS)
14410
14444
  );
14411
14445
  }
14412
14446
  function loadFromDisk(threadId) {
@@ -14424,51 +14458,52 @@ function loadFromDisk(threadId) {
14424
14458
  return null;
14425
14459
  }
14426
14460
  }
14461
+ function memFor(threadId) {
14462
+ const cached = memory.get(threadId);
14463
+ if (cached) return cached;
14464
+ const mem = fromSnapshot(loadFromDisk(threadId) ?? emptySetupLog());
14465
+ memory.set(threadId, mem);
14466
+ return mem;
14467
+ }
14427
14468
  function readSetupLog(threadId) {
14428
14469
  const cached = memory.get(threadId);
14429
- if (cached) return clone(cached);
14470
+ if (cached) return materialize(cached);
14430
14471
  const disk = loadFromDisk(threadId);
14431
14472
  if (disk) {
14432
- memory.set(threadId, disk);
14433
- return clone(disk);
14473
+ memory.set(threadId, fromSnapshot(disk));
14474
+ return disk;
14434
14475
  }
14435
14476
  return emptySetupLog();
14436
14477
  }
14437
14478
  function beginSetupLog(threadId) {
14438
- const snap = {
14439
- output: "",
14479
+ const mem = {
14480
+ chunks: [],
14481
+ length: 0,
14440
14482
  running: true,
14441
14483
  exitCode: null,
14442
14484
  source: null
14443
14485
  };
14444
- memory.set(threadId, snap);
14486
+ memory.set(threadId, mem);
14445
14487
  persistNow(threadId);
14446
- return clone(snap);
14488
+ return materialize(mem);
14447
14489
  }
14448
14490
  function appendSetupLog(threadId, line) {
14449
- const current = memory.get(threadId) ?? readSetupLog(threadId);
14450
- const snap = {
14451
- ...current,
14452
- output: appendSetupOutput(current.output, line),
14453
- running: true
14454
- };
14455
- memory.set(threadId, snap);
14491
+ const mem = memFor(threadId);
14492
+ mem.chunks.push(line);
14493
+ mem.length += line.length + 1;
14494
+ mem.running = true;
14495
+ if (mem.length > MAX_SETUP_LOG_CHARS * 2) materialize(mem);
14456
14496
  schedulePersist(threadId);
14457
- return clone(snap);
14458
14497
  }
14459
14498
  function finishSetupLog(threadId, exitCode, source) {
14460
- const current = memory.get(threadId) ?? readSetupLog(threadId);
14461
- const snap = {
14462
- ...current,
14463
- running: false,
14464
- exitCode,
14465
- source: source ?? current.source
14466
- };
14467
- memory.set(threadId, snap);
14499
+ const mem = memFor(threadId);
14500
+ mem.running = false;
14501
+ mem.exitCode = exitCode;
14502
+ mem.source = source ?? mem.source;
14468
14503
  persistNow(threadId);
14469
- return clone(snap);
14504
+ return materialize(mem);
14470
14505
  }
14471
- var import_node_crypto8, import_node_fs37, import_node_path38, EMPTY, MAX_SETUP_LOG_CHARS, memory, persistTimers;
14506
+ var import_node_crypto8, import_node_fs37, import_node_path38, EMPTY, MAX_SETUP_LOG_CHARS, memory, persistTimers, PERSIST_DEBOUNCE_MS;
14472
14507
  var init_setup_log = __esm({
14473
14508
  "src/store/setup-log.ts"() {
14474
14509
  "use strict";
@@ -14486,6 +14521,7 @@ var init_setup_log = __esm({
14486
14521
  MAX_SETUP_LOG_CHARS = 256e3;
14487
14522
  memory = /* @__PURE__ */ new Map();
14488
14523
  persistTimers = /* @__PURE__ */ new Map();
14524
+ PERSIST_DEBOUNCE_MS = 500;
14489
14525
  }
14490
14526
  });
14491
14527
 
@@ -17526,6 +17562,38 @@ var init_cowboy = __esm({
17526
17562
  }
17527
17563
  });
17528
17564
 
17565
+ // src/util/line-coalescer.ts
17566
+ function createLineCoalescer(onChunk, opts) {
17567
+ const delayMs = opts?.delayMs ?? 50;
17568
+ const maxLines = opts?.maxLines ?? 200;
17569
+ let buffer = [];
17570
+ let timer = null;
17571
+ const flush2 = () => {
17572
+ if (timer) {
17573
+ clearTimeout(timer);
17574
+ timer = null;
17575
+ }
17576
+ if (buffer.length === 0) return;
17577
+ const chunk = buffer.join("\n");
17578
+ buffer = [];
17579
+ onChunk(chunk);
17580
+ };
17581
+ const push = (line) => {
17582
+ buffer.push(line);
17583
+ if (buffer.length >= maxLines) {
17584
+ flush2();
17585
+ return;
17586
+ }
17587
+ if (!timer) timer = setTimeout(flush2, delayMs);
17588
+ };
17589
+ return { push, flush: flush2 };
17590
+ }
17591
+ var init_line_coalescer = __esm({
17592
+ "src/util/line-coalescer.ts"() {
17593
+ "use strict";
17594
+ }
17595
+ });
17596
+
17529
17597
  // src/store/turn-live.ts
17530
17598
  function trimParts(parts) {
17531
17599
  if (parts.length <= MAX_PARTS) return parts;
@@ -19175,6 +19243,29 @@ function writeWorktreeFile(worktreePath, relativePath, content) {
19175
19243
  (0, import_node_fs46.writeFileSync)(abs, content, "utf8");
19176
19244
  return { path: relativePath };
19177
19245
  }
19246
+ async function getWorktreeDirtyStat(worktreePath) {
19247
+ const status = await inspectGitWorktree(worktreePath);
19248
+ if (status !== "ok") {
19249
+ return { additions: 0, deletions: 0, dirty: false };
19250
+ }
19251
+ const head = await git(["rev-parse", "--verify", "HEAD"], worktreePath, {
19252
+ reject: false,
19253
+ timeoutMs: 4e3
19254
+ });
19255
+ if (head.exitCode !== 0) {
19256
+ return { additions: 0, deletions: 0, dirty: await isDirty(worktreePath) };
19257
+ }
19258
+ const [num2, dirty] = await Promise.all([
19259
+ gitDiff(["--numstat", "HEAD"], worktreePath, { timeoutMs: 4e3 }),
19260
+ isDirty(worktreePath)
19261
+ ]);
19262
+ const counts = statFromNumstat(num2.stdout);
19263
+ return {
19264
+ additions: counts.additions,
19265
+ deletions: counts.deletions,
19266
+ dirty: dirty || counts.additions > 0 || counts.deletions > 0
19267
+ };
19268
+ }
19178
19269
  async function getDiffSummary(worktreePath, repoPath, opts) {
19179
19270
  const full = await getDiff(worktreePath, repoPath, {
19180
19271
  maxHunkChars: opts?.maxHunkChars ?? 2e3,
@@ -19781,9 +19872,7 @@ function consumeComposerAttachments(thread) {
19781
19872
  };
19782
19873
  }
19783
19874
  function takePendingTurnAttachments(thread) {
19784
- const pending = thread.pendingTurnAttachments ?? [];
19785
- if (pending.length > 0) return [...pending];
19786
- return thread.attachments.length > 0 ? [...thread.attachments] : [];
19875
+ return [...thread.pendingTurnAttachments ?? []];
19787
19876
  }
19788
19877
  function alignQueueAttachments(queueLength, existing) {
19789
19878
  const next = (existing ?? []).slice(0, queueLength).map((slot) => [...slot ?? []]);
@@ -20995,6 +21084,7 @@ var init_title = __esm({
20995
21084
  // src/orchestrator/orchestrator.ts
20996
21085
  var orchestrator_exports = {};
20997
21086
  __export(orchestrator_exports, {
21087
+ LIGHT_RECONCILE_THROTTLE_MS: () => LIGHT_RECONCILE_THROTTLE_MS,
20998
21088
  LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
20999
21089
  Orchestrator: () => Orchestrator,
21000
21090
  getOrchestrator: () => getOrchestrator,
@@ -21098,7 +21188,7 @@ async function startOrchestration(opts) {
21098
21188
  }
21099
21189
  return updated;
21100
21190
  }
21101
- var import_node_events, import_node_fs54, LIVE_TURN_SPAWN_GRACE_MS, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
21191
+ var import_node_events, import_node_fs54, LIVE_TURN_SPAWN_GRACE_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton;
21102
21192
  var init_orchestrator = __esm({
21103
21193
  "src/orchestrator/orchestrator.ts"() {
21104
21194
  "use strict";
@@ -21132,6 +21222,7 @@ var init_orchestrator = __esm({
21132
21222
  init_orchestrator_capable();
21133
21223
  init_chat_tabs();
21134
21224
  init_enqueue_by_key();
21225
+ init_line_coalescer();
21135
21226
  init_run();
21136
21227
  init_repo_git_lock();
21137
21228
  init_turn_live();
@@ -21165,6 +21256,7 @@ var init_orchestrator = __esm({
21165
21256
  init_coordinator_prompt();
21166
21257
  LIVE_TURN_SPAWN_GRACE_MS = 15e3;
21167
21258
  STALE_AGENT_PID_WAIT_MS = 2500;
21259
+ LIGHT_RECONCILE_THROTTLE_MS = 1e4;
21168
21260
  Orchestrator = class {
21169
21261
  events = new import_node_events.EventEmitter();
21170
21262
  processes = /* @__PURE__ */ new Map();
@@ -21174,6 +21266,8 @@ var init_orchestrator = __esm({
21174
21266
  startingTurns = /* @__PURE__ */ new Set();
21175
21267
  /** Last sync thread-file read for false-stop heal (throttled per thread). */
21176
21268
  lastReconcileHealAt = /* @__PURE__ */ new Map();
21269
+ /** Per-repo timestamp of the last `reconcile(repo, { light: true })`. */
21270
+ lightReconcileAt = /* @__PURE__ */ new Map();
21177
21271
  /**
21178
21272
  * Threads intentionally force-stopped. Prevents runTurn from re-asserting
21179
21273
  * `running` after spawn, and from overwriting `stopped` with idle/error when
@@ -21259,6 +21353,20 @@ var init_orchestrator = __esm({
21259
21353
  async reconcile(repoPath, opts) {
21260
21354
  const reclaimStaleTurns = opts?.reclaimStaleTurns === true;
21261
21355
  const drainQueues = opts?.drainQueues !== false;
21356
+ if (opts?.light && repoPath) {
21357
+ const last = this.lightReconcileAt.get(repoPath) ?? 0;
21358
+ if (Date.now() - last < LIGHT_RECONCILE_THROTTLE_MS) return;
21359
+ this.lightReconcileAt.set(repoPath, Date.now());
21360
+ for (const thread of listThreads()) {
21361
+ if (isGlobalThread(thread) || thread.repoPath !== repoPath) continue;
21362
+ if (!(0, import_node_fs54.existsSync)(thread.worktreePath)) {
21363
+ setStatus(thread.id, "broken", "Worktree missing on disk");
21364
+ this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
21365
+ }
21366
+ }
21367
+ await this.reconcileOrphans([repoPath]);
21368
+ return;
21369
+ }
21262
21370
  healOrchestrationSoccerTitles();
21263
21371
  for (const thread of listThreads({ includeArchived: true })) {
21264
21372
  if (thread.status === "archived") continue;
@@ -21291,6 +21399,21 @@ var init_orchestrator = __esm({
21291
21399
  }
21292
21400
  }
21293
21401
  const repoPaths = (repoPath ? [repoPath] : [...new Set(listThreads({ includeArchived: true }).map((t) => t.repoPath))]).filter((p) => !isGlobalRepoPath(p));
21402
+ await this.reconcileOrphans(repoPaths);
21403
+ try {
21404
+ if (shouldRunHistoryCleanup()) {
21405
+ cleanupArchivedHistory();
21406
+ }
21407
+ } catch {
21408
+ }
21409
+ if (drainQueues) {
21410
+ this.adoptPersistedQueues();
21411
+ }
21412
+ this.schedulePendingQuotaResumes();
21413
+ armSchedules();
21414
+ }
21415
+ /** Surface (and, when enabled, clean up) worktrees git knows about but no thread owns. */
21416
+ async reconcileOrphans(repoPaths) {
21294
21417
  try {
21295
21418
  const orphans = await findOrphanWorktrees(repoPaths);
21296
21419
  if (orphans.length) {
@@ -21305,17 +21428,6 @@ var init_orchestrator = __esm({
21305
21428
  }
21306
21429
  } catch {
21307
21430
  }
21308
- try {
21309
- if (shouldRunHistoryCleanup()) {
21310
- cleanupArchivedHistory();
21311
- }
21312
- } catch {
21313
- }
21314
- if (drainQueues) {
21315
- this.adoptPersistedQueues();
21316
- }
21317
- this.schedulePendingQuotaResumes();
21318
- armSchedules();
21319
21431
  }
21320
21432
  /**
21321
21433
  * Adopt queues persisted by another process (MCP stdio / CLI) into this
@@ -21549,7 +21661,7 @@ var init_orchestrator = __esm({
21549
21661
  return listThreads({ includeArchived });
21550
21662
  }
21551
21663
  getThread(idOrRef) {
21552
- return findThreadByRef(idOrRef) ?? readThread(idOrRef);
21664
+ return readThread(idOrRef) ?? findThreadByRef(idOrRef);
21553
21665
  }
21554
21666
  async createThread(input) {
21555
21667
  const prior = new Set(
@@ -21720,9 +21832,11 @@ var init_orchestrator = __esm({
21720
21832
  const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id);
21721
21833
  updateThread(thread.id, {
21722
21834
  ...removed,
21723
- // Old sends parked on pendingTurnAttachments; drop that bag when the
21724
- // follow-up that owned it is gone so a later turn cannot inherit it.
21725
- ...stillQueued ? {} : { pendingTurnAttachments: [] },
21835
+ // Follow-up files live on queueAttachments. pendingTurnAttachments is
21836
+ // the in-flight / just-dequeued snapshot — do not wipe it when a
21837
+ // later follow-up is removed. Only drop a leftover bag when nothing
21838
+ // is running and the queue is empty (legacy sends that never drained).
21839
+ ...stillQueued || inFlight ? {} : { pendingTurnAttachments: [] },
21726
21840
  status: !stillQueued && !inFlight && current.status === "queued" ? "idle" : current.status
21727
21841
  });
21728
21842
  this.emit({ type: "queue_changed", threadId: thread.id, queue: removed.queue });
@@ -21804,7 +21918,9 @@ var init_orchestrator = __esm({
21804
21918
  updateThread(threadId, {
21805
21919
  queue: shifted.queue,
21806
21920
  queueAttachments: shifted.queueAttachments,
21807
- ...shifted.attachments.length > 0 ? { pendingTurnAttachments: shifted.attachments } : {}
21921
+ // Always write the snapshot, including [] for text-only, so
21922
+ // takePending cannot fall back to leftover pending or composer files.
21923
+ pendingTurnAttachments: shifted.attachments
21808
21924
  });
21809
21925
  this.emit({ type: "queue_changed", threadId, queue: shifted.queue });
21810
21926
  await this.runTurn(threadId, shifted.prompt);
@@ -21852,7 +21968,6 @@ var init_orchestrator = __esm({
21852
21968
  thread = this.requireThread(threadId);
21853
21969
  }
21854
21970
  const autoContinue = isJobContinuePrompt(prompt) || prompt.trim().startsWith("The previous agent process ended before it finished.");
21855
- const parkedSnapshot = thread.pendingTurnAttachments ?? [];
21856
21971
  const parked = takePendingTurnAttachments(thread);
21857
21972
  const sentAttachments = !autoContinue && parked.length > 0 ? parked : void 0;
21858
21973
  appendMessage(threadId, {
@@ -21868,7 +21983,7 @@ var init_orchestrator = __esm({
21868
21983
  thread.worktreePath,
21869
21984
  gitPrompt,
21870
21985
  {
21871
- attachments: autoContinue ? [] : sentAttachments ?? thread.attachments
21986
+ attachments: autoContinue ? [] : sentAttachments ?? []
21872
21987
  }
21873
21988
  );
21874
21989
  const slackInbound = /^(Slack DM|Slack @mention)(?:\n|$)/.test(
@@ -21922,10 +22037,7 @@ var init_orchestrator = __esm({
21922
22037
  expandedPrompt
21923
22038
  ].filter(Boolean).join("\n\n");
21924
22039
  if (!autoContinue && sentAttachments) {
21925
- updateThread(
21926
- threadId,
21927
- parkedSnapshot.length > 0 ? { pendingTurnAttachments: [] } : { attachments: [], pendingTurnAttachments: [] }
21928
- );
22040
+ updateThread(threadId, { pendingTurnAttachments: [] });
21929
22041
  }
21930
22042
  const adapter = getAdapter(thread.agent);
21931
22043
  const resolved = await adapter.resolveSessionId(thread.worktreePath, thread.sessionId);
@@ -22405,17 +22517,18 @@ var init_orchestrator = __esm({
22405
22517
  }
22406
22518
  }
22407
22519
  }
22520
+ const runOutput = createLineCoalescer((chunk) => {
22521
+ this.emit({
22522
+ type: "run_output",
22523
+ threadId: thread.id,
22524
+ scriptName: resolvedName,
22525
+ line: chunk
22526
+ });
22527
+ });
22408
22528
  const handle = await startDevServer(
22409
22529
  thread.repoPath,
22410
22530
  thread.worktreePath,
22411
- (line) => {
22412
- this.emit({
22413
- type: "run_output",
22414
- threadId: thread.id,
22415
- scriptName: resolvedName,
22416
- line
22417
- });
22418
- },
22531
+ runOutput.push,
22419
22532
  { scriptName: resolvedName }
22420
22533
  );
22421
22534
  if (!handle) {
@@ -22461,6 +22574,7 @@ var init_orchestrator = __esm({
22461
22574
  scriptName: resolvedName
22462
22575
  });
22463
22576
  void handle.done.then(() => {
22577
+ runOutput.flush();
22464
22578
  this.processes.delete(runKey);
22465
22579
  if (isDefault) this.processes.delete(worktreeDevProcessKey(thread.worktreePath));
22466
22580
  const latest = mergeWorktreeActiveRuns(threadsSharingWorktree(thread.worktreePath));
@@ -22546,9 +22660,14 @@ var init_orchestrator = __esm({
22546
22660
  (t) => this.processes.has(`${t.id}:setup`)
22547
22661
  );
22548
22662
  }
22549
- writeSetupLog(threadId, worktreePath, fn) {
22663
+ /**
22664
+ * The worktree-keyed log is canonical (`resolveWorktreeSetupLog` prefers it
22665
+ * whenever it has output/running/exitCode); per-chat keys only exist for
22666
+ * records that predate it. Writing one key halves the sync persists during
22667
+ * `pnpm install`.
22668
+ */
22669
+ writeSetupLog(worktreePath, fn) {
22550
22670
  fn(setupLogKeyForWorktree(worktreePath));
22551
- fn(threadId);
22552
22671
  }
22553
22672
  async runSetup(threadRef, opts) {
22554
22673
  const thread = this.requireThread(threadRef);
@@ -22563,14 +22682,18 @@ var init_orchestrator = __esm({
22563
22682
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
22564
22683
  kill: () => abort.abort()
22565
22684
  });
22566
- this.writeSetupLog(thread.id, thread.worktreePath, beginSetupLog);
22685
+ this.writeSetupLog(thread.worktreePath, beginSetupLog);
22567
22686
  this.emit({ type: "setup_started", threadId: thread.id });
22687
+ const output = createLineCoalescer((chunk) => {
22688
+ this.writeSetupLog(thread.worktreePath, (logKey) => appendSetupLog(logKey, chunk));
22689
+ this.emit({ type: "setup_output", threadId: thread.id, line: chunk });
22690
+ });
22568
22691
  let finished = false;
22569
22692
  const finish = (exitCode, source) => {
22570
22693
  if (finished) return;
22571
22694
  finished = true;
22695
+ output.flush();
22572
22696
  this.writeSetupLog(
22573
- thread.id,
22574
22697
  thread.worktreePath,
22575
22698
  (logKey) => finishSetupLog(logKey, exitCode, source)
22576
22699
  );
@@ -22580,24 +22703,12 @@ var init_orchestrator = __esm({
22580
22703
  const setup = await runWorkspaceSetup(
22581
22704
  thread.repoPath,
22582
22705
  thread.worktreePath,
22583
- (line) => {
22584
- this.writeSetupLog(
22585
- thread.id,
22586
- thread.worktreePath,
22587
- (logKey) => appendSetupLog(logKey, line)
22588
- );
22589
- this.emit({ type: "setup_output", threadId: thread.id, line });
22590
- },
22706
+ output.push,
22591
22707
  { signal: abort.signal }
22592
22708
  );
22593
22709
  if (!setup.ran) {
22594
22710
  const line = "No setup script in .sideboard/settings.toml, .conductor/settings.toml, .cursor/worktrees.json, or script/setup (bin/setup, scripts/setup)";
22595
- this.writeSetupLog(
22596
- thread.id,
22597
- thread.worktreePath,
22598
- (logKey) => appendSetupLog(logKey, line)
22599
- );
22600
- this.emit({ type: "setup_output", threadId: thread.id, line });
22711
+ output.push(line);
22601
22712
  finish(null, null);
22602
22713
  throw new Error(line);
22603
22714
  }
@@ -22803,6 +22914,11 @@ var init_orchestrator = __esm({
22803
22914
  lastTurnBase: this.turnBaselines.get(thread.id) ?? null
22804
22915
  });
22805
22916
  }
22917
+ async worktreeDirtyStat(threadRef) {
22918
+ const thread = this.requireThread(threadRef);
22919
+ this.assertNotGlobal(thread, "Diff");
22920
+ return getWorktreeDirtyStat(thread.worktreePath);
22921
+ }
22806
22922
  async diffSummary(threadRef) {
22807
22923
  const thread = this.requireThread(threadRef);
22808
22924
  this.assertNotGlobal(thread, "Diff");
@@ -50,7 +50,7 @@ import {
50
50
  syncBoardPins,
51
51
  updateSchedule,
52
52
  waitForDetachedJob
53
- } from "../chunk-ERNK7AWM.js";
53
+ } from "../chunk-D2IKXMF3.js";
54
54
  import "../chunk-JFOPOMK7.js";
55
55
  import "../chunk-YWI3IBP2.js";
56
56
  import {
@@ -61,12 +61,12 @@ import {
61
61
  materializeSystemCaBundle,
62
62
  sideboardMcpProfile,
63
63
  trustSystemCertificates
64
- } from "../chunk-IA5IPGZI.js";
64
+ } from "../chunk-7MTVRNP4.js";
65
65
  import {
66
66
  GLOBAL_WORKSPACE_ID,
67
67
  isCloudCoordinatorThread,
68
68
  listWorkspaces
69
- } from "../chunk-WNVQJZ7P.js";
69
+ } from "../chunk-KFD2OXCE.js";
70
70
  import "../chunk-3OHR73VK.js";
71
71
  import "../chunk-Y4MIXGPA.js";
72
72
  import "../chunk-YVE4PXCJ.js";
@@ -84,9 +84,9 @@ import {
84
84
  resolveListPrsOptions,
85
85
  resolveRepoRoot,
86
86
  warmGithubAgentAuth
87
- } from "../chunk-VPQXJYIW.js";
87
+ } from "../chunk-XYKVRRC2.js";
88
88
  import "../chunk-D6JWYJ4P.js";
89
- import "../chunk-GHKFSBES.js";
89
+ import "../chunk-HY2GFZ5S.js";
90
90
  import "../chunk-X5B3OS5I.js";
91
91
  import "../chunk-SYFVUF2C.js";
92
92
  import {
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import {
4
+ LIGHT_RECONCILE_THROTTLE_MS,
4
5
  LIVE_TURN_SPAWN_GRACE_MS,
5
6
  Orchestrator,
6
7
  getOrchestrator,
@@ -9,17 +10,17 @@ import {
9
10
  resolveSendFollowUp,
10
11
  startOrchestration,
11
12
  waitForPidExit
12
- } from "./chunk-ERNK7AWM.js";
13
+ } from "./chunk-D2IKXMF3.js";
13
14
  import "./chunk-JFOPOMK7.js";
14
15
  import "./chunk-YWI3IBP2.js";
15
- import "./chunk-IA5IPGZI.js";
16
- import "./chunk-WNVQJZ7P.js";
16
+ import "./chunk-7MTVRNP4.js";
17
+ import "./chunk-KFD2OXCE.js";
17
18
  import "./chunk-3OHR73VK.js";
18
19
  import "./chunk-Y4MIXGPA.js";
19
20
  import "./chunk-VKQGAWHY.js";
20
- import "./chunk-VPQXJYIW.js";
21
+ import "./chunk-XYKVRRC2.js";
21
22
  import "./chunk-D6JWYJ4P.js";
22
- import "./chunk-GHKFSBES.js";
23
+ import "./chunk-HY2GFZ5S.js";
23
24
  import "./chunk-X5B3OS5I.js";
24
25
  import "./chunk-SYFVUF2C.js";
25
26
  import "./chunk-FNQNJOHY.js";
@@ -29,6 +30,7 @@ import "./chunk-KGZBYWZ3.js";
29
30
  import "./chunk-EQNRWDLN.js";
30
31
  import "./chunk-FJZWM2ON.js";
31
32
  export {
33
+ LIGHT_RECONCILE_THROTTLE_MS,
32
34
  LIVE_TURN_SPAWN_GRACE_MS,
33
35
  Orchestrator,
34
36
  getOrchestrator,
@@ -1,4 +1,5 @@
1
1
  import {
2
+ LIGHT_RECONCILE_THROTTLE_MS,
2
3
  LIVE_TURN_SPAWN_GRACE_MS,
3
4
  Orchestrator,
4
5
  getOrchestrator,
@@ -7,11 +8,11 @@ import {
7
8
  resolveSendFollowUp,
8
9
  startOrchestration,
9
10
  waitForPidExit
10
- } from "./chunk-KZUA4QG2.js";
11
+ } from "./chunk-C32SBNA3.js";
11
12
  import "./chunk-DJU54RYW.js";
12
- import "./chunk-IRCAWYTN.js";
13
- import "./chunk-2PE6SZCM.js";
14
- import "./chunk-NRKDRQM3.js";
13
+ import "./chunk-DFTVZEZY.js";
14
+ import "./chunk-FNGXKY5W.js";
15
+ import "./chunk-NI243N27.js";
15
16
  import "./chunk-6K64FJDD.js";
16
17
  import "./chunk-QQKDGPUI.js";
17
18
  import "./chunk-SALM35KD.js";
@@ -24,12 +25,13 @@ import "./chunk-4TR3HZFT.js";
24
25
  import "./chunk-WDRMZKVB.js";
25
26
  import "./chunk-4TYXWPAJ.js";
26
27
  import "./chunk-JT7R45JB.js";
27
- import "./chunk-JJ3ONQ4Q.js";
28
+ import "./chunk-3IMSQNTS.js";
28
29
  import "./chunk-7J72QJOM.js";
29
30
  import "./chunk-77WWLBCI.js";
30
31
  import "./chunk-WFUDY6PC.js";
31
32
  import "./chunk-UFHNSFAS.js";
32
33
  export {
34
+ LIGHT_RECONCILE_THROTTLE_MS,
33
35
  LIVE_TURN_SPAWN_GRACE_MS,
34
36
  Orchestrator,
35
37
  getOrchestrator,