@sideboard-ai/core 0.1.157 → 0.1.159
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/{abletime-BEIDJG7W.js → abletime-HOQBDQC4.js} +2 -2
- package/dist/{abletime-GWZE6OYM.js → abletime-LK7GV556.js} +2 -2
- package/dist/{agents-LCDXN2B2.js → agents-5HY76BCR.js} +4 -4
- package/dist/{agents-C55LAEUR.js → agents-67ZBH5OE.js} +5 -5
- package/dist/{app-settings-VRQI3FIE.js → app-settings-BJ5GFAE5.js} +13 -17
- package/dist/{app-settings-H3INSR67.js → app-settings-YWJ4MVYM.js} +13 -17
- package/dist/{chunk-NVXVEGGM.js → chunk-5U4NZLBH.js} +4 -0
- package/dist/{chunk-DVJBO3M7.js → chunk-AGLPYXDT.js} +1 -1
- package/dist/{chunk-KQ4JOGUH.js → chunk-DWUOKF3W.js} +11 -5
- package/dist/{chunk-D7EGJ3EI.js → chunk-EQIJ5MHR.js} +119 -110
- package/dist/{chunk-3BWVOUQG.js → chunk-FLG4A5FJ.js} +119 -110
- package/dist/{chunk-2SDMENAL.js → chunk-JV4VNFMS.js} +1 -1
- package/dist/{chunk-LQMFCS54.js → chunk-KEDHHXKW.js} +3 -13
- package/dist/{chunk-CJQLPPEJ.js → chunk-MEZXWELT.js} +4 -14
- package/dist/{chunk-CVR4RJ6G.js → chunk-O7RWWPMR.js} +12 -13
- package/dist/{chunk-GWEEGE6L.js → chunk-OYOXLY6B.js} +404 -115
- package/dist/{chunk-4I4VKAPZ.js → chunk-SIMFKJIB.js} +13 -14
- package/dist/{chunk-SUCJAWV4.js → chunk-TGU3LSDG.js} +402 -113
- package/dist/{chunk-N27GVFZY.js → chunk-UBMCEZRE.js} +1 -1
- package/dist/{chunk-TIJ6QVX5.js → chunk-V4R6L2ZL.js} +15 -6
- package/dist/{coordinator-prompt-AM47SATF.js → coordinator-prompt-7NKY7QRK.js} +4 -4
- package/dist/{coordinator-prompt-26IJU2AV.js → coordinator-prompt-CNI6AK65.js} +3 -3
- package/dist/{global-workspace-QV7CC7SK.js → global-workspace-FKAJZHO5.js} +4 -4
- package/dist/{global-workspace-5BIW26YR.js → global-workspace-IJYCUO4M.js} +3 -3
- package/dist/index.cjs +1037 -648
- package/dist/index.d.cts +71 -57
- package/dist/index.d.ts +71 -57
- package/dist/index.js +339 -250
- package/dist/mcp/run-stdio.cjs +967 -575
- package/dist/mcp/run-stdio.js +283 -187
- package/dist/{orchestrator-BUH3LJLL.js → orchestrator-KFLS5BTP.js} +5 -5
- package/dist/{orchestrator-KQO4MXBI.js → orchestrator-NSVP7DJH.js} +7 -7
- package/dist/{plan-file-OZEBFSGQ.js → plan-file-I24VJVP2.js} +2 -2
- package/dist/{workspaces-NYSM2EPX.js → workspaces-D2M3AM2M.js} +3 -3
- package/dist/{workspaces-Q2VCHIAS.js → workspaces-OFSDJ7PZ.js} +4 -4
- package/dist/{worktree-PEWDAX5O.js → worktree-BQE5KLRY.js} +3 -3
- package/dist/{worktree-T4SWFSTT.js → worktree-EA6AD6D6.js} +2 -2
- package/package.json +1 -1
|
@@ -33,12 +33,12 @@ import {
|
|
|
33
33
|
summarizeTurnStderr,
|
|
34
34
|
toolDescription,
|
|
35
35
|
turnFailChatText
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-DWUOKF3W.js";
|
|
37
37
|
import {
|
|
38
38
|
extractPresentedPlan,
|
|
39
39
|
readPlanFile,
|
|
40
40
|
writePlanFile
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-JV4VNFMS.js";
|
|
42
42
|
import {
|
|
43
43
|
releaseCaffeinateHoldForThread
|
|
44
44
|
} from "./chunk-OCQPTUR7.js";
|
|
@@ -67,7 +67,7 @@ import {
|
|
|
67
67
|
stageAbsolutePathsAsAttachments,
|
|
68
68
|
stageBuffersAsAttachments,
|
|
69
69
|
syncWorkspacesFromThreads
|
|
70
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-SIMFKJIB.js";
|
|
71
71
|
import {
|
|
72
72
|
addPrStackLayer,
|
|
73
73
|
allocateTeamName,
|
|
@@ -115,11 +115,13 @@ import {
|
|
|
115
115
|
withRepoGitLock,
|
|
116
116
|
worktreeDisplayLabelForGroup,
|
|
117
117
|
worktreeNameFromPath
|
|
118
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-MEZXWELT.js";
|
|
119
119
|
import {
|
|
120
120
|
ATTACHMENTS_DIR,
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
DETACHED_JOBS_DIR,
|
|
122
|
+
LEGACY_ATTACHMENTS_DIR,
|
|
123
|
+
LEGACY_DETACHED_JOBS_DIR
|
|
124
|
+
} from "./chunk-5U4NZLBH.js";
|
|
123
125
|
import {
|
|
124
126
|
appendMessage,
|
|
125
127
|
createEmptyThread,
|
|
@@ -145,6 +147,8 @@ import {
|
|
|
145
147
|
} from "./chunk-FNQNJOHY.js";
|
|
146
148
|
import {
|
|
147
149
|
childEnvWithAppSettings,
|
|
150
|
+
formatViewerContextDirective,
|
|
151
|
+
formatViewerContextReminder,
|
|
148
152
|
getIssueSource,
|
|
149
153
|
isAbleTimeConnected,
|
|
150
154
|
isLinearConnected,
|
|
@@ -157,10 +161,11 @@ import {
|
|
|
157
161
|
resolveNewThreadOptions,
|
|
158
162
|
resolveThreadDefaults,
|
|
159
163
|
resolveVaultKey,
|
|
164
|
+
resolveViewerProfileForRepo,
|
|
160
165
|
stripNestedElectronEnv,
|
|
161
166
|
updateAdvancedSettings,
|
|
162
167
|
writeSecureJson
|
|
163
|
-
} from "./chunk-
|
|
168
|
+
} from "./chunk-EQIJ5MHR.js";
|
|
164
169
|
import {
|
|
165
170
|
writePrivateFile
|
|
166
171
|
} from "./chunk-NSTQ6QKD.js";
|
|
@@ -394,7 +399,7 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
394
399
|
await continueOnReply(threadId, prompt);
|
|
395
400
|
return;
|
|
396
401
|
}
|
|
397
|
-
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-
|
|
402
|
+
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-NSVP7DJH.js");
|
|
398
403
|
await getOrchestrator2().send(threadId, prompt);
|
|
399
404
|
} catch {
|
|
400
405
|
}
|
|
@@ -654,7 +659,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
654
659
|
}
|
|
655
660
|
|
|
656
661
|
// src/orchestrator/orchestrator.ts
|
|
657
|
-
import { existsSync as
|
|
662
|
+
import { existsSync as existsSync18 } from "fs";
|
|
658
663
|
|
|
659
664
|
// src/agents/spawn.ts
|
|
660
665
|
import { createInterface } from "readline";
|
|
@@ -735,9 +740,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
735
740
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
736
741
|
);
|
|
737
742
|
}
|
|
738
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
743
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-FKAJZHO5.js");
|
|
739
744
|
if (isGlobalThread2(thread)) {
|
|
740
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
745
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-7NKY7QRK.js");
|
|
741
746
|
ensureGlobalCoordinatorCwd2(
|
|
742
747
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
743
748
|
);
|
|
@@ -2479,8 +2484,232 @@ function notifyParentOfChildHalt(child, status, send) {
|
|
|
2479
2484
|
return true;
|
|
2480
2485
|
}
|
|
2481
2486
|
|
|
2487
|
+
// src/mcp/wait-for-job.ts
|
|
2488
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readdirSync as readdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
2489
|
+
import { dirname as dirname3, join as join10 } from "path";
|
|
2490
|
+
|
|
2491
|
+
// src/mcp/wait-for-turn.ts
|
|
2492
|
+
var MCP_WAIT_FOR_TURN_MAX_MS = 45e3;
|
|
2493
|
+
function mcpWaitForTurnTimeoutMs(requested) {
|
|
2494
|
+
const n = requested ?? MCP_WAIT_FOR_TURN_MAX_MS;
|
|
2495
|
+
if (!Number.isFinite(n)) return MCP_WAIT_FOR_TURN_MAX_MS;
|
|
2496
|
+
return Math.min(Math.max(1e3, Math.floor(n)), MCP_WAIT_FOR_TURN_MAX_MS);
|
|
2497
|
+
}
|
|
2498
|
+
var MCP_WAIT_STILL_RUNNING_HINT = "Child is still working. Call wait_for_turn again. Do not send a check-in prompt or assume a hang while progress is updating.";
|
|
2499
|
+
var MCP_WAIT_QUEUED_HINT = "Child is queued waiting for a concurrency slot \u2014 it has not started yet. Call wait_for_turn again. Do not send a check-in prompt, force_stop, or assume it failed to start.";
|
|
2500
|
+
function mcpWaitStillRunningHint(status) {
|
|
2501
|
+
return status === "queued" ? MCP_WAIT_QUEUED_HINT : MCP_WAIT_STILL_RUNNING_HINT;
|
|
2502
|
+
}
|
|
2503
|
+
var MCP_WAIT_STOPPED_HINT = "Child was stopped before the turn finished. Do not treat this as success. send_to_thread to resume, or tell the user.";
|
|
2504
|
+
var MCP_WAIT_BROKEN_HINT = "Child worktree is broken (missing on disk). Tell the user \u2014 do not treat this as success.";
|
|
2505
|
+
var MCP_WAIT_ERROR_HINT = "Child turn failed. lastError/text is the failure \u2014 switch agent, tell the user, or retry. Do not treat empty text as success.";
|
|
2506
|
+
function mcpWaitFinishedHint(status) {
|
|
2507
|
+
if (status === "stopped") return MCP_WAIT_STOPPED_HINT;
|
|
2508
|
+
if (status === "broken") return MCP_WAIT_BROKEN_HINT;
|
|
2509
|
+
if (status === "error") return MCP_WAIT_ERROR_HINT;
|
|
2510
|
+
return void 0;
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
// src/mcp/wait-for-job.ts
|
|
2514
|
+
var MAX_JOB_CONTINUES = 8;
|
|
2515
|
+
var MCP_WAIT_JOB_STILL_RUNNING_HINT = "Job is still running. present_artifact type=log with the same artifact_id and content=delta (new lines only). Then call wait_for_job again. Do not end the turn or tell the user you will let them know later.";
|
|
2516
|
+
var JOB_ID_RE = /^[a-zA-Z0-9._-]{1,64}$/;
|
|
2517
|
+
function mcpWaitForJobTimeoutMs(requested) {
|
|
2518
|
+
return mcpWaitForTurnTimeoutMs(requested);
|
|
2519
|
+
}
|
|
2520
|
+
function sanitizeDetachedJobId(id) {
|
|
2521
|
+
const s = id.trim();
|
|
2522
|
+
if (!JOB_ID_RE.test(s)) {
|
|
2523
|
+
throw new Error(`detached-job id must be 1\u201364 chars [A-Za-z0-9._-], got ${JSON.stringify(id)}`);
|
|
2524
|
+
}
|
|
2525
|
+
return s;
|
|
2526
|
+
}
|
|
2527
|
+
function jobAlive(pid) {
|
|
2528
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
2529
|
+
try {
|
|
2530
|
+
process.kill(pid, 0);
|
|
2531
|
+
return true;
|
|
2532
|
+
} catch {
|
|
2533
|
+
return false;
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
function readIntFile(file) {
|
|
2537
|
+
if (!existsSync8(file)) return null;
|
|
2538
|
+
const n = Number.parseInt(readFileSync7(file, "utf8").trim(), 10);
|
|
2539
|
+
return Number.isInteger(n) ? n : null;
|
|
2540
|
+
}
|
|
2541
|
+
function jobDir(root, id, legacy = false) {
|
|
2542
|
+
return join10(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
|
|
2543
|
+
}
|
|
2544
|
+
function resolveJobDir(root, id) {
|
|
2545
|
+
const modern = jobDir(root, id, false);
|
|
2546
|
+
if (existsSync8(modern)) return modern;
|
|
2547
|
+
const legacy = jobDir(root, id, true);
|
|
2548
|
+
if (existsSync8(legacy)) return legacy;
|
|
2549
|
+
return modern;
|
|
2550
|
+
}
|
|
2551
|
+
function listJobIdsIn(root, rel) {
|
|
2552
|
+
const dir = join10(root, rel);
|
|
2553
|
+
if (!existsSync8(dir)) return [];
|
|
2554
|
+
return readdirSync3(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && JOB_ID_RE.test(e.name)).map((e) => e.name);
|
|
2555
|
+
}
|
|
2556
|
+
function listRunningDetachedJobs(worktreePath) {
|
|
2557
|
+
const root = worktreePath.trim();
|
|
2558
|
+
if (!root) return [];
|
|
2559
|
+
const ids = /* @__PURE__ */ new Set([
|
|
2560
|
+
...listJobIdsIn(root, DETACHED_JOBS_DIR),
|
|
2561
|
+
...listJobIdsIn(root, LEGACY_DETACHED_JOBS_DIR)
|
|
2562
|
+
]);
|
|
2563
|
+
const running = [];
|
|
2564
|
+
for (const id of ids) {
|
|
2565
|
+
const dir = resolveJobDir(root, id);
|
|
2566
|
+
const pid = readIntFile(join10(dir, "pid"));
|
|
2567
|
+
if (pid != null && jobAlive(pid)) running.push(id);
|
|
2568
|
+
}
|
|
2569
|
+
return running.sort();
|
|
2570
|
+
}
|
|
2571
|
+
function looksLikeDeferredDonePromise(text) {
|
|
2572
|
+
const t = (text ?? "").trim();
|
|
2573
|
+
if (!t) return false;
|
|
2574
|
+
return /\b(i['’]?ll|i will)\s+let you know\b/i.test(t) || /\blet you know when\b/i.test(t) || /\b(check back|ping me)\s+when\b/i.test(t) || /\bi(?:['’]ll| will)\s+(report|update you)\s+when\b/i.test(t);
|
|
2575
|
+
}
|
|
2576
|
+
function formatJobStillRunningContinuePrompt(jobIds) {
|
|
2577
|
+
const ids = jobIds.join(", ");
|
|
2578
|
+
return [
|
|
2579
|
+
`Detached job still running: ${ids}.`,
|
|
2580
|
+
"Do not end this turn. Loop wait_for_job (same id) and present_artifact type=log with content=delta until stillRunning is false.",
|
|
2581
|
+
"Then report the result. Do not tell the user you will let them know later."
|
|
2582
|
+
].join(" ");
|
|
2583
|
+
}
|
|
2584
|
+
function formatDeferredDoneContinuePrompt() {
|
|
2585
|
+
return [
|
|
2586
|
+
"You ended the turn after promising to report later, but no detached job is running.",
|
|
2587
|
+
"If tests/pack/deploy still need to run: start once with detached-job.js, present_artifact type=log, then loop wait_for_job until stillRunning is false.",
|
|
2588
|
+
"Do not say you will let the user know later."
|
|
2589
|
+
].join(" ");
|
|
2590
|
+
}
|
|
2591
|
+
function turnWatchedDetachedJob(parts) {
|
|
2592
|
+
return parts.some((p) => {
|
|
2593
|
+
if (p.type !== "tool") return false;
|
|
2594
|
+
if (/wait_for_job$/i.test(p.name ?? "")) return true;
|
|
2595
|
+
const blob = [p.name, p.detail, p.description, p.input ? JSON.stringify(p.input) : ""].filter(Boolean).join(" ");
|
|
2596
|
+
return /detached-job\.js\b/i.test(blob);
|
|
2597
|
+
});
|
|
2598
|
+
}
|
|
2599
|
+
function planJobContinue(opts) {
|
|
2600
|
+
if (opts.isOrchestrator) return { action: "none" };
|
|
2601
|
+
if (opts.agent === "brightsy") return { action: "none" };
|
|
2602
|
+
if (opts.queueLength > 0) return { action: "none" };
|
|
2603
|
+
if (opts.continueCount >= MAX_JOB_CONTINUES) return { action: "none" };
|
|
2604
|
+
const farewell = looksLikeDeferredDonePromise(opts.chatText);
|
|
2605
|
+
if (opts.runningJobIds.length > 0 && (farewell || opts.watchedJob)) {
|
|
2606
|
+
return {
|
|
2607
|
+
action: "wait",
|
|
2608
|
+
jobIds: opts.runningJobIds,
|
|
2609
|
+
prompt: formatJobStillRunningContinuePrompt(opts.runningJobIds)
|
|
2610
|
+
};
|
|
2611
|
+
}
|
|
2612
|
+
if (looksLikeDeferredDonePromise(opts.chatText) && !opts.alreadyNudged) {
|
|
2613
|
+
return { action: "nudge", prompt: formatDeferredDoneContinuePrompt() };
|
|
2614
|
+
}
|
|
2615
|
+
return { action: "none" };
|
|
2616
|
+
}
|
|
2617
|
+
function tailProgress(logFile, maxLines = 12) {
|
|
2618
|
+
if (!existsSync8(logFile)) return "(no log yet)";
|
|
2619
|
+
const lines = readFileSync7(logFile, "utf8").split("\n");
|
|
2620
|
+
return lines.slice(-maxLines).join("\n");
|
|
2621
|
+
}
|
|
2622
|
+
function readLogLines(file) {
|
|
2623
|
+
if (!existsSync8(file)) return [];
|
|
2624
|
+
const lines = readFileSync7(file, "utf8").split("\n");
|
|
2625
|
+
if (lines.length && lines[lines.length - 1] === "") lines.pop();
|
|
2626
|
+
return lines;
|
|
2627
|
+
}
|
|
2628
|
+
function takeDelta(logFile, cursorFile) {
|
|
2629
|
+
const lines = readLogLines(logFile);
|
|
2630
|
+
const cursor = readIntFile(cursorFile) ?? 0;
|
|
2631
|
+
const start = Math.min(Math.max(0, cursor), lines.length);
|
|
2632
|
+
return { delta: lines.slice(start).join("\n"), nextCursor: lines.length };
|
|
2633
|
+
}
|
|
2634
|
+
function snapshotJob(dir) {
|
|
2635
|
+
const pid = readIntFile(join10(dir, "pid"));
|
|
2636
|
+
const running = pid != null && jobAlive(pid);
|
|
2637
|
+
return {
|
|
2638
|
+
pid,
|
|
2639
|
+
running,
|
|
2640
|
+
exitCode: readIntFile(join10(dir, "exit")),
|
|
2641
|
+
log: join10(dir, "log"),
|
|
2642
|
+
cursor: join10(dir, "present.cursor"),
|
|
2643
|
+
progress: tailProgress(join10(dir, "log"))
|
|
2644
|
+
};
|
|
2645
|
+
}
|
|
2646
|
+
function toResult(id, snap, extra) {
|
|
2647
|
+
const failed = extra?.failed === true || !snap.running && snap.exitCode != null && snap.exitCode !== 0;
|
|
2648
|
+
const ok = !snap.running && snap.exitCode === 0;
|
|
2649
|
+
const stillRunning = snap.running && !ok;
|
|
2650
|
+
const { delta, nextCursor } = takeDelta(snap.log, snap.cursor);
|
|
2651
|
+
try {
|
|
2652
|
+
mkdirSync3(dirname3(snap.cursor), { recursive: true });
|
|
2653
|
+
writeFileSync4(snap.cursor, `${nextCursor}
|
|
2654
|
+
`);
|
|
2655
|
+
} catch {
|
|
2656
|
+
}
|
|
2657
|
+
const status = ok ? "ok" : failed && !stillRunning ? "failed" : stillRunning ? "running" : "idle";
|
|
2658
|
+
return {
|
|
2659
|
+
stillRunning,
|
|
2660
|
+
ok,
|
|
2661
|
+
failed: Boolean(failed && !stillRunning && !ok),
|
|
2662
|
+
status,
|
|
2663
|
+
id,
|
|
2664
|
+
pid: snap.pid,
|
|
2665
|
+
exitCode: snap.exitCode ?? void 0,
|
|
2666
|
+
delta,
|
|
2667
|
+
progress: extra?.progress ?? snap.progress,
|
|
2668
|
+
hint: stillRunning ? MCP_WAIT_JOB_STILL_RUNNING_HINT : void 0
|
|
2669
|
+
};
|
|
2670
|
+
}
|
|
2671
|
+
async function sleepMs(ms) {
|
|
2672
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
2673
|
+
}
|
|
2674
|
+
async function waitForDetachedJob(cwd, id, opts) {
|
|
2675
|
+
const jobId = sanitizeDetachedJobId(id);
|
|
2676
|
+
const root = cwd.trim() || process.cwd();
|
|
2677
|
+
const dir = resolveJobDir(root, jobId);
|
|
2678
|
+
const timeoutMs = mcpWaitForJobTimeoutMs(opts?.timeoutMs);
|
|
2679
|
+
const sleep = opts?.sleep ?? sleepMs;
|
|
2680
|
+
if (!existsSync8(dir)) {
|
|
2681
|
+
return {
|
|
2682
|
+
stillRunning: false,
|
|
2683
|
+
ok: false,
|
|
2684
|
+
failed: true,
|
|
2685
|
+
status: "failed",
|
|
2686
|
+
id: jobId,
|
|
2687
|
+
delta: "",
|
|
2688
|
+
progress: "No detached job. Start one first.",
|
|
2689
|
+
hint: "Start with detached-job.js start <id> -- <command>, then call wait_for_job again."
|
|
2690
|
+
};
|
|
2691
|
+
}
|
|
2692
|
+
const deadline = Date.now() + timeoutMs;
|
|
2693
|
+
let snap = snapshotJob(dir);
|
|
2694
|
+
if (snap.exitCode === 0 && !snap.running) return toResult(jobId, snap);
|
|
2695
|
+
if (!snap.running && snap.pid == null && snap.progress === "(no log yet)") {
|
|
2696
|
+
return toResult(jobId, snap, {
|
|
2697
|
+
failed: true,
|
|
2698
|
+
progress: "No detached job. Start one first."
|
|
2699
|
+
});
|
|
2700
|
+
}
|
|
2701
|
+
while (Date.now() < deadline) {
|
|
2702
|
+
snap = snapshotJob(dir);
|
|
2703
|
+
if (snap.exitCode === 0 && !snap.running) return toResult(jobId, snap);
|
|
2704
|
+
if (!snap.running) return toResult(jobId, snap, { failed: true });
|
|
2705
|
+
await sleep(Math.min(2e3, Math.max(50, deadline - Date.now())));
|
|
2706
|
+
}
|
|
2707
|
+
snap = snapshotJob(dir);
|
|
2708
|
+
return toResult(jobId, snap);
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2482
2711
|
// src/threads/create.ts
|
|
2483
|
-
import { existsSync as
|
|
2712
|
+
import { existsSync as existsSync9 } from "fs";
|
|
2484
2713
|
|
|
2485
2714
|
// src/detect/detect.ts
|
|
2486
2715
|
var REQUIRE_AGENT_TIMEOUT_MS = 8e3;
|
|
@@ -3000,7 +3229,7 @@ function reuseLiveThread(input, repoPath, match) {
|
|
|
3000
3229
|
}
|
|
3001
3230
|
async function createThread(input, _onSetupLine) {
|
|
3002
3231
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
3003
|
-
if (!
|
|
3232
|
+
if (!existsSync9(repoPath)) {
|
|
3004
3233
|
throw new Error(`Repo not found: ${repoPath}`);
|
|
3005
3234
|
}
|
|
3006
3235
|
const reused = reuseLiveThread(input, repoPath, {
|
|
@@ -3017,7 +3246,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3017
3246
|
});
|
|
3018
3247
|
await requireAgent(resolved.agent);
|
|
3019
3248
|
if (input.cowboy) {
|
|
3020
|
-
const { cowboyModeEnabled } = await import("./app-settings-
|
|
3249
|
+
const { cowboyModeEnabled } = await import("./app-settings-BJ5GFAE5.js");
|
|
3021
3250
|
if (!cowboyModeEnabled()) {
|
|
3022
3251
|
throw new Error(
|
|
3023
3252
|
"Cowboy mode is off. Enable it in Settings \u2192 Advanced."
|
|
@@ -3075,7 +3304,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3075
3304
|
let sourceIsFork = false;
|
|
3076
3305
|
if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
|
|
3077
3306
|
if (isAbleTimeConnected() && getIssueSource() === "abletime") {
|
|
3078
|
-
const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-
|
|
3307
|
+
const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-HOQBDQC4.js");
|
|
3079
3308
|
const task = await ensureAbleTimeTask({
|
|
3080
3309
|
title: title?.trim() || "Untitled work",
|
|
3081
3310
|
description: input.prompt?.trim() || void 0
|
|
@@ -3186,11 +3415,11 @@ function shouldRemoveWorktreeOnTeardown(thread) {
|
|
|
3186
3415
|
|
|
3187
3416
|
// src/store/turn-live.ts
|
|
3188
3417
|
import {
|
|
3189
|
-
existsSync as
|
|
3418
|
+
existsSync as existsSync10,
|
|
3190
3419
|
renameSync,
|
|
3191
3420
|
unlinkSync as unlinkSync2,
|
|
3192
|
-
writeFileSync as
|
|
3193
|
-
readFileSync as
|
|
3421
|
+
writeFileSync as writeFileSync5,
|
|
3422
|
+
readFileSync as readFileSync8
|
|
3194
3423
|
} from "fs";
|
|
3195
3424
|
var buffers = /* @__PURE__ */ new Map();
|
|
3196
3425
|
var FLUSH_MS = 800;
|
|
@@ -3267,7 +3496,7 @@ function writeTurnLive(threadId, progress) {
|
|
|
3267
3496
|
const path = threadLivePath(threadId);
|
|
3268
3497
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
3269
3498
|
try {
|
|
3270
|
-
|
|
3499
|
+
writeFileSync5(tmp, JSON.stringify(progress), "utf8");
|
|
3271
3500
|
renameSync(tmp, path);
|
|
3272
3501
|
} catch {
|
|
3273
3502
|
try {
|
|
@@ -3278,9 +3507,9 @@ function writeTurnLive(threadId, progress) {
|
|
|
3278
3507
|
}
|
|
3279
3508
|
function readTurnLive(threadId) {
|
|
3280
3509
|
const path = threadLivePath(threadId);
|
|
3281
|
-
if (!
|
|
3510
|
+
if (!existsSync10(path)) return null;
|
|
3282
3511
|
try {
|
|
3283
|
-
const raw = JSON.parse(
|
|
3512
|
+
const raw = JSON.parse(readFileSync8(path, "utf8"));
|
|
3284
3513
|
if (!raw || typeof raw.summary !== "string") return null;
|
|
3285
3514
|
return raw;
|
|
3286
3515
|
} catch {
|
|
@@ -3292,7 +3521,7 @@ function clearTurnLive(threadId) {
|
|
|
3292
3521
|
if (buf?.timer) clearTimeout(buf.timer);
|
|
3293
3522
|
buffers.delete(threadId);
|
|
3294
3523
|
const path = threadLivePath(threadId);
|
|
3295
|
-
if (!
|
|
3524
|
+
if (!existsSync10(path)) return;
|
|
3296
3525
|
try {
|
|
3297
3526
|
unlinkSync2(path);
|
|
3298
3527
|
} catch {
|
|
@@ -3477,26 +3706,26 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
|
|
|
3477
3706
|
import { execFileSync } from "child_process";
|
|
3478
3707
|
import {
|
|
3479
3708
|
copyFileSync as copyFileSync2,
|
|
3480
|
-
existsSync as
|
|
3709
|
+
existsSync as existsSync11,
|
|
3481
3710
|
mkdtempSync,
|
|
3482
|
-
readdirSync as
|
|
3483
|
-
readFileSync as
|
|
3711
|
+
readdirSync as readdirSync4,
|
|
3712
|
+
readFileSync as readFileSync9,
|
|
3484
3713
|
rmSync
|
|
3485
3714
|
} from "fs";
|
|
3486
3715
|
import { tmpdir } from "os";
|
|
3487
|
-
import { join as
|
|
3716
|
+
import { join as join11 } from "path";
|
|
3488
3717
|
import { createRequire } from "module";
|
|
3489
|
-
var CONDUCTOR_APP_SUPPORT =
|
|
3718
|
+
var CONDUCTOR_APP_SUPPORT = join11(
|
|
3490
3719
|
process.env.HOME ?? "",
|
|
3491
3720
|
"Library",
|
|
3492
3721
|
"Application Support",
|
|
3493
3722
|
"com.conductor.app"
|
|
3494
3723
|
);
|
|
3495
|
-
var CONDUCTOR_DB =
|
|
3496
|
-
var CURSOR_SDK_STORE =
|
|
3724
|
+
var CONDUCTOR_DB = join11(CONDUCTOR_APP_SUPPORT, "conductor.db");
|
|
3725
|
+
var CURSOR_SDK_STORE = join11(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
|
|
3497
3726
|
function thisModuleFile() {
|
|
3498
3727
|
const cjsFile = typeof __filename !== "undefined" ? __filename : "";
|
|
3499
|
-
return cjsFile || process.argv[1] ||
|
|
3728
|
+
return cjsFile || process.argv[1] || join11(process.cwd(), "package.json");
|
|
3500
3729
|
}
|
|
3501
3730
|
function openReadonlySqlite(file) {
|
|
3502
3731
|
const req = createRequire(thisModuleFile());
|
|
@@ -3514,21 +3743,21 @@ function mapAgentType(raw) {
|
|
|
3514
3743
|
return null;
|
|
3515
3744
|
}
|
|
3516
3745
|
function resolveConductorCursorAgentId(workspacePath) {
|
|
3517
|
-
if (!workspacePath || !
|
|
3746
|
+
if (!workspacePath || !existsSync11(CURSOR_SDK_STORE)) return null;
|
|
3518
3747
|
const normalized = workspacePath.replace(/\/$/, "");
|
|
3519
3748
|
let best = null;
|
|
3520
3749
|
let hashes;
|
|
3521
3750
|
try {
|
|
3522
|
-
hashes =
|
|
3751
|
+
hashes = readdirSync4(CURSOR_SDK_STORE);
|
|
3523
3752
|
} catch {
|
|
3524
3753
|
return null;
|
|
3525
3754
|
}
|
|
3526
3755
|
for (const hash of hashes) {
|
|
3527
|
-
const agentsFile =
|
|
3528
|
-
if (!
|
|
3756
|
+
const agentsFile = join11(CURSOR_SDK_STORE, hash, "agents.ndjson");
|
|
3757
|
+
if (!existsSync11(agentsFile)) continue;
|
|
3529
3758
|
let text;
|
|
3530
3759
|
try {
|
|
3531
|
-
text =
|
|
3760
|
+
text = readFileSync9(agentsFile, "utf8");
|
|
3532
3761
|
} catch {
|
|
3533
3762
|
continue;
|
|
3534
3763
|
}
|
|
@@ -3552,7 +3781,7 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
3552
3781
|
return best?.agentId ?? null;
|
|
3553
3782
|
}
|
|
3554
3783
|
async function adoptThread(input) {
|
|
3555
|
-
if (!
|
|
3784
|
+
if (!existsSync11(input.worktreePath)) {
|
|
3556
3785
|
throw new Error(`Worktree not found: ${input.worktreePath}`);
|
|
3557
3786
|
}
|
|
3558
3787
|
const repoPath = await resolveRepoRoot(input.worktreePath);
|
|
@@ -3571,23 +3800,23 @@ async function adoptThread(input) {
|
|
|
3571
3800
|
messages: input.messages ?? []
|
|
3572
3801
|
});
|
|
3573
3802
|
writeThread(thread);
|
|
3574
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
3803
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-OFSDJ7PZ.js");
|
|
3575
3804
|
await ensureWorkspace2(repoPath);
|
|
3576
3805
|
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-N5X5I422.js");
|
|
3577
3806
|
await ensureWorktreeSideboardIgnored2(input.worktreePath);
|
|
3578
3807
|
return thread;
|
|
3579
3808
|
}
|
|
3580
3809
|
function listConductorWorkspaces() {
|
|
3581
|
-
if (!
|
|
3810
|
+
if (!existsSync11(CONDUCTOR_DB)) {
|
|
3582
3811
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
3583
3812
|
}
|
|
3584
|
-
const tmp = mkdtempSync(
|
|
3585
|
-
const snapshot =
|
|
3813
|
+
const tmp = mkdtempSync(join11(tmpdir(), "sideboard-conductor-"));
|
|
3814
|
+
const snapshot = join11(tmp, "conductor.db");
|
|
3586
3815
|
try {
|
|
3587
3816
|
copyFileSync2(CONDUCTOR_DB, snapshot);
|
|
3588
3817
|
for (const suffix of ["-wal", "-shm"]) {
|
|
3589
3818
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
3590
|
-
if (
|
|
3819
|
+
if (existsSync11(src)) {
|
|
3591
3820
|
try {
|
|
3592
3821
|
copyFileSync2(src, `${snapshot}${suffix}`);
|
|
3593
3822
|
} catch {
|
|
@@ -3669,16 +3898,16 @@ function listConductorWorkspaces() {
|
|
|
3669
3898
|
}
|
|
3670
3899
|
}
|
|
3671
3900
|
function importConductorWorkspace(workspaceId) {
|
|
3672
|
-
if (!
|
|
3901
|
+
if (!existsSync11(CONDUCTOR_DB)) {
|
|
3673
3902
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
3674
3903
|
}
|
|
3675
|
-
const tmp = mkdtempSync(
|
|
3676
|
-
const snapshot =
|
|
3904
|
+
const tmp = mkdtempSync(join11(tmpdir(), "sideboard-conductor-"));
|
|
3905
|
+
const snapshot = join11(tmp, "conductor.db");
|
|
3677
3906
|
try {
|
|
3678
3907
|
copyFileSync2(CONDUCTOR_DB, snapshot);
|
|
3679
3908
|
for (const suffix of ["-wal", "-shm"]) {
|
|
3680
3909
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
3681
|
-
if (
|
|
3910
|
+
if (existsSync11(src)) {
|
|
3682
3911
|
try {
|
|
3683
3912
|
copyFileSync2(src, `${snapshot}${suffix}`);
|
|
3684
3913
|
} catch {
|
|
@@ -3698,7 +3927,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
3698
3927
|
).get(workspaceId);
|
|
3699
3928
|
if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
|
|
3700
3929
|
const worktreePath = String(row.workspacePath);
|
|
3701
|
-
if (!
|
|
3930
|
+
if (!existsSync11(worktreePath)) {
|
|
3702
3931
|
throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
|
|
3703
3932
|
}
|
|
3704
3933
|
let sessionId = null;
|
|
@@ -3769,7 +3998,7 @@ async function importConductorWorkspaceAsync(workspaceId) {
|
|
|
3769
3998
|
}
|
|
3770
3999
|
|
|
3771
4000
|
// src/threads/stack-layers.ts
|
|
3772
|
-
import { existsSync as
|
|
4001
|
+
import { existsSync as existsSync12 } from "fs";
|
|
3773
4002
|
function stackIdFrom(stack) {
|
|
3774
4003
|
if (stack.stackNumber != null) return `gh-stack-${stack.stackNumber}`;
|
|
3775
4004
|
const key = stack.layers.map((l) => l.branchName).join("|");
|
|
@@ -3832,7 +4061,7 @@ async function openStackLayer(input, _onSetupLine) {
|
|
|
3832
4061
|
let createdWorktree = false;
|
|
3833
4062
|
const trees = await listWorktrees(repoPath);
|
|
3834
4063
|
const checkedOut = trees.find((w) => w.branch === branchName);
|
|
3835
|
-
if (checkedOut?.path &&
|
|
4064
|
+
if (checkedOut?.path && existsSync12(checkedOut.path)) {
|
|
3836
4065
|
if (input.reuseExistingWorktree !== false) {
|
|
3837
4066
|
worktreePath = checkedOut.path;
|
|
3838
4067
|
} else {
|
|
@@ -3974,7 +4203,7 @@ async function initStackFromThread(input, onSetupLine) {
|
|
|
3974
4203
|
async function createPrStack(input, onSetupLine) {
|
|
3975
4204
|
await requireAgent(input.agent);
|
|
3976
4205
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
3977
|
-
if (!
|
|
4206
|
+
if (!existsSync12(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
|
|
3978
4207
|
if (!input.branches.length) throw new Error("At least one branch name required");
|
|
3979
4208
|
const status = await detectGhStack(repoPath);
|
|
3980
4209
|
if (!status.available) throw new Error(status.reason);
|
|
@@ -4041,7 +4270,7 @@ async function createPrStack(input, onSetupLine) {
|
|
|
4041
4270
|
}
|
|
4042
4271
|
}
|
|
4043
4272
|
const claimed = new Set(threads.map((t) => t.worktreePath));
|
|
4044
|
-
if (!claimed.has(bootstrap.worktreePath) &&
|
|
4273
|
+
if (!claimed.has(bootstrap.worktreePath) && existsSync12(bootstrap.worktreePath)) {
|
|
4045
4274
|
try {
|
|
4046
4275
|
await removeWorktree(repoPath, bootstrap.worktreePath, {
|
|
4047
4276
|
deleteBranch: bootstrap.branchName
|
|
@@ -4053,10 +4282,10 @@ async function createPrStack(input, onSetupLine) {
|
|
|
4053
4282
|
}
|
|
4054
4283
|
|
|
4055
4284
|
// src/diff/diff.ts
|
|
4056
|
-
import { existsSync as
|
|
4057
|
-
import { dirname as
|
|
4285
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync4, readFileSync as readFileSync10, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
4286
|
+
import { dirname as dirname4, join as join12 } from "path";
|
|
4058
4287
|
async function inspectGitWorktree(worktreePath) {
|
|
4059
|
-
if (!worktreePath || !
|
|
4288
|
+
if (!worktreePath || !existsSync13(worktreePath)) return "missing_worktree";
|
|
4060
4289
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
4061
4290
|
reject: false
|
|
4062
4291
|
});
|
|
@@ -4064,7 +4293,7 @@ async function inspectGitWorktree(worktreePath) {
|
|
|
4064
4293
|
return "ok";
|
|
4065
4294
|
}
|
|
4066
4295
|
async function initializeGitRepository(worktreePath) {
|
|
4067
|
-
if (!worktreePath || !
|
|
4296
|
+
if (!worktreePath || !existsSync13(worktreePath)) {
|
|
4068
4297
|
throw new Error("Worktree not found");
|
|
4069
4298
|
}
|
|
4070
4299
|
const status = await inspectGitWorktree(worktreePath);
|
|
@@ -4200,11 +4429,11 @@ new file mode 100644
|
|
|
4200
4429
|
};
|
|
4201
4430
|
}
|
|
4202
4431
|
async function untrackedPatch(worktreePath, path, maxHunk) {
|
|
4203
|
-
const abs =
|
|
4432
|
+
const abs = join12(worktreePath, path);
|
|
4204
4433
|
try {
|
|
4205
4434
|
const st = statSync2(abs);
|
|
4206
4435
|
if (st.isFile() && st.size > maxHunk) {
|
|
4207
|
-
const buf =
|
|
4436
|
+
const buf = readFileSync10(abs).subarray(0, maxHunk);
|
|
4208
4437
|
return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
|
|
4209
4438
|
}
|
|
4210
4439
|
} catch {
|
|
@@ -4705,7 +4934,7 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
|
|
|
4705
4934
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
4706
4935
|
assertSafeRelativePath(relativePath);
|
|
4707
4936
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
4708
|
-
const abs =
|
|
4937
|
+
const abs = join12(worktreePath, relativePath);
|
|
4709
4938
|
const st = statSync2(abs);
|
|
4710
4939
|
if (!st.isFile()) {
|
|
4711
4940
|
throw new Error(`Not a file: ${relativePath}`);
|
|
@@ -4715,7 +4944,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
4715
4944
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
4716
4945
|
);
|
|
4717
4946
|
}
|
|
4718
|
-
const buf =
|
|
4947
|
+
const buf = readFileSync10(abs);
|
|
4719
4948
|
return {
|
|
4720
4949
|
path: relativePath,
|
|
4721
4950
|
contentBase64: buf.toString("base64"),
|
|
@@ -4725,12 +4954,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
4725
4954
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
4726
4955
|
assertSafeRelativePath(relativePath);
|
|
4727
4956
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
4728
|
-
const abs =
|
|
4957
|
+
const abs = join12(worktreePath, relativePath);
|
|
4729
4958
|
const st = statSync2(abs);
|
|
4730
4959
|
if (!st.isFile()) {
|
|
4731
4960
|
throw new Error(`Not a file: ${relativePath}`);
|
|
4732
4961
|
}
|
|
4733
|
-
const buf =
|
|
4962
|
+
const buf = readFileSync10(abs);
|
|
4734
4963
|
if (isImageRelativePath(relativePath)) {
|
|
4735
4964
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
4736
4965
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -4773,9 +5002,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
4773
5002
|
}
|
|
4774
5003
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
4775
5004
|
assertSafeRelativePath(relativePath);
|
|
4776
|
-
const abs =
|
|
4777
|
-
|
|
4778
|
-
|
|
5005
|
+
const abs = join12(worktreePath, relativePath);
|
|
5006
|
+
mkdirSync4(dirname4(abs), { recursive: true });
|
|
5007
|
+
writeFileSync6(abs, content, "utf8");
|
|
4779
5008
|
return { path: relativePath };
|
|
4780
5009
|
}
|
|
4781
5010
|
async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
@@ -4900,9 +5129,9 @@ async function confirmLand(thread, opts) {
|
|
|
4900
5129
|
}
|
|
4901
5130
|
|
|
4902
5131
|
// src/skills/discover.ts
|
|
4903
|
-
import { existsSync as
|
|
5132
|
+
import { existsSync as existsSync14, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync3 } from "fs";
|
|
4904
5133
|
import { homedir } from "os";
|
|
4905
|
-
import { join as
|
|
5134
|
+
import { join as join13 } from "path";
|
|
4906
5135
|
|
|
4907
5136
|
// src/skills/bundled/long-running.ts
|
|
4908
5137
|
var LONG_RUNNING_SKILL_COMMAND = "long-running";
|
|
@@ -4913,7 +5142,7 @@ var LONG_RUNNING_SKILL_BODY = `# Long-running jobs
|
|
|
4913
5142
|
|
|
4914
5143
|
A Sideboard or Cursor **worktree turn** SIGTERMs the agent shell (and its process group) when the user sends another message or the turn is interrupted. \`block_until_ms: 0\` is not enough \u2014 the child stays in that group.
|
|
4915
5144
|
|
|
4916
|
-
Do **not** ask the human to check back. Detach, then **wait** in 45s slices (same idea as
|
|
5145
|
+
Do **not** ask the human to check back. Detach, then **wait** in 45s slices (MCP \`wait_for_job\`, same idea as \`wait_for_turn\`) until \`stillRunning\` is false. Do not end the turn with \u201CI\u2019ll let you know.\u201D
|
|
4917
5146
|
|
|
4918
5147
|
## Tool
|
|
4919
5148
|
|
|
@@ -4923,7 +5152,8 @@ Use the helper from the Sideboard playbook \u2014 an absolute \`node "\u2026" st
|
|
|
4923
5152
|
# Start (exits in ~1s; job survives this turn)
|
|
4924
5153
|
node <detached-job.js> start <id> -- <command> [args...]
|
|
4925
5154
|
|
|
4926
|
-
# Wait \u2014
|
|
5155
|
+
# Wait \u2014 prefer MCP wait_for_job (same 45s / stillRunning contract).
|
|
5156
|
+
# Shell fallback:
|
|
4927
5157
|
node <detached-job.js> wait <id>
|
|
4928
5158
|
|
|
4929
5159
|
# Block until the process exits (humans / a turn that will not be interrupted)
|
|
@@ -4936,7 +5166,7 @@ node <detached-job.js> status <id>
|
|
|
4936
5166
|
|
|
4937
5167
|
Wait JSON:
|
|
4938
5168
|
|
|
4939
|
-
- \`stillRunning: true\` \u2192
|
|
5169
|
+
- \`stillRunning: true\` \u2192 **call wait_for_job again** (or shell wait). Progress is in \`progress\` / \`phase\`. Do not start a second job. Do not ping the user.
|
|
4940
5170
|
- \`ok: true\` \u2192 exit 0 \u2192 continue the rest of the task.
|
|
4941
5171
|
- \`failed: true\` \u2192 exit 1 \u2192 read \`progress\`, fix, start **once**.
|
|
4942
5172
|
|
|
@@ -4966,7 +5196,7 @@ node <detached-job.js> wait --pid-file FILE --log-file FILE [--ok-pattern TEXT]
|
|
|
4966
5196
|
|
|
4967
5197
|
1. \`start\` once. If JSON says \`already-running\`, do not start again.
|
|
4968
5198
|
2. Immediately \`present_artifact\` \`type=log\` (same \`artifact_id\`, \`status=running\`) \u2014 the human should see **working** in the side column, not a \u201Ccheck back later\u201D message.
|
|
4969
|
-
3. Loop \`
|
|
5199
|
+
3. Loop \`wait_for_job\` (or shell \`wait\`). After each slice, \`present_artifact\` the same id with \`content=delta\` only.
|
|
4970
5200
|
4. On \`ok\`, present once more (\`status=ok\`, last \`delta\`) and finish the task. On \`failed\`, fix from the log.
|
|
4971
5201
|
|
|
4972
5202
|
Never tell the user \u201Csay status when it\u2019s done.\u201D You wait.
|
|
@@ -5031,7 +5261,7 @@ function parseFrontmatter(content) {
|
|
|
5031
5261
|
}
|
|
5032
5262
|
function readSkill(skillMd, source) {
|
|
5033
5263
|
try {
|
|
5034
|
-
const content =
|
|
5264
|
+
const content = readFileSync11(skillMd, "utf8");
|
|
5035
5265
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
5036
5266
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
5037
5267
|
const name = fmName || dirName;
|
|
@@ -5050,17 +5280,17 @@ function readSkill(skillMd, source) {
|
|
|
5050
5280
|
}
|
|
5051
5281
|
}
|
|
5052
5282
|
function scanSkillsDir(dir, source, out) {
|
|
5053
|
-
if (!
|
|
5283
|
+
if (!existsSync14(dir)) return;
|
|
5054
5284
|
let entries;
|
|
5055
5285
|
try {
|
|
5056
|
-
entries =
|
|
5286
|
+
entries = readdirSync5(dir);
|
|
5057
5287
|
} catch {
|
|
5058
5288
|
return;
|
|
5059
5289
|
}
|
|
5060
5290
|
for (const entry of entries) {
|
|
5061
5291
|
if (entry.startsWith(".")) continue;
|
|
5062
|
-
const skillMd =
|
|
5063
|
-
if (!
|
|
5292
|
+
const skillMd = join13(dir, entry, "SKILL.md");
|
|
5293
|
+
if (!existsSync14(skillMd)) continue;
|
|
5064
5294
|
try {
|
|
5065
5295
|
if (!statSync3(skillMd).isFile()) continue;
|
|
5066
5296
|
} catch {
|
|
@@ -5071,22 +5301,22 @@ function scanSkillsDir(dir, source, out) {
|
|
|
5071
5301
|
}
|
|
5072
5302
|
}
|
|
5073
5303
|
function scanClaudePluginSkills(pluginsRoot, out) {
|
|
5074
|
-
if (!
|
|
5304
|
+
if (!existsSync14(pluginsRoot)) return;
|
|
5075
5305
|
const walk = (dir, depth, lookingForSkillsDir) => {
|
|
5076
5306
|
if (depth > 7) return;
|
|
5077
5307
|
let entries;
|
|
5078
5308
|
try {
|
|
5079
|
-
entries =
|
|
5309
|
+
entries = readdirSync5(dir);
|
|
5080
5310
|
} catch {
|
|
5081
5311
|
return;
|
|
5082
5312
|
}
|
|
5083
5313
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
5084
|
-
const skill = readSkill(
|
|
5314
|
+
const skill = readSkill(join13(dir, "SKILL.md"), "cli");
|
|
5085
5315
|
if (skill) out.push(skill);
|
|
5086
5316
|
}
|
|
5087
5317
|
for (const entry of entries) {
|
|
5088
5318
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
5089
|
-
const full =
|
|
5319
|
+
const full = join13(dir, entry);
|
|
5090
5320
|
try {
|
|
5091
5321
|
if (!statSync3(full).isDirectory()) continue;
|
|
5092
5322
|
} catch {
|
|
@@ -5106,17 +5336,17 @@ function discoverSkills(worktreePath) {
|
|
|
5106
5336
|
const home = homedir();
|
|
5107
5337
|
const collected = [];
|
|
5108
5338
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
5109
|
-
scanSkillsDir(
|
|
5339
|
+
scanSkillsDir(join13(worktreePath, rel), "workspace", collected);
|
|
5110
5340
|
}
|
|
5111
5341
|
for (const abs of [
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5342
|
+
join13(home, ".claude/skills"),
|
|
5343
|
+
join13(home, ".cursor/skills"),
|
|
5344
|
+
join13(home, ".sideboard/skills"),
|
|
5345
|
+
join13(home, ".brightsy/skills")
|
|
5116
5346
|
]) {
|
|
5117
5347
|
scanSkillsDir(abs, "user", collected);
|
|
5118
5348
|
}
|
|
5119
|
-
scanClaudePluginSkills(
|
|
5349
|
+
scanClaudePluginSkills(join13(home, ".claude/plugins"), collected);
|
|
5120
5350
|
collected.push(...bundledSkills());
|
|
5121
5351
|
const rank = {
|
|
5122
5352
|
workspace: 0,
|
|
@@ -5142,7 +5372,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
5142
5372
|
\u2026(truncated)` : body;
|
|
5143
5373
|
}
|
|
5144
5374
|
}
|
|
5145
|
-
const raw =
|
|
5375
|
+
const raw = readFileSync11(skillPath, "utf8");
|
|
5146
5376
|
if (raw.startsWith("---")) {
|
|
5147
5377
|
const end = raw.indexOf("\n---", 3);
|
|
5148
5378
|
if (end >= 0) {
|
|
@@ -5235,27 +5465,27 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
|
|
|
5235
5465
|
}
|
|
5236
5466
|
|
|
5237
5467
|
// src/agents/instructions.ts
|
|
5238
|
-
import { existsSync as
|
|
5239
|
-
import { join as
|
|
5468
|
+
import { existsSync as existsSync16, readFileSync as readFileSync12, statSync as statSync4 } from "fs";
|
|
5469
|
+
import { join as join15 } from "path";
|
|
5240
5470
|
|
|
5241
5471
|
// src/skills/detached-job-path.ts
|
|
5242
|
-
import { existsSync as
|
|
5243
|
-
import { dirname as
|
|
5472
|
+
import { existsSync as existsSync15 } from "fs";
|
|
5473
|
+
import { dirname as dirname5, join as join14 } from "path";
|
|
5244
5474
|
import { fileURLToPath } from "url";
|
|
5245
5475
|
function packagedDetachedJobPath() {
|
|
5246
5476
|
const dir = packagedMcpDir();
|
|
5247
5477
|
if (!dir) return null;
|
|
5248
|
-
const script =
|
|
5249
|
-
return
|
|
5478
|
+
const script = join14(dir, "scripts", "detached-job.js");
|
|
5479
|
+
return existsSync15(script) ? script : null;
|
|
5250
5480
|
}
|
|
5251
5481
|
function resolveDetachedJobScript() {
|
|
5252
5482
|
const packaged = packagedDetachedJobPath();
|
|
5253
5483
|
if (packaged) return packaged;
|
|
5254
|
-
let dir =
|
|
5484
|
+
let dir = dirname5(fileURLToPath(import.meta.url));
|
|
5255
5485
|
for (let i = 0; i < 8; i++) {
|
|
5256
|
-
const candidate =
|
|
5257
|
-
if (
|
|
5258
|
-
const parent =
|
|
5486
|
+
const candidate = join14(dir, "scripts", "detached-job.js");
|
|
5487
|
+
if (existsSync15(candidate)) return candidate;
|
|
5488
|
+
const parent = dirname5(dir);
|
|
5259
5489
|
if (parent === dir) break;
|
|
5260
5490
|
dir = parent;
|
|
5261
5491
|
}
|
|
@@ -5461,14 +5691,15 @@ function formatLongRunningDirective(opts) {
|
|
|
5461
5691
|
`Helper (same tool as \`scripts/detached-job.js\` when that file exists in the worktree): \`${invoke}\``,
|
|
5462
5692
|
`- Start once: \`${invoke} start <id> -- <command> [args...]\` (cwd = this worktree). If JSON says already-running, do not start again.`,
|
|
5463
5693
|
"- Immediately `present_artifact` `type=log` with `artifact_id=<id>` and `status=running` \u2014 the side column is the live view.",
|
|
5464
|
-
`- Loop
|
|
5694
|
+
`- Loop Sideboard MCP \`wait_for_job\` with the same id (returns in ~45s). stillRunning \u2192 present the same id with \`content=delta\` only \u2192 wait_for_job again. Shell fallback: \`${invoke} wait <id>\`. Do not resend the full log or HTML.`,
|
|
5695
|
+
"- Do not end the turn with \u201CI\u2019ll let you know when it\u2019s done.\u201D Stay in the loop until stillRunning is false.",
|
|
5465
5696
|
"- ok \u2192 finish the task. failed \u2192 read the log, fix, start once.",
|
|
5466
5697
|
"State: `.context/.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
|
|
5467
5698
|
].join("\n");
|
|
5468
5699
|
}
|
|
5469
5700
|
function formatLongRunningReminder(opts) {
|
|
5470
5701
|
const invoke = formatDetachedJobInvoke(opts?.scriptPath);
|
|
5471
|
-
return `Long jobs: \`${invoke} start <id> -- <cmd>\`, loop wait, present_artifact type=log (delta). Do not
|
|
5702
|
+
return `Long jobs: \`${invoke} start <id> -- <cmd>\`, loop wait_for_job (or detached-job wait), present_artifact type=log (delta). Do not say you will let the user know later \u2014 stay in the turn.`;
|
|
5472
5703
|
}
|
|
5473
5704
|
function formatArtifactDirective() {
|
|
5474
5705
|
return [
|
|
@@ -5616,8 +5847,8 @@ async function syncThreadBranchFromGit(threadId) {
|
|
|
5616
5847
|
|
|
5617
5848
|
// src/store/schedules.ts
|
|
5618
5849
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
5619
|
-
import { existsSync as
|
|
5620
|
-
import { join as
|
|
5850
|
+
import { existsSync as existsSync17, readFileSync as readFileSync13 } from "fs";
|
|
5851
|
+
import { join as join16 } from "path";
|
|
5621
5852
|
import { Cron } from "croner";
|
|
5622
5853
|
var DURATION_RE = /^(\d+)(s|m|h|d)$/i;
|
|
5623
5854
|
var UNIT_MS = {
|
|
@@ -5627,7 +5858,7 @@ var UNIT_MS = {
|
|
|
5627
5858
|
d: 864e5
|
|
5628
5859
|
};
|
|
5629
5860
|
function schedulesPath() {
|
|
5630
|
-
return
|
|
5861
|
+
return join16(appDataDir(), "schedules.json");
|
|
5631
5862
|
}
|
|
5632
5863
|
function parseDurationMs(every) {
|
|
5633
5864
|
const m = every.trim().match(DURATION_RE);
|
|
@@ -5727,9 +5958,9 @@ function normalizeTask(raw) {
|
|
|
5727
5958
|
}
|
|
5728
5959
|
function readAll() {
|
|
5729
5960
|
const path = schedulesPath();
|
|
5730
|
-
if (!
|
|
5961
|
+
if (!existsSync17(path)) return [];
|
|
5731
5962
|
try {
|
|
5732
|
-
const parsed = JSON.parse(
|
|
5963
|
+
const parsed = JSON.parse(readFileSync13(path, "utf8"));
|
|
5733
5964
|
if (!Array.isArray(parsed)) return [];
|
|
5734
5965
|
return parsed.map((row) => {
|
|
5735
5966
|
try {
|
|
@@ -5852,7 +6083,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
5852
6083
|
${prompt}`;
|
|
5853
6084
|
}
|
|
5854
6085
|
async function defaultDeps() {
|
|
5855
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
6086
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-NSVP7DJH.js");
|
|
5856
6087
|
const orch = getOrchestrator2();
|
|
5857
6088
|
return {
|
|
5858
6089
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -6009,6 +6240,9 @@ var Orchestrator = class {
|
|
|
6009
6240
|
* finish or a user send so a later crash can recover again.
|
|
6010
6241
|
*/
|
|
6011
6242
|
crashContinued = /* @__PURE__ */ new Set();
|
|
6243
|
+
/** Auto-continues after a worktree turn ended while a detached job still runs. */
|
|
6244
|
+
jobContinueCount = /* @__PURE__ */ new Map();
|
|
6245
|
+
jobContinueNudged = /* @__PURE__ */ new Set();
|
|
6012
6246
|
maxConcurrent;
|
|
6013
6247
|
runningCount = 0;
|
|
6014
6248
|
constructor(opts) {
|
|
@@ -6092,7 +6326,7 @@ var Orchestrator = class {
|
|
|
6092
6326
|
}
|
|
6093
6327
|
continue;
|
|
6094
6328
|
}
|
|
6095
|
-
if (!
|
|
6329
|
+
if (!existsSync18(thread.worktreePath)) {
|
|
6096
6330
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
6097
6331
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
6098
6332
|
continue;
|
|
@@ -6111,7 +6345,7 @@ var Orchestrator = class {
|
|
|
6111
6345
|
orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
|
|
6112
6346
|
});
|
|
6113
6347
|
}
|
|
6114
|
-
const { autoCleanupOrphansEnabled } = await import("./app-settings-
|
|
6348
|
+
const { autoCleanupOrphansEnabled } = await import("./app-settings-BJ5GFAE5.js");
|
|
6115
6349
|
if (autoCleanupOrphansEnabled() && shouldRunWorktreeCleanup() && orphans.length > 0) {
|
|
6116
6350
|
await cleanupOrphanWorktrees({ repoPaths });
|
|
6117
6351
|
}
|
|
@@ -6307,6 +6541,37 @@ var Orchestrator = class {
|
|
|
6307
6541
|
this.emit({ type: "queue_changed", threadId, queue });
|
|
6308
6542
|
this.haltDrain.delete(threadId);
|
|
6309
6543
|
}
|
|
6544
|
+
/**
|
|
6545
|
+
* Worktree agent ended the turn after “I’ll let you know” (or left a
|
|
6546
|
+
* detached test/pack job running). Queue a continue so the chat does not
|
|
6547
|
+
* go idle with nobody watching the log.
|
|
6548
|
+
*/
|
|
6549
|
+
maybeEnqueueJobContinue(threadId, chatText, parts = []) {
|
|
6550
|
+
if (this.haltDrain.has(threadId)) return;
|
|
6551
|
+
const thread = readThread(threadId);
|
|
6552
|
+
if (!thread || thread.status === "archived") return;
|
|
6553
|
+
const runningJobIds = listRunningDetachedJobs(thread.worktreePath ?? "");
|
|
6554
|
+
const decision = planJobContinue({
|
|
6555
|
+
runningJobIds,
|
|
6556
|
+
chatText,
|
|
6557
|
+
queueLength: thread.queue.length,
|
|
6558
|
+
continueCount: this.jobContinueCount.get(threadId) ?? 0,
|
|
6559
|
+
alreadyNudged: this.jobContinueNudged.has(threadId),
|
|
6560
|
+
isOrchestrator: isOrchestratorThread(thread),
|
|
6561
|
+
agent: thread.agent,
|
|
6562
|
+
watchedJob: turnWatchedDetachedJob(parts)
|
|
6563
|
+
});
|
|
6564
|
+
if (decision.action === "none") {
|
|
6565
|
+
if (runningJobIds.length === 0) this.jobContinueCount.delete(threadId);
|
|
6566
|
+
return;
|
|
6567
|
+
}
|
|
6568
|
+
if (decision.action === "nudge") this.jobContinueNudged.add(threadId);
|
|
6569
|
+
else this.jobContinueCount.set(threadId, (this.jobContinueCount.get(threadId) ?? 0) + 1);
|
|
6570
|
+
const queue = [decision.prompt, ...thread.queue];
|
|
6571
|
+
updateThread(threadId, { queue });
|
|
6572
|
+
this.emit({ type: "queue_changed", threadId, queue });
|
|
6573
|
+
this.haltDrain.delete(threadId);
|
|
6574
|
+
}
|
|
6310
6575
|
getThreads(includeArchived = false) {
|
|
6311
6576
|
return listThreads({ includeArchived });
|
|
6312
6577
|
}
|
|
@@ -6351,7 +6616,7 @@ var Orchestrator = class {
|
|
|
6351
6616
|
}
|
|
6352
6617
|
await setup;
|
|
6353
6618
|
if (skipSetup) return;
|
|
6354
|
-
const { autoRunAfterSetupEnabled } = await import("./app-settings-
|
|
6619
|
+
const { autoRunAfterSetupEnabled } = await import("./app-settings-BJ5GFAE5.js");
|
|
6355
6620
|
if (autoRunAfterSetupEnabled()) {
|
|
6356
6621
|
try {
|
|
6357
6622
|
await this.startDev(threadId);
|
|
@@ -6406,6 +6671,8 @@ var Orchestrator = class {
|
|
|
6406
6671
|
}
|
|
6407
6672
|
const queue = [...current.queue, prompt];
|
|
6408
6673
|
this.crashContinued.delete(thread.id);
|
|
6674
|
+
this.jobContinueCount.delete(thread.id);
|
|
6675
|
+
this.jobContinueNudged.delete(thread.id);
|
|
6409
6676
|
this.haltDrain.delete(thread.id);
|
|
6410
6677
|
const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
|
|
6411
6678
|
shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
|
|
@@ -6628,6 +6895,7 @@ var Orchestrator = class {
|
|
|
6628
6895
|
ticketId: issueTicket?.id,
|
|
6629
6896
|
ticketProvider: issueTicket?.provider
|
|
6630
6897
|
}) : null;
|
|
6898
|
+
const viewerContextReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatViewerContextReminder() : null;
|
|
6631
6899
|
const slackReplyContext = formatSlackRepliesForTurn(
|
|
6632
6900
|
pendingSlackExternalReplies(thread.messages)
|
|
6633
6901
|
);
|
|
@@ -6637,6 +6905,7 @@ var Orchestrator = class {
|
|
|
6637
6905
|
worktreeReminder,
|
|
6638
6906
|
optionalServicesReminder,
|
|
6639
6907
|
issueToolsReminder,
|
|
6908
|
+
viewerContextReminder,
|
|
6640
6909
|
artifactReminder,
|
|
6641
6910
|
longRunningReminder,
|
|
6642
6911
|
slackReplyContext,
|
|
@@ -6658,7 +6927,7 @@ var Orchestrator = class {
|
|
|
6658
6927
|
}
|
|
6659
6928
|
const isBrightsy = fresh.agent === "brightsy";
|
|
6660
6929
|
const isOrchestration = isOrchestratorThread(fresh);
|
|
6661
|
-
const { autoRenameBranchEnabled, getGithubGitAuthMode } = await import("./app-settings-
|
|
6930
|
+
const { autoRenameBranchEnabled, getGithubGitAuthMode } = await import("./app-settings-BJ5GFAE5.js");
|
|
6662
6931
|
const gitAuthMode = getGithubGitAuthMode();
|
|
6663
6932
|
const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
|
|
6664
6933
|
githubSlug: await resolveGithubRepoSlug(fresh.worktreePath).catch(
|
|
@@ -6677,6 +6946,18 @@ var Orchestrator = class {
|
|
|
6677
6946
|
ticketId: freshIssueTicket?.id,
|
|
6678
6947
|
ticketProvider: freshIssueTicket?.provider
|
|
6679
6948
|
});
|
|
6949
|
+
let viewerContextDirective = null;
|
|
6950
|
+
if (!isBrightsy && !isOrchestration) {
|
|
6951
|
+
try {
|
|
6952
|
+
viewerContextDirective = formatViewerContextDirective(
|
|
6953
|
+
resolveViewerProfileForRepo(fresh.repoPath || fresh.worktreePath)
|
|
6954
|
+
);
|
|
6955
|
+
} catch {
|
|
6956
|
+
viewerContextDirective = formatViewerContextDirective(
|
|
6957
|
+
resolveViewerProfileForRepo()
|
|
6958
|
+
);
|
|
6959
|
+
}
|
|
6960
|
+
}
|
|
6680
6961
|
const settings = loadWorkspaceSettings(fresh.worktreePath, fresh.repoPath);
|
|
6681
6962
|
const renameBranchDirective = !isBrightsy && !isOrchestration && autoRenameBranchEnabled() ? formatRenameBranchDirective(fresh, {
|
|
6682
6963
|
customPrompt: settings?.prompts?.renameBranch
|
|
@@ -6708,6 +6989,7 @@ var Orchestrator = class {
|
|
|
6708
6989
|
worktreeDirective,
|
|
6709
6990
|
optionalServicesDirective,
|
|
6710
6991
|
issueToolsDirective,
|
|
6992
|
+
viewerContextDirective,
|
|
6711
6993
|
artifactDirective,
|
|
6712
6994
|
longRunningDirective,
|
|
6713
6995
|
renameBranchDirective,
|
|
@@ -6818,6 +7100,7 @@ var Orchestrator = class {
|
|
|
6818
7100
|
worktreeDirective,
|
|
6819
7101
|
optionalServicesDirective,
|
|
6820
7102
|
issueToolsDirective,
|
|
7103
|
+
viewerContextDirective,
|
|
6821
7104
|
artifactDirective,
|
|
6822
7105
|
longRunningDirective,
|
|
6823
7106
|
renameBranchDirective,
|
|
@@ -6920,6 +7203,7 @@ var Orchestrator = class {
|
|
|
6920
7203
|
this.emit({ type: "turn_finished", threadId, exitCode });
|
|
6921
7204
|
if (exitCode === 0) {
|
|
6922
7205
|
this.crashContinued.delete(threadId);
|
|
7206
|
+
this.maybeEnqueueJobContinue(threadId, chatText, parts);
|
|
6923
7207
|
} else {
|
|
6924
7208
|
const blob = [chatText, detail].filter(Boolean).join("\n");
|
|
6925
7209
|
void this.maybeHandleOrchestrationQuotaFailover(threadId, blob);
|
|
@@ -7555,7 +7839,7 @@ var Orchestrator = class {
|
|
|
7555
7839
|
updateThread(thread.id, { title: meta.title });
|
|
7556
7840
|
}
|
|
7557
7841
|
}
|
|
7558
|
-
const { autoArchiveOnMergeEnabled } = await import("./app-settings-
|
|
7842
|
+
const { autoArchiveOnMergeEnabled } = await import("./app-settings-BJ5GFAE5.js");
|
|
7559
7843
|
const latest = this.requireThread(thread.id);
|
|
7560
7844
|
if (!shouldAutoArchiveOnPrMerge({
|
|
7561
7845
|
previousPrState: prevState || null,
|
|
@@ -7872,7 +8156,7 @@ var Orchestrator = class {
|
|
|
7872
8156
|
this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
|
|
7873
8157
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
7874
8158
|
try {
|
|
7875
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
8159
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-OFSDJ7PZ.js");
|
|
7876
8160
|
await ensureWorkspace2(thread.repoPath);
|
|
7877
8161
|
} catch {
|
|
7878
8162
|
}
|
|
@@ -7899,7 +8183,7 @@ var Orchestrator = class {
|
|
|
7899
8183
|
await runArchiveScript(thread.repoPath, thread.worktreePath);
|
|
7900
8184
|
} catch {
|
|
7901
8185
|
}
|
|
7902
|
-
const { deleteBranchOnPurgeEnabled } = await import("./app-settings-
|
|
8186
|
+
const { deleteBranchOnPurgeEnabled } = await import("./app-settings-BJ5GFAE5.js");
|
|
7903
8187
|
const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled();
|
|
7904
8188
|
await removeWorktree(thread.repoPath, thread.worktreePath, {
|
|
7905
8189
|
deleteBranch: deleteBranch ? thread.branchName : void 0
|
|
@@ -7920,13 +8204,13 @@ var Orchestrator = class {
|
|
|
7920
8204
|
this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
|
|
7921
8205
|
return restored2;
|
|
7922
8206
|
}
|
|
7923
|
-
if (!
|
|
8207
|
+
if (!existsSync18(thread.worktreePath)) {
|
|
7924
8208
|
if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
|
|
7925
8209
|
throw new Error(
|
|
7926
8210
|
`Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
|
|
7927
8211
|
);
|
|
7928
8212
|
}
|
|
7929
|
-
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-
|
|
8213
|
+
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-BQE5KLRY.js");
|
|
7930
8214
|
const slug = thread.worktreePath.split("/").pop();
|
|
7931
8215
|
const dest = thread.worktreePath;
|
|
7932
8216
|
await withRepoGitLock(thread.repoPath, async () => {
|
|
@@ -8036,7 +8320,7 @@ async function startOrchestration(opts) {
|
|
|
8036
8320
|
sourceRef: "default",
|
|
8037
8321
|
...createOpts
|
|
8038
8322
|
}).catch(async () => {
|
|
8039
|
-
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-
|
|
8323
|
+
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-BQE5KLRY.js");
|
|
8040
8324
|
const repo = await resolveRepoRoot2(repoPath);
|
|
8041
8325
|
const def = await resolveDefaultBranch2(repo);
|
|
8042
8326
|
return orch.createThread({
|
|
@@ -8066,6 +8350,11 @@ export {
|
|
|
8066
8350
|
recordSlackOutboundWatch,
|
|
8067
8351
|
pollSlackOutboundWatches,
|
|
8068
8352
|
AGENT_GIT_ACTIONS,
|
|
8353
|
+
mcpWaitForTurnTimeoutMs,
|
|
8354
|
+
mcpWaitStillRunningHint,
|
|
8355
|
+
mcpWaitFinishedHint,
|
|
8356
|
+
mcpWaitForJobTimeoutMs,
|
|
8357
|
+
waitForDetachedJob,
|
|
8069
8358
|
BOARD_COLUMN_DEFS,
|
|
8070
8359
|
HOME_BOARD_CACHE_TTL_MS,
|
|
8071
8360
|
dedupeBoardIssues,
|