@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.
- package/dist/{agents-GQANI7M5.js → agents-HETHRRZJ.js} +4 -4
- package/dist/{agents-A2U3K7VK.js → agents-WBDDLRBY.js} +4 -4
- package/dist/{chunk-JJ3ONQ4Q.js → chunk-3IMSQNTS.js} +12 -2
- package/dist/{chunk-IA5IPGZI.js → chunk-7MTVRNP4.js} +3 -3
- package/dist/{chunk-KZUA4QG2.js → chunk-C32SBNA3.js} +198 -97
- package/dist/{chunk-ERNK7AWM.js → chunk-D2IKXMF3.js} +196 -96
- package/dist/{chunk-IRCAWYTN.js → chunk-DFTVZEZY.js} +3 -3
- package/dist/{chunk-2PE6SZCM.js → chunk-FNGXKY5W.js} +2 -2
- package/dist/{chunk-GHKFSBES.js → chunk-HY2GFZ5S.js} +12 -2
- package/dist/{chunk-WNVQJZ7P.js → chunk-KFD2OXCE.js} +2 -2
- package/dist/{chunk-NRKDRQM3.js → chunk-NI243N27.js} +1 -1
- package/dist/{chunk-VPQXJYIW.js → chunk-XYKVRRC2.js} +1 -1
- package/dist/{coordinator-prompt-LMTMWCPN.js → coordinator-prompt-FQX6ALAI.js} +3 -3
- package/dist/{coordinator-prompt-EHRDZ2ZU.js → coordinator-prompt-LE2GQZ2X.js} +3 -3
- package/dist/{global-workspace-NG2TBUI5.js → global-workspace-6P236KKG.js} +3 -3
- package/dist/{global-workspace-RHABXQWB.js → global-workspace-KT3FRHZL.js} +3 -3
- package/dist/index.cjs +210 -88
- package/dist/index.d.cts +61 -6
- package/dist/index.d.ts +61 -6
- package/dist/index.js +11 -5
- package/dist/mcp/run-stdio.cjs +204 -88
- package/dist/mcp/run-stdio.js +5 -5
- package/dist/{orchestrator-NZO4PVFH.js → orchestrator-MI7A5DQZ.js} +7 -5
- package/dist/{orchestrator-QMGH4V4K.js → orchestrator-WVZPTHBV.js} +7 -5
- package/dist/{thread-store-MSMBQ3V4.js → thread-store-KDPPXJJ3.js} +3 -1
- package/dist/{thread-store-4M6WETL6.js → thread-store-N6WQIWZ4.js} +3 -1
- package/dist/{workspaces-VIUUE4RT.js → workspaces-KM7KTLVO.js} +3 -3
- package/dist/{workspaces-FRR6Y4BY.js → workspaces-R5LJCJRB.js} +3 -3
- package/dist/{worktree-GKUOHXXB.js → worktree-MDMTCAHX.js} +2 -2
- package/dist/{worktree-3MEG62KB.js → worktree-VXRI7LYM.js} +2 -2
- package/package.json +1 -1
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
|
-
|
|
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
|
|
5787
|
-
if (!
|
|
5816
|
+
const mem = memory.get(threadId);
|
|
5817
|
+
if (!mem) return;
|
|
5788
5818
|
try {
|
|
5789
|
-
(0, import_node_fs10.writeFileSync)(
|
|
5790
|
-
|
|
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
|
-
},
|
|
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
|
|
5862
|
+
if (cached) return materialize(cached);
|
|
5822
5863
|
const disk = loadFromDisk(threadId);
|
|
5823
5864
|
if (disk) {
|
|
5824
|
-
memory.set(threadId, disk);
|
|
5825
|
-
return
|
|
5865
|
+
memory.set(threadId, fromSnapshot(disk));
|
|
5866
|
+
return disk;
|
|
5826
5867
|
}
|
|
5827
5868
|
return emptySetupLog();
|
|
5828
5869
|
}
|
|
5829
5870
|
function beginSetupLog(threadId) {
|
|
5830
|
-
const
|
|
5831
|
-
|
|
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,
|
|
5878
|
+
memory.set(threadId, mem);
|
|
5837
5879
|
persistNow(threadId);
|
|
5838
|
-
return
|
|
5880
|
+
return materialize(mem);
|
|
5839
5881
|
}
|
|
5840
5882
|
function appendSetupLog(threadId, line) {
|
|
5841
|
-
const
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
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
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
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
|
|
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,
|
|
@@ -21901,9 +21992,7 @@ function consumeComposerAttachments(thread) {
|
|
|
21901
21992
|
};
|
|
21902
21993
|
}
|
|
21903
21994
|
function takePendingTurnAttachments(thread) {
|
|
21904
|
-
|
|
21905
|
-
if (pending.length > 0) return [...pending];
|
|
21906
|
-
return thread.attachments.length > 0 ? [...thread.attachments] : [];
|
|
21995
|
+
return [...thread.pendingTurnAttachments ?? []];
|
|
21907
21996
|
}
|
|
21908
21997
|
function alignQueueAttachments(queueLength, existing) {
|
|
21909
21998
|
const next = (existing ?? []).slice(0, queueLength).map((slot) => [...slot ?? []]);
|
|
@@ -22767,6 +22856,7 @@ var init_title = __esm({
|
|
|
22767
22856
|
// src/orchestrator/orchestrator.ts
|
|
22768
22857
|
var orchestrator_exports = {};
|
|
22769
22858
|
__export(orchestrator_exports, {
|
|
22859
|
+
LIGHT_RECONCILE_THROTTLE_MS: () => LIGHT_RECONCILE_THROTTLE_MS,
|
|
22770
22860
|
LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
|
|
22771
22861
|
Orchestrator: () => Orchestrator,
|
|
22772
22862
|
getOrchestrator: () => getOrchestrator,
|
|
@@ -22870,7 +22960,7 @@ async function startOrchestration(opts) {
|
|
|
22870
22960
|
}
|
|
22871
22961
|
return updated;
|
|
22872
22962
|
}
|
|
22873
|
-
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;
|
|
22874
22964
|
var init_orchestrator = __esm({
|
|
22875
22965
|
"src/orchestrator/orchestrator.ts"() {
|
|
22876
22966
|
"use strict";
|
|
@@ -22904,6 +22994,7 @@ var init_orchestrator = __esm({
|
|
|
22904
22994
|
init_orchestrator_capable();
|
|
22905
22995
|
init_chat_tabs();
|
|
22906
22996
|
init_enqueue_by_key();
|
|
22997
|
+
init_line_coalescer();
|
|
22907
22998
|
init_run();
|
|
22908
22999
|
init_repo_git_lock();
|
|
22909
23000
|
init_turn_live();
|
|
@@ -22937,6 +23028,7 @@ var init_orchestrator = __esm({
|
|
|
22937
23028
|
init_coordinator_prompt();
|
|
22938
23029
|
LIVE_TURN_SPAWN_GRACE_MS = 15e3;
|
|
22939
23030
|
STALE_AGENT_PID_WAIT_MS = 2500;
|
|
23031
|
+
LIGHT_RECONCILE_THROTTLE_MS = 1e4;
|
|
22940
23032
|
Orchestrator = class {
|
|
22941
23033
|
events = new import_node_events.EventEmitter();
|
|
22942
23034
|
processes = /* @__PURE__ */ new Map();
|
|
@@ -22946,6 +23038,8 @@ var init_orchestrator = __esm({
|
|
|
22946
23038
|
startingTurns = /* @__PURE__ */ new Set();
|
|
22947
23039
|
/** Last sync thread-file read for false-stop heal (throttled per thread). */
|
|
22948
23040
|
lastReconcileHealAt = /* @__PURE__ */ new Map();
|
|
23041
|
+
/** Per-repo timestamp of the last `reconcile(repo, { light: true })`. */
|
|
23042
|
+
lightReconcileAt = /* @__PURE__ */ new Map();
|
|
22949
23043
|
/**
|
|
22950
23044
|
* Threads intentionally force-stopped. Prevents runTurn from re-asserting
|
|
22951
23045
|
* `running` after spawn, and from overwriting `stopped` with idle/error when
|
|
@@ -23031,6 +23125,20 @@ var init_orchestrator = __esm({
|
|
|
23031
23125
|
async reconcile(repoPath, opts) {
|
|
23032
23126
|
const reclaimStaleTurns = opts?.reclaimStaleTurns === true;
|
|
23033
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
|
+
}
|
|
23034
23142
|
healOrchestrationSoccerTitles();
|
|
23035
23143
|
for (const thread of listThreads({ includeArchived: true })) {
|
|
23036
23144
|
if (thread.status === "archived") continue;
|
|
@@ -23063,6 +23171,21 @@ var init_orchestrator = __esm({
|
|
|
23063
23171
|
}
|
|
23064
23172
|
}
|
|
23065
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) {
|
|
23066
23189
|
try {
|
|
23067
23190
|
const orphans = await findOrphanWorktrees(repoPaths);
|
|
23068
23191
|
if (orphans.length) {
|
|
@@ -23077,17 +23200,6 @@ var init_orchestrator = __esm({
|
|
|
23077
23200
|
}
|
|
23078
23201
|
} catch {
|
|
23079
23202
|
}
|
|
23080
|
-
try {
|
|
23081
|
-
if (shouldRunHistoryCleanup()) {
|
|
23082
|
-
cleanupArchivedHistory();
|
|
23083
|
-
}
|
|
23084
|
-
} catch {
|
|
23085
|
-
}
|
|
23086
|
-
if (drainQueues) {
|
|
23087
|
-
this.adoptPersistedQueues();
|
|
23088
|
-
}
|
|
23089
|
-
this.schedulePendingQuotaResumes();
|
|
23090
|
-
armSchedules();
|
|
23091
23203
|
}
|
|
23092
23204
|
/**
|
|
23093
23205
|
* Adopt queues persisted by another process (MCP stdio / CLI) into this
|
|
@@ -23321,7 +23433,7 @@ var init_orchestrator = __esm({
|
|
|
23321
23433
|
return listThreads({ includeArchived });
|
|
23322
23434
|
}
|
|
23323
23435
|
getThread(idOrRef) {
|
|
23324
|
-
return
|
|
23436
|
+
return readThread(idOrRef) ?? findThreadByRef(idOrRef);
|
|
23325
23437
|
}
|
|
23326
23438
|
async createThread(input) {
|
|
23327
23439
|
const prior = new Set(
|
|
@@ -23492,9 +23604,11 @@ var init_orchestrator = __esm({
|
|
|
23492
23604
|
const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id);
|
|
23493
23605
|
updateThread(thread.id, {
|
|
23494
23606
|
...removed,
|
|
23495
|
-
//
|
|
23496
|
-
//
|
|
23497
|
-
|
|
23607
|
+
// Follow-up files live on queueAttachments. pendingTurnAttachments is
|
|
23608
|
+
// the in-flight / just-dequeued snapshot — do not wipe it when a
|
|
23609
|
+
// later follow-up is removed. Only drop a leftover bag when nothing
|
|
23610
|
+
// is running and the queue is empty (legacy sends that never drained).
|
|
23611
|
+
...stillQueued || inFlight ? {} : { pendingTurnAttachments: [] },
|
|
23498
23612
|
status: !stillQueued && !inFlight && current.status === "queued" ? "idle" : current.status
|
|
23499
23613
|
});
|
|
23500
23614
|
this.emit({ type: "queue_changed", threadId: thread.id, queue: removed.queue });
|
|
@@ -23576,7 +23690,9 @@ var init_orchestrator = __esm({
|
|
|
23576
23690
|
updateThread(threadId, {
|
|
23577
23691
|
queue: shifted.queue,
|
|
23578
23692
|
queueAttachments: shifted.queueAttachments,
|
|
23579
|
-
|
|
23693
|
+
// Always write the snapshot, including [] for text-only, so
|
|
23694
|
+
// takePending cannot fall back to leftover pending or composer files.
|
|
23695
|
+
pendingTurnAttachments: shifted.attachments
|
|
23580
23696
|
});
|
|
23581
23697
|
this.emit({ type: "queue_changed", threadId, queue: shifted.queue });
|
|
23582
23698
|
await this.runTurn(threadId, shifted.prompt);
|
|
@@ -23624,7 +23740,6 @@ var init_orchestrator = __esm({
|
|
|
23624
23740
|
thread = this.requireThread(threadId);
|
|
23625
23741
|
}
|
|
23626
23742
|
const autoContinue = isJobContinuePrompt(prompt) || prompt.trim().startsWith("The previous agent process ended before it finished.");
|
|
23627
|
-
const parkedSnapshot = thread.pendingTurnAttachments ?? [];
|
|
23628
23743
|
const parked = takePendingTurnAttachments(thread);
|
|
23629
23744
|
const sentAttachments = !autoContinue && parked.length > 0 ? parked : void 0;
|
|
23630
23745
|
appendMessage(threadId, {
|
|
@@ -23640,7 +23755,7 @@ var init_orchestrator = __esm({
|
|
|
23640
23755
|
thread.worktreePath,
|
|
23641
23756
|
gitPrompt,
|
|
23642
23757
|
{
|
|
23643
|
-
attachments: autoContinue ? [] : sentAttachments ??
|
|
23758
|
+
attachments: autoContinue ? [] : sentAttachments ?? []
|
|
23644
23759
|
}
|
|
23645
23760
|
);
|
|
23646
23761
|
const slackInbound = /^(Slack DM|Slack @mention)(?:\n|$)/.test(
|
|
@@ -23694,10 +23809,7 @@ var init_orchestrator = __esm({
|
|
|
23694
23809
|
expandedPrompt
|
|
23695
23810
|
].filter(Boolean).join("\n\n");
|
|
23696
23811
|
if (!autoContinue && sentAttachments) {
|
|
23697
|
-
updateThread(
|
|
23698
|
-
threadId,
|
|
23699
|
-
parkedSnapshot.length > 0 ? { pendingTurnAttachments: [] } : { attachments: [], pendingTurnAttachments: [] }
|
|
23700
|
-
);
|
|
23812
|
+
updateThread(threadId, { pendingTurnAttachments: [] });
|
|
23701
23813
|
}
|
|
23702
23814
|
const adapter = getAdapter(thread.agent);
|
|
23703
23815
|
const resolved = await adapter.resolveSessionId(thread.worktreePath, thread.sessionId);
|
|
@@ -24177,17 +24289,18 @@ var init_orchestrator = __esm({
|
|
|
24177
24289
|
}
|
|
24178
24290
|
}
|
|
24179
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
|
+
});
|
|
24180
24300
|
const handle = await startDevServer(
|
|
24181
24301
|
thread.repoPath,
|
|
24182
24302
|
thread.worktreePath,
|
|
24183
|
-
|
|
24184
|
-
this.emit({
|
|
24185
|
-
type: "run_output",
|
|
24186
|
-
threadId: thread.id,
|
|
24187
|
-
scriptName: resolvedName,
|
|
24188
|
-
line
|
|
24189
|
-
});
|
|
24190
|
-
},
|
|
24303
|
+
runOutput.push,
|
|
24191
24304
|
{ scriptName: resolvedName }
|
|
24192
24305
|
);
|
|
24193
24306
|
if (!handle) {
|
|
@@ -24233,6 +24346,7 @@ var init_orchestrator = __esm({
|
|
|
24233
24346
|
scriptName: resolvedName
|
|
24234
24347
|
});
|
|
24235
24348
|
void handle.done.then(() => {
|
|
24349
|
+
runOutput.flush();
|
|
24236
24350
|
this.processes.delete(runKey);
|
|
24237
24351
|
if (isDefault) this.processes.delete(worktreeDevProcessKey(thread.worktreePath));
|
|
24238
24352
|
const latest = mergeWorktreeActiveRuns(threadsSharingWorktree(thread.worktreePath));
|
|
@@ -24318,9 +24432,14 @@ var init_orchestrator = __esm({
|
|
|
24318
24432
|
(t) => this.processes.has(`${t.id}:setup`)
|
|
24319
24433
|
);
|
|
24320
24434
|
}
|
|
24321
|
-
|
|
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) {
|
|
24322
24442
|
fn(setupLogKeyForWorktree(worktreePath));
|
|
24323
|
-
fn(threadId);
|
|
24324
24443
|
}
|
|
24325
24444
|
async runSetup(threadRef, opts) {
|
|
24326
24445
|
const thread = this.requireThread(threadRef);
|
|
@@ -24335,14 +24454,18 @@ var init_orchestrator = __esm({
|
|
|
24335
24454
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24336
24455
|
kill: () => abort.abort()
|
|
24337
24456
|
});
|
|
24338
|
-
this.writeSetupLog(thread.
|
|
24457
|
+
this.writeSetupLog(thread.worktreePath, beginSetupLog);
|
|
24339
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
|
+
});
|
|
24340
24463
|
let finished = false;
|
|
24341
24464
|
const finish = (exitCode, source) => {
|
|
24342
24465
|
if (finished) return;
|
|
24343
24466
|
finished = true;
|
|
24467
|
+
output.flush();
|
|
24344
24468
|
this.writeSetupLog(
|
|
24345
|
-
thread.id,
|
|
24346
24469
|
thread.worktreePath,
|
|
24347
24470
|
(logKey) => finishSetupLog(logKey, exitCode, source)
|
|
24348
24471
|
);
|
|
@@ -24352,24 +24475,12 @@ var init_orchestrator = __esm({
|
|
|
24352
24475
|
const setup = await runWorkspaceSetup(
|
|
24353
24476
|
thread.repoPath,
|
|
24354
24477
|
thread.worktreePath,
|
|
24355
|
-
|
|
24356
|
-
this.writeSetupLog(
|
|
24357
|
-
thread.id,
|
|
24358
|
-
thread.worktreePath,
|
|
24359
|
-
(logKey) => appendSetupLog(logKey, line)
|
|
24360
|
-
);
|
|
24361
|
-
this.emit({ type: "setup_output", threadId: thread.id, line });
|
|
24362
|
-
},
|
|
24478
|
+
output.push,
|
|
24363
24479
|
{ signal: abort.signal }
|
|
24364
24480
|
);
|
|
24365
24481
|
if (!setup.ran) {
|
|
24366
24482
|
const line = "No setup script in .sideboard/settings.toml, .conductor/settings.toml, .cursor/worktrees.json, or script/setup (bin/setup, scripts/setup)";
|
|
24367
|
-
|
|
24368
|
-
thread.id,
|
|
24369
|
-
thread.worktreePath,
|
|
24370
|
-
(logKey) => appendSetupLog(logKey, line)
|
|
24371
|
-
);
|
|
24372
|
-
this.emit({ type: "setup_output", threadId: thread.id, line });
|
|
24483
|
+
output.push(line);
|
|
24373
24484
|
finish(null, null);
|
|
24374
24485
|
throw new Error(line);
|
|
24375
24486
|
}
|
|
@@ -24575,6 +24686,11 @@ var init_orchestrator = __esm({
|
|
|
24575
24686
|
lastTurnBase: this.turnBaselines.get(thread.id) ?? null
|
|
24576
24687
|
});
|
|
24577
24688
|
}
|
|
24689
|
+
async worktreeDirtyStat(threadRef) {
|
|
24690
|
+
const thread = this.requireThread(threadRef);
|
|
24691
|
+
this.assertNotGlobal(thread, "Diff");
|
|
24692
|
+
return getWorktreeDirtyStat(thread.worktreePath);
|
|
24693
|
+
}
|
|
24578
24694
|
async diffSummary(threadRef) {
|
|
24579
24695
|
const thread = this.requireThread(threadRef);
|
|
24580
24696
|
this.assertNotGlobal(thread, "Diff");
|
|
@@ -25334,6 +25450,7 @@ __export(index_exports, {
|
|
|
25334
25450
|
LEGACY_DETACHED_JOBS_DIR: () => LEGACY_DETACHED_JOBS_DIR,
|
|
25335
25451
|
LEGACY_PLAN_FILE_REL: () => LEGACY_PLAN_FILE_REL,
|
|
25336
25452
|
LEGACY_REVIEW_REQUEST_PATH: () => LEGACY_REVIEW_REQUEST_PATH,
|
|
25453
|
+
LIGHT_RECONCILE_THROTTLE_MS: () => LIGHT_RECONCILE_THROTTLE_MS,
|
|
25337
25454
|
LINEAR_OAUTH_CANCELLED: () => LINEAR_OAUTH_CANCELLED,
|
|
25338
25455
|
LINEAR_OAUTH_PORT: () => LINEAR_OAUTH_PORT,
|
|
25339
25456
|
LINEAR_OAUTH_REDIRECT: () => LINEAR_OAUTH_REDIRECT,
|
|
@@ -25691,6 +25808,7 @@ __export(index_exports, {
|
|
|
25691
25808
|
getRunScript: () => getRunScript,
|
|
25692
25809
|
getSchedule: () => getSchedule,
|
|
25693
25810
|
getSlackWorkspace: () => getSlackWorkspace,
|
|
25811
|
+
getWorktreeDirtyStat: () => getWorktreeDirtyStat,
|
|
25694
25812
|
gh: () => gh,
|
|
25695
25813
|
ghHeadRef: () => ghHeadRef,
|
|
25696
25814
|
ghRepoSelectArgs: () => ghRepoSelectArgs,
|
|
@@ -25768,6 +25886,7 @@ __export(index_exports, {
|
|
|
25768
25886
|
isPrNotMergeableError: () => isPrNotMergeableError,
|
|
25769
25887
|
isPresentPlanToolName: () => isPresentPlanToolName,
|
|
25770
25888
|
isPrimaryCheckoutThread: () => isPrimaryCheckoutThread,
|
|
25889
|
+
isSelfWrittenRecord: () => isSelfWrittenRecord,
|
|
25771
25890
|
isSessionQuotaLimit: () => isSessionQuotaLimit,
|
|
25772
25891
|
isSetupLastError: () => isSetupLastError,
|
|
25773
25892
|
isShellToolName: () => isShellToolName,
|
|
@@ -34120,6 +34239,7 @@ init_outbound_watch();
|
|
|
34120
34239
|
LEGACY_DETACHED_JOBS_DIR,
|
|
34121
34240
|
LEGACY_PLAN_FILE_REL,
|
|
34122
34241
|
LEGACY_REVIEW_REQUEST_PATH,
|
|
34242
|
+
LIGHT_RECONCILE_THROTTLE_MS,
|
|
34123
34243
|
LINEAR_OAUTH_CANCELLED,
|
|
34124
34244
|
LINEAR_OAUTH_PORT,
|
|
34125
34245
|
LINEAR_OAUTH_REDIRECT,
|
|
@@ -34477,6 +34597,7 @@ init_outbound_watch();
|
|
|
34477
34597
|
getRunScript,
|
|
34478
34598
|
getSchedule,
|
|
34479
34599
|
getSlackWorkspace,
|
|
34600
|
+
getWorktreeDirtyStat,
|
|
34480
34601
|
gh,
|
|
34481
34602
|
ghHeadRef,
|
|
34482
34603
|
ghRepoSelectArgs,
|
|
@@ -34554,6 +34675,7 @@ init_outbound_watch();
|
|
|
34554
34675
|
isPrNotMergeableError,
|
|
34555
34676
|
isPresentPlanToolName,
|
|
34556
34677
|
isPrimaryCheckoutThread,
|
|
34678
|
+
isSelfWrittenRecord,
|
|
34557
34679
|
isSessionQuotaLimit,
|
|
34558
34680
|
isSetupLastError,
|
|
34559
34681
|
isShellToolName,
|