@sideboard-ai/core 0.1.156 → 0.1.158
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-JSTJLXAW.js → abletime-BEIDJG7W.js} +5 -1
- package/dist/{abletime-H7LPGIP2.js → abletime-GWZE6OYM.js} +5 -1
- package/dist/{agents-IY4CSPWV.js → agents-E3ZPWZRS.js} +2 -2
- package/dist/{agents-2FTZAXO3.js → agents-RGE7PSUY.js} +4 -4
- package/dist/{chunk-TI6UMRWK.js → chunk-3SUZMPGL.js} +5 -4
- package/dist/{chunk-NVXVEGGM.js → chunk-5U4NZLBH.js} +4 -0
- package/dist/{chunk-CJQLPPEJ.js → chunk-A7QXLYBN.js} +1 -1
- package/dist/{chunk-XLU7DXHH.js → chunk-BLRHO7XQ.js} +54 -5
- package/dist/{chunk-MSFPM5VK.js → chunk-CVR4RJ6G.js} +3 -2
- package/dist/{chunk-JOK4XWBG.js → chunk-DVJBO3M7.js} +87 -3
- package/dist/{chunk-UA3YZKRX.js → chunk-EPQIOAAY.js} +25 -5
- package/dist/{chunk-OLE2BLIX.js → chunk-FBFIOVDH.js} +457 -106
- package/dist/{chunk-2SDMENAL.js → chunk-JV4VNFMS.js} +1 -1
- package/dist/{chunk-7EIPEPAH.js → chunk-KYKNFJK5.js} +484 -105
- package/dist/{chunk-FDCFXMDG.js → chunk-N27GVFZY.js} +87 -3
- package/dist/{coordinator-prompt-D2FHU5IZ.js → coordinator-prompt-26IJU2AV.js} +1 -1
- package/dist/{coordinator-prompt-UZDNIVP7.js → coordinator-prompt-GZESIQNH.js} +3 -3
- package/dist/{global-workspace-5WZVSWNT.js → global-workspace-5BIW26YR.js} +1 -1
- package/dist/{global-workspace-MR75BDBY.js → global-workspace-REI55FZ6.js} +3 -3
- package/dist/index.cjs +1405 -560
- package/dist/index.d.cts +138 -4
- package/dist/index.d.ts +138 -4
- package/dist/index.js +609 -274
- package/dist/mcp/run-stdio.cjs +1253 -500
- package/dist/mcp/run-stdio.js +525 -226
- package/dist/{orchestrator-LXO2CDOG.js → orchestrator-J727WIJY.js} +6 -6
- package/dist/{orchestrator-G4WKJG5Y.js → orchestrator-ZVW2AC6B.js} +3 -3
- package/dist/{plan-file-OZEBFSGQ.js → plan-file-I24VJVP2.js} +2 -2
- package/dist/{workspaces-RP32AW6X.js → workspaces-NYSM2EPX.js} +1 -1
- package/dist/{workspaces-HO4EQNNM.js → workspaces-OCEPZXFD.js} +3 -3
- package/dist/{worktree-PEWDAX5O.js → worktree-VTMBZKY6.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-EPQIOAAY.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-3SUZMPGL.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-A7QXLYBN.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,
|
|
@@ -147,11 +149,13 @@ import {
|
|
|
147
149
|
childEnvWithAppSettings,
|
|
148
150
|
getIssueSource,
|
|
149
151
|
isAbleTimeConnected,
|
|
152
|
+
isLinearConnected,
|
|
150
153
|
isSecureFileEncrypted,
|
|
151
154
|
loadAppSettings,
|
|
152
155
|
orchestrationQuotaFallbackAgent,
|
|
153
156
|
orchestrationQuotaOnLimit,
|
|
154
157
|
readSecureJson,
|
|
158
|
+
resolveEffectiveIssueSource,
|
|
155
159
|
resolveNewThreadOptions,
|
|
156
160
|
resolveThreadDefaults,
|
|
157
161
|
resolveVaultKey,
|
|
@@ -392,7 +396,7 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
392
396
|
await continueOnReply(threadId, prompt);
|
|
393
397
|
return;
|
|
394
398
|
}
|
|
395
|
-
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-
|
|
399
|
+
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-J727WIJY.js");
|
|
396
400
|
await getOrchestrator2().send(threadId, prompt);
|
|
397
401
|
} catch {
|
|
398
402
|
}
|
|
@@ -652,7 +656,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
652
656
|
}
|
|
653
657
|
|
|
654
658
|
// src/orchestrator/orchestrator.ts
|
|
655
|
-
import { existsSync as
|
|
659
|
+
import { existsSync as existsSync18 } from "fs";
|
|
656
660
|
|
|
657
661
|
// src/agents/spawn.ts
|
|
658
662
|
import { createInterface } from "readline";
|
|
@@ -733,9 +737,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
733
737
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
734
738
|
);
|
|
735
739
|
}
|
|
736
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
740
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-REI55FZ6.js");
|
|
737
741
|
if (isGlobalThread2(thread)) {
|
|
738
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
742
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-GZESIQNH.js");
|
|
739
743
|
ensureGlobalCoordinatorCwd2(
|
|
740
744
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
741
745
|
);
|
|
@@ -2477,8 +2481,232 @@ function notifyParentOfChildHalt(child, status, send) {
|
|
|
2477
2481
|
return true;
|
|
2478
2482
|
}
|
|
2479
2483
|
|
|
2484
|
+
// src/mcp/wait-for-job.ts
|
|
2485
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readdirSync as readdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
2486
|
+
import { dirname as dirname3, join as join10 } from "path";
|
|
2487
|
+
|
|
2488
|
+
// src/mcp/wait-for-turn.ts
|
|
2489
|
+
var MCP_WAIT_FOR_TURN_MAX_MS = 45e3;
|
|
2490
|
+
function mcpWaitForTurnTimeoutMs(requested) {
|
|
2491
|
+
const n = requested ?? MCP_WAIT_FOR_TURN_MAX_MS;
|
|
2492
|
+
if (!Number.isFinite(n)) return MCP_WAIT_FOR_TURN_MAX_MS;
|
|
2493
|
+
return Math.min(Math.max(1e3, Math.floor(n)), MCP_WAIT_FOR_TURN_MAX_MS);
|
|
2494
|
+
}
|
|
2495
|
+
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.";
|
|
2496
|
+
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.";
|
|
2497
|
+
function mcpWaitStillRunningHint(status) {
|
|
2498
|
+
return status === "queued" ? MCP_WAIT_QUEUED_HINT : MCP_WAIT_STILL_RUNNING_HINT;
|
|
2499
|
+
}
|
|
2500
|
+
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.";
|
|
2501
|
+
var MCP_WAIT_BROKEN_HINT = "Child worktree is broken (missing on disk). Tell the user \u2014 do not treat this as success.";
|
|
2502
|
+
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.";
|
|
2503
|
+
function mcpWaitFinishedHint(status) {
|
|
2504
|
+
if (status === "stopped") return MCP_WAIT_STOPPED_HINT;
|
|
2505
|
+
if (status === "broken") return MCP_WAIT_BROKEN_HINT;
|
|
2506
|
+
if (status === "error") return MCP_WAIT_ERROR_HINT;
|
|
2507
|
+
return void 0;
|
|
2508
|
+
}
|
|
2509
|
+
|
|
2510
|
+
// src/mcp/wait-for-job.ts
|
|
2511
|
+
var MAX_JOB_CONTINUES = 8;
|
|
2512
|
+
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.";
|
|
2513
|
+
var JOB_ID_RE = /^[a-zA-Z0-9._-]{1,64}$/;
|
|
2514
|
+
function mcpWaitForJobTimeoutMs(requested) {
|
|
2515
|
+
return mcpWaitForTurnTimeoutMs(requested);
|
|
2516
|
+
}
|
|
2517
|
+
function sanitizeDetachedJobId(id) {
|
|
2518
|
+
const s = id.trim();
|
|
2519
|
+
if (!JOB_ID_RE.test(s)) {
|
|
2520
|
+
throw new Error(`detached-job id must be 1\u201364 chars [A-Za-z0-9._-], got ${JSON.stringify(id)}`);
|
|
2521
|
+
}
|
|
2522
|
+
return s;
|
|
2523
|
+
}
|
|
2524
|
+
function jobAlive(pid) {
|
|
2525
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
2526
|
+
try {
|
|
2527
|
+
process.kill(pid, 0);
|
|
2528
|
+
return true;
|
|
2529
|
+
} catch {
|
|
2530
|
+
return false;
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
function readIntFile(file) {
|
|
2534
|
+
if (!existsSync8(file)) return null;
|
|
2535
|
+
const n = Number.parseInt(readFileSync7(file, "utf8").trim(), 10);
|
|
2536
|
+
return Number.isInteger(n) ? n : null;
|
|
2537
|
+
}
|
|
2538
|
+
function jobDir(root, id, legacy = false) {
|
|
2539
|
+
return join10(root, legacy ? LEGACY_DETACHED_JOBS_DIR : DETACHED_JOBS_DIR, id);
|
|
2540
|
+
}
|
|
2541
|
+
function resolveJobDir(root, id) {
|
|
2542
|
+
const modern = jobDir(root, id, false);
|
|
2543
|
+
if (existsSync8(modern)) return modern;
|
|
2544
|
+
const legacy = jobDir(root, id, true);
|
|
2545
|
+
if (existsSync8(legacy)) return legacy;
|
|
2546
|
+
return modern;
|
|
2547
|
+
}
|
|
2548
|
+
function listJobIdsIn(root, rel) {
|
|
2549
|
+
const dir = join10(root, rel);
|
|
2550
|
+
if (!existsSync8(dir)) return [];
|
|
2551
|
+
return readdirSync3(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && JOB_ID_RE.test(e.name)).map((e) => e.name);
|
|
2552
|
+
}
|
|
2553
|
+
function listRunningDetachedJobs(worktreePath) {
|
|
2554
|
+
const root = worktreePath.trim();
|
|
2555
|
+
if (!root) return [];
|
|
2556
|
+
const ids = /* @__PURE__ */ new Set([
|
|
2557
|
+
...listJobIdsIn(root, DETACHED_JOBS_DIR),
|
|
2558
|
+
...listJobIdsIn(root, LEGACY_DETACHED_JOBS_DIR)
|
|
2559
|
+
]);
|
|
2560
|
+
const running = [];
|
|
2561
|
+
for (const id of ids) {
|
|
2562
|
+
const dir = resolveJobDir(root, id);
|
|
2563
|
+
const pid = readIntFile(join10(dir, "pid"));
|
|
2564
|
+
if (pid != null && jobAlive(pid)) running.push(id);
|
|
2565
|
+
}
|
|
2566
|
+
return running.sort();
|
|
2567
|
+
}
|
|
2568
|
+
function looksLikeDeferredDonePromise(text) {
|
|
2569
|
+
const t = (text ?? "").trim();
|
|
2570
|
+
if (!t) return false;
|
|
2571
|
+
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);
|
|
2572
|
+
}
|
|
2573
|
+
function formatJobStillRunningContinuePrompt(jobIds) {
|
|
2574
|
+
const ids = jobIds.join(", ");
|
|
2575
|
+
return [
|
|
2576
|
+
`Detached job still running: ${ids}.`,
|
|
2577
|
+
"Do not end this turn. Loop wait_for_job (same id) and present_artifact type=log with content=delta until stillRunning is false.",
|
|
2578
|
+
"Then report the result. Do not tell the user you will let them know later."
|
|
2579
|
+
].join(" ");
|
|
2580
|
+
}
|
|
2581
|
+
function formatDeferredDoneContinuePrompt() {
|
|
2582
|
+
return [
|
|
2583
|
+
"You ended the turn after promising to report later, but no detached job is running.",
|
|
2584
|
+
"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.",
|
|
2585
|
+
"Do not say you will let the user know later."
|
|
2586
|
+
].join(" ");
|
|
2587
|
+
}
|
|
2588
|
+
function turnWatchedDetachedJob(parts) {
|
|
2589
|
+
return parts.some((p) => {
|
|
2590
|
+
if (p.type !== "tool") return false;
|
|
2591
|
+
if (/wait_for_job$/i.test(p.name ?? "")) return true;
|
|
2592
|
+
const blob = [p.name, p.detail, p.description, p.input ? JSON.stringify(p.input) : ""].filter(Boolean).join(" ");
|
|
2593
|
+
return /detached-job\.js\b/i.test(blob);
|
|
2594
|
+
});
|
|
2595
|
+
}
|
|
2596
|
+
function planJobContinue(opts) {
|
|
2597
|
+
if (opts.isOrchestrator) return { action: "none" };
|
|
2598
|
+
if (opts.agent === "brightsy") return { action: "none" };
|
|
2599
|
+
if (opts.queueLength > 0) return { action: "none" };
|
|
2600
|
+
if (opts.continueCount >= MAX_JOB_CONTINUES) return { action: "none" };
|
|
2601
|
+
const farewell = looksLikeDeferredDonePromise(opts.chatText);
|
|
2602
|
+
if (opts.runningJobIds.length > 0 && (farewell || opts.watchedJob)) {
|
|
2603
|
+
return {
|
|
2604
|
+
action: "wait",
|
|
2605
|
+
jobIds: opts.runningJobIds,
|
|
2606
|
+
prompt: formatJobStillRunningContinuePrompt(opts.runningJobIds)
|
|
2607
|
+
};
|
|
2608
|
+
}
|
|
2609
|
+
if (looksLikeDeferredDonePromise(opts.chatText) && !opts.alreadyNudged) {
|
|
2610
|
+
return { action: "nudge", prompt: formatDeferredDoneContinuePrompt() };
|
|
2611
|
+
}
|
|
2612
|
+
return { action: "none" };
|
|
2613
|
+
}
|
|
2614
|
+
function tailProgress(logFile, maxLines = 12) {
|
|
2615
|
+
if (!existsSync8(logFile)) return "(no log yet)";
|
|
2616
|
+
const lines = readFileSync7(logFile, "utf8").split("\n");
|
|
2617
|
+
return lines.slice(-maxLines).join("\n");
|
|
2618
|
+
}
|
|
2619
|
+
function readLogLines(file) {
|
|
2620
|
+
if (!existsSync8(file)) return [];
|
|
2621
|
+
const lines = readFileSync7(file, "utf8").split("\n");
|
|
2622
|
+
if (lines.length && lines[lines.length - 1] === "") lines.pop();
|
|
2623
|
+
return lines;
|
|
2624
|
+
}
|
|
2625
|
+
function takeDelta(logFile, cursorFile) {
|
|
2626
|
+
const lines = readLogLines(logFile);
|
|
2627
|
+
const cursor = readIntFile(cursorFile) ?? 0;
|
|
2628
|
+
const start = Math.min(Math.max(0, cursor), lines.length);
|
|
2629
|
+
return { delta: lines.slice(start).join("\n"), nextCursor: lines.length };
|
|
2630
|
+
}
|
|
2631
|
+
function snapshotJob(dir) {
|
|
2632
|
+
const pid = readIntFile(join10(dir, "pid"));
|
|
2633
|
+
const running = pid != null && jobAlive(pid);
|
|
2634
|
+
return {
|
|
2635
|
+
pid,
|
|
2636
|
+
running,
|
|
2637
|
+
exitCode: readIntFile(join10(dir, "exit")),
|
|
2638
|
+
log: join10(dir, "log"),
|
|
2639
|
+
cursor: join10(dir, "present.cursor"),
|
|
2640
|
+
progress: tailProgress(join10(dir, "log"))
|
|
2641
|
+
};
|
|
2642
|
+
}
|
|
2643
|
+
function toResult(id, snap, extra) {
|
|
2644
|
+
const failed = extra?.failed === true || !snap.running && snap.exitCode != null && snap.exitCode !== 0;
|
|
2645
|
+
const ok = !snap.running && snap.exitCode === 0;
|
|
2646
|
+
const stillRunning = snap.running && !ok;
|
|
2647
|
+
const { delta, nextCursor } = takeDelta(snap.log, snap.cursor);
|
|
2648
|
+
try {
|
|
2649
|
+
mkdirSync3(dirname3(snap.cursor), { recursive: true });
|
|
2650
|
+
writeFileSync4(snap.cursor, `${nextCursor}
|
|
2651
|
+
`);
|
|
2652
|
+
} catch {
|
|
2653
|
+
}
|
|
2654
|
+
const status = ok ? "ok" : failed && !stillRunning ? "failed" : stillRunning ? "running" : "idle";
|
|
2655
|
+
return {
|
|
2656
|
+
stillRunning,
|
|
2657
|
+
ok,
|
|
2658
|
+
failed: Boolean(failed && !stillRunning && !ok),
|
|
2659
|
+
status,
|
|
2660
|
+
id,
|
|
2661
|
+
pid: snap.pid,
|
|
2662
|
+
exitCode: snap.exitCode ?? void 0,
|
|
2663
|
+
delta,
|
|
2664
|
+
progress: extra?.progress ?? snap.progress,
|
|
2665
|
+
hint: stillRunning ? MCP_WAIT_JOB_STILL_RUNNING_HINT : void 0
|
|
2666
|
+
};
|
|
2667
|
+
}
|
|
2668
|
+
async function sleepMs(ms) {
|
|
2669
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
2670
|
+
}
|
|
2671
|
+
async function waitForDetachedJob(cwd, id, opts) {
|
|
2672
|
+
const jobId = sanitizeDetachedJobId(id);
|
|
2673
|
+
const root = cwd.trim() || process.cwd();
|
|
2674
|
+
const dir = resolveJobDir(root, jobId);
|
|
2675
|
+
const timeoutMs = mcpWaitForJobTimeoutMs(opts?.timeoutMs);
|
|
2676
|
+
const sleep = opts?.sleep ?? sleepMs;
|
|
2677
|
+
if (!existsSync8(dir)) {
|
|
2678
|
+
return {
|
|
2679
|
+
stillRunning: false,
|
|
2680
|
+
ok: false,
|
|
2681
|
+
failed: true,
|
|
2682
|
+
status: "failed",
|
|
2683
|
+
id: jobId,
|
|
2684
|
+
delta: "",
|
|
2685
|
+
progress: "No detached job. Start one first.",
|
|
2686
|
+
hint: "Start with detached-job.js start <id> -- <command>, then call wait_for_job again."
|
|
2687
|
+
};
|
|
2688
|
+
}
|
|
2689
|
+
const deadline = Date.now() + timeoutMs;
|
|
2690
|
+
let snap = snapshotJob(dir);
|
|
2691
|
+
if (snap.exitCode === 0 && !snap.running) return toResult(jobId, snap);
|
|
2692
|
+
if (!snap.running && snap.pid == null && snap.progress === "(no log yet)") {
|
|
2693
|
+
return toResult(jobId, snap, {
|
|
2694
|
+
failed: true,
|
|
2695
|
+
progress: "No detached job. Start one first."
|
|
2696
|
+
});
|
|
2697
|
+
}
|
|
2698
|
+
while (Date.now() < deadline) {
|
|
2699
|
+
snap = snapshotJob(dir);
|
|
2700
|
+
if (snap.exitCode === 0 && !snap.running) return toResult(jobId, snap);
|
|
2701
|
+
if (!snap.running) return toResult(jobId, snap, { failed: true });
|
|
2702
|
+
await sleep(Math.min(2e3, Math.max(50, deadline - Date.now())));
|
|
2703
|
+
}
|
|
2704
|
+
snap = snapshotJob(dir);
|
|
2705
|
+
return toResult(jobId, snap);
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2480
2708
|
// src/threads/create.ts
|
|
2481
|
-
import { existsSync as
|
|
2709
|
+
import { existsSync as existsSync9 } from "fs";
|
|
2482
2710
|
|
|
2483
2711
|
// src/detect/detect.ts
|
|
2484
2712
|
var REQUIRE_AGENT_TIMEOUT_MS = 8e3;
|
|
@@ -2998,7 +3226,7 @@ function reuseLiveThread(input, repoPath, match) {
|
|
|
2998
3226
|
}
|
|
2999
3227
|
async function createThread(input, _onSetupLine) {
|
|
3000
3228
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
3001
|
-
if (!
|
|
3229
|
+
if (!existsSync9(repoPath)) {
|
|
3002
3230
|
throw new Error(`Repo not found: ${repoPath}`);
|
|
3003
3231
|
}
|
|
3004
3232
|
const reused = reuseLiveThread(input, repoPath, {
|
|
@@ -3073,7 +3301,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3073
3301
|
let sourceIsFork = false;
|
|
3074
3302
|
if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
|
|
3075
3303
|
if (isAbleTimeConnected() && getIssueSource() === "abletime") {
|
|
3076
|
-
const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-
|
|
3304
|
+
const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-BEIDJG7W.js");
|
|
3077
3305
|
const task = await ensureAbleTimeTask({
|
|
3078
3306
|
title: title?.trim() || "Untitled work",
|
|
3079
3307
|
description: input.prompt?.trim() || void 0
|
|
@@ -3184,11 +3412,11 @@ function shouldRemoveWorktreeOnTeardown(thread) {
|
|
|
3184
3412
|
|
|
3185
3413
|
// src/store/turn-live.ts
|
|
3186
3414
|
import {
|
|
3187
|
-
existsSync as
|
|
3415
|
+
existsSync as existsSync10,
|
|
3188
3416
|
renameSync,
|
|
3189
3417
|
unlinkSync as unlinkSync2,
|
|
3190
|
-
writeFileSync as
|
|
3191
|
-
readFileSync as
|
|
3418
|
+
writeFileSync as writeFileSync5,
|
|
3419
|
+
readFileSync as readFileSync8
|
|
3192
3420
|
} from "fs";
|
|
3193
3421
|
var buffers = /* @__PURE__ */ new Map();
|
|
3194
3422
|
var FLUSH_MS = 800;
|
|
@@ -3265,7 +3493,7 @@ function writeTurnLive(threadId, progress) {
|
|
|
3265
3493
|
const path = threadLivePath(threadId);
|
|
3266
3494
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
3267
3495
|
try {
|
|
3268
|
-
|
|
3496
|
+
writeFileSync5(tmp, JSON.stringify(progress), "utf8");
|
|
3269
3497
|
renameSync(tmp, path);
|
|
3270
3498
|
} catch {
|
|
3271
3499
|
try {
|
|
@@ -3276,9 +3504,9 @@ function writeTurnLive(threadId, progress) {
|
|
|
3276
3504
|
}
|
|
3277
3505
|
function readTurnLive(threadId) {
|
|
3278
3506
|
const path = threadLivePath(threadId);
|
|
3279
|
-
if (!
|
|
3507
|
+
if (!existsSync10(path)) return null;
|
|
3280
3508
|
try {
|
|
3281
|
-
const raw = JSON.parse(
|
|
3509
|
+
const raw = JSON.parse(readFileSync8(path, "utf8"));
|
|
3282
3510
|
if (!raw || typeof raw.summary !== "string") return null;
|
|
3283
3511
|
return raw;
|
|
3284
3512
|
} catch {
|
|
@@ -3290,7 +3518,7 @@ function clearTurnLive(threadId) {
|
|
|
3290
3518
|
if (buf?.timer) clearTimeout(buf.timer);
|
|
3291
3519
|
buffers.delete(threadId);
|
|
3292
3520
|
const path = threadLivePath(threadId);
|
|
3293
|
-
if (!
|
|
3521
|
+
if (!existsSync10(path)) return;
|
|
3294
3522
|
try {
|
|
3295
3523
|
unlinkSync2(path);
|
|
3296
3524
|
} catch {
|
|
@@ -3475,26 +3703,26 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
|
|
|
3475
3703
|
import { execFileSync } from "child_process";
|
|
3476
3704
|
import {
|
|
3477
3705
|
copyFileSync as copyFileSync2,
|
|
3478
|
-
existsSync as
|
|
3706
|
+
existsSync as existsSync11,
|
|
3479
3707
|
mkdtempSync,
|
|
3480
|
-
readdirSync as
|
|
3481
|
-
readFileSync as
|
|
3708
|
+
readdirSync as readdirSync4,
|
|
3709
|
+
readFileSync as readFileSync9,
|
|
3482
3710
|
rmSync
|
|
3483
3711
|
} from "fs";
|
|
3484
3712
|
import { tmpdir } from "os";
|
|
3485
|
-
import { join as
|
|
3713
|
+
import { join as join11 } from "path";
|
|
3486
3714
|
import { createRequire } from "module";
|
|
3487
|
-
var CONDUCTOR_APP_SUPPORT =
|
|
3715
|
+
var CONDUCTOR_APP_SUPPORT = join11(
|
|
3488
3716
|
process.env.HOME ?? "",
|
|
3489
3717
|
"Library",
|
|
3490
3718
|
"Application Support",
|
|
3491
3719
|
"com.conductor.app"
|
|
3492
3720
|
);
|
|
3493
|
-
var CONDUCTOR_DB =
|
|
3494
|
-
var CURSOR_SDK_STORE =
|
|
3721
|
+
var CONDUCTOR_DB = join11(CONDUCTOR_APP_SUPPORT, "conductor.db");
|
|
3722
|
+
var CURSOR_SDK_STORE = join11(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
|
|
3495
3723
|
function thisModuleFile() {
|
|
3496
3724
|
const cjsFile = typeof __filename !== "undefined" ? __filename : "";
|
|
3497
|
-
return cjsFile || process.argv[1] ||
|
|
3725
|
+
return cjsFile || process.argv[1] || join11(process.cwd(), "package.json");
|
|
3498
3726
|
}
|
|
3499
3727
|
function openReadonlySqlite(file) {
|
|
3500
3728
|
const req = createRequire(thisModuleFile());
|
|
@@ -3512,21 +3740,21 @@ function mapAgentType(raw) {
|
|
|
3512
3740
|
return null;
|
|
3513
3741
|
}
|
|
3514
3742
|
function resolveConductorCursorAgentId(workspacePath) {
|
|
3515
|
-
if (!workspacePath || !
|
|
3743
|
+
if (!workspacePath || !existsSync11(CURSOR_SDK_STORE)) return null;
|
|
3516
3744
|
const normalized = workspacePath.replace(/\/$/, "");
|
|
3517
3745
|
let best = null;
|
|
3518
3746
|
let hashes;
|
|
3519
3747
|
try {
|
|
3520
|
-
hashes =
|
|
3748
|
+
hashes = readdirSync4(CURSOR_SDK_STORE);
|
|
3521
3749
|
} catch {
|
|
3522
3750
|
return null;
|
|
3523
3751
|
}
|
|
3524
3752
|
for (const hash of hashes) {
|
|
3525
|
-
const agentsFile =
|
|
3526
|
-
if (!
|
|
3753
|
+
const agentsFile = join11(CURSOR_SDK_STORE, hash, "agents.ndjson");
|
|
3754
|
+
if (!existsSync11(agentsFile)) continue;
|
|
3527
3755
|
let text;
|
|
3528
3756
|
try {
|
|
3529
|
-
text =
|
|
3757
|
+
text = readFileSync9(agentsFile, "utf8");
|
|
3530
3758
|
} catch {
|
|
3531
3759
|
continue;
|
|
3532
3760
|
}
|
|
@@ -3550,7 +3778,7 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
3550
3778
|
return best?.agentId ?? null;
|
|
3551
3779
|
}
|
|
3552
3780
|
async function adoptThread(input) {
|
|
3553
|
-
if (!
|
|
3781
|
+
if (!existsSync11(input.worktreePath)) {
|
|
3554
3782
|
throw new Error(`Worktree not found: ${input.worktreePath}`);
|
|
3555
3783
|
}
|
|
3556
3784
|
const repoPath = await resolveRepoRoot(input.worktreePath);
|
|
@@ -3569,23 +3797,23 @@ async function adoptThread(input) {
|
|
|
3569
3797
|
messages: input.messages ?? []
|
|
3570
3798
|
});
|
|
3571
3799
|
writeThread(thread);
|
|
3572
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
3800
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-OCEPZXFD.js");
|
|
3573
3801
|
await ensureWorkspace2(repoPath);
|
|
3574
3802
|
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-N5X5I422.js");
|
|
3575
3803
|
await ensureWorktreeSideboardIgnored2(input.worktreePath);
|
|
3576
3804
|
return thread;
|
|
3577
3805
|
}
|
|
3578
3806
|
function listConductorWorkspaces() {
|
|
3579
|
-
if (!
|
|
3807
|
+
if (!existsSync11(CONDUCTOR_DB)) {
|
|
3580
3808
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
3581
3809
|
}
|
|
3582
|
-
const tmp = mkdtempSync(
|
|
3583
|
-
const snapshot =
|
|
3810
|
+
const tmp = mkdtempSync(join11(tmpdir(), "sideboard-conductor-"));
|
|
3811
|
+
const snapshot = join11(tmp, "conductor.db");
|
|
3584
3812
|
try {
|
|
3585
3813
|
copyFileSync2(CONDUCTOR_DB, snapshot);
|
|
3586
3814
|
for (const suffix of ["-wal", "-shm"]) {
|
|
3587
3815
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
3588
|
-
if (
|
|
3816
|
+
if (existsSync11(src)) {
|
|
3589
3817
|
try {
|
|
3590
3818
|
copyFileSync2(src, `${snapshot}${suffix}`);
|
|
3591
3819
|
} catch {
|
|
@@ -3667,16 +3895,16 @@ function listConductorWorkspaces() {
|
|
|
3667
3895
|
}
|
|
3668
3896
|
}
|
|
3669
3897
|
function importConductorWorkspace(workspaceId) {
|
|
3670
|
-
if (!
|
|
3898
|
+
if (!existsSync11(CONDUCTOR_DB)) {
|
|
3671
3899
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
3672
3900
|
}
|
|
3673
|
-
const tmp = mkdtempSync(
|
|
3674
|
-
const snapshot =
|
|
3901
|
+
const tmp = mkdtempSync(join11(tmpdir(), "sideboard-conductor-"));
|
|
3902
|
+
const snapshot = join11(tmp, "conductor.db");
|
|
3675
3903
|
try {
|
|
3676
3904
|
copyFileSync2(CONDUCTOR_DB, snapshot);
|
|
3677
3905
|
for (const suffix of ["-wal", "-shm"]) {
|
|
3678
3906
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
3679
|
-
if (
|
|
3907
|
+
if (existsSync11(src)) {
|
|
3680
3908
|
try {
|
|
3681
3909
|
copyFileSync2(src, `${snapshot}${suffix}`);
|
|
3682
3910
|
} catch {
|
|
@@ -3696,7 +3924,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
3696
3924
|
).get(workspaceId);
|
|
3697
3925
|
if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
|
|
3698
3926
|
const worktreePath = String(row.workspacePath);
|
|
3699
|
-
if (!
|
|
3927
|
+
if (!existsSync11(worktreePath)) {
|
|
3700
3928
|
throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
|
|
3701
3929
|
}
|
|
3702
3930
|
let sessionId = null;
|
|
@@ -3767,7 +3995,7 @@ async function importConductorWorkspaceAsync(workspaceId) {
|
|
|
3767
3995
|
}
|
|
3768
3996
|
|
|
3769
3997
|
// src/threads/stack-layers.ts
|
|
3770
|
-
import { existsSync as
|
|
3998
|
+
import { existsSync as existsSync12 } from "fs";
|
|
3771
3999
|
function stackIdFrom(stack) {
|
|
3772
4000
|
if (stack.stackNumber != null) return `gh-stack-${stack.stackNumber}`;
|
|
3773
4001
|
const key = stack.layers.map((l) => l.branchName).join("|");
|
|
@@ -3830,7 +4058,7 @@ async function openStackLayer(input, _onSetupLine) {
|
|
|
3830
4058
|
let createdWorktree = false;
|
|
3831
4059
|
const trees = await listWorktrees(repoPath);
|
|
3832
4060
|
const checkedOut = trees.find((w) => w.branch === branchName);
|
|
3833
|
-
if (checkedOut?.path &&
|
|
4061
|
+
if (checkedOut?.path && existsSync12(checkedOut.path)) {
|
|
3834
4062
|
if (input.reuseExistingWorktree !== false) {
|
|
3835
4063
|
worktreePath = checkedOut.path;
|
|
3836
4064
|
} else {
|
|
@@ -3972,7 +4200,7 @@ async function initStackFromThread(input, onSetupLine) {
|
|
|
3972
4200
|
async function createPrStack(input, onSetupLine) {
|
|
3973
4201
|
await requireAgent(input.agent);
|
|
3974
4202
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
3975
|
-
if (!
|
|
4203
|
+
if (!existsSync12(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
|
|
3976
4204
|
if (!input.branches.length) throw new Error("At least one branch name required");
|
|
3977
4205
|
const status = await detectGhStack(repoPath);
|
|
3978
4206
|
if (!status.available) throw new Error(status.reason);
|
|
@@ -4039,7 +4267,7 @@ async function createPrStack(input, onSetupLine) {
|
|
|
4039
4267
|
}
|
|
4040
4268
|
}
|
|
4041
4269
|
const claimed = new Set(threads.map((t) => t.worktreePath));
|
|
4042
|
-
if (!claimed.has(bootstrap.worktreePath) &&
|
|
4270
|
+
if (!claimed.has(bootstrap.worktreePath) && existsSync12(bootstrap.worktreePath)) {
|
|
4043
4271
|
try {
|
|
4044
4272
|
await removeWorktree(repoPath, bootstrap.worktreePath, {
|
|
4045
4273
|
deleteBranch: bootstrap.branchName
|
|
@@ -4051,10 +4279,10 @@ async function createPrStack(input, onSetupLine) {
|
|
|
4051
4279
|
}
|
|
4052
4280
|
|
|
4053
4281
|
// src/diff/diff.ts
|
|
4054
|
-
import { existsSync as
|
|
4055
|
-
import { dirname as
|
|
4282
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync4, readFileSync as readFileSync10, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
4283
|
+
import { dirname as dirname4, join as join12 } from "path";
|
|
4056
4284
|
async function inspectGitWorktree(worktreePath) {
|
|
4057
|
-
if (!worktreePath || !
|
|
4285
|
+
if (!worktreePath || !existsSync13(worktreePath)) return "missing_worktree";
|
|
4058
4286
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
4059
4287
|
reject: false
|
|
4060
4288
|
});
|
|
@@ -4062,7 +4290,7 @@ async function inspectGitWorktree(worktreePath) {
|
|
|
4062
4290
|
return "ok";
|
|
4063
4291
|
}
|
|
4064
4292
|
async function initializeGitRepository(worktreePath) {
|
|
4065
|
-
if (!worktreePath || !
|
|
4293
|
+
if (!worktreePath || !existsSync13(worktreePath)) {
|
|
4066
4294
|
throw new Error("Worktree not found");
|
|
4067
4295
|
}
|
|
4068
4296
|
const status = await inspectGitWorktree(worktreePath);
|
|
@@ -4198,11 +4426,11 @@ new file mode 100644
|
|
|
4198
4426
|
};
|
|
4199
4427
|
}
|
|
4200
4428
|
async function untrackedPatch(worktreePath, path, maxHunk) {
|
|
4201
|
-
const abs =
|
|
4429
|
+
const abs = join12(worktreePath, path);
|
|
4202
4430
|
try {
|
|
4203
4431
|
const st = statSync2(abs);
|
|
4204
4432
|
if (st.isFile() && st.size > maxHunk) {
|
|
4205
|
-
const buf =
|
|
4433
|
+
const buf = readFileSync10(abs).subarray(0, maxHunk);
|
|
4206
4434
|
return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
|
|
4207
4435
|
}
|
|
4208
4436
|
} catch {
|
|
@@ -4703,7 +4931,7 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
|
|
|
4703
4931
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
4704
4932
|
assertSafeRelativePath(relativePath);
|
|
4705
4933
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
4706
|
-
const abs =
|
|
4934
|
+
const abs = join12(worktreePath, relativePath);
|
|
4707
4935
|
const st = statSync2(abs);
|
|
4708
4936
|
if (!st.isFile()) {
|
|
4709
4937
|
throw new Error(`Not a file: ${relativePath}`);
|
|
@@ -4713,7 +4941,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
4713
4941
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
4714
4942
|
);
|
|
4715
4943
|
}
|
|
4716
|
-
const buf =
|
|
4944
|
+
const buf = readFileSync10(abs);
|
|
4717
4945
|
return {
|
|
4718
4946
|
path: relativePath,
|
|
4719
4947
|
contentBase64: buf.toString("base64"),
|
|
@@ -4723,12 +4951,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
4723
4951
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
4724
4952
|
assertSafeRelativePath(relativePath);
|
|
4725
4953
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
4726
|
-
const abs =
|
|
4954
|
+
const abs = join12(worktreePath, relativePath);
|
|
4727
4955
|
const st = statSync2(abs);
|
|
4728
4956
|
if (!st.isFile()) {
|
|
4729
4957
|
throw new Error(`Not a file: ${relativePath}`);
|
|
4730
4958
|
}
|
|
4731
|
-
const buf =
|
|
4959
|
+
const buf = readFileSync10(abs);
|
|
4732
4960
|
if (isImageRelativePath(relativePath)) {
|
|
4733
4961
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
4734
4962
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -4771,9 +4999,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
4771
4999
|
}
|
|
4772
5000
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
4773
5001
|
assertSafeRelativePath(relativePath);
|
|
4774
|
-
const abs =
|
|
4775
|
-
|
|
4776
|
-
|
|
5002
|
+
const abs = join12(worktreePath, relativePath);
|
|
5003
|
+
mkdirSync4(dirname4(abs), { recursive: true });
|
|
5004
|
+
writeFileSync6(abs, content, "utf8");
|
|
4777
5005
|
return { path: relativePath };
|
|
4778
5006
|
}
|
|
4779
5007
|
async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
@@ -4898,9 +5126,9 @@ async function confirmLand(thread, opts) {
|
|
|
4898
5126
|
}
|
|
4899
5127
|
|
|
4900
5128
|
// src/skills/discover.ts
|
|
4901
|
-
import { existsSync as
|
|
5129
|
+
import { existsSync as existsSync14, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync3 } from "fs";
|
|
4902
5130
|
import { homedir } from "os";
|
|
4903
|
-
import { join as
|
|
5131
|
+
import { join as join13 } from "path";
|
|
4904
5132
|
|
|
4905
5133
|
// src/skills/bundled/long-running.ts
|
|
4906
5134
|
var LONG_RUNNING_SKILL_COMMAND = "long-running";
|
|
@@ -4911,7 +5139,7 @@ var LONG_RUNNING_SKILL_BODY = `# Long-running jobs
|
|
|
4911
5139
|
|
|
4912
5140
|
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.
|
|
4913
5141
|
|
|
4914
|
-
Do **not** ask the human to check back. Detach, then **wait** in 45s slices (same idea as
|
|
5142
|
+
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
|
|
4915
5143
|
|
|
4916
5144
|
## Tool
|
|
4917
5145
|
|
|
@@ -4921,7 +5149,8 @@ Use the helper from the Sideboard playbook \u2014 an absolute \`node "\u2026" st
|
|
|
4921
5149
|
# Start (exits in ~1s; job survives this turn)
|
|
4922
5150
|
node <detached-job.js> start <id> -- <command> [args...]
|
|
4923
5151
|
|
|
4924
|
-
# Wait \u2014
|
|
5152
|
+
# Wait \u2014 prefer MCP wait_for_job (same 45s / stillRunning contract).
|
|
5153
|
+
# Shell fallback:
|
|
4925
5154
|
node <detached-job.js> wait <id>
|
|
4926
5155
|
|
|
4927
5156
|
# Block until the process exits (humans / a turn that will not be interrupted)
|
|
@@ -4934,7 +5163,7 @@ node <detached-job.js> status <id>
|
|
|
4934
5163
|
|
|
4935
5164
|
Wait JSON:
|
|
4936
5165
|
|
|
4937
|
-
- \`stillRunning: true\` \u2192
|
|
5166
|
+
- \`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.
|
|
4938
5167
|
- \`ok: true\` \u2192 exit 0 \u2192 continue the rest of the task.
|
|
4939
5168
|
- \`failed: true\` \u2192 exit 1 \u2192 read \`progress\`, fix, start **once**.
|
|
4940
5169
|
|
|
@@ -4964,7 +5193,7 @@ node <detached-job.js> wait --pid-file FILE --log-file FILE [--ok-pattern TEXT]
|
|
|
4964
5193
|
|
|
4965
5194
|
1. \`start\` once. If JSON says \`already-running\`, do not start again.
|
|
4966
5195
|
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.
|
|
4967
|
-
3. Loop \`
|
|
5196
|
+
3. Loop \`wait_for_job\` (or shell \`wait\`). After each slice, \`present_artifact\` the same id with \`content=delta\` only.
|
|
4968
5197
|
4. On \`ok\`, present once more (\`status=ok\`, last \`delta\`) and finish the task. On \`failed\`, fix from the log.
|
|
4969
5198
|
|
|
4970
5199
|
Never tell the user \u201Csay status when it\u2019s done.\u201D You wait.
|
|
@@ -5029,7 +5258,7 @@ function parseFrontmatter(content) {
|
|
|
5029
5258
|
}
|
|
5030
5259
|
function readSkill(skillMd, source) {
|
|
5031
5260
|
try {
|
|
5032
|
-
const content =
|
|
5261
|
+
const content = readFileSync11(skillMd, "utf8");
|
|
5033
5262
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
5034
5263
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
5035
5264
|
const name = fmName || dirName;
|
|
@@ -5048,17 +5277,17 @@ function readSkill(skillMd, source) {
|
|
|
5048
5277
|
}
|
|
5049
5278
|
}
|
|
5050
5279
|
function scanSkillsDir(dir, source, out) {
|
|
5051
|
-
if (!
|
|
5280
|
+
if (!existsSync14(dir)) return;
|
|
5052
5281
|
let entries;
|
|
5053
5282
|
try {
|
|
5054
|
-
entries =
|
|
5283
|
+
entries = readdirSync5(dir);
|
|
5055
5284
|
} catch {
|
|
5056
5285
|
return;
|
|
5057
5286
|
}
|
|
5058
5287
|
for (const entry of entries) {
|
|
5059
5288
|
if (entry.startsWith(".")) continue;
|
|
5060
|
-
const skillMd =
|
|
5061
|
-
if (!
|
|
5289
|
+
const skillMd = join13(dir, entry, "SKILL.md");
|
|
5290
|
+
if (!existsSync14(skillMd)) continue;
|
|
5062
5291
|
try {
|
|
5063
5292
|
if (!statSync3(skillMd).isFile()) continue;
|
|
5064
5293
|
} catch {
|
|
@@ -5069,22 +5298,22 @@ function scanSkillsDir(dir, source, out) {
|
|
|
5069
5298
|
}
|
|
5070
5299
|
}
|
|
5071
5300
|
function scanClaudePluginSkills(pluginsRoot, out) {
|
|
5072
|
-
if (!
|
|
5301
|
+
if (!existsSync14(pluginsRoot)) return;
|
|
5073
5302
|
const walk = (dir, depth, lookingForSkillsDir) => {
|
|
5074
5303
|
if (depth > 7) return;
|
|
5075
5304
|
let entries;
|
|
5076
5305
|
try {
|
|
5077
|
-
entries =
|
|
5306
|
+
entries = readdirSync5(dir);
|
|
5078
5307
|
} catch {
|
|
5079
5308
|
return;
|
|
5080
5309
|
}
|
|
5081
5310
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
5082
|
-
const skill = readSkill(
|
|
5311
|
+
const skill = readSkill(join13(dir, "SKILL.md"), "cli");
|
|
5083
5312
|
if (skill) out.push(skill);
|
|
5084
5313
|
}
|
|
5085
5314
|
for (const entry of entries) {
|
|
5086
5315
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
5087
|
-
const full =
|
|
5316
|
+
const full = join13(dir, entry);
|
|
5088
5317
|
try {
|
|
5089
5318
|
if (!statSync3(full).isDirectory()) continue;
|
|
5090
5319
|
} catch {
|
|
@@ -5104,17 +5333,17 @@ function discoverSkills(worktreePath) {
|
|
|
5104
5333
|
const home = homedir();
|
|
5105
5334
|
const collected = [];
|
|
5106
5335
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
5107
|
-
scanSkillsDir(
|
|
5336
|
+
scanSkillsDir(join13(worktreePath, rel), "workspace", collected);
|
|
5108
5337
|
}
|
|
5109
5338
|
for (const abs of [
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5339
|
+
join13(home, ".claude/skills"),
|
|
5340
|
+
join13(home, ".cursor/skills"),
|
|
5341
|
+
join13(home, ".sideboard/skills"),
|
|
5342
|
+
join13(home, ".brightsy/skills")
|
|
5114
5343
|
]) {
|
|
5115
5344
|
scanSkillsDir(abs, "user", collected);
|
|
5116
5345
|
}
|
|
5117
|
-
scanClaudePluginSkills(
|
|
5346
|
+
scanClaudePluginSkills(join13(home, ".claude/plugins"), collected);
|
|
5118
5347
|
collected.push(...bundledSkills());
|
|
5119
5348
|
const rank = {
|
|
5120
5349
|
workspace: 0,
|
|
@@ -5140,7 +5369,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
5140
5369
|
\u2026(truncated)` : body;
|
|
5141
5370
|
}
|
|
5142
5371
|
}
|
|
5143
|
-
const raw =
|
|
5372
|
+
const raw = readFileSync11(skillPath, "utf8");
|
|
5144
5373
|
if (raw.startsWith("---")) {
|
|
5145
5374
|
const end = raw.indexOf("\n---", 3);
|
|
5146
5375
|
if (end >= 0) {
|
|
@@ -5233,27 +5462,27 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
|
|
|
5233
5462
|
}
|
|
5234
5463
|
|
|
5235
5464
|
// src/agents/instructions.ts
|
|
5236
|
-
import { existsSync as
|
|
5237
|
-
import { join as
|
|
5465
|
+
import { existsSync as existsSync16, readFileSync as readFileSync12, statSync as statSync4 } from "fs";
|
|
5466
|
+
import { join as join15 } from "path";
|
|
5238
5467
|
|
|
5239
5468
|
// src/skills/detached-job-path.ts
|
|
5240
|
-
import { existsSync as
|
|
5241
|
-
import { dirname as
|
|
5469
|
+
import { existsSync as existsSync15 } from "fs";
|
|
5470
|
+
import { dirname as dirname5, join as join14 } from "path";
|
|
5242
5471
|
import { fileURLToPath } from "url";
|
|
5243
5472
|
function packagedDetachedJobPath() {
|
|
5244
5473
|
const dir = packagedMcpDir();
|
|
5245
5474
|
if (!dir) return null;
|
|
5246
|
-
const script =
|
|
5247
|
-
return
|
|
5475
|
+
const script = join14(dir, "scripts", "detached-job.js");
|
|
5476
|
+
return existsSync15(script) ? script : null;
|
|
5248
5477
|
}
|
|
5249
5478
|
function resolveDetachedJobScript() {
|
|
5250
5479
|
const packaged = packagedDetachedJobPath();
|
|
5251
5480
|
if (packaged) return packaged;
|
|
5252
|
-
let dir =
|
|
5481
|
+
let dir = dirname5(fileURLToPath(import.meta.url));
|
|
5253
5482
|
for (let i = 0; i < 8; i++) {
|
|
5254
|
-
const candidate =
|
|
5255
|
-
if (
|
|
5256
|
-
const parent =
|
|
5483
|
+
const candidate = join14(dir, "scripts", "detached-job.js");
|
|
5484
|
+
if (existsSync15(candidate)) return candidate;
|
|
5485
|
+
const parent = dirname5(dir);
|
|
5257
5486
|
if (parent === dir) break;
|
|
5258
5487
|
dir = parent;
|
|
5259
5488
|
}
|
|
@@ -5372,6 +5601,66 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
5372
5601
|
function formatWorktreeReminder() {
|
|
5373
5602
|
return "Sideboard worktree: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout. If a goal is given (Greptile 5/5, CI green), watch-fix-push until it lands \u2014 do not watch after every push.";
|
|
5374
5603
|
}
|
|
5604
|
+
var GITHUB_TICKET_REF = /^(?:#?\d+|gh-\d+)$/i;
|
|
5605
|
+
var KEYED_TICKET_REF = /^(?:[A-Z][A-Z0-9]{0,9}-\d+|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i;
|
|
5606
|
+
function issueTicketFromThread(thread, preferredSource = "github") {
|
|
5607
|
+
if (thread?.sourceType !== "ticket") return null;
|
|
5608
|
+
const ref = thread.sourceRef?.trim() ?? "";
|
|
5609
|
+
if (!ref) return null;
|
|
5610
|
+
if (/github\.com\/[^/]+\/[^/]+\/issues\/\d+/i.test(ref) || GITHUB_TICKET_REF.test(ref)) {
|
|
5611
|
+
return { id: ref, provider: "github" };
|
|
5612
|
+
}
|
|
5613
|
+
if (KEYED_TICKET_REF.test(ref)) {
|
|
5614
|
+
return { id: ref, provider: preferredSource === "github" ? "linear" : preferredSource };
|
|
5615
|
+
}
|
|
5616
|
+
return { id: ref, provider: preferredSource };
|
|
5617
|
+
}
|
|
5618
|
+
function formatIssueToolsDirective(opts) {
|
|
5619
|
+
const github = opts.github !== false;
|
|
5620
|
+
if (!opts.linear && !opts.abletime && !github) return null;
|
|
5621
|
+
const lines = [
|
|
5622
|
+
"Issue tracking (Settings \u2192 Issues / Git \u2014 already signed in):",
|
|
5623
|
+
"- Use Sideboard `linear_*` / `github_*` / `abletime_*` tools. Do not call Claude Linear MCP, vendor GitHub MCP, or any other vendor issue MCP \u2014 those need a separate login and hang. If a vendor namespace shows needsAuth, ignore it and keep going with Sideboard tools."
|
|
5624
|
+
];
|
|
5625
|
+
if (opts.linear) {
|
|
5626
|
+
lines.push(
|
|
5627
|
+
"- Linear: `linear_get_issue` (comments), `linear_comment`, `linear_update_issue` (state), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
|
|
5628
|
+
);
|
|
5629
|
+
}
|
|
5630
|
+
if (github) {
|
|
5631
|
+
lines.push(
|
|
5632
|
+
"- GitHub: `github_get_issue` (comments), `github_comment`, `github_update_issue` (state open|closed), `github_create_issue` (pass `parent` for spin-offs). Uses Account `gh`."
|
|
5633
|
+
);
|
|
5634
|
+
}
|
|
5635
|
+
if (opts.abletime) {
|
|
5636
|
+
lines.push(
|
|
5637
|
+
"- AbleTime: `abletime_get_task` (comments), `abletime_comment`, `abletime_update_task` (state), `abletime_create_task` (pass `parent` for spin-offs; `abletime_list_projects` if needed)."
|
|
5638
|
+
);
|
|
5639
|
+
}
|
|
5640
|
+
lines.push(
|
|
5641
|
+
"- Do not ask the user to `claude mcp login` for tickets. Reconnect the Account source in Settings \u2192 Issues (or Git for `gh`)."
|
|
5642
|
+
);
|
|
5643
|
+
const ticket = opts.ticketId?.trim();
|
|
5644
|
+
if (ticket) {
|
|
5645
|
+
const provider = opts.ticketProvider ?? "linear";
|
|
5646
|
+
lines.push(
|
|
5647
|
+
`- This thread's ticket is \`${ticket}\` (${provider}). Use that id for get/comment/update; pass it as \`parent\` on spin-offs.`
|
|
5648
|
+
);
|
|
5649
|
+
}
|
|
5650
|
+
return lines.join("\n");
|
|
5651
|
+
}
|
|
5652
|
+
function formatIssueToolsReminder(opts) {
|
|
5653
|
+
const github = opts.github !== false;
|
|
5654
|
+
if (!opts.linear && !opts.abletime && !github) return null;
|
|
5655
|
+
const names = [
|
|
5656
|
+
opts.linear ? "linear_*" : null,
|
|
5657
|
+
github ? "github_*" : null,
|
|
5658
|
+
opts.abletime ? "abletime_*" : null
|
|
5659
|
+
].filter(Boolean);
|
|
5660
|
+
const ticket = opts.ticketId?.trim();
|
|
5661
|
+
const ticketBit = ticket ? ` This ticket: ${ticket}${opts.ticketProvider ? ` (${opts.ticketProvider})` : ""} \u2014 get/comment/update; create with parent for spin-offs.` : " get/comment/update/create (parent= for spin-offs).";
|
|
5662
|
+
return `Issues: Sideboard ${names.join(" / ")} (Account). Ignore vendor issue MCP auth.${ticketBit}`;
|
|
5663
|
+
}
|
|
5375
5664
|
function formatPrGateDirective() {
|
|
5376
5665
|
return [
|
|
5377
5666
|
"If a goal is given (not after every push):",
|
|
@@ -5399,14 +5688,15 @@ function formatLongRunningDirective(opts) {
|
|
|
5399
5688
|
`Helper (same tool as \`scripts/detached-job.js\` when that file exists in the worktree): \`${invoke}\``,
|
|
5400
5689
|
`- Start once: \`${invoke} start <id> -- <command> [args...]\` (cwd = this worktree). If JSON says already-running, do not start again.`,
|
|
5401
5690
|
"- Immediately `present_artifact` `type=log` with `artifact_id=<id>` and `status=running` \u2014 the side column is the live view.",
|
|
5402
|
-
`- Loop
|
|
5691
|
+
`- 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.`,
|
|
5692
|
+
"- Do not end the turn with \u201CI\u2019ll let you know when it\u2019s done.\u201D Stay in the loop until stillRunning is false.",
|
|
5403
5693
|
"- ok \u2192 finish the task. failed \u2192 read the log, fix, start once.",
|
|
5404
5694
|
"State: `.context/.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
|
|
5405
5695
|
].join("\n");
|
|
5406
5696
|
}
|
|
5407
5697
|
function formatLongRunningReminder(opts) {
|
|
5408
5698
|
const invoke = formatDetachedJobInvoke(opts?.scriptPath);
|
|
5409
|
-
return `Long jobs: \`${invoke} start <id> -- <cmd>\`, loop wait, present_artifact type=log (delta). Do not
|
|
5699
|
+
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.`;
|
|
5410
5700
|
}
|
|
5411
5701
|
function formatArtifactDirective() {
|
|
5412
5702
|
return [
|
|
@@ -5554,8 +5844,8 @@ async function syncThreadBranchFromGit(threadId) {
|
|
|
5554
5844
|
|
|
5555
5845
|
// src/store/schedules.ts
|
|
5556
5846
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
5557
|
-
import { existsSync as
|
|
5558
|
-
import { join as
|
|
5847
|
+
import { existsSync as existsSync17, readFileSync as readFileSync13 } from "fs";
|
|
5848
|
+
import { join as join16 } from "path";
|
|
5559
5849
|
import { Cron } from "croner";
|
|
5560
5850
|
var DURATION_RE = /^(\d+)(s|m|h|d)$/i;
|
|
5561
5851
|
var UNIT_MS = {
|
|
@@ -5565,7 +5855,7 @@ var UNIT_MS = {
|
|
|
5565
5855
|
d: 864e5
|
|
5566
5856
|
};
|
|
5567
5857
|
function schedulesPath() {
|
|
5568
|
-
return
|
|
5858
|
+
return join16(appDataDir(), "schedules.json");
|
|
5569
5859
|
}
|
|
5570
5860
|
function parseDurationMs(every) {
|
|
5571
5861
|
const m = every.trim().match(DURATION_RE);
|
|
@@ -5665,9 +5955,9 @@ function normalizeTask(raw) {
|
|
|
5665
5955
|
}
|
|
5666
5956
|
function readAll() {
|
|
5667
5957
|
const path = schedulesPath();
|
|
5668
|
-
if (!
|
|
5958
|
+
if (!existsSync17(path)) return [];
|
|
5669
5959
|
try {
|
|
5670
|
-
const parsed = JSON.parse(
|
|
5960
|
+
const parsed = JSON.parse(readFileSync13(path, "utf8"));
|
|
5671
5961
|
if (!Array.isArray(parsed)) return [];
|
|
5672
5962
|
return parsed.map((row) => {
|
|
5673
5963
|
try {
|
|
@@ -5790,7 +6080,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
5790
6080
|
${prompt}`;
|
|
5791
6081
|
}
|
|
5792
6082
|
async function defaultDeps() {
|
|
5793
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
6083
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-J727WIJY.js");
|
|
5794
6084
|
const orch = getOrchestrator2();
|
|
5795
6085
|
return {
|
|
5796
6086
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -5947,6 +6237,9 @@ var Orchestrator = class {
|
|
|
5947
6237
|
* finish or a user send so a later crash can recover again.
|
|
5948
6238
|
*/
|
|
5949
6239
|
crashContinued = /* @__PURE__ */ new Set();
|
|
6240
|
+
/** Auto-continues after a worktree turn ended while a detached job still runs. */
|
|
6241
|
+
jobContinueCount = /* @__PURE__ */ new Map();
|
|
6242
|
+
jobContinueNudged = /* @__PURE__ */ new Set();
|
|
5950
6243
|
maxConcurrent;
|
|
5951
6244
|
runningCount = 0;
|
|
5952
6245
|
constructor(opts) {
|
|
@@ -6030,7 +6323,7 @@ var Orchestrator = class {
|
|
|
6030
6323
|
}
|
|
6031
6324
|
continue;
|
|
6032
6325
|
}
|
|
6033
|
-
if (!
|
|
6326
|
+
if (!existsSync18(thread.worktreePath)) {
|
|
6034
6327
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
6035
6328
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
6036
6329
|
continue;
|
|
@@ -6245,6 +6538,37 @@ var Orchestrator = class {
|
|
|
6245
6538
|
this.emit({ type: "queue_changed", threadId, queue });
|
|
6246
6539
|
this.haltDrain.delete(threadId);
|
|
6247
6540
|
}
|
|
6541
|
+
/**
|
|
6542
|
+
* Worktree agent ended the turn after “I’ll let you know” (or left a
|
|
6543
|
+
* detached test/pack job running). Queue a continue so the chat does not
|
|
6544
|
+
* go idle with nobody watching the log.
|
|
6545
|
+
*/
|
|
6546
|
+
maybeEnqueueJobContinue(threadId, chatText, parts = []) {
|
|
6547
|
+
if (this.haltDrain.has(threadId)) return;
|
|
6548
|
+
const thread = readThread(threadId);
|
|
6549
|
+
if (!thread || thread.status === "archived") return;
|
|
6550
|
+
const runningJobIds = listRunningDetachedJobs(thread.worktreePath ?? "");
|
|
6551
|
+
const decision = planJobContinue({
|
|
6552
|
+
runningJobIds,
|
|
6553
|
+
chatText,
|
|
6554
|
+
queueLength: thread.queue.length,
|
|
6555
|
+
continueCount: this.jobContinueCount.get(threadId) ?? 0,
|
|
6556
|
+
alreadyNudged: this.jobContinueNudged.has(threadId),
|
|
6557
|
+
isOrchestrator: isOrchestratorThread(thread),
|
|
6558
|
+
agent: thread.agent,
|
|
6559
|
+
watchedJob: turnWatchedDetachedJob(parts)
|
|
6560
|
+
});
|
|
6561
|
+
if (decision.action === "none") {
|
|
6562
|
+
if (runningJobIds.length === 0) this.jobContinueCount.delete(threadId);
|
|
6563
|
+
return;
|
|
6564
|
+
}
|
|
6565
|
+
if (decision.action === "nudge") this.jobContinueNudged.add(threadId);
|
|
6566
|
+
else this.jobContinueCount.set(threadId, (this.jobContinueCount.get(threadId) ?? 0) + 1);
|
|
6567
|
+
const queue = [decision.prompt, ...thread.queue];
|
|
6568
|
+
updateThread(threadId, { queue });
|
|
6569
|
+
this.emit({ type: "queue_changed", threadId, queue });
|
|
6570
|
+
this.haltDrain.delete(threadId);
|
|
6571
|
+
}
|
|
6248
6572
|
getThreads(includeArchived = false) {
|
|
6249
6573
|
return listThreads({ includeArchived });
|
|
6250
6574
|
}
|
|
@@ -6344,6 +6668,8 @@ var Orchestrator = class {
|
|
|
6344
6668
|
}
|
|
6345
6669
|
const queue = [...current.queue, prompt];
|
|
6346
6670
|
this.crashContinued.delete(thread.id);
|
|
6671
|
+
this.jobContinueCount.delete(thread.id);
|
|
6672
|
+
this.jobContinueNudged.delete(thread.id);
|
|
6347
6673
|
this.haltDrain.delete(thread.id);
|
|
6348
6674
|
const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
|
|
6349
6675
|
shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
|
|
@@ -6558,6 +6884,14 @@ var Orchestrator = class {
|
|
|
6558
6884
|
const longRunningReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatLongRunningReminder() : null;
|
|
6559
6885
|
const worktreeReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatWorktreeReminder() : null;
|
|
6560
6886
|
const optionalServicesReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatOptionalServicesReminder(loadAppSettings().integrations) : null;
|
|
6887
|
+
const issueTicket = issueTicketFromThread(thread, resolveEffectiveIssueSource());
|
|
6888
|
+
const issueToolsReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatIssueToolsReminder({
|
|
6889
|
+
linear: isLinearConnected(),
|
|
6890
|
+
abletime: isAbleTimeConnected(),
|
|
6891
|
+
github: true,
|
|
6892
|
+
ticketId: issueTicket?.id,
|
|
6893
|
+
ticketProvider: issueTicket?.provider
|
|
6894
|
+
}) : null;
|
|
6561
6895
|
const slackReplyContext = formatSlackRepliesForTurn(
|
|
6562
6896
|
pendingSlackExternalReplies(thread.messages)
|
|
6563
6897
|
);
|
|
@@ -6566,6 +6900,7 @@ var Orchestrator = class {
|
|
|
6566
6900
|
orchestrationReminder,
|
|
6567
6901
|
worktreeReminder,
|
|
6568
6902
|
optionalServicesReminder,
|
|
6903
|
+
issueToolsReminder,
|
|
6569
6904
|
artifactReminder,
|
|
6570
6905
|
longRunningReminder,
|
|
6571
6906
|
slackReplyContext,
|
|
@@ -6598,6 +6933,14 @@ var Orchestrator = class {
|
|
|
6598
6933
|
const artifactDirective = isBrightsy ? null : formatArtifactDirective();
|
|
6599
6934
|
const longRunningDirective = isBrightsy || isOrchestration ? null : formatLongRunningDirective();
|
|
6600
6935
|
const optionalServicesDirective = isBrightsy || isOrchestration ? null : formatOptionalServicesDirective(loadAppSettings().integrations);
|
|
6936
|
+
const freshIssueTicket = issueTicketFromThread(fresh, resolveEffectiveIssueSource());
|
|
6937
|
+
const issueToolsDirective = isBrightsy || isOrchestration ? null : formatIssueToolsDirective({
|
|
6938
|
+
linear: isLinearConnected(),
|
|
6939
|
+
abletime: isAbleTimeConnected(),
|
|
6940
|
+
github: true,
|
|
6941
|
+
ticketId: freshIssueTicket?.id,
|
|
6942
|
+
ticketProvider: freshIssueTicket?.provider
|
|
6943
|
+
});
|
|
6601
6944
|
const settings = loadWorkspaceSettings(fresh.worktreePath, fresh.repoPath);
|
|
6602
6945
|
const renameBranchDirective = !isBrightsy && !isOrchestration && autoRenameBranchEnabled() ? formatRenameBranchDirective(fresh, {
|
|
6603
6946
|
customPrompt: settings?.prompts?.renameBranch
|
|
@@ -6628,6 +6971,7 @@ var Orchestrator = class {
|
|
|
6628
6971
|
coordinatorDirective,
|
|
6629
6972
|
worktreeDirective,
|
|
6630
6973
|
optionalServicesDirective,
|
|
6974
|
+
issueToolsDirective,
|
|
6631
6975
|
artifactDirective,
|
|
6632
6976
|
longRunningDirective,
|
|
6633
6977
|
renameBranchDirective,
|
|
@@ -6737,6 +7081,7 @@ var Orchestrator = class {
|
|
|
6737
7081
|
coordinatorDirective,
|
|
6738
7082
|
worktreeDirective,
|
|
6739
7083
|
optionalServicesDirective,
|
|
7084
|
+
issueToolsDirective,
|
|
6740
7085
|
artifactDirective,
|
|
6741
7086
|
longRunningDirective,
|
|
6742
7087
|
renameBranchDirective,
|
|
@@ -6839,6 +7184,7 @@ var Orchestrator = class {
|
|
|
6839
7184
|
this.emit({ type: "turn_finished", threadId, exitCode });
|
|
6840
7185
|
if (exitCode === 0) {
|
|
6841
7186
|
this.crashContinued.delete(threadId);
|
|
7187
|
+
this.maybeEnqueueJobContinue(threadId, chatText, parts);
|
|
6842
7188
|
} else {
|
|
6843
7189
|
const blob = [chatText, detail].filter(Boolean).join("\n");
|
|
6844
7190
|
void this.maybeHandleOrchestrationQuotaFailover(threadId, blob);
|
|
@@ -7791,7 +8137,7 @@ var Orchestrator = class {
|
|
|
7791
8137
|
this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
|
|
7792
8138
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
7793
8139
|
try {
|
|
7794
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
8140
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-OCEPZXFD.js");
|
|
7795
8141
|
await ensureWorkspace2(thread.repoPath);
|
|
7796
8142
|
} catch {
|
|
7797
8143
|
}
|
|
@@ -7839,13 +8185,13 @@ var Orchestrator = class {
|
|
|
7839
8185
|
this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
|
|
7840
8186
|
return restored2;
|
|
7841
8187
|
}
|
|
7842
|
-
if (!
|
|
8188
|
+
if (!existsSync18(thread.worktreePath)) {
|
|
7843
8189
|
if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
|
|
7844
8190
|
throw new Error(
|
|
7845
8191
|
`Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
|
|
7846
8192
|
);
|
|
7847
8193
|
}
|
|
7848
|
-
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-
|
|
8194
|
+
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-VTMBZKY6.js");
|
|
7849
8195
|
const slug = thread.worktreePath.split("/").pop();
|
|
7850
8196
|
const dest = thread.worktreePath;
|
|
7851
8197
|
await withRepoGitLock(thread.repoPath, async () => {
|
|
@@ -7955,7 +8301,7 @@ async function startOrchestration(opts) {
|
|
|
7955
8301
|
sourceRef: "default",
|
|
7956
8302
|
...createOpts
|
|
7957
8303
|
}).catch(async () => {
|
|
7958
|
-
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-
|
|
8304
|
+
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-VTMBZKY6.js");
|
|
7959
8305
|
const repo = await resolveRepoRoot2(repoPath);
|
|
7960
8306
|
const def = await resolveDefaultBranch2(repo);
|
|
7961
8307
|
return orch.createThread({
|
|
@@ -7985,6 +8331,11 @@ export {
|
|
|
7985
8331
|
recordSlackOutboundWatch,
|
|
7986
8332
|
pollSlackOutboundWatches,
|
|
7987
8333
|
AGENT_GIT_ACTIONS,
|
|
8334
|
+
mcpWaitForTurnTimeoutMs,
|
|
8335
|
+
mcpWaitStillRunningHint,
|
|
8336
|
+
mcpWaitFinishedHint,
|
|
8337
|
+
mcpWaitForJobTimeoutMs,
|
|
8338
|
+
waitForDetachedJob,
|
|
7988
8339
|
BOARD_COLUMN_DEFS,
|
|
7989
8340
|
HOME_BOARD_CACHE_TTL_MS,
|
|
7990
8341
|
dedupeBoardIssues,
|