@sideboard-ai/core 0.1.212 → 0.1.214

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-DINKOGEU.js → chunk-C32SBNA3.js} +187 -84
  6. package/dist/{chunk-MS6HGW2H.js → chunk-D2IKXMF3.js} +185 -83
  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 +199 -75
  18. package/dist/index.d.cts +59 -3
  19. package/dist/index.d.ts +59 -3
  20. package/dist/index.js +11 -5
  21. package/dist/mcp/run-stdio.cjs +193 -75
  22. package/dist/mcp/run-stdio.js +5 -5
  23. package/dist/{orchestrator-DW4HDWLA.js → orchestrator-MI7A5DQZ.js} +7 -5
  24. package/dist/{orchestrator-333M3JAU.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
@@ -15,15 +15,15 @@ import {
15
15
  orchestratorSessionPoisonedByBuiltins,
16
16
  slackCoordinatorSourceRef,
17
17
  takenTeamSlugsForOrchestration
18
- } from "./chunk-2PE6SZCM.js";
19
- import "./chunk-NRKDRQM3.js";
18
+ } from "./chunk-FNGXKY5W.js";
19
+ import "./chunk-NI243N27.js";
20
20
  import "./chunk-6K64FJDD.js";
21
21
  import "./chunk-QQKDGPUI.js";
22
22
  import "./chunk-L5CIEBLR.js";
23
23
  import "./chunk-4TR3HZFT.js";
24
24
  import "./chunk-WDRMZKVB.js";
25
25
  import "./chunk-JT7R45JB.js";
26
- import "./chunk-JJ3ONQ4Q.js";
26
+ import "./chunk-3IMSQNTS.js";
27
27
  import "./chunk-7J72QJOM.js";
28
28
  import "./chunk-77WWLBCI.js";
29
29
  import {
@@ -17,10 +17,10 @@ import {
17
17
  orchestratorSessionPoisonedByBuiltins,
18
18
  slackCoordinatorSourceRef,
19
19
  takenTeamSlugsForOrchestration
20
- } from "./chunk-WNVQJZ7P.js";
21
- import "./chunk-VPQXJYIW.js";
20
+ } from "./chunk-KFD2OXCE.js";
21
+ import "./chunk-XYKVRRC2.js";
22
22
  import "./chunk-D6JWYJ4P.js";
23
- import "./chunk-GHKFSBES.js";
23
+ import "./chunk-HY2GFZ5S.js";
24
24
  import "./chunk-X5B3OS5I.js";
25
25
  import "./chunk-SYFVUF2C.js";
26
26
  import "./chunk-FNQNJOHY.js";
package/dist/index.cjs CHANGED
@@ -3079,6 +3079,7 @@ __export(thread_store_exports, {
3079
3079
  findThreadByRef: () => findThreadByRef,
3080
3080
  invalidateThreadListCache: () => invalidateThreadListCache,
3081
3081
  invalidateThreadRecord: () => invalidateThreadRecord,
3082
+ isSelfWrittenRecord: () => isSelfWrittenRecord,
3082
3083
  isThreadRecordFile: () => isThreadRecordFile,
3083
3084
  listThreads: () => listThreads,
3084
3085
  normalizeThread: () => normalizeThread,
@@ -3208,6 +3209,7 @@ function forgetThread(id) {
3208
3209
  const cache2 = cacheForDir();
3209
3210
  cache2.byId.delete(id);
3210
3211
  cache2.mtimeMs.delete(id);
3212
+ selfWriteMtimes.delete(id);
3211
3213
  }
3212
3214
  function invalidateThreadListCache() {
3213
3215
  listCache = null;
@@ -3237,14 +3239,21 @@ function writeThread(thread, opts) {
3237
3239
  const next = opts?.touch === false ? { ...thread } : { ...thread, updatedAt: nowIso() };
3238
3240
  (0, import_node_fs9.writeFileSync)(tmp, JSON.stringify(next, null, 2), "utf8");
3239
3241
  (0, import_node_fs9.renameSync)(tmp, path2);
3240
- rememberThread(next, fileMtimeMs(path2) ?? Date.now());
3242
+ const mtimeMs = fileMtimeMs(path2) ?? Date.now();
3243
+ rememberThread(next, mtimeMs);
3244
+ selfWriteMtimes.set(thread.id, mtimeMs);
3245
+ }
3246
+ function isSelfWrittenRecord(id) {
3247
+ const ours = selfWriteMtimes.get(id);
3248
+ if (ours == null) return false;
3249
+ return fileMtimeMs(threadFilePath(id)) === ours;
3241
3250
  }
3242
3251
  function idPath(id) {
3243
3252
  return id;
3244
3253
  }
3245
3254
  function isThreadRecordFile(nameOrPath) {
3246
3255
  const name = (0, import_node_path11.basename)(nameOrPath);
3247
- return name.endsWith(".json") && !name.endsWith(".live.json");
3256
+ return name.endsWith(".json") && !name.endsWith(".live.json") && !name.endsWith(".setup.log.json");
3248
3257
  }
3249
3258
  function listThreads(opts) {
3250
3259
  const cache2 = cacheForDir();
@@ -3310,7 +3319,7 @@ function findThreadByRef(ref) {
3310
3319
  (t) => t.id === ref || t.id.startsWith(ref) || t.branchName === ref || t.title === ref
3311
3320
  ) ?? null;
3312
3321
  }
3313
- var import_node_crypto3, import_node_fs9, import_node_path11, import_proper_lockfile, listCache;
3322
+ var import_node_crypto3, import_node_fs9, import_node_path11, import_proper_lockfile, listCache, selfWriteMtimes;
3314
3323
  var init_thread_store = __esm({
3315
3324
  "src/store/thread-store.ts"() {
3316
3325
  "use strict";
@@ -3322,6 +3331,7 @@ var init_thread_store = __esm({
3322
3331
  init_cursor_store();
3323
3332
  init_paths();
3324
3333
  listCache = null;
3334
+ selfWriteMtimes = /* @__PURE__ */ new Map();
3325
3335
  }
3326
3336
  });
3327
3337
 
@@ -5756,6 +5766,29 @@ ${line}` : line;
5756
5766
  const nl = cut.indexOf("\n");
5757
5767
  return nl >= 0 && nl < cut.length - 1 ? cut.slice(nl + 1) : cut;
5758
5768
  }
5769
+ function fromSnapshot(snap) {
5770
+ return {
5771
+ chunks: snap.output ? [snap.output] : [],
5772
+ length: snap.output.length,
5773
+ running: snap.running,
5774
+ exitCode: snap.exitCode,
5775
+ source: snap.source
5776
+ };
5777
+ }
5778
+ function materialize(mem) {
5779
+ let output = mem.chunks.join("\n");
5780
+ if (output.length > MAX_SETUP_LOG_CHARS) {
5781
+ output = appendSetupOutput("", output);
5782
+ mem.chunks = [output];
5783
+ mem.length = output.length;
5784
+ }
5785
+ return {
5786
+ output,
5787
+ running: mem.running,
5788
+ exitCode: mem.exitCode,
5789
+ source: mem.source
5790
+ };
5791
+ }
5759
5792
  function setupLogPath(threadId) {
5760
5793
  return (0, import_node_path12.join)(threadsDir(), `${threadId}.setup.log.json`);
5761
5794
  }
@@ -5774,20 +5807,21 @@ function mergeSetupOutput(prev, incoming) {
5774
5807
  if (incoming.startsWith(prev) || incoming.endsWith(prev)) return incoming;
5775
5808
  return incoming.length >= prev.length ? incoming : prev;
5776
5809
  }
5777
- function clone(snap) {
5778
- return { ...snap };
5779
- }
5780
5810
  function persistNow(threadId) {
5781
5811
  const timer = persistTimers.get(threadId);
5782
5812
  if (timer) {
5783
5813
  clearTimeout(timer);
5784
5814
  persistTimers.delete(threadId);
5785
5815
  }
5786
- const snap = memory.get(threadId);
5787
- if (!snap) return;
5816
+ const mem = memory.get(threadId);
5817
+ if (!mem) return;
5788
5818
  try {
5789
- (0, import_node_fs10.writeFileSync)(setupLogPath(threadId), `${JSON.stringify(snap)}
5790
- `, "utf8");
5819
+ (0, import_node_fs10.writeFileSync)(
5820
+ setupLogPath(threadId),
5821
+ `${JSON.stringify(materialize(mem))}
5822
+ `,
5823
+ "utf8"
5824
+ );
5791
5825
  } catch {
5792
5826
  }
5793
5827
  }
@@ -5798,7 +5832,7 @@ function schedulePersist(threadId) {
5798
5832
  setTimeout(() => {
5799
5833
  persistTimers.delete(threadId);
5800
5834
  persistNow(threadId);
5801
- }, 100)
5835
+ }, PERSIST_DEBOUNCE_MS)
5802
5836
  );
5803
5837
  }
5804
5838
  function loadFromDisk(threadId) {
@@ -5816,51 +5850,52 @@ function loadFromDisk(threadId) {
5816
5850
  return null;
5817
5851
  }
5818
5852
  }
5853
+ function memFor(threadId) {
5854
+ const cached = memory.get(threadId);
5855
+ if (cached) return cached;
5856
+ const mem = fromSnapshot(loadFromDisk(threadId) ?? emptySetupLog());
5857
+ memory.set(threadId, mem);
5858
+ return mem;
5859
+ }
5819
5860
  function readSetupLog(threadId) {
5820
5861
  const cached = memory.get(threadId);
5821
- if (cached) return clone(cached);
5862
+ if (cached) return materialize(cached);
5822
5863
  const disk = loadFromDisk(threadId);
5823
5864
  if (disk) {
5824
- memory.set(threadId, disk);
5825
- return clone(disk);
5865
+ memory.set(threadId, fromSnapshot(disk));
5866
+ return disk;
5826
5867
  }
5827
5868
  return emptySetupLog();
5828
5869
  }
5829
5870
  function beginSetupLog(threadId) {
5830
- const snap = {
5831
- output: "",
5871
+ const mem = {
5872
+ chunks: [],
5873
+ length: 0,
5832
5874
  running: true,
5833
5875
  exitCode: null,
5834
5876
  source: null
5835
5877
  };
5836
- memory.set(threadId, snap);
5878
+ memory.set(threadId, mem);
5837
5879
  persistNow(threadId);
5838
- return clone(snap);
5880
+ return materialize(mem);
5839
5881
  }
5840
5882
  function appendSetupLog(threadId, line) {
5841
- const current = memory.get(threadId) ?? readSetupLog(threadId);
5842
- const snap = {
5843
- ...current,
5844
- output: appendSetupOutput(current.output, line),
5845
- running: true
5846
- };
5847
- memory.set(threadId, snap);
5883
+ const mem = memFor(threadId);
5884
+ mem.chunks.push(line);
5885
+ mem.length += line.length + 1;
5886
+ mem.running = true;
5887
+ if (mem.length > MAX_SETUP_LOG_CHARS * 2) materialize(mem);
5848
5888
  schedulePersist(threadId);
5849
- return clone(snap);
5850
5889
  }
5851
5890
  function finishSetupLog(threadId, exitCode, source) {
5852
- const current = memory.get(threadId) ?? readSetupLog(threadId);
5853
- const snap = {
5854
- ...current,
5855
- running: false,
5856
- exitCode,
5857
- source: source ?? current.source
5858
- };
5859
- memory.set(threadId, snap);
5891
+ const mem = memFor(threadId);
5892
+ mem.running = false;
5893
+ mem.exitCode = exitCode;
5894
+ mem.source = source ?? mem.source;
5860
5895
  persistNow(threadId);
5861
- return clone(snap);
5896
+ return materialize(mem);
5862
5897
  }
5863
- var import_node_crypto4, import_node_fs10, import_node_path12, EMPTY, MAX_SETUP_LOG_CHARS, memory, persistTimers;
5898
+ var import_node_crypto4, import_node_fs10, import_node_path12, EMPTY, MAX_SETUP_LOG_CHARS, memory, persistTimers, PERSIST_DEBOUNCE_MS;
5864
5899
  var init_setup_log = __esm({
5865
5900
  "src/store/setup-log.ts"() {
5866
5901
  "use strict";
@@ -5878,6 +5913,7 @@ var init_setup_log = __esm({
5878
5913
  MAX_SETUP_LOG_CHARS = 256e3;
5879
5914
  memory = /* @__PURE__ */ new Map();
5880
5915
  persistTimers = /* @__PURE__ */ new Map();
5916
+ PERSIST_DEBOUNCE_MS = 500;
5881
5917
  }
5882
5918
  });
5883
5919
 
@@ -19630,6 +19666,38 @@ var init_cowboy = __esm({
19630
19666
  }
19631
19667
  });
19632
19668
 
19669
+ // src/util/line-coalescer.ts
19670
+ function createLineCoalescer(onChunk, opts) {
19671
+ const delayMs = opts?.delayMs ?? 50;
19672
+ const maxLines = opts?.maxLines ?? 200;
19673
+ let buffer = [];
19674
+ let timer = null;
19675
+ const flush2 = () => {
19676
+ if (timer) {
19677
+ clearTimeout(timer);
19678
+ timer = null;
19679
+ }
19680
+ if (buffer.length === 0) return;
19681
+ const chunk = buffer.join("\n");
19682
+ buffer = [];
19683
+ onChunk(chunk);
19684
+ };
19685
+ const push = (line) => {
19686
+ buffer.push(line);
19687
+ if (buffer.length >= maxLines) {
19688
+ flush2();
19689
+ return;
19690
+ }
19691
+ if (!timer) timer = setTimeout(flush2, delayMs);
19692
+ };
19693
+ return { push, flush: flush2 };
19694
+ }
19695
+ var init_line_coalescer = __esm({
19696
+ "src/util/line-coalescer.ts"() {
19697
+ "use strict";
19698
+ }
19699
+ });
19700
+
19633
19701
  // src/store/turn-live.ts
19634
19702
  function trimParts(parts) {
19635
19703
  if (parts.length <= MAX_PARTS) return parts;
@@ -21295,6 +21363,29 @@ function writeWorktreeFile(worktreePath, relativePath, content) {
21295
21363
  (0, import_node_fs48.writeFileSync)(abs, content, "utf8");
21296
21364
  return { path: relativePath };
21297
21365
  }
21366
+ async function getWorktreeDirtyStat(worktreePath) {
21367
+ const status = await inspectGitWorktree(worktreePath);
21368
+ if (status !== "ok") {
21369
+ return { additions: 0, deletions: 0, dirty: false };
21370
+ }
21371
+ const head = await git(["rev-parse", "--verify", "HEAD"], worktreePath, {
21372
+ reject: false,
21373
+ timeoutMs: 4e3
21374
+ });
21375
+ if (head.exitCode !== 0) {
21376
+ return { additions: 0, deletions: 0, dirty: await isDirty(worktreePath) };
21377
+ }
21378
+ const [num2, dirty] = await Promise.all([
21379
+ gitDiff(["--numstat", "HEAD"], worktreePath, { timeoutMs: 4e3 }),
21380
+ isDirty(worktreePath)
21381
+ ]);
21382
+ const counts = statFromNumstat(num2.stdout);
21383
+ return {
21384
+ additions: counts.additions,
21385
+ deletions: counts.deletions,
21386
+ dirty: dirty || counts.additions > 0 || counts.deletions > 0
21387
+ };
21388
+ }
21298
21389
  async function getDiffSummary(worktreePath, repoPath, opts) {
21299
21390
  const full = await getDiff(worktreePath, repoPath, {
21300
21391
  maxHunkChars: opts?.maxHunkChars ?? 2e3,
@@ -22765,6 +22856,7 @@ var init_title = __esm({
22765
22856
  // src/orchestrator/orchestrator.ts
22766
22857
  var orchestrator_exports = {};
22767
22858
  __export(orchestrator_exports, {
22859
+ LIGHT_RECONCILE_THROTTLE_MS: () => LIGHT_RECONCILE_THROTTLE_MS,
22768
22860
  LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
22769
22861
  Orchestrator: () => Orchestrator,
22770
22862
  getOrchestrator: () => getOrchestrator,
@@ -22868,7 +22960,7 @@ async function startOrchestration(opts) {
22868
22960
  }
22869
22961
  return updated;
22870
22962
  }
22871
- var import_node_events, import_node_fs54, LIVE_TURN_SPAWN_GRACE_MS, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
22963
+ var import_node_events, import_node_fs54, LIVE_TURN_SPAWN_GRACE_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton;
22872
22964
  var init_orchestrator = __esm({
22873
22965
  "src/orchestrator/orchestrator.ts"() {
22874
22966
  "use strict";
@@ -22902,6 +22994,7 @@ var init_orchestrator = __esm({
22902
22994
  init_orchestrator_capable();
22903
22995
  init_chat_tabs();
22904
22996
  init_enqueue_by_key();
22997
+ init_line_coalescer();
22905
22998
  init_run();
22906
22999
  init_repo_git_lock();
22907
23000
  init_turn_live();
@@ -22935,6 +23028,7 @@ var init_orchestrator = __esm({
22935
23028
  init_coordinator_prompt();
22936
23029
  LIVE_TURN_SPAWN_GRACE_MS = 15e3;
22937
23030
  STALE_AGENT_PID_WAIT_MS = 2500;
23031
+ LIGHT_RECONCILE_THROTTLE_MS = 1e4;
22938
23032
  Orchestrator = class {
22939
23033
  events = new import_node_events.EventEmitter();
22940
23034
  processes = /* @__PURE__ */ new Map();
@@ -22944,6 +23038,8 @@ var init_orchestrator = __esm({
22944
23038
  startingTurns = /* @__PURE__ */ new Set();
22945
23039
  /** Last sync thread-file read for false-stop heal (throttled per thread). */
22946
23040
  lastReconcileHealAt = /* @__PURE__ */ new Map();
23041
+ /** Per-repo timestamp of the last `reconcile(repo, { light: true })`. */
23042
+ lightReconcileAt = /* @__PURE__ */ new Map();
22947
23043
  /**
22948
23044
  * Threads intentionally force-stopped. Prevents runTurn from re-asserting
22949
23045
  * `running` after spawn, and from overwriting `stopped` with idle/error when
@@ -23029,6 +23125,20 @@ var init_orchestrator = __esm({
23029
23125
  async reconcile(repoPath, opts) {
23030
23126
  const reclaimStaleTurns = opts?.reclaimStaleTurns === true;
23031
23127
  const drainQueues = opts?.drainQueues !== false;
23128
+ if (opts?.light && repoPath) {
23129
+ const last = this.lightReconcileAt.get(repoPath) ?? 0;
23130
+ if (Date.now() - last < LIGHT_RECONCILE_THROTTLE_MS) return;
23131
+ this.lightReconcileAt.set(repoPath, Date.now());
23132
+ for (const thread of listThreads()) {
23133
+ if (isGlobalThread(thread) || thread.repoPath !== repoPath) continue;
23134
+ if (!(0, import_node_fs54.existsSync)(thread.worktreePath)) {
23135
+ setStatus(thread.id, "broken", "Worktree missing on disk");
23136
+ this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
23137
+ }
23138
+ }
23139
+ await this.reconcileOrphans([repoPath]);
23140
+ return;
23141
+ }
23032
23142
  healOrchestrationSoccerTitles();
23033
23143
  for (const thread of listThreads({ includeArchived: true })) {
23034
23144
  if (thread.status === "archived") continue;
@@ -23061,6 +23171,21 @@ var init_orchestrator = __esm({
23061
23171
  }
23062
23172
  }
23063
23173
  const repoPaths = (repoPath ? [repoPath] : [...new Set(listThreads({ includeArchived: true }).map((t) => t.repoPath))]).filter((p) => !isGlobalRepoPath(p));
23174
+ await this.reconcileOrphans(repoPaths);
23175
+ try {
23176
+ if (shouldRunHistoryCleanup()) {
23177
+ cleanupArchivedHistory();
23178
+ }
23179
+ } catch {
23180
+ }
23181
+ if (drainQueues) {
23182
+ this.adoptPersistedQueues();
23183
+ }
23184
+ this.schedulePendingQuotaResumes();
23185
+ armSchedules();
23186
+ }
23187
+ /** Surface (and, when enabled, clean up) worktrees git knows about but no thread owns. */
23188
+ async reconcileOrphans(repoPaths) {
23064
23189
  try {
23065
23190
  const orphans = await findOrphanWorktrees(repoPaths);
23066
23191
  if (orphans.length) {
@@ -23075,17 +23200,6 @@ var init_orchestrator = __esm({
23075
23200
  }
23076
23201
  } catch {
23077
23202
  }
23078
- try {
23079
- if (shouldRunHistoryCleanup()) {
23080
- cleanupArchivedHistory();
23081
- }
23082
- } catch {
23083
- }
23084
- if (drainQueues) {
23085
- this.adoptPersistedQueues();
23086
- }
23087
- this.schedulePendingQuotaResumes();
23088
- armSchedules();
23089
23203
  }
23090
23204
  /**
23091
23205
  * Adopt queues persisted by another process (MCP stdio / CLI) into this
@@ -23319,7 +23433,7 @@ var init_orchestrator = __esm({
23319
23433
  return listThreads({ includeArchived });
23320
23434
  }
23321
23435
  getThread(idOrRef) {
23322
- return findThreadByRef(idOrRef) ?? readThread(idOrRef);
23436
+ return readThread(idOrRef) ?? findThreadByRef(idOrRef);
23323
23437
  }
23324
23438
  async createThread(input) {
23325
23439
  const prior = new Set(
@@ -24175,17 +24289,18 @@ var init_orchestrator = __esm({
24175
24289
  }
24176
24290
  }
24177
24291
  }
24292
+ const runOutput = createLineCoalescer((chunk) => {
24293
+ this.emit({
24294
+ type: "run_output",
24295
+ threadId: thread.id,
24296
+ scriptName: resolvedName,
24297
+ line: chunk
24298
+ });
24299
+ });
24178
24300
  const handle = await startDevServer(
24179
24301
  thread.repoPath,
24180
24302
  thread.worktreePath,
24181
- (line) => {
24182
- this.emit({
24183
- type: "run_output",
24184
- threadId: thread.id,
24185
- scriptName: resolvedName,
24186
- line
24187
- });
24188
- },
24303
+ runOutput.push,
24189
24304
  { scriptName: resolvedName }
24190
24305
  );
24191
24306
  if (!handle) {
@@ -24231,6 +24346,7 @@ var init_orchestrator = __esm({
24231
24346
  scriptName: resolvedName
24232
24347
  });
24233
24348
  void handle.done.then(() => {
24349
+ runOutput.flush();
24234
24350
  this.processes.delete(runKey);
24235
24351
  if (isDefault) this.processes.delete(worktreeDevProcessKey(thread.worktreePath));
24236
24352
  const latest = mergeWorktreeActiveRuns(threadsSharingWorktree(thread.worktreePath));
@@ -24316,9 +24432,14 @@ var init_orchestrator = __esm({
24316
24432
  (t) => this.processes.has(`${t.id}:setup`)
24317
24433
  );
24318
24434
  }
24319
- writeSetupLog(threadId, worktreePath, fn) {
24435
+ /**
24436
+ * The worktree-keyed log is canonical (`resolveWorktreeSetupLog` prefers it
24437
+ * whenever it has output/running/exitCode); per-chat keys only exist for
24438
+ * records that predate it. Writing one key halves the sync persists during
24439
+ * `pnpm install`.
24440
+ */
24441
+ writeSetupLog(worktreePath, fn) {
24320
24442
  fn(setupLogKeyForWorktree(worktreePath));
24321
- fn(threadId);
24322
24443
  }
24323
24444
  async runSetup(threadRef, opts) {
24324
24445
  const thread = this.requireThread(threadRef);
@@ -24333,14 +24454,18 @@ var init_orchestrator = __esm({
24333
24454
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
24334
24455
  kill: () => abort.abort()
24335
24456
  });
24336
- this.writeSetupLog(thread.id, thread.worktreePath, beginSetupLog);
24457
+ this.writeSetupLog(thread.worktreePath, beginSetupLog);
24337
24458
  this.emit({ type: "setup_started", threadId: thread.id });
24459
+ const output = createLineCoalescer((chunk) => {
24460
+ this.writeSetupLog(thread.worktreePath, (logKey) => appendSetupLog(logKey, chunk));
24461
+ this.emit({ type: "setup_output", threadId: thread.id, line: chunk });
24462
+ });
24338
24463
  let finished = false;
24339
24464
  const finish = (exitCode, source) => {
24340
24465
  if (finished) return;
24341
24466
  finished = true;
24467
+ output.flush();
24342
24468
  this.writeSetupLog(
24343
- thread.id,
24344
24469
  thread.worktreePath,
24345
24470
  (logKey) => finishSetupLog(logKey, exitCode, source)
24346
24471
  );
@@ -24350,24 +24475,12 @@ var init_orchestrator = __esm({
24350
24475
  const setup = await runWorkspaceSetup(
24351
24476
  thread.repoPath,
24352
24477
  thread.worktreePath,
24353
- (line) => {
24354
- this.writeSetupLog(
24355
- thread.id,
24356
- thread.worktreePath,
24357
- (logKey) => appendSetupLog(logKey, line)
24358
- );
24359
- this.emit({ type: "setup_output", threadId: thread.id, line });
24360
- },
24478
+ output.push,
24361
24479
  { signal: abort.signal }
24362
24480
  );
24363
24481
  if (!setup.ran) {
24364
24482
  const line = "No setup script in .sideboard/settings.toml, .conductor/settings.toml, .cursor/worktrees.json, or script/setup (bin/setup, scripts/setup)";
24365
- this.writeSetupLog(
24366
- thread.id,
24367
- thread.worktreePath,
24368
- (logKey) => appendSetupLog(logKey, line)
24369
- );
24370
- this.emit({ type: "setup_output", threadId: thread.id, line });
24483
+ output.push(line);
24371
24484
  finish(null, null);
24372
24485
  throw new Error(line);
24373
24486
  }
@@ -24573,6 +24686,11 @@ var init_orchestrator = __esm({
24573
24686
  lastTurnBase: this.turnBaselines.get(thread.id) ?? null
24574
24687
  });
24575
24688
  }
24689
+ async worktreeDirtyStat(threadRef) {
24690
+ const thread = this.requireThread(threadRef);
24691
+ this.assertNotGlobal(thread, "Diff");
24692
+ return getWorktreeDirtyStat(thread.worktreePath);
24693
+ }
24576
24694
  async diffSummary(threadRef) {
24577
24695
  const thread = this.requireThread(threadRef);
24578
24696
  this.assertNotGlobal(thread, "Diff");
@@ -25332,6 +25450,7 @@ __export(index_exports, {
25332
25450
  LEGACY_DETACHED_JOBS_DIR: () => LEGACY_DETACHED_JOBS_DIR,
25333
25451
  LEGACY_PLAN_FILE_REL: () => LEGACY_PLAN_FILE_REL,
25334
25452
  LEGACY_REVIEW_REQUEST_PATH: () => LEGACY_REVIEW_REQUEST_PATH,
25453
+ LIGHT_RECONCILE_THROTTLE_MS: () => LIGHT_RECONCILE_THROTTLE_MS,
25335
25454
  LINEAR_OAUTH_CANCELLED: () => LINEAR_OAUTH_CANCELLED,
25336
25455
  LINEAR_OAUTH_PORT: () => LINEAR_OAUTH_PORT,
25337
25456
  LINEAR_OAUTH_REDIRECT: () => LINEAR_OAUTH_REDIRECT,
@@ -25689,6 +25808,7 @@ __export(index_exports, {
25689
25808
  getRunScript: () => getRunScript,
25690
25809
  getSchedule: () => getSchedule,
25691
25810
  getSlackWorkspace: () => getSlackWorkspace,
25811
+ getWorktreeDirtyStat: () => getWorktreeDirtyStat,
25692
25812
  gh: () => gh,
25693
25813
  ghHeadRef: () => ghHeadRef,
25694
25814
  ghRepoSelectArgs: () => ghRepoSelectArgs,
@@ -25766,6 +25886,7 @@ __export(index_exports, {
25766
25886
  isPrNotMergeableError: () => isPrNotMergeableError,
25767
25887
  isPresentPlanToolName: () => isPresentPlanToolName,
25768
25888
  isPrimaryCheckoutThread: () => isPrimaryCheckoutThread,
25889
+ isSelfWrittenRecord: () => isSelfWrittenRecord,
25769
25890
  isSessionQuotaLimit: () => isSessionQuotaLimit,
25770
25891
  isSetupLastError: () => isSetupLastError,
25771
25892
  isShellToolName: () => isShellToolName,
@@ -34118,6 +34239,7 @@ init_outbound_watch();
34118
34239
  LEGACY_DETACHED_JOBS_DIR,
34119
34240
  LEGACY_PLAN_FILE_REL,
34120
34241
  LEGACY_REVIEW_REQUEST_PATH,
34242
+ LIGHT_RECONCILE_THROTTLE_MS,
34121
34243
  LINEAR_OAUTH_CANCELLED,
34122
34244
  LINEAR_OAUTH_PORT,
34123
34245
  LINEAR_OAUTH_REDIRECT,
@@ -34475,6 +34597,7 @@ init_outbound_watch();
34475
34597
  getRunScript,
34476
34598
  getSchedule,
34477
34599
  getSlackWorkspace,
34600
+ getWorktreeDirtyStat,
34478
34601
  gh,
34479
34602
  ghHeadRef,
34480
34603
  ghRepoSelectArgs,
@@ -34552,6 +34675,7 @@ init_outbound_watch();
34552
34675
  isPrNotMergeableError,
34553
34676
  isPresentPlanToolName,
34554
34677
  isPrimaryCheckoutThread,
34678
+ isSelfWrittenRecord,
34555
34679
  isSessionQuotaLimit,
34556
34680
  isSetupLastError,
34557
34681
  isShellToolName,