@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
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
stripBrightsyNdjsonNoise,
|
|
25
25
|
sumUsageList,
|
|
26
26
|
toolDescription
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-V4R6L2ZL.js";
|
|
28
28
|
import {
|
|
29
29
|
SLACK_REPLY_FORMATTING,
|
|
30
30
|
addWorkspace,
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
stageAbsolutePathsAsAttachments,
|
|
51
51
|
stageBuffersAsAttachments,
|
|
52
52
|
syncWorkspacesFromThreads
|
|
53
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-O7RWWPMR.js";
|
|
54
54
|
import {
|
|
55
55
|
addPrStackLayer,
|
|
56
56
|
allocateTeamName,
|
|
@@ -98,10 +98,12 @@ import {
|
|
|
98
98
|
withRepoGitLock,
|
|
99
99
|
worktreeDisplayLabelForGroup,
|
|
100
100
|
worktreeNameFromPath
|
|
101
|
-
} from "./chunk-
|
|
101
|
+
} from "./chunk-KEDHHXKW.js";
|
|
102
102
|
import {
|
|
103
103
|
ATTACHMENTS_DIR,
|
|
104
|
-
|
|
104
|
+
DETACHED_JOBS_DIR,
|
|
105
|
+
LEGACY_ATTACHMENTS_DIR,
|
|
106
|
+
LEGACY_DETACHED_JOBS_DIR
|
|
105
107
|
} from "./chunk-JRH62XC4.js";
|
|
106
108
|
import {
|
|
107
109
|
httpFetch
|
|
@@ -126,6 +128,8 @@ import {
|
|
|
126
128
|
} from "./chunk-HEII7W3Q.js";
|
|
127
129
|
import {
|
|
128
130
|
childEnvWithAppSettings,
|
|
131
|
+
formatViewerContextDirective,
|
|
132
|
+
formatViewerContextReminder,
|
|
129
133
|
getIssueSource,
|
|
130
134
|
isAbleTimeConnected,
|
|
131
135
|
isLinearConnected,
|
|
@@ -138,10 +142,11 @@ import {
|
|
|
138
142
|
resolveNewThreadOptions,
|
|
139
143
|
resolveThreadDefaults,
|
|
140
144
|
resolveVaultKey,
|
|
145
|
+
resolveViewerProfileForRepo,
|
|
141
146
|
saveAppSettings,
|
|
142
147
|
updateAdvancedSettings,
|
|
143
148
|
writeSecureJson
|
|
144
|
-
} from "./chunk-
|
|
149
|
+
} from "./chunk-FLG4A5FJ.js";
|
|
145
150
|
import {
|
|
146
151
|
stripNestedElectronEnv
|
|
147
152
|
} from "./chunk-4TR3HZFT.js";
|
|
@@ -459,7 +464,7 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
459
464
|
await continueOnReply(threadId, prompt);
|
|
460
465
|
return;
|
|
461
466
|
}
|
|
462
|
-
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-
|
|
467
|
+
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-KFLS5BTP.js");
|
|
463
468
|
await getOrchestrator2().send(threadId, prompt);
|
|
464
469
|
} catch {
|
|
465
470
|
}
|
|
@@ -719,7 +724,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
719
724
|
}
|
|
720
725
|
|
|
721
726
|
// src/orchestrator/orchestrator.ts
|
|
722
|
-
import { existsSync as
|
|
727
|
+
import { existsSync as existsSync18 } from "fs";
|
|
723
728
|
|
|
724
729
|
// src/agents/spawn.ts
|
|
725
730
|
import { createInterface } from "readline";
|
|
@@ -739,9 +744,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
739
744
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
740
745
|
);
|
|
741
746
|
}
|
|
742
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
747
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-IJYCUO4M.js");
|
|
743
748
|
if (isGlobalThread2(thread)) {
|
|
744
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
749
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-CNI6AK65.js");
|
|
745
750
|
ensureGlobalCoordinatorCwd2(
|
|
746
751
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
747
752
|
);
|
|
@@ -2564,8 +2569,232 @@ function notifyParentOfChildHalt(child, status, send) {
|
|
|
2564
2569
|
return true;
|
|
2565
2570
|
}
|
|
2566
2571
|
|
|
2572
|
+
// src/mcp/wait-for-job.ts
|
|
2573
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readdirSync as readdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
2574
|
+
import { dirname as dirname3, join as join10 } from "path";
|
|
2575
|
+
|
|
2576
|
+
// src/mcp/wait-for-turn.ts
|
|
2577
|
+
var MCP_WAIT_FOR_TURN_MAX_MS = 45e3;
|
|
2578
|
+
function mcpWaitForTurnTimeoutMs(requested) {
|
|
2579
|
+
const n = requested ?? MCP_WAIT_FOR_TURN_MAX_MS;
|
|
2580
|
+
if (!Number.isFinite(n)) return MCP_WAIT_FOR_TURN_MAX_MS;
|
|
2581
|
+
return Math.min(Math.max(1e3, Math.floor(n)), MCP_WAIT_FOR_TURN_MAX_MS);
|
|
2582
|
+
}
|
|
2583
|
+
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.";
|
|
2584
|
+
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.";
|
|
2585
|
+
function mcpWaitStillRunningHint(status) {
|
|
2586
|
+
return status === "queued" ? MCP_WAIT_QUEUED_HINT : MCP_WAIT_STILL_RUNNING_HINT;
|
|
2587
|
+
}
|
|
2588
|
+
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.";
|
|
2589
|
+
var MCP_WAIT_BROKEN_HINT = "Child worktree is broken (missing on disk). Tell the user \u2014 do not treat this as success.";
|
|
2590
|
+
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.";
|
|
2591
|
+
function mcpWaitFinishedHint(status) {
|
|
2592
|
+
if (status === "stopped") return MCP_WAIT_STOPPED_HINT;
|
|
2593
|
+
if (status === "broken") return MCP_WAIT_BROKEN_HINT;
|
|
2594
|
+
if (status === "error") return MCP_WAIT_ERROR_HINT;
|
|
2595
|
+
return void 0;
|
|
2596
|
+
}
|
|
2597
|
+
|
|
2598
|
+
// src/mcp/wait-for-job.ts
|
|
2599
|
+
var MAX_JOB_CONTINUES = 8;
|
|
2600
|
+
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.";
|
|
2601
|
+
var JOB_ID_RE = /^[a-zA-Z0-9._-]{1,64}$/;
|
|
2602
|
+
function mcpWaitForJobTimeoutMs(requested) {
|
|
2603
|
+
return mcpWaitForTurnTimeoutMs(requested);
|
|
2604
|
+
}
|
|
2605
|
+
function sanitizeDetachedJobId(id) {
|
|
2606
|
+
const s = id.trim();
|
|
2607
|
+
if (!JOB_ID_RE.test(s)) {
|
|
2608
|
+
throw new Error(`detached-job id must be 1\u201364 chars [A-Za-z0-9._-], got ${JSON.stringify(id)}`);
|
|
2609
|
+
}
|
|
2610
|
+
return s;
|
|
2611
|
+
}
|
|
2612
|
+
function jobAlive(pid) {
|
|
2613
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
2614
|
+
try {
|
|
2615
|
+
process.kill(pid, 0);
|
|
2616
|
+
return true;
|
|
2617
|
+
} catch {
|
|
2618
|
+
return false;
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
function readIntFile(file) {
|
|
2622
|
+
if (!existsSync8(file)) return null;
|
|
2623
|
+
const n = Number.parseInt(readFileSync7(file, "utf8").trim(), 10);
|
|
2624
|
+
return Number.isInteger(n) ? n : null;
|
|
2625
|
+
}
|
|
2626
|
+
function jobDir(root, id, legacy = false) {
|
|
2627
|
+
return join10(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
|
|
2628
|
+
}
|
|
2629
|
+
function resolveJobDir(root, id) {
|
|
2630
|
+
const modern = jobDir(root, id, false);
|
|
2631
|
+
if (existsSync8(modern)) return modern;
|
|
2632
|
+
const legacy = jobDir(root, id, true);
|
|
2633
|
+
if (existsSync8(legacy)) return legacy;
|
|
2634
|
+
return modern;
|
|
2635
|
+
}
|
|
2636
|
+
function listJobIdsIn(root, rel) {
|
|
2637
|
+
const dir = join10(root, rel);
|
|
2638
|
+
if (!existsSync8(dir)) return [];
|
|
2639
|
+
return readdirSync3(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && JOB_ID_RE.test(e.name)).map((e) => e.name);
|
|
2640
|
+
}
|
|
2641
|
+
function listRunningDetachedJobs(worktreePath) {
|
|
2642
|
+
const root = worktreePath.trim();
|
|
2643
|
+
if (!root) return [];
|
|
2644
|
+
const ids = /* @__PURE__ */ new Set([
|
|
2645
|
+
...listJobIdsIn(root, DETACHED_JOBS_DIR),
|
|
2646
|
+
...listJobIdsIn(root, LEGACY_DETACHED_JOBS_DIR)
|
|
2647
|
+
]);
|
|
2648
|
+
const running = [];
|
|
2649
|
+
for (const id of ids) {
|
|
2650
|
+
const dir = resolveJobDir(root, id);
|
|
2651
|
+
const pid = readIntFile(join10(dir, "pid"));
|
|
2652
|
+
if (pid != null && jobAlive(pid)) running.push(id);
|
|
2653
|
+
}
|
|
2654
|
+
return running.sort();
|
|
2655
|
+
}
|
|
2656
|
+
function looksLikeDeferredDonePromise(text) {
|
|
2657
|
+
const t = (text ?? "").trim();
|
|
2658
|
+
if (!t) return false;
|
|
2659
|
+
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);
|
|
2660
|
+
}
|
|
2661
|
+
function formatJobStillRunningContinuePrompt(jobIds) {
|
|
2662
|
+
const ids = jobIds.join(", ");
|
|
2663
|
+
return [
|
|
2664
|
+
`Detached job still running: ${ids}.`,
|
|
2665
|
+
"Do not end this turn. Loop wait_for_job (same id) and present_artifact type=log with content=delta until stillRunning is false.",
|
|
2666
|
+
"Then report the result. Do not tell the user you will let them know later."
|
|
2667
|
+
].join(" ");
|
|
2668
|
+
}
|
|
2669
|
+
function formatDeferredDoneContinuePrompt() {
|
|
2670
|
+
return [
|
|
2671
|
+
"You ended the turn after promising to report later, but no detached job is running.",
|
|
2672
|
+
"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.",
|
|
2673
|
+
"Do not say you will let the user know later."
|
|
2674
|
+
].join(" ");
|
|
2675
|
+
}
|
|
2676
|
+
function turnWatchedDetachedJob(parts) {
|
|
2677
|
+
return parts.some((p) => {
|
|
2678
|
+
if (p.type !== "tool") return false;
|
|
2679
|
+
if (/wait_for_job$/i.test(p.name ?? "")) return true;
|
|
2680
|
+
const blob = [p.name, p.detail, p.description, p.input ? JSON.stringify(p.input) : ""].filter(Boolean).join(" ");
|
|
2681
|
+
return /detached-job\.js\b/i.test(blob);
|
|
2682
|
+
});
|
|
2683
|
+
}
|
|
2684
|
+
function planJobContinue(opts) {
|
|
2685
|
+
if (opts.isOrchestrator) return { action: "none" };
|
|
2686
|
+
if (opts.agent === "brightsy") return { action: "none" };
|
|
2687
|
+
if (opts.queueLength > 0) return { action: "none" };
|
|
2688
|
+
if (opts.continueCount >= MAX_JOB_CONTINUES) return { action: "none" };
|
|
2689
|
+
const farewell = looksLikeDeferredDonePromise(opts.chatText);
|
|
2690
|
+
if (opts.runningJobIds.length > 0 && (farewell || opts.watchedJob)) {
|
|
2691
|
+
return {
|
|
2692
|
+
action: "wait",
|
|
2693
|
+
jobIds: opts.runningJobIds,
|
|
2694
|
+
prompt: formatJobStillRunningContinuePrompt(opts.runningJobIds)
|
|
2695
|
+
};
|
|
2696
|
+
}
|
|
2697
|
+
if (looksLikeDeferredDonePromise(opts.chatText) && !opts.alreadyNudged) {
|
|
2698
|
+
return { action: "nudge", prompt: formatDeferredDoneContinuePrompt() };
|
|
2699
|
+
}
|
|
2700
|
+
return { action: "none" };
|
|
2701
|
+
}
|
|
2702
|
+
function tailProgress(logFile, maxLines = 12) {
|
|
2703
|
+
if (!existsSync8(logFile)) return "(no log yet)";
|
|
2704
|
+
const lines = readFileSync7(logFile, "utf8").split("\n");
|
|
2705
|
+
return lines.slice(-maxLines).join("\n");
|
|
2706
|
+
}
|
|
2707
|
+
function readLogLines(file) {
|
|
2708
|
+
if (!existsSync8(file)) return [];
|
|
2709
|
+
const lines = readFileSync7(file, "utf8").split("\n");
|
|
2710
|
+
if (lines.length && lines[lines.length - 1] === "") lines.pop();
|
|
2711
|
+
return lines;
|
|
2712
|
+
}
|
|
2713
|
+
function takeDelta(logFile, cursorFile) {
|
|
2714
|
+
const lines = readLogLines(logFile);
|
|
2715
|
+
const cursor = readIntFile(cursorFile) ?? 0;
|
|
2716
|
+
const start = Math.min(Math.max(0, cursor), lines.length);
|
|
2717
|
+
return { delta: lines.slice(start).join("\n"), nextCursor: lines.length };
|
|
2718
|
+
}
|
|
2719
|
+
function snapshotJob(dir) {
|
|
2720
|
+
const pid = readIntFile(join10(dir, "pid"));
|
|
2721
|
+
const running = pid != null && jobAlive(pid);
|
|
2722
|
+
return {
|
|
2723
|
+
pid,
|
|
2724
|
+
running,
|
|
2725
|
+
exitCode: readIntFile(join10(dir, "exit")),
|
|
2726
|
+
log: join10(dir, "log"),
|
|
2727
|
+
cursor: join10(dir, "present.cursor"),
|
|
2728
|
+
progress: tailProgress(join10(dir, "log"))
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2731
|
+
function toResult(id, snap, extra) {
|
|
2732
|
+
const failed = extra?.failed === true || !snap.running && snap.exitCode != null && snap.exitCode !== 0;
|
|
2733
|
+
const ok = !snap.running && snap.exitCode === 0;
|
|
2734
|
+
const stillRunning = snap.running && !ok;
|
|
2735
|
+
const { delta, nextCursor } = takeDelta(snap.log, snap.cursor);
|
|
2736
|
+
try {
|
|
2737
|
+
mkdirSync3(dirname3(snap.cursor), { recursive: true });
|
|
2738
|
+
writeFileSync4(snap.cursor, `${nextCursor}
|
|
2739
|
+
`);
|
|
2740
|
+
} catch {
|
|
2741
|
+
}
|
|
2742
|
+
const status = ok ? "ok" : failed && !stillRunning ? "failed" : stillRunning ? "running" : "idle";
|
|
2743
|
+
return {
|
|
2744
|
+
stillRunning,
|
|
2745
|
+
ok,
|
|
2746
|
+
failed: Boolean(failed && !stillRunning && !ok),
|
|
2747
|
+
status,
|
|
2748
|
+
id,
|
|
2749
|
+
pid: snap.pid,
|
|
2750
|
+
exitCode: snap.exitCode ?? void 0,
|
|
2751
|
+
delta,
|
|
2752
|
+
progress: extra?.progress ?? snap.progress,
|
|
2753
|
+
hint: stillRunning ? MCP_WAIT_JOB_STILL_RUNNING_HINT : void 0
|
|
2754
|
+
};
|
|
2755
|
+
}
|
|
2756
|
+
async function sleepMs(ms) {
|
|
2757
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
2758
|
+
}
|
|
2759
|
+
async function waitForDetachedJob(cwd, id, opts) {
|
|
2760
|
+
const jobId = sanitizeDetachedJobId(id);
|
|
2761
|
+
const root = cwd.trim() || process.cwd();
|
|
2762
|
+
const dir = resolveJobDir(root, jobId);
|
|
2763
|
+
const timeoutMs = mcpWaitForJobTimeoutMs(opts?.timeoutMs);
|
|
2764
|
+
const sleep = opts?.sleep ?? sleepMs;
|
|
2765
|
+
if (!existsSync8(dir)) {
|
|
2766
|
+
return {
|
|
2767
|
+
stillRunning: false,
|
|
2768
|
+
ok: false,
|
|
2769
|
+
failed: true,
|
|
2770
|
+
status: "failed",
|
|
2771
|
+
id: jobId,
|
|
2772
|
+
delta: "",
|
|
2773
|
+
progress: "No detached job. Start one first.",
|
|
2774
|
+
hint: "Start with detached-job.js start <id> -- <command>, then call wait_for_job again."
|
|
2775
|
+
};
|
|
2776
|
+
}
|
|
2777
|
+
const deadline = Date.now() + timeoutMs;
|
|
2778
|
+
let snap = snapshotJob(dir);
|
|
2779
|
+
if (snap.exitCode === 0 && !snap.running) return toResult(jobId, snap);
|
|
2780
|
+
if (!snap.running && snap.pid == null && snap.progress === "(no log yet)") {
|
|
2781
|
+
return toResult(jobId, snap, {
|
|
2782
|
+
failed: true,
|
|
2783
|
+
progress: "No detached job. Start one first."
|
|
2784
|
+
});
|
|
2785
|
+
}
|
|
2786
|
+
while (Date.now() < deadline) {
|
|
2787
|
+
snap = snapshotJob(dir);
|
|
2788
|
+
if (snap.exitCode === 0 && !snap.running) return toResult(jobId, snap);
|
|
2789
|
+
if (!snap.running) return toResult(jobId, snap, { failed: true });
|
|
2790
|
+
await sleep(Math.min(2e3, Math.max(50, deadline - Date.now())));
|
|
2791
|
+
}
|
|
2792
|
+
snap = snapshotJob(dir);
|
|
2793
|
+
return toResult(jobId, snap);
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2567
2796
|
// src/threads/create.ts
|
|
2568
|
-
import { existsSync as
|
|
2797
|
+
import { existsSync as existsSync9 } from "fs";
|
|
2569
2798
|
|
|
2570
2799
|
// src/detect/detect.ts
|
|
2571
2800
|
async function detectAgents() {
|
|
@@ -3127,7 +3356,7 @@ function reuseLiveThread(input, repoPath, match) {
|
|
|
3127
3356
|
}
|
|
3128
3357
|
async function createThread(input, _onSetupLine) {
|
|
3129
3358
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
3130
|
-
if (!
|
|
3359
|
+
if (!existsSync9(repoPath)) {
|
|
3131
3360
|
throw new Error(`Repo not found: ${repoPath}`);
|
|
3132
3361
|
}
|
|
3133
3362
|
const reused = reuseLiveThread(input, repoPath, {
|
|
@@ -3144,7 +3373,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3144
3373
|
});
|
|
3145
3374
|
await requireAgent(resolved.agent);
|
|
3146
3375
|
if (input.cowboy) {
|
|
3147
|
-
const { cowboyModeEnabled } = await import("./app-settings-
|
|
3376
|
+
const { cowboyModeEnabled } = await import("./app-settings-YWJ4MVYM.js");
|
|
3148
3377
|
if (!cowboyModeEnabled()) {
|
|
3149
3378
|
throw new Error(
|
|
3150
3379
|
"Cowboy mode is off. Enable it in Settings \u2192 Advanced."
|
|
@@ -3202,7 +3431,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3202
3431
|
let sourceIsFork = false;
|
|
3203
3432
|
if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
|
|
3204
3433
|
if (isAbleTimeConnected() && getIssueSource() === "abletime") {
|
|
3205
|
-
const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-
|
|
3434
|
+
const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-LK7GV556.js");
|
|
3206
3435
|
const task = await ensureAbleTimeTask({
|
|
3207
3436
|
title: title?.trim() || "Untitled work",
|
|
3208
3437
|
description: input.prompt?.trim() || void 0
|
|
@@ -3299,7 +3528,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3299
3528
|
return readThread(thread.id) ?? thread;
|
|
3300
3529
|
}
|
|
3301
3530
|
async function listLinearIssues(agent, repoPath) {
|
|
3302
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
3531
|
+
const { getAdapter: getAdapter2 } = await import("./agents-5HY76BCR.js");
|
|
3303
3532
|
await requireAgent(agent, { requireLinear: true });
|
|
3304
3533
|
const adapter = getAdapter2(agent);
|
|
3305
3534
|
if (!adapter.listLinearIssues) {
|
|
@@ -3322,11 +3551,11 @@ function shouldRemoveWorktreeOnTeardown(thread) {
|
|
|
3322
3551
|
|
|
3323
3552
|
// src/store/turn-live.ts
|
|
3324
3553
|
import {
|
|
3325
|
-
existsSync as
|
|
3554
|
+
existsSync as existsSync10,
|
|
3326
3555
|
renameSync,
|
|
3327
3556
|
unlinkSync as unlinkSync2,
|
|
3328
|
-
writeFileSync as
|
|
3329
|
-
readFileSync as
|
|
3557
|
+
writeFileSync as writeFileSync5,
|
|
3558
|
+
readFileSync as readFileSync8
|
|
3330
3559
|
} from "fs";
|
|
3331
3560
|
var buffers = /* @__PURE__ */ new Map();
|
|
3332
3561
|
var FLUSH_MS = 800;
|
|
@@ -3403,7 +3632,7 @@ function writeTurnLive(threadId, progress) {
|
|
|
3403
3632
|
const path = threadLivePath(threadId);
|
|
3404
3633
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
3405
3634
|
try {
|
|
3406
|
-
|
|
3635
|
+
writeFileSync5(tmp, JSON.stringify(progress), "utf8");
|
|
3407
3636
|
renameSync(tmp, path);
|
|
3408
3637
|
} catch {
|
|
3409
3638
|
try {
|
|
@@ -3414,9 +3643,9 @@ function writeTurnLive(threadId, progress) {
|
|
|
3414
3643
|
}
|
|
3415
3644
|
function readTurnLive(threadId) {
|
|
3416
3645
|
const path = threadLivePath(threadId);
|
|
3417
|
-
if (!
|
|
3646
|
+
if (!existsSync10(path)) return null;
|
|
3418
3647
|
try {
|
|
3419
|
-
const raw = JSON.parse(
|
|
3648
|
+
const raw = JSON.parse(readFileSync8(path, "utf8"));
|
|
3420
3649
|
if (!raw || typeof raw.summary !== "string") return null;
|
|
3421
3650
|
return raw;
|
|
3422
3651
|
} catch {
|
|
@@ -3428,7 +3657,7 @@ function clearTurnLive(threadId) {
|
|
|
3428
3657
|
if (buf?.timer) clearTimeout(buf.timer);
|
|
3429
3658
|
buffers.delete(threadId);
|
|
3430
3659
|
const path = threadLivePath(threadId);
|
|
3431
|
-
if (!
|
|
3660
|
+
if (!existsSync10(path)) return;
|
|
3432
3661
|
try {
|
|
3433
3662
|
unlinkSync2(path);
|
|
3434
3663
|
} catch {
|
|
@@ -3616,26 +3845,26 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
|
|
|
3616
3845
|
import { execFileSync } from "child_process";
|
|
3617
3846
|
import {
|
|
3618
3847
|
copyFileSync as copyFileSync2,
|
|
3619
|
-
existsSync as
|
|
3848
|
+
existsSync as existsSync11,
|
|
3620
3849
|
mkdtempSync,
|
|
3621
|
-
readdirSync as
|
|
3622
|
-
readFileSync as
|
|
3850
|
+
readdirSync as readdirSync4,
|
|
3851
|
+
readFileSync as readFileSync9,
|
|
3623
3852
|
rmSync
|
|
3624
3853
|
} from "fs";
|
|
3625
3854
|
import { tmpdir } from "os";
|
|
3626
|
-
import { join as
|
|
3855
|
+
import { join as join11 } from "path";
|
|
3627
3856
|
import { createRequire } from "module";
|
|
3628
|
-
var CONDUCTOR_APP_SUPPORT =
|
|
3857
|
+
var CONDUCTOR_APP_SUPPORT = join11(
|
|
3629
3858
|
process.env.HOME ?? "",
|
|
3630
3859
|
"Library",
|
|
3631
3860
|
"Application Support",
|
|
3632
3861
|
"com.conductor.app"
|
|
3633
3862
|
);
|
|
3634
|
-
var CONDUCTOR_DB =
|
|
3635
|
-
var CURSOR_SDK_STORE =
|
|
3863
|
+
var CONDUCTOR_DB = join11(CONDUCTOR_APP_SUPPORT, "conductor.db");
|
|
3864
|
+
var CURSOR_SDK_STORE = join11(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
|
|
3636
3865
|
function thisModuleFile() {
|
|
3637
3866
|
const cjsFile = typeof __filename !== "undefined" ? __filename : "";
|
|
3638
|
-
return cjsFile || process.argv[1] ||
|
|
3867
|
+
return cjsFile || process.argv[1] || join11(process.cwd(), "package.json");
|
|
3639
3868
|
}
|
|
3640
3869
|
function openReadonlySqlite(file) {
|
|
3641
3870
|
const req = createRequire(thisModuleFile());
|
|
@@ -3653,21 +3882,21 @@ function mapAgentType(raw) {
|
|
|
3653
3882
|
return null;
|
|
3654
3883
|
}
|
|
3655
3884
|
function resolveConductorCursorAgentId(workspacePath) {
|
|
3656
|
-
if (!workspacePath || !
|
|
3885
|
+
if (!workspacePath || !existsSync11(CURSOR_SDK_STORE)) return null;
|
|
3657
3886
|
const normalized = workspacePath.replace(/\/$/, "");
|
|
3658
3887
|
let best = null;
|
|
3659
3888
|
let hashes;
|
|
3660
3889
|
try {
|
|
3661
|
-
hashes =
|
|
3890
|
+
hashes = readdirSync4(CURSOR_SDK_STORE);
|
|
3662
3891
|
} catch {
|
|
3663
3892
|
return null;
|
|
3664
3893
|
}
|
|
3665
3894
|
for (const hash of hashes) {
|
|
3666
|
-
const agentsFile =
|
|
3667
|
-
if (!
|
|
3895
|
+
const agentsFile = join11(CURSOR_SDK_STORE, hash, "agents.ndjson");
|
|
3896
|
+
if (!existsSync11(agentsFile)) continue;
|
|
3668
3897
|
let text;
|
|
3669
3898
|
try {
|
|
3670
|
-
text =
|
|
3899
|
+
text = readFileSync9(agentsFile, "utf8");
|
|
3671
3900
|
} catch {
|
|
3672
3901
|
continue;
|
|
3673
3902
|
}
|
|
@@ -3691,7 +3920,7 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
3691
3920
|
return best?.agentId ?? null;
|
|
3692
3921
|
}
|
|
3693
3922
|
async function adoptThread(input) {
|
|
3694
|
-
if (!
|
|
3923
|
+
if (!existsSync11(input.worktreePath)) {
|
|
3695
3924
|
throw new Error(`Worktree not found: ${input.worktreePath}`);
|
|
3696
3925
|
}
|
|
3697
3926
|
const repoPath = await resolveRepoRoot(input.worktreePath);
|
|
@@ -3710,7 +3939,7 @@ async function adoptThread(input) {
|
|
|
3710
3939
|
messages: input.messages ?? []
|
|
3711
3940
|
});
|
|
3712
3941
|
writeThread(thread);
|
|
3713
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
3942
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-D2M3AM2M.js");
|
|
3714
3943
|
await ensureWorkspace2(repoPath);
|
|
3715
3944
|
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-X54WSOXM.js");
|
|
3716
3945
|
await ensureWorktreeSideboardIgnored2(input.worktreePath);
|
|
@@ -3720,16 +3949,16 @@ function conductorDbPath() {
|
|
|
3720
3949
|
return CONDUCTOR_DB;
|
|
3721
3950
|
}
|
|
3722
3951
|
function listConductorWorkspaces() {
|
|
3723
|
-
if (!
|
|
3952
|
+
if (!existsSync11(CONDUCTOR_DB)) {
|
|
3724
3953
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
3725
3954
|
}
|
|
3726
|
-
const tmp = mkdtempSync(
|
|
3727
|
-
const snapshot =
|
|
3955
|
+
const tmp = mkdtempSync(join11(tmpdir(), "sideboard-conductor-"));
|
|
3956
|
+
const snapshot = join11(tmp, "conductor.db");
|
|
3728
3957
|
try {
|
|
3729
3958
|
copyFileSync2(CONDUCTOR_DB, snapshot);
|
|
3730
3959
|
for (const suffix of ["-wal", "-shm"]) {
|
|
3731
3960
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
3732
|
-
if (
|
|
3961
|
+
if (existsSync11(src)) {
|
|
3733
3962
|
try {
|
|
3734
3963
|
copyFileSync2(src, `${snapshot}${suffix}`);
|
|
3735
3964
|
} catch {
|
|
@@ -3811,16 +4040,16 @@ function listConductorWorkspaces() {
|
|
|
3811
4040
|
}
|
|
3812
4041
|
}
|
|
3813
4042
|
function importConductorWorkspace(workspaceId) {
|
|
3814
|
-
if (!
|
|
4043
|
+
if (!existsSync11(CONDUCTOR_DB)) {
|
|
3815
4044
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
3816
4045
|
}
|
|
3817
|
-
const tmp = mkdtempSync(
|
|
3818
|
-
const snapshot =
|
|
4046
|
+
const tmp = mkdtempSync(join11(tmpdir(), "sideboard-conductor-"));
|
|
4047
|
+
const snapshot = join11(tmp, "conductor.db");
|
|
3819
4048
|
try {
|
|
3820
4049
|
copyFileSync2(CONDUCTOR_DB, snapshot);
|
|
3821
4050
|
for (const suffix of ["-wal", "-shm"]) {
|
|
3822
4051
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
3823
|
-
if (
|
|
4052
|
+
if (existsSync11(src)) {
|
|
3824
4053
|
try {
|
|
3825
4054
|
copyFileSync2(src, `${snapshot}${suffix}`);
|
|
3826
4055
|
} catch {
|
|
@@ -3840,7 +4069,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
3840
4069
|
).get(workspaceId);
|
|
3841
4070
|
if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
|
|
3842
4071
|
const worktreePath = String(row.workspacePath);
|
|
3843
|
-
if (!
|
|
4072
|
+
if (!existsSync11(worktreePath)) {
|
|
3844
4073
|
throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
|
|
3845
4074
|
}
|
|
3846
4075
|
let sessionId = null;
|
|
@@ -3911,7 +4140,7 @@ async function importConductorWorkspaceAsync(workspaceId) {
|
|
|
3911
4140
|
}
|
|
3912
4141
|
|
|
3913
4142
|
// src/threads/stack-layers.ts
|
|
3914
|
-
import { existsSync as
|
|
4143
|
+
import { existsSync as existsSync12 } from "fs";
|
|
3915
4144
|
function stackIdFrom(stack) {
|
|
3916
4145
|
if (stack.stackNumber != null) return `gh-stack-${stack.stackNumber}`;
|
|
3917
4146
|
const key = stack.layers.map((l) => l.branchName).join("|");
|
|
@@ -3974,7 +4203,7 @@ async function openStackLayer(input, _onSetupLine) {
|
|
|
3974
4203
|
let createdWorktree = false;
|
|
3975
4204
|
const trees = await listWorktrees(repoPath);
|
|
3976
4205
|
const checkedOut = trees.find((w) => w.branch === branchName);
|
|
3977
|
-
if (checkedOut?.path &&
|
|
4206
|
+
if (checkedOut?.path && existsSync12(checkedOut.path)) {
|
|
3978
4207
|
if (input.reuseExistingWorktree !== false) {
|
|
3979
4208
|
worktreePath = checkedOut.path;
|
|
3980
4209
|
} else {
|
|
@@ -4116,7 +4345,7 @@ async function initStackFromThread(input, onSetupLine) {
|
|
|
4116
4345
|
async function createPrStack(input, onSetupLine) {
|
|
4117
4346
|
await requireAgent(input.agent);
|
|
4118
4347
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
4119
|
-
if (!
|
|
4348
|
+
if (!existsSync12(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
|
|
4120
4349
|
if (!input.branches.length) throw new Error("At least one branch name required");
|
|
4121
4350
|
const status = await detectGhStack(repoPath);
|
|
4122
4351
|
if (!status.available) throw new Error(status.reason);
|
|
@@ -4183,7 +4412,7 @@ async function createPrStack(input, onSetupLine) {
|
|
|
4183
4412
|
}
|
|
4184
4413
|
}
|
|
4185
4414
|
const claimed = new Set(threads.map((t) => t.worktreePath));
|
|
4186
|
-
if (!claimed.has(bootstrap.worktreePath) &&
|
|
4415
|
+
if (!claimed.has(bootstrap.worktreePath) && existsSync12(bootstrap.worktreePath)) {
|
|
4187
4416
|
try {
|
|
4188
4417
|
await removeWorktree(repoPath, bootstrap.worktreePath, {
|
|
4189
4418
|
deleteBranch: bootstrap.branchName
|
|
@@ -4205,10 +4434,10 @@ function stackAgentDefaultsFrom(input) {
|
|
|
4205
4434
|
}
|
|
4206
4435
|
|
|
4207
4436
|
// src/diff/diff.ts
|
|
4208
|
-
import { existsSync as
|
|
4209
|
-
import { dirname as
|
|
4437
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync4, readFileSync as readFileSync10, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
4438
|
+
import { dirname as dirname4, join as join12 } from "path";
|
|
4210
4439
|
async function inspectGitWorktree(worktreePath) {
|
|
4211
|
-
if (!worktreePath || !
|
|
4440
|
+
if (!worktreePath || !existsSync13(worktreePath)) return "missing_worktree";
|
|
4212
4441
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
4213
4442
|
reject: false
|
|
4214
4443
|
});
|
|
@@ -4216,7 +4445,7 @@ async function inspectGitWorktree(worktreePath) {
|
|
|
4216
4445
|
return "ok";
|
|
4217
4446
|
}
|
|
4218
4447
|
async function initializeGitRepository(worktreePath) {
|
|
4219
|
-
if (!worktreePath || !
|
|
4448
|
+
if (!worktreePath || !existsSync13(worktreePath)) {
|
|
4220
4449
|
throw new Error("Worktree not found");
|
|
4221
4450
|
}
|
|
4222
4451
|
const status = await inspectGitWorktree(worktreePath);
|
|
@@ -4352,11 +4581,11 @@ new file mode 100644
|
|
|
4352
4581
|
};
|
|
4353
4582
|
}
|
|
4354
4583
|
async function untrackedPatch(worktreePath, path, maxHunk) {
|
|
4355
|
-
const abs =
|
|
4584
|
+
const abs = join12(worktreePath, path);
|
|
4356
4585
|
try {
|
|
4357
4586
|
const st = statSync2(abs);
|
|
4358
4587
|
if (st.isFile() && st.size > maxHunk) {
|
|
4359
|
-
const buf =
|
|
4588
|
+
const buf = readFileSync10(abs).subarray(0, maxHunk);
|
|
4360
4589
|
return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
|
|
4361
4590
|
}
|
|
4362
4591
|
} catch {
|
|
@@ -4857,7 +5086,7 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
|
|
|
4857
5086
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
4858
5087
|
assertSafeRelativePath(relativePath);
|
|
4859
5088
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
4860
|
-
const abs =
|
|
5089
|
+
const abs = join12(worktreePath, relativePath);
|
|
4861
5090
|
const st = statSync2(abs);
|
|
4862
5091
|
if (!st.isFile()) {
|
|
4863
5092
|
throw new Error(`Not a file: ${relativePath}`);
|
|
@@ -4867,7 +5096,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
4867
5096
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
4868
5097
|
);
|
|
4869
5098
|
}
|
|
4870
|
-
const buf =
|
|
5099
|
+
const buf = readFileSync10(abs);
|
|
4871
5100
|
return {
|
|
4872
5101
|
path: relativePath,
|
|
4873
5102
|
contentBase64: buf.toString("base64"),
|
|
@@ -4877,12 +5106,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
4877
5106
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
4878
5107
|
assertSafeRelativePath(relativePath);
|
|
4879
5108
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
4880
|
-
const abs =
|
|
5109
|
+
const abs = join12(worktreePath, relativePath);
|
|
4881
5110
|
const st = statSync2(abs);
|
|
4882
5111
|
if (!st.isFile()) {
|
|
4883
5112
|
throw new Error(`Not a file: ${relativePath}`);
|
|
4884
5113
|
}
|
|
4885
|
-
const buf =
|
|
5114
|
+
const buf = readFileSync10(abs);
|
|
4886
5115
|
if (isImageRelativePath(relativePath)) {
|
|
4887
5116
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
4888
5117
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -4925,9 +5154,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
4925
5154
|
}
|
|
4926
5155
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
4927
5156
|
assertSafeRelativePath(relativePath);
|
|
4928
|
-
const abs =
|
|
4929
|
-
|
|
4930
|
-
|
|
5157
|
+
const abs = join12(worktreePath, relativePath);
|
|
5158
|
+
mkdirSync4(dirname4(abs), { recursive: true });
|
|
5159
|
+
writeFileSync6(abs, content, "utf8");
|
|
4931
5160
|
return { path: relativePath };
|
|
4932
5161
|
}
|
|
4933
5162
|
async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
@@ -5052,9 +5281,9 @@ async function confirmLand(thread, opts) {
|
|
|
5052
5281
|
}
|
|
5053
5282
|
|
|
5054
5283
|
// src/skills/discover.ts
|
|
5055
|
-
import { existsSync as
|
|
5284
|
+
import { existsSync as existsSync14, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync3 } from "fs";
|
|
5056
5285
|
import { homedir } from "os";
|
|
5057
|
-
import { join as
|
|
5286
|
+
import { join as join13 } from "path";
|
|
5058
5287
|
|
|
5059
5288
|
// src/skills/bundled/long-running.ts
|
|
5060
5289
|
var LONG_RUNNING_SKILL_COMMAND = "long-running";
|
|
@@ -5065,7 +5294,7 @@ var LONG_RUNNING_SKILL_BODY = `# Long-running jobs
|
|
|
5065
5294
|
|
|
5066
5295
|
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.
|
|
5067
5296
|
|
|
5068
|
-
Do **not** ask the human to check back. Detach, then **wait** in 45s slices (same idea as
|
|
5297
|
+
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
|
|
5069
5298
|
|
|
5070
5299
|
## Tool
|
|
5071
5300
|
|
|
@@ -5075,7 +5304,8 @@ Use the helper from the Sideboard playbook \u2014 an absolute \`node "\u2026" st
|
|
|
5075
5304
|
# Start (exits in ~1s; job survives this turn)
|
|
5076
5305
|
node <detached-job.js> start <id> -- <command> [args...]
|
|
5077
5306
|
|
|
5078
|
-
# Wait \u2014
|
|
5307
|
+
# Wait \u2014 prefer MCP wait_for_job (same 45s / stillRunning contract).
|
|
5308
|
+
# Shell fallback:
|
|
5079
5309
|
node <detached-job.js> wait <id>
|
|
5080
5310
|
|
|
5081
5311
|
# Block until the process exits (humans / a turn that will not be interrupted)
|
|
@@ -5088,7 +5318,7 @@ node <detached-job.js> status <id>
|
|
|
5088
5318
|
|
|
5089
5319
|
Wait JSON:
|
|
5090
5320
|
|
|
5091
|
-
- \`stillRunning: true\` \u2192
|
|
5321
|
+
- \`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.
|
|
5092
5322
|
- \`ok: true\` \u2192 exit 0 \u2192 continue the rest of the task.
|
|
5093
5323
|
- \`failed: true\` \u2192 exit 1 \u2192 read \`progress\`, fix, start **once**.
|
|
5094
5324
|
|
|
@@ -5118,7 +5348,7 @@ node <detached-job.js> wait --pid-file FILE --log-file FILE [--ok-pattern TEXT]
|
|
|
5118
5348
|
|
|
5119
5349
|
1. \`start\` once. If JSON says \`already-running\`, do not start again.
|
|
5120
5350
|
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.
|
|
5121
|
-
3. Loop \`
|
|
5351
|
+
3. Loop \`wait_for_job\` (or shell \`wait\`). After each slice, \`present_artifact\` the same id with \`content=delta\` only.
|
|
5122
5352
|
4. On \`ok\`, present once more (\`status=ok\`, last \`delta\`) and finish the task. On \`failed\`, fix from the log.
|
|
5123
5353
|
|
|
5124
5354
|
Never tell the user \u201Csay status when it\u2019s done.\u201D You wait.
|
|
@@ -5183,7 +5413,7 @@ function parseFrontmatter(content) {
|
|
|
5183
5413
|
}
|
|
5184
5414
|
function readSkill(skillMd, source) {
|
|
5185
5415
|
try {
|
|
5186
|
-
const content =
|
|
5416
|
+
const content = readFileSync11(skillMd, "utf8");
|
|
5187
5417
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
5188
5418
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
5189
5419
|
const name = fmName || dirName;
|
|
@@ -5202,17 +5432,17 @@ function readSkill(skillMd, source) {
|
|
|
5202
5432
|
}
|
|
5203
5433
|
}
|
|
5204
5434
|
function scanSkillsDir(dir, source, out) {
|
|
5205
|
-
if (!
|
|
5435
|
+
if (!existsSync14(dir)) return;
|
|
5206
5436
|
let entries;
|
|
5207
5437
|
try {
|
|
5208
|
-
entries =
|
|
5438
|
+
entries = readdirSync5(dir);
|
|
5209
5439
|
} catch {
|
|
5210
5440
|
return;
|
|
5211
5441
|
}
|
|
5212
5442
|
for (const entry of entries) {
|
|
5213
5443
|
if (entry.startsWith(".")) continue;
|
|
5214
|
-
const skillMd =
|
|
5215
|
-
if (!
|
|
5444
|
+
const skillMd = join13(dir, entry, "SKILL.md");
|
|
5445
|
+
if (!existsSync14(skillMd)) continue;
|
|
5216
5446
|
try {
|
|
5217
5447
|
if (!statSync3(skillMd).isFile()) continue;
|
|
5218
5448
|
} catch {
|
|
@@ -5223,22 +5453,22 @@ function scanSkillsDir(dir, source, out) {
|
|
|
5223
5453
|
}
|
|
5224
5454
|
}
|
|
5225
5455
|
function scanClaudePluginSkills(pluginsRoot, out) {
|
|
5226
|
-
if (!
|
|
5456
|
+
if (!existsSync14(pluginsRoot)) return;
|
|
5227
5457
|
const walk = (dir, depth, lookingForSkillsDir) => {
|
|
5228
5458
|
if (depth > 7) return;
|
|
5229
5459
|
let entries;
|
|
5230
5460
|
try {
|
|
5231
|
-
entries =
|
|
5461
|
+
entries = readdirSync5(dir);
|
|
5232
5462
|
} catch {
|
|
5233
5463
|
return;
|
|
5234
5464
|
}
|
|
5235
5465
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
5236
|
-
const skill = readSkill(
|
|
5466
|
+
const skill = readSkill(join13(dir, "SKILL.md"), "cli");
|
|
5237
5467
|
if (skill) out.push(skill);
|
|
5238
5468
|
}
|
|
5239
5469
|
for (const entry of entries) {
|
|
5240
5470
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
5241
|
-
const full =
|
|
5471
|
+
const full = join13(dir, entry);
|
|
5242
5472
|
try {
|
|
5243
5473
|
if (!statSync3(full).isDirectory()) continue;
|
|
5244
5474
|
} catch {
|
|
@@ -5258,17 +5488,17 @@ function discoverSkills(worktreePath) {
|
|
|
5258
5488
|
const home = homedir();
|
|
5259
5489
|
const collected = [];
|
|
5260
5490
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
5261
|
-
scanSkillsDir(
|
|
5491
|
+
scanSkillsDir(join13(worktreePath, rel), "workspace", collected);
|
|
5262
5492
|
}
|
|
5263
5493
|
for (const abs of [
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5494
|
+
join13(home, ".claude/skills"),
|
|
5495
|
+
join13(home, ".cursor/skills"),
|
|
5496
|
+
join13(home, ".sideboard/skills"),
|
|
5497
|
+
join13(home, ".brightsy/skills")
|
|
5268
5498
|
]) {
|
|
5269
5499
|
scanSkillsDir(abs, "user", collected);
|
|
5270
5500
|
}
|
|
5271
|
-
scanClaudePluginSkills(
|
|
5501
|
+
scanClaudePluginSkills(join13(home, ".claude/plugins"), collected);
|
|
5272
5502
|
collected.push(...bundledSkills());
|
|
5273
5503
|
const rank = {
|
|
5274
5504
|
workspace: 0,
|
|
@@ -5294,7 +5524,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
5294
5524
|
\u2026(truncated)` : body;
|
|
5295
5525
|
}
|
|
5296
5526
|
}
|
|
5297
|
-
const raw =
|
|
5527
|
+
const raw = readFileSync11(skillPath, "utf8");
|
|
5298
5528
|
if (raw.startsWith("---")) {
|
|
5299
5529
|
const end = raw.indexOf("\n---", 3);
|
|
5300
5530
|
if (end >= 0) {
|
|
@@ -5387,27 +5617,27 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
|
|
|
5387
5617
|
}
|
|
5388
5618
|
|
|
5389
5619
|
// src/agents/instructions.ts
|
|
5390
|
-
import { existsSync as
|
|
5391
|
-
import { join as
|
|
5620
|
+
import { existsSync as existsSync16, readFileSync as readFileSync12, statSync as statSync4 } from "fs";
|
|
5621
|
+
import { join as join15 } from "path";
|
|
5392
5622
|
|
|
5393
5623
|
// src/skills/detached-job-path.ts
|
|
5394
|
-
import { existsSync as
|
|
5395
|
-
import { dirname as
|
|
5624
|
+
import { existsSync as existsSync15 } from "fs";
|
|
5625
|
+
import { dirname as dirname5, join as join14 } from "path";
|
|
5396
5626
|
import { fileURLToPath } from "url";
|
|
5397
5627
|
function packagedDetachedJobPath() {
|
|
5398
5628
|
const dir = packagedMcpDir();
|
|
5399
5629
|
if (!dir) return null;
|
|
5400
|
-
const script =
|
|
5401
|
-
return
|
|
5630
|
+
const script = join14(dir, "scripts", "detached-job.js");
|
|
5631
|
+
return existsSync15(script) ? script : null;
|
|
5402
5632
|
}
|
|
5403
5633
|
function resolveDetachedJobScript() {
|
|
5404
5634
|
const packaged = packagedDetachedJobPath();
|
|
5405
5635
|
if (packaged) return packaged;
|
|
5406
|
-
let dir =
|
|
5636
|
+
let dir = dirname5(fileURLToPath(import.meta.url));
|
|
5407
5637
|
for (let i = 0; i < 8; i++) {
|
|
5408
|
-
const candidate =
|
|
5409
|
-
if (
|
|
5410
|
-
const parent =
|
|
5638
|
+
const candidate = join14(dir, "scripts", "detached-job.js");
|
|
5639
|
+
if (existsSync15(candidate)) return candidate;
|
|
5640
|
+
const parent = dirname5(dir);
|
|
5411
5641
|
if (parent === dir) break;
|
|
5412
5642
|
dir = parent;
|
|
5413
5643
|
}
|
|
@@ -5635,14 +5865,15 @@ function formatLongRunningDirective(opts) {
|
|
|
5635
5865
|
`Helper (same tool as \`scripts/detached-job.js\` when that file exists in the worktree): \`${invoke}\``,
|
|
5636
5866
|
`- Start once: \`${invoke} start <id> -- <command> [args...]\` (cwd = this worktree). If JSON says already-running, do not start again.`,
|
|
5637
5867
|
"- Immediately `present_artifact` `type=log` with `artifact_id=<id>` and `status=running` \u2014 the side column is the live view.",
|
|
5638
|
-
`- Loop
|
|
5868
|
+
`- 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.`,
|
|
5869
|
+
"- Do not end the turn with \u201CI\u2019ll let you know when it\u2019s done.\u201D Stay in the loop until stillRunning is false.",
|
|
5639
5870
|
"- ok \u2192 finish the task. failed \u2192 read the log, fix, start once.",
|
|
5640
5871
|
"State: `.context/.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
|
|
5641
5872
|
].join("\n");
|
|
5642
5873
|
}
|
|
5643
5874
|
function formatLongRunningReminder(opts) {
|
|
5644
5875
|
const invoke = formatDetachedJobInvoke(opts?.scriptPath);
|
|
5645
|
-
return `Long jobs: \`${invoke} start <id> -- <cmd>\`, loop wait, present_artifact type=log (delta). Do not
|
|
5876
|
+
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.`;
|
|
5646
5877
|
}
|
|
5647
5878
|
function formatArtifactDirective() {
|
|
5648
5879
|
return [
|
|
@@ -5693,11 +5924,11 @@ function loadAgentInstructions(worktreePath, agent) {
|
|
|
5693
5924
|
const out = [];
|
|
5694
5925
|
for (const rel of candidates) {
|
|
5695
5926
|
if (seenPaths.has(rel)) continue;
|
|
5696
|
-
const abs =
|
|
5697
|
-
if (!
|
|
5927
|
+
const abs = join15(worktreePath, rel);
|
|
5928
|
+
if (!existsSync16(abs)) continue;
|
|
5698
5929
|
try {
|
|
5699
5930
|
if (!statSync4(abs).isFile()) continue;
|
|
5700
|
-
let content =
|
|
5931
|
+
let content = readFileSync12(abs, "utf8");
|
|
5701
5932
|
if (!content.trim()) continue;
|
|
5702
5933
|
if (content.length > MAX_CHARS_PER_FILE) {
|
|
5703
5934
|
content = `${content.slice(0, MAX_CHARS_PER_FILE)}
|
|
@@ -6017,8 +6248,8 @@ async function syncThreadBranchFromGit(threadId) {
|
|
|
6017
6248
|
|
|
6018
6249
|
// src/store/schedules.ts
|
|
6019
6250
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
6020
|
-
import { existsSync as
|
|
6021
|
-
import { join as
|
|
6251
|
+
import { existsSync as existsSync17, readFileSync as readFileSync13 } from "fs";
|
|
6252
|
+
import { join as join16 } from "path";
|
|
6022
6253
|
import { Cron } from "croner";
|
|
6023
6254
|
var DURATION_RE = /^(\d+)(s|m|h|d)$/i;
|
|
6024
6255
|
var UNIT_MS = {
|
|
@@ -6028,7 +6259,7 @@ var UNIT_MS = {
|
|
|
6028
6259
|
d: 864e5
|
|
6029
6260
|
};
|
|
6030
6261
|
function schedulesPath() {
|
|
6031
|
-
return
|
|
6262
|
+
return join16(appDataDir(), "schedules.json");
|
|
6032
6263
|
}
|
|
6033
6264
|
function parseDurationMs(every) {
|
|
6034
6265
|
const m = every.trim().match(DURATION_RE);
|
|
@@ -6134,9 +6365,9 @@ function normalizeTask(raw) {
|
|
|
6134
6365
|
}
|
|
6135
6366
|
function readAll() {
|
|
6136
6367
|
const path = schedulesPath();
|
|
6137
|
-
if (!
|
|
6368
|
+
if (!existsSync17(path)) return [];
|
|
6138
6369
|
try {
|
|
6139
|
-
const parsed = JSON.parse(
|
|
6370
|
+
const parsed = JSON.parse(readFileSync13(path, "utf8"));
|
|
6140
6371
|
if (!Array.isArray(parsed)) return [];
|
|
6141
6372
|
return parsed.map((row) => {
|
|
6142
6373
|
try {
|
|
@@ -6262,7 +6493,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
6262
6493
|
${prompt}`;
|
|
6263
6494
|
}
|
|
6264
6495
|
async function defaultDeps() {
|
|
6265
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
6496
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-KFLS5BTP.js");
|
|
6266
6497
|
const orch = getOrchestrator2();
|
|
6267
6498
|
return {
|
|
6268
6499
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -6419,6 +6650,9 @@ var Orchestrator = class {
|
|
|
6419
6650
|
* finish or a user send so a later crash can recover again.
|
|
6420
6651
|
*/
|
|
6421
6652
|
crashContinued = /* @__PURE__ */ new Set();
|
|
6653
|
+
/** Auto-continues after a worktree turn ended while a detached job still runs. */
|
|
6654
|
+
jobContinueCount = /* @__PURE__ */ new Map();
|
|
6655
|
+
jobContinueNudged = /* @__PURE__ */ new Set();
|
|
6422
6656
|
maxConcurrent;
|
|
6423
6657
|
runningCount = 0;
|
|
6424
6658
|
constructor(opts) {
|
|
@@ -6502,7 +6736,7 @@ var Orchestrator = class {
|
|
|
6502
6736
|
}
|
|
6503
6737
|
continue;
|
|
6504
6738
|
}
|
|
6505
|
-
if (!
|
|
6739
|
+
if (!existsSync18(thread.worktreePath)) {
|
|
6506
6740
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
6507
6741
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
6508
6742
|
continue;
|
|
@@ -6521,7 +6755,7 @@ var Orchestrator = class {
|
|
|
6521
6755
|
orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
|
|
6522
6756
|
});
|
|
6523
6757
|
}
|
|
6524
|
-
const { autoCleanupOrphansEnabled } = await import("./app-settings-
|
|
6758
|
+
const { autoCleanupOrphansEnabled } = await import("./app-settings-YWJ4MVYM.js");
|
|
6525
6759
|
if (autoCleanupOrphansEnabled() && shouldRunWorktreeCleanup() && orphans.length > 0) {
|
|
6526
6760
|
await cleanupOrphanWorktrees({ repoPaths });
|
|
6527
6761
|
}
|
|
@@ -6717,6 +6951,37 @@ var Orchestrator = class {
|
|
|
6717
6951
|
this.emit({ type: "queue_changed", threadId, queue });
|
|
6718
6952
|
this.haltDrain.delete(threadId);
|
|
6719
6953
|
}
|
|
6954
|
+
/**
|
|
6955
|
+
* Worktree agent ended the turn after “I’ll let you know” (or left a
|
|
6956
|
+
* detached test/pack job running). Queue a continue so the chat does not
|
|
6957
|
+
* go idle with nobody watching the log.
|
|
6958
|
+
*/
|
|
6959
|
+
maybeEnqueueJobContinue(threadId, chatText, parts = []) {
|
|
6960
|
+
if (this.haltDrain.has(threadId)) return;
|
|
6961
|
+
const thread = readThread(threadId);
|
|
6962
|
+
if (!thread || thread.status === "archived") return;
|
|
6963
|
+
const runningJobIds = listRunningDetachedJobs(thread.worktreePath ?? "");
|
|
6964
|
+
const decision = planJobContinue({
|
|
6965
|
+
runningJobIds,
|
|
6966
|
+
chatText,
|
|
6967
|
+
queueLength: thread.queue.length,
|
|
6968
|
+
continueCount: this.jobContinueCount.get(threadId) ?? 0,
|
|
6969
|
+
alreadyNudged: this.jobContinueNudged.has(threadId),
|
|
6970
|
+
isOrchestrator: isOrchestratorThread(thread),
|
|
6971
|
+
agent: thread.agent,
|
|
6972
|
+
watchedJob: turnWatchedDetachedJob(parts)
|
|
6973
|
+
});
|
|
6974
|
+
if (decision.action === "none") {
|
|
6975
|
+
if (runningJobIds.length === 0) this.jobContinueCount.delete(threadId);
|
|
6976
|
+
return;
|
|
6977
|
+
}
|
|
6978
|
+
if (decision.action === "nudge") this.jobContinueNudged.add(threadId);
|
|
6979
|
+
else this.jobContinueCount.set(threadId, (this.jobContinueCount.get(threadId) ?? 0) + 1);
|
|
6980
|
+
const queue = [decision.prompt, ...thread.queue];
|
|
6981
|
+
updateThread(threadId, { queue });
|
|
6982
|
+
this.emit({ type: "queue_changed", threadId, queue });
|
|
6983
|
+
this.haltDrain.delete(threadId);
|
|
6984
|
+
}
|
|
6720
6985
|
getThreads(includeArchived = false) {
|
|
6721
6986
|
return listThreads({ includeArchived });
|
|
6722
6987
|
}
|
|
@@ -6761,7 +7026,7 @@ var Orchestrator = class {
|
|
|
6761
7026
|
}
|
|
6762
7027
|
await setup;
|
|
6763
7028
|
if (skipSetup) return;
|
|
6764
|
-
const { autoRunAfterSetupEnabled } = await import("./app-settings-
|
|
7029
|
+
const { autoRunAfterSetupEnabled } = await import("./app-settings-YWJ4MVYM.js");
|
|
6765
7030
|
if (autoRunAfterSetupEnabled()) {
|
|
6766
7031
|
try {
|
|
6767
7032
|
await this.startDev(threadId);
|
|
@@ -6816,6 +7081,8 @@ var Orchestrator = class {
|
|
|
6816
7081
|
}
|
|
6817
7082
|
const queue = [...current.queue, prompt];
|
|
6818
7083
|
this.crashContinued.delete(thread.id);
|
|
7084
|
+
this.jobContinueCount.delete(thread.id);
|
|
7085
|
+
this.jobContinueNudged.delete(thread.id);
|
|
6819
7086
|
this.haltDrain.delete(thread.id);
|
|
6820
7087
|
const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
|
|
6821
7088
|
shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
|
|
@@ -7038,6 +7305,7 @@ var Orchestrator = class {
|
|
|
7038
7305
|
ticketId: issueTicket?.id,
|
|
7039
7306
|
ticketProvider: issueTicket?.provider
|
|
7040
7307
|
}) : null;
|
|
7308
|
+
const viewerContextReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatViewerContextReminder() : null;
|
|
7041
7309
|
const slackReplyContext = formatSlackRepliesForTurn(
|
|
7042
7310
|
pendingSlackExternalReplies(thread.messages)
|
|
7043
7311
|
);
|
|
@@ -7047,6 +7315,7 @@ var Orchestrator = class {
|
|
|
7047
7315
|
worktreeReminder,
|
|
7048
7316
|
optionalServicesReminder,
|
|
7049
7317
|
issueToolsReminder,
|
|
7318
|
+
viewerContextReminder,
|
|
7050
7319
|
artifactReminder,
|
|
7051
7320
|
longRunningReminder,
|
|
7052
7321
|
slackReplyContext,
|
|
@@ -7068,7 +7337,7 @@ var Orchestrator = class {
|
|
|
7068
7337
|
}
|
|
7069
7338
|
const isBrightsy = fresh.agent === "brightsy";
|
|
7070
7339
|
const isOrchestration = isOrchestratorThread(fresh);
|
|
7071
|
-
const { autoRenameBranchEnabled, getGithubGitAuthMode } = await import("./app-settings-
|
|
7340
|
+
const { autoRenameBranchEnabled, getGithubGitAuthMode } = await import("./app-settings-YWJ4MVYM.js");
|
|
7072
7341
|
const gitAuthMode = getGithubGitAuthMode();
|
|
7073
7342
|
const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
|
|
7074
7343
|
githubSlug: await resolveGithubRepoSlug(fresh.worktreePath).catch(
|
|
@@ -7087,6 +7356,18 @@ var Orchestrator = class {
|
|
|
7087
7356
|
ticketId: freshIssueTicket?.id,
|
|
7088
7357
|
ticketProvider: freshIssueTicket?.provider
|
|
7089
7358
|
});
|
|
7359
|
+
let viewerContextDirective = null;
|
|
7360
|
+
if (!isBrightsy && !isOrchestration) {
|
|
7361
|
+
try {
|
|
7362
|
+
viewerContextDirective = formatViewerContextDirective(
|
|
7363
|
+
resolveViewerProfileForRepo(fresh.repoPath || fresh.worktreePath)
|
|
7364
|
+
);
|
|
7365
|
+
} catch {
|
|
7366
|
+
viewerContextDirective = formatViewerContextDirective(
|
|
7367
|
+
resolveViewerProfileForRepo()
|
|
7368
|
+
);
|
|
7369
|
+
}
|
|
7370
|
+
}
|
|
7090
7371
|
const settings = loadWorkspaceSettings(fresh.worktreePath, fresh.repoPath);
|
|
7091
7372
|
const renameBranchDirective = !isBrightsy && !isOrchestration && autoRenameBranchEnabled() ? formatRenameBranchDirective(fresh, {
|
|
7092
7373
|
customPrompt: settings?.prompts?.renameBranch
|
|
@@ -7118,6 +7399,7 @@ var Orchestrator = class {
|
|
|
7118
7399
|
worktreeDirective,
|
|
7119
7400
|
optionalServicesDirective,
|
|
7120
7401
|
issueToolsDirective,
|
|
7402
|
+
viewerContextDirective,
|
|
7121
7403
|
artifactDirective,
|
|
7122
7404
|
longRunningDirective,
|
|
7123
7405
|
renameBranchDirective,
|
|
@@ -7228,6 +7510,7 @@ var Orchestrator = class {
|
|
|
7228
7510
|
worktreeDirective,
|
|
7229
7511
|
optionalServicesDirective,
|
|
7230
7512
|
issueToolsDirective,
|
|
7513
|
+
viewerContextDirective,
|
|
7231
7514
|
artifactDirective,
|
|
7232
7515
|
longRunningDirective,
|
|
7233
7516
|
renameBranchDirective,
|
|
@@ -7330,6 +7613,7 @@ var Orchestrator = class {
|
|
|
7330
7613
|
this.emit({ type: "turn_finished", threadId, exitCode });
|
|
7331
7614
|
if (exitCode === 0) {
|
|
7332
7615
|
this.crashContinued.delete(threadId);
|
|
7616
|
+
this.maybeEnqueueJobContinue(threadId, chatText, parts);
|
|
7333
7617
|
} else {
|
|
7334
7618
|
const blob = [chatText, detail].filter(Boolean).join("\n");
|
|
7335
7619
|
void this.maybeHandleOrchestrationQuotaFailover(threadId, blob);
|
|
@@ -7965,7 +8249,7 @@ var Orchestrator = class {
|
|
|
7965
8249
|
updateThread(thread.id, { title: meta.title });
|
|
7966
8250
|
}
|
|
7967
8251
|
}
|
|
7968
|
-
const { autoArchiveOnMergeEnabled } = await import("./app-settings-
|
|
8252
|
+
const { autoArchiveOnMergeEnabled } = await import("./app-settings-YWJ4MVYM.js");
|
|
7969
8253
|
const latest = this.requireThread(thread.id);
|
|
7970
8254
|
if (!shouldAutoArchiveOnPrMerge({
|
|
7971
8255
|
previousPrState: prevState || null,
|
|
@@ -8282,7 +8566,7 @@ var Orchestrator = class {
|
|
|
8282
8566
|
this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
|
|
8283
8567
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
8284
8568
|
try {
|
|
8285
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
8569
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-D2M3AM2M.js");
|
|
8286
8570
|
await ensureWorkspace2(thread.repoPath);
|
|
8287
8571
|
} catch {
|
|
8288
8572
|
}
|
|
@@ -8309,7 +8593,7 @@ var Orchestrator = class {
|
|
|
8309
8593
|
await runArchiveScript(thread.repoPath, thread.worktreePath);
|
|
8310
8594
|
} catch {
|
|
8311
8595
|
}
|
|
8312
|
-
const { deleteBranchOnPurgeEnabled } = await import("./app-settings-
|
|
8596
|
+
const { deleteBranchOnPurgeEnabled } = await import("./app-settings-YWJ4MVYM.js");
|
|
8313
8597
|
const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled();
|
|
8314
8598
|
await removeWorktree(thread.repoPath, thread.worktreePath, {
|
|
8315
8599
|
deleteBranch: deleteBranch ? thread.branchName : void 0
|
|
@@ -8330,13 +8614,13 @@ var Orchestrator = class {
|
|
|
8330
8614
|
this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
|
|
8331
8615
|
return restored2;
|
|
8332
8616
|
}
|
|
8333
|
-
if (!
|
|
8617
|
+
if (!existsSync18(thread.worktreePath)) {
|
|
8334
8618
|
if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
|
|
8335
8619
|
throw new Error(
|
|
8336
8620
|
`Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
|
|
8337
8621
|
);
|
|
8338
8622
|
}
|
|
8339
|
-
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-
|
|
8623
|
+
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-EA6AD6D6.js");
|
|
8340
8624
|
const slug = thread.worktreePath.split("/").pop();
|
|
8341
8625
|
const dest = thread.worktreePath;
|
|
8342
8626
|
await withRepoGitLock(thread.repoPath, async () => {
|
|
@@ -8446,7 +8730,7 @@ async function startOrchestration(opts) {
|
|
|
8446
8730
|
sourceRef: "default",
|
|
8447
8731
|
...createOpts
|
|
8448
8732
|
}).catch(async () => {
|
|
8449
|
-
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-
|
|
8733
|
+
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-EA6AD6D6.js");
|
|
8450
8734
|
const repo = await resolveRepoRoot2(repoPath);
|
|
8451
8735
|
const def = await resolveDefaultBranch2(repo);
|
|
8452
8736
|
return orch.createThread({
|
|
@@ -8592,6 +8876,11 @@ export {
|
|
|
8592
8876
|
worktreeCleanupSettings,
|
|
8593
8877
|
applyThreadIntoMain,
|
|
8594
8878
|
cloneRepoIntoSideboard,
|
|
8879
|
+
mcpWaitForTurnTimeoutMs,
|
|
8880
|
+
mcpWaitStillRunningHint,
|
|
8881
|
+
mcpWaitFinishedHint,
|
|
8882
|
+
mcpWaitForJobTimeoutMs,
|
|
8883
|
+
waitForDetachedJob,
|
|
8595
8884
|
detectAgents,
|
|
8596
8885
|
requireAgent,
|
|
8597
8886
|
isHomeBoardThread,
|