@runfusion/fusion 0.14.1 → 0.14.3
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/bin.js +934 -166
- package/dist/client/assets/AgentDetailView-BBCnqhqI.js +18 -0
- package/dist/client/assets/{AgentsView-DoXb_amw.js → AgentsView-BY-Yq-Te.js} +3 -3
- package/dist/client/assets/ChatView-DkoJNxFW.js +1 -0
- package/dist/client/assets/{DevServerView-DbgM4tlT.js → DevServerView-qvs6pp6c.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-DfmtfMiu.js → DirectoryPicker-BkAIXNrP.js} +1 -1
- package/dist/client/assets/{DocumentsView-_-Efkx_W.js → DocumentsView-BcaUGgaL.js} +1 -1
- package/dist/client/assets/{InsightsView-DUjcfW53.js → InsightsView-Dz9Ivclw.js} +1 -1
- package/dist/client/assets/{MemoryView-DxMPBb0q.js → MemoryView-BsweARBT.js} +1 -1
- package/dist/client/assets/{NodesView-BEBTI15s.js → NodesView-bAU-v4bJ.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-BpMYhHH_.js → PiExtensionsManager-C_U2g7y3.js} +2 -2
- package/dist/client/assets/{PluginManager-CPv7yQd3.js → PluginManager-pIDsTk5v.js} +1 -1
- package/dist/client/assets/{ResearchView-BrFvdyXT.js → ResearchView-D4Eib_uR.js} +1 -1
- package/dist/client/assets/{RoadmapsView-BDjLrtcj.js → RoadmapsView-BaGwsUGS.js} +1 -1
- package/dist/client/assets/{SettingsModal-CxDxiTRy.js → SettingsModal-BiZVi3cI.js} +1 -1
- package/dist/client/assets/SettingsModal-CRyg643t.js +31 -0
- package/dist/client/assets/{SetupWizardModal-DFUA4X3z.js → SetupWizardModal-BcIGBBpA.js} +1 -1
- package/dist/client/assets/{SkillMultiselect-BUWe5ujb.js → SkillMultiselect-DPARHJeQ.js} +1 -1
- package/dist/client/assets/{SkillsView-RAkqGX3y.js → SkillsView-Da_d_HPu.js} +1 -1
- package/dist/client/assets/{TodoView-Ceb0wrg1.js → TodoView-5rAeqYtV.js} +1 -1
- package/dist/client/assets/{folder-open-DcM-Vd6r.js → folder-open-CgjcFqww.js} +1 -1
- package/dist/client/assets/index-D1gTSlYB.css +1 -0
- package/dist/client/assets/{index-DH3aprf6.js → index-DoQ5ALYY.js} +150 -149
- package/dist/client/assets/{list-checks-ByGHVQpZ.js → list-checks-C9YWtF7h.js} +1 -1
- package/dist/client/assets/{star-DlEYI8GL.js → star-4nUh67-U.js} +1 -1
- package/dist/client/assets/{upload-DKshabz-.js → upload-CEt5-Bnq.js} +1 -1
- package/dist/client/assets/{users-X6tYPPBV.js → users-4I0JDmgO.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/version.json +1 -1
- package/dist/extension.js +709 -146
- package/dist/pi-claude-cli/index.ts +2 -2
- package/dist/pi-claude-cli/package.json +1 -1
- package/dist/pi-claude-cli/src/__tests__/event-bridge.test.ts +107 -0
- package/dist/pi-claude-cli/src/event-bridge.ts +48 -4
- package/package.json +1 -1
- package/skill/fusion/references/engine-tools.md +0 -1
- package/dist/client/assets/AgentDetailView-B3KAsP2O.js +0 -18
- package/dist/client/assets/ChatView-BJ2c7wvd.js +0 -1
- package/dist/client/assets/SettingsModal-Cd-QGB0C.js +0 -31
- package/dist/client/assets/index-C1prPuSl.css +0 -1
package/dist/extension.js
CHANGED
|
@@ -75,6 +75,7 @@ var init_settings_schema = __esm({
|
|
|
75
75
|
favoriteModels: void 0,
|
|
76
76
|
openrouterModelSync: true,
|
|
77
77
|
updateCheckEnabled: true,
|
|
78
|
+
fnBinaryCheckEnabled: true,
|
|
78
79
|
updateCheckFrequency: "daily",
|
|
79
80
|
showGitHubStarButton: true,
|
|
80
81
|
modelOnboardingComplete: void 0,
|
|
@@ -3290,6 +3291,12 @@ CREATE INDEX IF NOT EXISTS idxTodoItemsSortOrder ON todo_items(listId, sortOrder
|
|
|
3290
3291
|
if (!inMemory && !isAbsolute(fusionDir)) {
|
|
3291
3292
|
throw new Error(`[fusion] Database constructor requires an absolute fusionDir path, got: ${fusionDir}`);
|
|
3292
3293
|
}
|
|
3294
|
+
if (!inMemory && /\.fusion[\\/]\.fusion(?:[\\/]|$)/.test(fusionDir)) {
|
|
3295
|
+
throw new Error(
|
|
3296
|
+
`[fusion] Refusing to open Database at nested .fusion/.fusion path: ${fusionDir}
|
|
3297
|
+
This means a caller passed a .fusion directory where a project root was expected. Audit the call site for an extra \`join(rootDir, '.fusion')\` step.`
|
|
3298
|
+
);
|
|
3299
|
+
}
|
|
3293
3300
|
if (!inMemory && !existsSync(fusionDir)) {
|
|
3294
3301
|
mkdirSync(fusionDir, { recursive: true });
|
|
3295
3302
|
}
|
|
@@ -6016,6 +6023,7 @@ var init_agent_store = __esm({
|
|
|
6016
6023
|
};
|
|
6017
6024
|
const line = JSON.stringify(safeEntry) + "\n";
|
|
6018
6025
|
await appendFile(this.runLogPath(agentId, runId), line, "utf-8");
|
|
6026
|
+
this.emit("run:log", agentId, runId, safeEntry);
|
|
6019
6027
|
}
|
|
6020
6028
|
/**
|
|
6021
6029
|
* Read all log entries for a given run from its JSONL file.
|
|
@@ -36342,12 +36350,16 @@ var init_gh_cli = __esm({
|
|
|
36342
36350
|
|
|
36343
36351
|
// ../core/src/fn-binary.ts
|
|
36344
36352
|
import { spawn as spawn2 } from "node:child_process";
|
|
36345
|
-
import { platform as platform2 } from "node:os";
|
|
36353
|
+
import { platform as platform2, tmpdir as tmpdir2 } from "node:os";
|
|
36346
36354
|
function runProbe(command, args, timeoutMs) {
|
|
36347
36355
|
return new Promise((resolve19) => {
|
|
36348
36356
|
let stdout = "";
|
|
36349
36357
|
let stderr = "";
|
|
36350
|
-
const child = spawn2(command, args, {
|
|
36358
|
+
const child = spawn2(command, args, {
|
|
36359
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
36360
|
+
shell: false,
|
|
36361
|
+
cwd: tmpdir2()
|
|
36362
|
+
});
|
|
36351
36363
|
const timer = setTimeout(() => {
|
|
36352
36364
|
try {
|
|
36353
36365
|
child.kill("SIGKILL");
|
|
@@ -37491,6 +37503,60 @@ var init_plugin_loader = __esm({
|
|
|
37491
37503
|
}
|
|
37492
37504
|
return runtimes;
|
|
37493
37505
|
}
|
|
37506
|
+
/**
|
|
37507
|
+
* Get all skill contributions from loaded plugins.
|
|
37508
|
+
*/
|
|
37509
|
+
getPluginSkills() {
|
|
37510
|
+
const skills = [];
|
|
37511
|
+
for (const [pluginId, plugin4] of this.plugins) {
|
|
37512
|
+
if (plugin4.skills) {
|
|
37513
|
+
for (const skill of plugin4.skills) {
|
|
37514
|
+
skills.push({ pluginId, skill });
|
|
37515
|
+
}
|
|
37516
|
+
}
|
|
37517
|
+
}
|
|
37518
|
+
return skills;
|
|
37519
|
+
}
|
|
37520
|
+
/**
|
|
37521
|
+
* Get all workflow step contributions from loaded plugins.
|
|
37522
|
+
*/
|
|
37523
|
+
getPluginWorkflowSteps() {
|
|
37524
|
+
const steps = [];
|
|
37525
|
+
for (const [pluginId, plugin4] of this.plugins) {
|
|
37526
|
+
if (plugin4.workflowSteps) {
|
|
37527
|
+
for (const step of plugin4.workflowSteps) {
|
|
37528
|
+
steps.push({ pluginId, step });
|
|
37529
|
+
}
|
|
37530
|
+
}
|
|
37531
|
+
}
|
|
37532
|
+
return steps;
|
|
37533
|
+
}
|
|
37534
|
+
/**
|
|
37535
|
+
* Get all prompt contributions from loaded plugins.
|
|
37536
|
+
*/
|
|
37537
|
+
getPluginPromptContributions() {
|
|
37538
|
+
const contributions = [];
|
|
37539
|
+
for (const [pluginId, plugin4] of this.plugins) {
|
|
37540
|
+
if (plugin4.promptContributions) {
|
|
37541
|
+
for (const contribution of plugin4.promptContributions.contributions) {
|
|
37542
|
+
contributions.push({ pluginId, contribution, config: plugin4.promptContributions });
|
|
37543
|
+
}
|
|
37544
|
+
}
|
|
37545
|
+
}
|
|
37546
|
+
return contributions;
|
|
37547
|
+
}
|
|
37548
|
+
/**
|
|
37549
|
+
* Get all setup metadata and hooks from loaded plugins.
|
|
37550
|
+
*/
|
|
37551
|
+
getPluginSetupInfo() {
|
|
37552
|
+
const setups = [];
|
|
37553
|
+
for (const [pluginId, plugin4] of this.plugins) {
|
|
37554
|
+
if (plugin4.setup) {
|
|
37555
|
+
setups.push({ pluginId, manifest: plugin4.setup.manifest, hooks: plugin4.setup.hooks });
|
|
37556
|
+
}
|
|
37557
|
+
}
|
|
37558
|
+
return setups;
|
|
37559
|
+
}
|
|
37494
37560
|
/**
|
|
37495
37561
|
* Get all loaded plugin instances.
|
|
37496
37562
|
*/
|
|
@@ -37611,7 +37677,7 @@ async function syncBackupAutomation(automationStore, settings) {
|
|
|
37611
37677
|
if (!AutomationStore2.isValidCron(schedule)) {
|
|
37612
37678
|
throw new Error(`Invalid backup schedule: ${schedule}`);
|
|
37613
37679
|
}
|
|
37614
|
-
const command = "
|
|
37680
|
+
const command = "fn backup --create";
|
|
37615
37681
|
if (existingSchedule) {
|
|
37616
37682
|
return await automationStore.updateSchedule(existingSchedule.id, {
|
|
37617
37683
|
scheduleType: "custom",
|
|
@@ -37644,7 +37710,7 @@ async function syncBackupRoutine(routineStore, settings) {
|
|
|
37644
37710
|
if (!RoutineStore2.isValidCron(schedule)) {
|
|
37645
37711
|
throw new Error(`Invalid backup schedule: ${schedule}`);
|
|
37646
37712
|
}
|
|
37647
|
-
const command = "
|
|
37713
|
+
const command = "fn backup --create";
|
|
37648
37714
|
const input = {
|
|
37649
37715
|
name: BACKUP_SCHEDULE_NAME,
|
|
37650
37716
|
description: "Automatic database backup based on project settings",
|
|
@@ -49519,7 +49585,7 @@ var require_dist3 = __commonJS({
|
|
|
49519
49585
|
|
|
49520
49586
|
// ../core/src/agent-companies-parser.ts
|
|
49521
49587
|
import { existsSync as existsSync17, mkdtempSync, readdirSync as readdirSync2, readFileSync as readFileSync4, rmSync, statSync as statSync4 } from "node:fs";
|
|
49522
|
-
import { tmpdir as
|
|
49588
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
49523
49589
|
import { join as join20, resolve as resolve9 } from "node:path";
|
|
49524
49590
|
function slugifyAgentReference(value) {
|
|
49525
49591
|
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -49842,7 +49908,7 @@ async function extractTarArchive(archivePath, outputDir) {
|
|
|
49842
49908
|
}
|
|
49843
49909
|
async function parseCompanyArchive(archivePath) {
|
|
49844
49910
|
const resolvedArchivePath = resolve9(archivePath);
|
|
49845
|
-
const tempDir = mkdtempSync(join20(
|
|
49911
|
+
const tempDir = mkdtempSync(join20(tmpdir3(), "agent-companies-"));
|
|
49846
49912
|
try {
|
|
49847
49913
|
if (resolvedArchivePath.endsWith(".tar.gz") || resolvedArchivePath.endsWith(".tgz")) {
|
|
49848
49914
|
await extractTarArchive(resolvedArchivePath, tempDir);
|
|
@@ -55419,65 +55485,6 @@ ${lines.join("\n")}`
|
|
|
55419
55485
|
}
|
|
55420
55486
|
};
|
|
55421
55487
|
}
|
|
55422
|
-
function createIdentityTool({ agent, resolvedInstructions }) {
|
|
55423
|
-
const identityParams = Type.Object({});
|
|
55424
|
-
return {
|
|
55425
|
-
name: "fn_identity",
|
|
55426
|
-
label: "Identity Check",
|
|
55427
|
-
description: "Return a structured summary of which soul, instructions, and memory are loaded for this heartbeat tick. Call this FIRST before any other tool.",
|
|
55428
|
-
parameters: identityParams,
|
|
55429
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55430
|
-
execute: async (_id, _params, _signal, _onUpdate, _ctx) => {
|
|
55431
|
-
const PREVIEW_CHARS = 500;
|
|
55432
|
-
const INSTRUCTIONS_PREVIEW_CHARS = 1e3;
|
|
55433
|
-
const MEMORY_PREVIEW_CHARS = 1e3;
|
|
55434
|
-
const soulPresent = typeof agent.soul === "string" && agent.soul.trim().length > 0;
|
|
55435
|
-
const instructionsPresent = resolvedInstructions.trim().length > 0;
|
|
55436
|
-
const memoryPresent = typeof agent.memory === "string" && agent.memory.trim().length > 0;
|
|
55437
|
-
const soulPreview = soulPresent ? agent.soul.slice(0, PREVIEW_CHARS) : "";
|
|
55438
|
-
const instructionsPreview = instructionsPresent ? resolvedInstructions.slice(0, INSTRUCTIONS_PREVIEW_CHARS) : "";
|
|
55439
|
-
const memoryPreview = memoryPresent ? agent.memory.slice(0, MEMORY_PREVIEW_CHARS) : "";
|
|
55440
|
-
const result = {
|
|
55441
|
-
agentId: agent.id,
|
|
55442
|
-
name: agent.name,
|
|
55443
|
-
role: agent.role,
|
|
55444
|
-
soulPresent,
|
|
55445
|
-
instructionsPresent,
|
|
55446
|
-
memoryPresent,
|
|
55447
|
-
soulPreview,
|
|
55448
|
-
instructionsPreview,
|
|
55449
|
-
memoryPreview
|
|
55450
|
-
};
|
|
55451
|
-
const lines = [
|
|
55452
|
-
`agentId: ${result.agentId}`,
|
|
55453
|
-
`name: ${result.name}`,
|
|
55454
|
-
`role: ${result.role}`,
|
|
55455
|
-
`soul: ${result.soulPresent ? "loaded" : "absent"}`,
|
|
55456
|
-
`instructions: ${result.instructionsPresent ? "loaded" : "absent"}`,
|
|
55457
|
-
`memory: ${result.memoryPresent ? "loaded" : "absent"}`
|
|
55458
|
-
];
|
|
55459
|
-
if (result.soulPresent && result.soulPreview) {
|
|
55460
|
-
lines.push(`
|
|
55461
|
-
Soul preview (first ${PREVIEW_CHARS} chars):
|
|
55462
|
-
${result.soulPreview}`);
|
|
55463
|
-
}
|
|
55464
|
-
if (result.instructionsPresent && result.instructionsPreview) {
|
|
55465
|
-
lines.push(`
|
|
55466
|
-
Instructions preview (first ${INSTRUCTIONS_PREVIEW_CHARS} chars):
|
|
55467
|
-
${result.instructionsPreview}`);
|
|
55468
|
-
}
|
|
55469
|
-
if (result.memoryPresent && result.memoryPreview) {
|
|
55470
|
-
lines.push(`
|
|
55471
|
-
Memory preview (first ${MEMORY_PREVIEW_CHARS} chars):
|
|
55472
|
-
${result.memoryPreview}`);
|
|
55473
|
-
}
|
|
55474
|
-
return {
|
|
55475
|
-
content: [{ type: "text", text: lines.join("\n") }],
|
|
55476
|
-
details: result
|
|
55477
|
-
};
|
|
55478
|
-
}
|
|
55479
|
-
};
|
|
55480
|
-
}
|
|
55481
55488
|
var taskCreateParams, taskLogParams, taskDocumentWriteParams, taskDocumentReadParams, reflectOnPerformanceParams, listAgentsParams, delegateTaskParams, sendMessageParams, readMessagesParams, memorySearchParams, memoryGetParams, researchRunParams, researchListParams, researchGetParams, researchCancelParams, memoryAppendParams, log10, AGENT_MEMORY_ROOT2, AGENT_MEMORY_FILENAME2, AGENT_DREAMS_FILENAME2, agentQmdRefreshState, AGENT_QMD_REFRESH_INTERVAL_MS, DAILY_AGENT_MEMORY_RE2;
|
|
55482
55489
|
var init_agent_tools = __esm({
|
|
55483
55490
|
"../engine/src/agent-tools.ts"() {
|
|
@@ -65013,6 +65020,20 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65013
65020
|
);
|
|
65014
65021
|
this.activeStepExecutors.delete(task.id);
|
|
65015
65022
|
}
|
|
65023
|
+
if (this.activeWorkflowStepSessions.has(task.id)) {
|
|
65024
|
+
executorLog.log(`${task.id} moved from in-progress to ${to} \u2014 terminating workflow step session`);
|
|
65025
|
+
this.pausedAborted.add(task.id);
|
|
65026
|
+
this.options.stuckTaskDetector?.untrackTask(task.id);
|
|
65027
|
+
const workflowSession = this.activeWorkflowStepSessions.get(task.id);
|
|
65028
|
+
const sessionWithAbort = workflowSession;
|
|
65029
|
+
if (typeof sessionWithAbort.abort === "function") {
|
|
65030
|
+
void sessionWithAbort.abort().catch((err) => {
|
|
65031
|
+
executorLog.warn(`Failed to abort workflow step session for ${task.id}: ${err}`);
|
|
65032
|
+
});
|
|
65033
|
+
}
|
|
65034
|
+
workflowSession.dispose();
|
|
65035
|
+
this.activeWorkflowStepSessions.delete(task.id);
|
|
65036
|
+
}
|
|
65016
65037
|
this.disposeSubagentsForTask(task.id, `parent moved from in-progress to ${to}`);
|
|
65017
65038
|
this.loopRecoveryState.delete(task.id);
|
|
65018
65039
|
this.spawnedAgents.delete(task.id);
|
|
@@ -65045,8 +65066,42 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65045
65066
|
this.disposeSubagentsForTask(task.id, "task paused");
|
|
65046
65067
|
return;
|
|
65047
65068
|
}
|
|
65048
|
-
if (
|
|
65069
|
+
if (task.paused && this.activeWorkflowStepSessions.has(task.id)) {
|
|
65070
|
+
executorLog.log(`Pausing ${task.id} \u2014 terminating workflow step session`);
|
|
65071
|
+
this.pausedAborted.add(task.id);
|
|
65072
|
+
this.options.stuckTaskDetector?.untrackTask(task.id);
|
|
65073
|
+
const workflowSession = this.activeWorkflowStepSessions.get(task.id);
|
|
65074
|
+
const sessionWithAbort = workflowSession;
|
|
65075
|
+
if (typeof sessionWithAbort.abort === "function") {
|
|
65076
|
+
await sessionWithAbort.abort().catch(
|
|
65077
|
+
(err) => executorLog.warn(`Failed to abort workflow step session for pause ${task.id}: ${err}`)
|
|
65078
|
+
);
|
|
65079
|
+
}
|
|
65080
|
+
workflowSession.dispose();
|
|
65081
|
+
this.activeWorkflowStepSessions.delete(task.id);
|
|
65082
|
+
this.loopRecoveryState.delete(task.id);
|
|
65083
|
+
this.spawnedAgents.delete(task.id);
|
|
65084
|
+
this.stuckAborted.delete(task.id);
|
|
65085
|
+
this.disposeSubagentsForTask(task.id, "task paused");
|
|
65086
|
+
return;
|
|
65087
|
+
}
|
|
65088
|
+
if (!task.paused && task.column === "in-progress" && !this.activeSessions.has(task.id) && !this.activeStepExecutors.has(task.id) && !this.activeWorkflowStepSessions.has(task.id)) {
|
|
65049
65089
|
if (!this.executing.has(task.id) && !this.resumingUnpaused.has(task.id) && !this.recoveringCompleted.has(task.id)) {
|
|
65090
|
+
const pauseLabel = await this.getExecutionPauseLabel();
|
|
65091
|
+
if (pauseLabel) {
|
|
65092
|
+
executorLog.log(`Skipping unpause resume for ${task.id} \u2014 ${pauseLabel} active`);
|
|
65093
|
+
return;
|
|
65094
|
+
}
|
|
65095
|
+
if (this.isTaskWorkComplete(task) && !task.mergeDetails) {
|
|
65096
|
+
this.recoveringCompleted.add(task.id);
|
|
65097
|
+
executorLog.log(`${task.id} unpaused with completed work and no session \u2014 recovering directly to in-review`);
|
|
65098
|
+
void this.recoverCompletedTask(task).catch(
|
|
65099
|
+
(err) => executorLog.error(`Failed to recover completed unpaused task ${task.id}:`, err)
|
|
65100
|
+
).finally(() => {
|
|
65101
|
+
this.recoveringCompleted.delete(task.id);
|
|
65102
|
+
});
|
|
65103
|
+
return;
|
|
65104
|
+
}
|
|
65050
65105
|
this.resumingUnpaused.add(task.id);
|
|
65051
65106
|
executorLog.log(`Unpaused ${task.id} in-progress with no session \u2014 resuming execution`);
|
|
65052
65107
|
try {
|
|
@@ -65165,6 +65220,22 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65165
65220
|
this.spawnedAgents.delete(taskId);
|
|
65166
65221
|
this.stuckAborted.delete(taskId);
|
|
65167
65222
|
}
|
|
65223
|
+
for (const [taskId, workflowSession] of this.activeWorkflowStepSessions) {
|
|
65224
|
+
executorLog.log(`Global pause \u2014 terminating workflow step session for ${taskId}`);
|
|
65225
|
+
this.pausedAborted.add(taskId);
|
|
65226
|
+
this.options.stuckTaskDetector?.untrackTask(taskId);
|
|
65227
|
+
const sessionWithAbort = workflowSession;
|
|
65228
|
+
if (typeof sessionWithAbort.abort === "function") {
|
|
65229
|
+
void sessionWithAbort.abort().catch((err) => {
|
|
65230
|
+
executorLog.warn(`Failed to abort workflow step session for ${taskId}: ${err}`);
|
|
65231
|
+
});
|
|
65232
|
+
}
|
|
65233
|
+
workflowSession.dispose();
|
|
65234
|
+
this.activeWorkflowStepSessions.delete(taskId);
|
|
65235
|
+
this.loopRecoveryState.delete(taskId);
|
|
65236
|
+
this.spawnedAgents.delete(taskId);
|
|
65237
|
+
this.stuckAborted.delete(taskId);
|
|
65238
|
+
}
|
|
65168
65239
|
}
|
|
65169
65240
|
});
|
|
65170
65241
|
}
|
|
@@ -65182,6 +65253,8 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65182
65253
|
activeSessions = /* @__PURE__ */ new Map();
|
|
65183
65254
|
/** Active step-session executors per task (mutually exclusive with activeSessions). */
|
|
65184
65255
|
activeStepExecutors = /* @__PURE__ */ new Map();
|
|
65256
|
+
/** Active pre-merge workflow step sessions per task. */
|
|
65257
|
+
activeWorkflowStepSessions = /* @__PURE__ */ new Map();
|
|
65185
65258
|
/**
|
|
65186
65259
|
* Reviewer subagent sessions per task. Reviewers (`reviewer.ts`) create their
|
|
65187
65260
|
* own AgentSessions that aren't part of `activeSessions`/`activeStepExecutors`,
|
|
@@ -65228,6 +65301,69 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65228
65301
|
await this.store.mergeTask(taskId);
|
|
65229
65302
|
return "merged";
|
|
65230
65303
|
}
|
|
65304
|
+
async getExecutionPauseLabel() {
|
|
65305
|
+
const settings = await this.store.getSettings();
|
|
65306
|
+
if (settings.globalPause) return "global pause";
|
|
65307
|
+
if (settings.enginePaused) return "engine pause";
|
|
65308
|
+
return null;
|
|
65309
|
+
}
|
|
65310
|
+
async shouldDeferCompletionForGlobalPause(taskId, context) {
|
|
65311
|
+
const settings = await this.store.getSettings();
|
|
65312
|
+
if (!settings.globalPause) {
|
|
65313
|
+
return false;
|
|
65314
|
+
}
|
|
65315
|
+
this.clearCompletedTaskWatchdog(taskId);
|
|
65316
|
+
executorLog.log(`${taskId}: completion handoff deferred \u2014 global pause active (${context})`);
|
|
65317
|
+
await this.store.logEntry(
|
|
65318
|
+
taskId,
|
|
65319
|
+
`Completion handoff deferred \u2014 global pause active (${context})`,
|
|
65320
|
+
void 0,
|
|
65321
|
+
this.currentRunContext
|
|
65322
|
+
).catch(() => void 0);
|
|
65323
|
+
return true;
|
|
65324
|
+
}
|
|
65325
|
+
async shouldDeferWorkflowStepCompletion(taskId, context) {
|
|
65326
|
+
let latestTask = null;
|
|
65327
|
+
try {
|
|
65328
|
+
latestTask = await this.store.getTask(taskId);
|
|
65329
|
+
} catch {
|
|
65330
|
+
latestTask = null;
|
|
65331
|
+
}
|
|
65332
|
+
if (latestTask?.paused || this.pausedAborted.has(taskId)) {
|
|
65333
|
+
this.clearCompletedTaskWatchdog(taskId);
|
|
65334
|
+
executorLog.log(`${taskId}: completion handoff deferred \u2014 task paused (${context})`);
|
|
65335
|
+
await this.store.logEntry(
|
|
65336
|
+
taskId,
|
|
65337
|
+
`Completion handoff deferred \u2014 task paused (${context})`,
|
|
65338
|
+
void 0,
|
|
65339
|
+
this.currentRunContext
|
|
65340
|
+
).catch(() => void 0);
|
|
65341
|
+
return true;
|
|
65342
|
+
}
|
|
65343
|
+
return this.shouldDeferCompletionForGlobalPause(taskId, context);
|
|
65344
|
+
}
|
|
65345
|
+
async parkTaskAfterWorkflowStepPause(taskId) {
|
|
65346
|
+
let latestTask = null;
|
|
65347
|
+
try {
|
|
65348
|
+
latestTask = await this.store.getTask(taskId);
|
|
65349
|
+
} catch {
|
|
65350
|
+
latestTask = null;
|
|
65351
|
+
}
|
|
65352
|
+
if (!latestTask?.paused) {
|
|
65353
|
+
return false;
|
|
65354
|
+
}
|
|
65355
|
+
executorLog.log(`${taskId}: workflow step interrupted by task pause \u2014 moving to todo`);
|
|
65356
|
+
await this.store.logEntry(
|
|
65357
|
+
taskId,
|
|
65358
|
+
"Execution paused during pre-merge workflow step \u2014 moved to todo",
|
|
65359
|
+
void 0,
|
|
65360
|
+
this.currentRunContext
|
|
65361
|
+
).catch(() => void 0);
|
|
65362
|
+
if (latestTask.column === "in-progress") {
|
|
65363
|
+
await this.store.moveTask(taskId, "todo", { preserveResumeState: true });
|
|
65364
|
+
}
|
|
65365
|
+
return true;
|
|
65366
|
+
}
|
|
65231
65367
|
/** Child agent sessions keyed by agent ID. Used for termination. */
|
|
65232
65368
|
childSessions = /* @__PURE__ */ new Map();
|
|
65233
65369
|
/** Total count of currently spawned agents (across all parents). */
|
|
@@ -65422,11 +65558,15 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65422
65558
|
this.clearCompletedTaskWatchdog(taskId);
|
|
65423
65559
|
const handle = setTimeout(async () => {
|
|
65424
65560
|
this.completedTaskWatchdogs.delete(taskId);
|
|
65425
|
-
if (this.recoveringCompleted.has(taskId) || this.executing.has(taskId) || this.activeSessions.has(taskId) || this.activeStepExecutors.has(taskId) || this.resumingUnpaused.has(taskId)) {
|
|
65561
|
+
if (this.recoveringCompleted.has(taskId) || this.executing.has(taskId) || this.activeSessions.has(taskId) || this.activeStepExecutors.has(taskId) || this.activeWorkflowStepSessions.has(taskId) || this.resumingUnpaused.has(taskId)) {
|
|
65426
65562
|
return;
|
|
65427
65563
|
}
|
|
65428
65564
|
this.recoveringCompleted.add(taskId);
|
|
65429
65565
|
try {
|
|
65566
|
+
const pauseLabel = await this.getExecutionPauseLabel();
|
|
65567
|
+
if (pauseLabel) {
|
|
65568
|
+
return;
|
|
65569
|
+
}
|
|
65430
65570
|
let currentTask = null;
|
|
65431
65571
|
try {
|
|
65432
65572
|
currentTask = await this.store.getTask(taskId);
|
|
@@ -65472,6 +65612,11 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65472
65612
|
* stuck.
|
|
65473
65613
|
*/
|
|
65474
65614
|
async performWorkflowRerunBounce(taskId, worktreePath, preserveResumeState = true) {
|
|
65615
|
+
const pauseLabel = await this.getExecutionPauseLabel();
|
|
65616
|
+
if (pauseLabel) {
|
|
65617
|
+
executorLog.log(`${taskId}: workflow rerun deferred \u2014 ${pauseLabel} active`);
|
|
65618
|
+
return "deferred-paused";
|
|
65619
|
+
}
|
|
65475
65620
|
if (this.workflowRerunPending.has(taskId)) {
|
|
65476
65621
|
executorLog.warn(`${taskId}: workflow rerun bounce already in flight \u2014 skipping re-entry`);
|
|
65477
65622
|
return "skipped-pending";
|
|
@@ -65482,6 +65627,10 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65482
65627
|
if (!latestTask) {
|
|
65483
65628
|
throw new Error("task missing during workflow rerun bounce");
|
|
65484
65629
|
}
|
|
65630
|
+
if (latestTask.paused) {
|
|
65631
|
+
executorLog.log(`${taskId}: workflow rerun deferred \u2014 task is paused`);
|
|
65632
|
+
return "deferred-paused";
|
|
65633
|
+
}
|
|
65485
65634
|
if (latestTask.column === "in-progress") {
|
|
65486
65635
|
const originalExecutionStartedAt = latestTask.executionStartedAt;
|
|
65487
65636
|
if (preserveResumeState) {
|
|
@@ -65493,11 +65642,21 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65493
65642
|
worktree: worktreePath,
|
|
65494
65643
|
executionStartedAt: originalExecutionStartedAt ?? null
|
|
65495
65644
|
});
|
|
65645
|
+
const pauseLabelAfterTodo = await this.getExecutionPauseLabel();
|
|
65646
|
+
if (pauseLabelAfterTodo) {
|
|
65647
|
+
executorLog.log(`${taskId}: workflow rerun parked in todo \u2014 ${pauseLabelAfterTodo} became active during bounce`);
|
|
65648
|
+
return "deferred-paused";
|
|
65649
|
+
}
|
|
65496
65650
|
await this.store.moveTask(taskId, "in-progress");
|
|
65497
65651
|
return "bounced";
|
|
65498
65652
|
}
|
|
65499
65653
|
if (latestTask.column === "todo") {
|
|
65500
65654
|
await this.store.updateTask(taskId, { worktree: worktreePath });
|
|
65655
|
+
const pauseLabelBeforeResume = await this.getExecutionPauseLabel();
|
|
65656
|
+
if (pauseLabelBeforeResume) {
|
|
65657
|
+
executorLog.log(`${taskId}: workflow rerun parked in todo \u2014 ${pauseLabelBeforeResume} became active before resume`);
|
|
65658
|
+
return "deferred-paused";
|
|
65659
|
+
}
|
|
65501
65660
|
await this.store.moveTask(taskId, "in-progress");
|
|
65502
65661
|
return "bounced";
|
|
65503
65662
|
}
|
|
@@ -65513,8 +65672,10 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65513
65672
|
const outcome = await this.performWorkflowRerunBounce(taskId, worktreePath, preserveResumeState);
|
|
65514
65673
|
if (outcome === "bounced") {
|
|
65515
65674
|
executorLog.log(successMessage);
|
|
65516
|
-
} else {
|
|
65675
|
+
} else if (outcome === "skipped-pending") {
|
|
65517
65676
|
executorLog.warn(`${taskId}: rerun bounce skipped \u2014 another bounce already in flight`);
|
|
65677
|
+
} else {
|
|
65678
|
+
executorLog.log(`${taskId}: rerun bounce deferred while pause is active`);
|
|
65518
65679
|
}
|
|
65519
65680
|
} catch (err) {
|
|
65520
65681
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
@@ -65523,6 +65684,11 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65523
65684
|
}, 0);
|
|
65524
65685
|
const watchdog = setTimeout(async () => {
|
|
65525
65686
|
this.workflowRerunWatchdogs.delete(taskId);
|
|
65687
|
+
const pauseLabel = await this.getExecutionPauseLabel();
|
|
65688
|
+
if (pauseLabel) {
|
|
65689
|
+
executorLog.log(`${taskId}: workflow rerun watchdog skipped \u2014 ${pauseLabel} active`);
|
|
65690
|
+
return;
|
|
65691
|
+
}
|
|
65526
65692
|
let currentTask = null;
|
|
65527
65693
|
try {
|
|
65528
65694
|
currentTask = await this.store.getTask(taskId);
|
|
@@ -65545,7 +65711,7 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65545
65711
|
const outcome = await this.performWorkflowRerunBounce(taskId, worktreePath, preserveResumeState);
|
|
65546
65712
|
if (outcome === "bounced") {
|
|
65547
65713
|
executorLog.warn(`${taskId}: workflow rerun watchdog retry succeeded`);
|
|
65548
|
-
} else {
|
|
65714
|
+
} else if (outcome === "skipped-pending") {
|
|
65549
65715
|
executorLog.error(
|
|
65550
65716
|
`${taskId}: workflow rerun watchdog retry skipped \u2014 original bounce still in flight after ${WORKFLOW_RERUN_WATCHDOG_MS / 1e3}s; task may be stuck`
|
|
65551
65717
|
);
|
|
@@ -65553,6 +65719,8 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65553
65719
|
taskId,
|
|
65554
65720
|
`Workflow rerun watchdog retry skipped \u2014 original bounce still in flight after ${WORKFLOW_RERUN_WATCHDOG_MS / 1e3}s; task may be stuck`
|
|
65555
65721
|
).catch(() => void 0);
|
|
65722
|
+
} else {
|
|
65723
|
+
executorLog.log(`${taskId}: workflow rerun watchdog retry deferred while pause is active`);
|
|
65556
65724
|
}
|
|
65557
65725
|
} catch (err) {
|
|
65558
65726
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
@@ -65675,11 +65843,17 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65675
65843
|
*/
|
|
65676
65844
|
async recoverCompletedTask(task) {
|
|
65677
65845
|
try {
|
|
65678
|
-
if (this.executing.has(task.id) || this.activeSessions.has(task.id) || this.activeStepExecutors.has(task.id) || this.resumingUnpaused.has(task.id)) {
|
|
65846
|
+
if (this.executing.has(task.id) || this.activeSessions.has(task.id) || this.activeStepExecutors.has(task.id) || this.activeWorkflowStepSessions.has(task.id) || this.resumingUnpaused.has(task.id)) {
|
|
65679
65847
|
executorLog.log(`${task.id}: skipping recoverCompletedTask \u2014 task has active execution in flight`);
|
|
65680
65848
|
return false;
|
|
65681
65849
|
}
|
|
65682
65850
|
const settings = await this.store.getSettings();
|
|
65851
|
+
if (settings.globalPause || settings.enginePaused) {
|
|
65852
|
+
executorLog.log(
|
|
65853
|
+
`${task.id}: skipping recoverCompletedTask \u2014 ${settings.globalPause ? "global pause" : "engine pause"} active`
|
|
65854
|
+
);
|
|
65855
|
+
return false;
|
|
65856
|
+
}
|
|
65683
65857
|
if (task.worktree && existsSync27(task.worktree)) {
|
|
65684
65858
|
const modifiedFiles = await this.captureModifiedFiles(task.worktree, task.baseCommitSha);
|
|
65685
65859
|
if (modifiedFiles.length > 0) {
|
|
@@ -65687,7 +65861,16 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65687
65861
|
executorLog.log(`${task.id}: recovered ${modifiedFiles.length} modified files`);
|
|
65688
65862
|
}
|
|
65689
65863
|
if (task.executionMode !== "fast") {
|
|
65864
|
+
if (await this.shouldDeferCompletionForGlobalPause(task.id, "before workflow steps during completed-task recovery")) {
|
|
65865
|
+
return false;
|
|
65866
|
+
}
|
|
65690
65867
|
const workflowResult = await this.runWorkflowSteps(task, task.worktree, settings);
|
|
65868
|
+
if (workflowResult === "deferred-paused") {
|
|
65869
|
+
if (this.pausedAborted.has(task.id)) {
|
|
65870
|
+
this.pausedAborted.delete(task.id);
|
|
65871
|
+
}
|
|
65872
|
+
return false;
|
|
65873
|
+
}
|
|
65691
65874
|
if (!workflowResult.allPassed) {
|
|
65692
65875
|
await this.sendTaskBackForFix(task, task.worktree, workflowResult.feedback, workflowResult.stepName || "Unknown", "Workflow step failed during recovery", false);
|
|
65693
65876
|
return true;
|
|
@@ -65696,6 +65879,9 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65696
65879
|
executorLog.log(`${task.id}: fast mode \u2014 skipping workflow steps on auto-recovery`);
|
|
65697
65880
|
}
|
|
65698
65881
|
}
|
|
65882
|
+
if (await this.shouldDeferCompletionForGlobalPause(task.id, "before in-review transition during completed-task recovery")) {
|
|
65883
|
+
return false;
|
|
65884
|
+
}
|
|
65699
65885
|
await this.persistTokenUsage(task.id);
|
|
65700
65886
|
await this.store.moveTask(task.id, "in-review");
|
|
65701
65887
|
this.clearCompletedTaskWatchdog(task.id);
|
|
@@ -65761,6 +65947,13 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
65761
65947
|
* directly to in-review without spawning a new agent session.
|
|
65762
65948
|
*/
|
|
65763
65949
|
async resumeOrphaned() {
|
|
65950
|
+
const settings = await this.store.getSettings();
|
|
65951
|
+
if (settings.globalPause || settings.enginePaused) {
|
|
65952
|
+
executorLog.log(
|
|
65953
|
+
`resumeOrphaned skipped \u2014 ${settings.globalPause ? "global pause" : "engine pause"} is active`
|
|
65954
|
+
);
|
|
65955
|
+
return;
|
|
65956
|
+
}
|
|
65764
65957
|
const tasks = await this.store.listTasks({ slim: true, column: "in-progress" });
|
|
65765
65958
|
const inProgress = tasks.filter(
|
|
65766
65959
|
(t) => t.column === "in-progress" && !this.executing.has(t.id) && !t.paused
|
|
@@ -66199,8 +66392,21 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
66199
66392
|
await audit.filesystem({ type: "file:capture-modified", target: task.id, metadata: { files: modifiedFiles } });
|
|
66200
66393
|
}
|
|
66201
66394
|
this.scheduleCompletedTaskWatchdog(task.id, "step-session completion");
|
|
66395
|
+
if (await this.shouldDeferCompletionForGlobalPause(task.id, "before workflow steps after step-session completion")) {
|
|
66396
|
+
return;
|
|
66397
|
+
}
|
|
66202
66398
|
if (executionMode !== "fast") {
|
|
66203
66399
|
const workflowResult = await this.runWorkflowSteps(task, worktreePath, settings);
|
|
66400
|
+
if (workflowResult === "deferred-paused") {
|
|
66401
|
+
if (await this.parkTaskAfterWorkflowStepPause(task.id)) {
|
|
66402
|
+
this.pausedAborted.delete(task.id);
|
|
66403
|
+
return;
|
|
66404
|
+
}
|
|
66405
|
+
if (this.pausedAborted.has(task.id)) {
|
|
66406
|
+
this.pausedAborted.delete(task.id);
|
|
66407
|
+
}
|
|
66408
|
+
return;
|
|
66409
|
+
}
|
|
66204
66410
|
if (!workflowResult.allPassed) {
|
|
66205
66411
|
if (workflowResult.revisionRequested) {
|
|
66206
66412
|
await this.handleWorkflowRevisionRequest(task, worktreePath, workflowResult.feedback, workflowResult.stepName);
|
|
@@ -66218,6 +66424,9 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
66218
66424
|
await this.store.logEntry(task.id, "Fast mode \u2014 pre-merge workflow steps skipped", void 0, this.currentRunContext);
|
|
66219
66425
|
}
|
|
66220
66426
|
await this.store.updateTask(task.id, { workflowStepRetries: void 0, taskDoneRetryCount: null });
|
|
66427
|
+
if (await this.shouldDeferCompletionForGlobalPause(task.id, "before in-review transition after step-session completion")) {
|
|
66428
|
+
return;
|
|
66429
|
+
}
|
|
66221
66430
|
await this.store.moveTask(task.id, "in-review");
|
|
66222
66431
|
this.clearCompletedTaskWatchdog(task.id);
|
|
66223
66432
|
await audit.database({ type: "task:move", target: task.id, metadata: { to: "in-review" } });
|
|
@@ -66570,6 +66779,9 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
66570
66779
|
this.pausedAborted.delete(task.id);
|
|
66571
66780
|
wasPaused = true;
|
|
66572
66781
|
if (await this.shouldFinalizeCompletedTask(task.id, taskDone)) {
|
|
66782
|
+
if (await this.shouldDeferCompletionForGlobalPause(task.id, "paused after completion")) {
|
|
66783
|
+
return;
|
|
66784
|
+
}
|
|
66573
66785
|
executorLog.log(`${task.id} paused after completion (graceful session exit) \u2014 finalizing to in-review`);
|
|
66574
66786
|
await this.store.logEntry(task.id, "Execution paused after completion \u2014 finalizing to in-review");
|
|
66575
66787
|
await this.persistTokenUsage(task.id);
|
|
@@ -66606,8 +66818,23 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
66606
66818
|
executorLog.log(`${task.id}: captured ${modifiedFiles.length} modified files`);
|
|
66607
66819
|
}
|
|
66608
66820
|
this.scheduleCompletedTaskWatchdog(task.id, "task completion");
|
|
66821
|
+
if (await this.shouldDeferCompletionForGlobalPause(task.id, "before workflow steps after task completion")) {
|
|
66822
|
+
return;
|
|
66823
|
+
}
|
|
66609
66824
|
if (executionMode !== "fast") {
|
|
66610
66825
|
const workflowResult = await this.runWorkflowSteps(task, worktreePath, settings);
|
|
66826
|
+
if (workflowResult === "deferred-paused") {
|
|
66827
|
+
if (await this.parkTaskAfterWorkflowStepPause(task.id)) {
|
|
66828
|
+
this.pausedAborted.delete(task.id);
|
|
66829
|
+
wasPaused = true;
|
|
66830
|
+
return;
|
|
66831
|
+
}
|
|
66832
|
+
if (this.pausedAborted.has(task.id)) {
|
|
66833
|
+
this.pausedAborted.delete(task.id);
|
|
66834
|
+
wasPaused = true;
|
|
66835
|
+
}
|
|
66836
|
+
return;
|
|
66837
|
+
}
|
|
66611
66838
|
if (!workflowResult.allPassed) {
|
|
66612
66839
|
if (workflowResult.revisionRequested) {
|
|
66613
66840
|
await this.handleWorkflowRevisionRequest(task, worktreePath, workflowResult.feedback, workflowResult.stepName);
|
|
@@ -66625,6 +66852,9 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
66625
66852
|
await this.store.logEntry(task.id, "Fast mode \u2014 pre-merge workflow steps skipped", void 0, this.currentRunContext);
|
|
66626
66853
|
}
|
|
66627
66854
|
await this.store.updateTask(task.id, { workflowStepRetries: void 0, taskDoneRetryCount: null });
|
|
66855
|
+
if (await this.shouldDeferCompletionForGlobalPause(task.id, "before in-review transition after task completion")) {
|
|
66856
|
+
return;
|
|
66857
|
+
}
|
|
66628
66858
|
await this.persistTokenUsage(task.id);
|
|
66629
66859
|
await this.store.moveTask(task.id, "in-review");
|
|
66630
66860
|
this.clearCompletedTaskWatchdog(task.id);
|
|
@@ -66749,8 +66979,23 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
66749
66979
|
executorLog.log(`${task.id}: captured ${modifiedFiles.length} modified files`);
|
|
66750
66980
|
}
|
|
66751
66981
|
this.scheduleCompletedTaskWatchdog(task.id, "task completion retry");
|
|
66982
|
+
if (await this.shouldDeferCompletionForGlobalPause(task.id, "before workflow steps after task completion retry")) {
|
|
66983
|
+
return;
|
|
66984
|
+
}
|
|
66752
66985
|
if (executionMode !== "fast") {
|
|
66753
66986
|
const workflowResult = await this.runWorkflowSteps(task, worktreePath, settings);
|
|
66987
|
+
if (workflowResult === "deferred-paused") {
|
|
66988
|
+
if (await this.parkTaskAfterWorkflowStepPause(task.id)) {
|
|
66989
|
+
this.pausedAborted.delete(task.id);
|
|
66990
|
+
wasPaused = true;
|
|
66991
|
+
return;
|
|
66992
|
+
}
|
|
66993
|
+
if (this.pausedAborted.has(task.id)) {
|
|
66994
|
+
this.pausedAborted.delete(task.id);
|
|
66995
|
+
wasPaused = true;
|
|
66996
|
+
}
|
|
66997
|
+
return;
|
|
66998
|
+
}
|
|
66754
66999
|
if (!workflowResult.allPassed) {
|
|
66755
67000
|
if (workflowResult.revisionRequested) {
|
|
66756
67001
|
await this.handleWorkflowRevisionRequest(task, worktreePath, workflowResult.feedback, workflowResult.stepName);
|
|
@@ -66764,6 +67009,9 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
66764
67009
|
await this.store.logEntry(task.id, "Fast mode \u2014 pre-merge workflow steps skipped", void 0, this.currentRunContext);
|
|
66765
67010
|
}
|
|
66766
67011
|
await this.store.updateTask(task.id, { workflowStepRetries: void 0, taskDoneRetryCount: null });
|
|
67012
|
+
if (await this.shouldDeferCompletionForGlobalPause(task.id, "before in-review transition after task completion retry")) {
|
|
67013
|
+
return;
|
|
67014
|
+
}
|
|
66767
67015
|
await this.persistTokenUsage(task.id);
|
|
66768
67016
|
await this.store.moveTask(task.id, "in-review");
|
|
66769
67017
|
this.clearCompletedTaskWatchdog(task.id);
|
|
@@ -66856,6 +67104,9 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
66856
67104
|
} else if (this.pausedAborted.has(task.id)) {
|
|
66857
67105
|
this.pausedAborted.delete(task.id);
|
|
66858
67106
|
if (await this.shouldFinalizeCompletedTask(task.id, taskDone)) {
|
|
67107
|
+
if (await this.shouldDeferCompletionForGlobalPause(task.id, "paused after completion")) {
|
|
67108
|
+
return;
|
|
67109
|
+
}
|
|
66859
67110
|
executorLog.log(`${task.id} paused after completion \u2014 finalizing to in-review`);
|
|
66860
67111
|
await this.store.logEntry(task.id, "Execution paused after completion \u2014 finalizing to in-review", void 0, this.currentRunContext);
|
|
66861
67112
|
await this.persistTokenUsage(task.id);
|
|
@@ -67214,22 +67465,28 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
67214
67465
|
if (params.summary) {
|
|
67215
67466
|
await store.updateTask(taskId, { summary: params.summary });
|
|
67216
67467
|
}
|
|
67217
|
-
await store.
|
|
67468
|
+
const settings = await store.getSettings();
|
|
67469
|
+
const hardPauseActive = Boolean(task.paused || settings.globalPause);
|
|
67470
|
+
if (hardPauseActive) {
|
|
67471
|
+
await store.updateTask(taskId, { status: null });
|
|
67472
|
+
} else {
|
|
67473
|
+
await store.updateTask(taskId, { paused: false, status: null });
|
|
67474
|
+
}
|
|
67218
67475
|
await store.logEntry(taskId, "Task marked done by agent");
|
|
67219
67476
|
const latestTask = await store.getTask(taskId);
|
|
67220
67477
|
let latestColumn = latestTask.column;
|
|
67221
67478
|
if (latestColumn === "todo") {
|
|
67222
67479
|
await store.logEntry(
|
|
67223
67480
|
taskId,
|
|
67224
|
-
"fn_task_done called while task was in todo \u2014 promoting to in-progress before completion handoff"
|
|
67481
|
+
hardPauseActive ? "fn_task_done called while task was in todo during pause \u2014 promoting to in-progress for deferred completion handoff" : "fn_task_done called while task was in todo \u2014 promoting to in-progress before completion handoff"
|
|
67225
67482
|
);
|
|
67226
67483
|
await store.moveTask(taskId, "in-progress");
|
|
67227
67484
|
latestColumn = "in-progress";
|
|
67228
67485
|
}
|
|
67229
|
-
if (latestColumn === "in-progress") {
|
|
67486
|
+
if (latestColumn === "in-progress" && !hardPauseActive) {
|
|
67230
67487
|
this.scheduleCompletedTaskWatchdog(taskId, "fn_task_done");
|
|
67231
67488
|
}
|
|
67232
|
-
const successMessage = params.summary ? "Task marked complete with summary. All steps done. Moving to in-review." : "Task marked complete. All steps done. Moving to in-review.";
|
|
67489
|
+
const successMessage = hardPauseActive ? "Task marked complete. Completion handoff deferred until pause is cleared." : params.summary ? "Task marked complete with summary. All steps done. Moving to in-review." : "Task marked complete. All steps done. Moving to in-review.";
|
|
67233
67490
|
return {
|
|
67234
67491
|
content: [{ type: "text", text: successMessage }],
|
|
67235
67492
|
details: {}
|
|
@@ -67804,6 +68061,9 @@ ${failureFeedback}
|
|
|
67804
68061
|
await this.store.updateTask(task.id, { workflowStepResults: results });
|
|
67805
68062
|
continue;
|
|
67806
68063
|
}
|
|
68064
|
+
if (await this.shouldDeferWorkflowStepCompletion(task.id, `before workflow step '${ws.name}'`)) {
|
|
68065
|
+
return "deferred-paused";
|
|
68066
|
+
}
|
|
67807
68067
|
await this.store.logEntry(task.id, `[pre-merge] Starting workflow step: ${ws.name} (${stepMode} mode)`);
|
|
67808
68068
|
executorLog.log(`${task.id} \u2014 [pre-merge] running workflow step: ${ws.name} (${stepMode} mode)`);
|
|
67809
68069
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -67818,6 +68078,9 @@ ${failureFeedback}
|
|
|
67818
68078
|
await this.store.updateTask(task.id, { workflowStepResults: results });
|
|
67819
68079
|
try {
|
|
67820
68080
|
const result = stepMode === "script" ? await this.executeScriptWorkflowStep(task, ws, worktreePath, settings) : await this.executeWorkflowStep(task, ws, worktreePath, settings);
|
|
68081
|
+
if (await this.shouldDeferWorkflowStepCompletion(task.id, `workflow step '${ws.name}'`)) {
|
|
68082
|
+
return "deferred-paused";
|
|
68083
|
+
}
|
|
67821
68084
|
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
67822
68085
|
if (result.success) {
|
|
67823
68086
|
await this.store.logEntry(task.id, `[timing] Workflow step '${ws.name}' completed in ${Date.now() - stepStartedAtMs}ms`);
|
|
@@ -67883,6 +68146,9 @@ ${failureFeedback}
|
|
|
67883
68146
|
};
|
|
67884
68147
|
}
|
|
67885
68148
|
} catch (err) {
|
|
68149
|
+
if (await this.shouldDeferWorkflowStepCompletion(task.id, `workflow step '${ws.name}'`)) {
|
|
68150
|
+
return "deferred-paused";
|
|
68151
|
+
}
|
|
67886
68152
|
const { message: errorMessage, detail: errorDetail, stack: errorStack } = formatError(err);
|
|
67887
68153
|
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
67888
68154
|
await this.store.logEntry(
|
|
@@ -68048,6 +68314,7 @@ and show an appropriate message to the user.\`
|
|
|
68048
68314
|
task.id,
|
|
68049
68315
|
`Workflow step '${workflowStep.name}' using model: ${describeModel(session)}${useOverride && attemptLabel === "primary" ? " (workflow step override)" : ""}${attemptLabel === "fallback" ? " (fallback after timeout)" : ""}`
|
|
68050
68316
|
);
|
|
68317
|
+
this.activeWorkflowStepSessions.set(task.id, session);
|
|
68051
68318
|
let output = "";
|
|
68052
68319
|
session.subscribe((event) => {
|
|
68053
68320
|
if (event.type === "message_update") {
|
|
@@ -68120,6 +68387,10 @@ Review the work done in this worktree and evaluate it against the criteria in yo
|
|
|
68120
68387
|
return { success: false, error: errorMessage };
|
|
68121
68388
|
} finally {
|
|
68122
68389
|
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
68390
|
+
const activeWorkflowStepSession = this.activeWorkflowStepSessions.get(task.id);
|
|
68391
|
+
if (activeWorkflowStepSession === session) {
|
|
68392
|
+
this.activeWorkflowStepSessions.delete(task.id);
|
|
68393
|
+
}
|
|
68123
68394
|
void timedOut;
|
|
68124
68395
|
}
|
|
68125
68396
|
};
|
|
@@ -69863,6 +70134,15 @@ var init_scheduler = __esm({
|
|
|
69863
70134
|
schedulerLog.log(`Task ${task.id} is paused \u2014 skipping dispatch`);
|
|
69864
70135
|
continue;
|
|
69865
70136
|
}
|
|
70137
|
+
const latestSettings = await this.store.getSettings();
|
|
70138
|
+
if (latestSettings.globalPause) {
|
|
70139
|
+
schedulerLog.log(`Task ${task.id} dispatch aborted \u2014 globalPause became active mid-pass`);
|
|
70140
|
+
continue;
|
|
70141
|
+
}
|
|
70142
|
+
if (latestSettings.enginePaused) {
|
|
70143
|
+
schedulerLog.log(`Task ${task.id} dispatch aborted \u2014 enginePaused became active mid-pass`);
|
|
70144
|
+
continue;
|
|
70145
|
+
}
|
|
69866
70146
|
let effectiveNode = resolveEffectiveNode(freshTask, settings);
|
|
69867
70147
|
schedulerLog.log(`Task ${task.id} routed to node=${effectiveNode.nodeId ?? "local"} (source=${effectiveNode.source})`);
|
|
69868
70148
|
if (effectiveNode.nodeId !== void 0 && this.options.nodeHealthMonitor) {
|
|
@@ -71983,6 +72263,7 @@ Rules:
|
|
|
71983
72263
|
|
|
71984
72264
|
// ../engine/src/agent-heartbeat.ts
|
|
71985
72265
|
import { Type as Type6 } from "@mariozechner/pi-ai";
|
|
72266
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
71986
72267
|
function isBlockedStateDuplicate(current, previous) {
|
|
71987
72268
|
return current.blockedBy === previous.blockedBy && current.contextHash === previous.contextHash;
|
|
71988
72269
|
}
|
|
@@ -71992,39 +72273,30 @@ function truncatePrompt(text, maxChars) {
|
|
|
71992
72273
|
|
|
71993
72274
|
... (truncated, ${text.length} chars)`;
|
|
71994
72275
|
}
|
|
72276
|
+
function shortContentHash(value) {
|
|
72277
|
+
return createHash5("sha256").update(value).digest("hex").slice(0, 8);
|
|
72278
|
+
}
|
|
71995
72279
|
function buildIdentitySnapshot(args) {
|
|
71996
72280
|
const { agent, resolvedInstructions } = args;
|
|
71997
|
-
const
|
|
71998
|
-
const
|
|
71999
|
-
const
|
|
72000
|
-
const
|
|
72001
|
-
|
|
72002
|
-
|
|
72003
|
-
|
|
72281
|
+
const soulTrimmed = typeof agent.soul === "string" ? agent.soul.trim() : "";
|
|
72282
|
+
const instrTrimmed = resolvedInstructions.trim();
|
|
72283
|
+
const memTrimmed = typeof agent.memory === "string" ? agent.memory.trim() : "";
|
|
72284
|
+
const formatField = (trimmed) => {
|
|
72285
|
+
if (!trimmed) return "absent";
|
|
72286
|
+
return `loaded (${trimmed.length} chars, sha256:${shortContentHash(trimmed)})`;
|
|
72287
|
+
};
|
|
72288
|
+
return [
|
|
72004
72289
|
"## Identity Snapshot",
|
|
72005
72290
|
"",
|
|
72006
|
-
"
|
|
72291
|
+
"Full content is in the Custom Instructions section of your system prompt. Surface anomalies in your first text output before acting.",
|
|
72007
72292
|
"",
|
|
72008
72293
|
`- agentId: ${agent.id}`,
|
|
72009
72294
|
`- name: ${agent.name}`,
|
|
72010
72295
|
`- role: ${agent.role}`,
|
|
72011
|
-
`- soul: ${
|
|
72012
|
-
`- instructions: ${
|
|
72013
|
-
`- memory: ${
|
|
72014
|
-
];
|
|
72015
|
-
if (soulPresent) {
|
|
72016
|
-
const preview = agent.soul.trim().slice(0, SOUL_PREVIEW);
|
|
72017
|
-
lines.push("", `### Soul (first ${SOUL_PREVIEW} chars)`, preview);
|
|
72018
|
-
}
|
|
72019
|
-
if (instrPresent) {
|
|
72020
|
-
const preview = resolvedInstructions.trim().slice(0, INSTR_PREVIEW);
|
|
72021
|
-
lines.push("", `### Instructions (first ${INSTR_PREVIEW} chars)`, preview);
|
|
72022
|
-
}
|
|
72023
|
-
if (memPresent) {
|
|
72024
|
-
const preview = agent.memory.trim().slice(0, MEM_PREVIEW);
|
|
72025
|
-
lines.push("", `### Memory (first ${MEM_PREVIEW} chars)`, preview);
|
|
72026
|
-
}
|
|
72027
|
-
return lines.join("\n");
|
|
72296
|
+
`- soul: ${formatField(soulTrimmed)}`,
|
|
72297
|
+
`- instructions: ${formatField(instrTrimmed)}`,
|
|
72298
|
+
`- memory: ${formatField(memTrimmed)}`
|
|
72299
|
+
].join("\n");
|
|
72028
72300
|
}
|
|
72029
72301
|
async function getHeartbeatMemorySettings(taskStore) {
|
|
72030
72302
|
const maybeGetSettings = taskStore.getSettings;
|
|
@@ -72206,9 +72478,8 @@ When sending messages:
|
|
|
72206
72478
|
1. **Identity & context** \u2014 review the **Identity Snapshot** at the top of
|
|
72207
72479
|
this prompt. Confirm your role, soul, instructions, and memory match what
|
|
72208
72480
|
you expect, and surface any anomalies in your first text output before
|
|
72209
|
-
doing anything else.
|
|
72210
|
-
|
|
72211
|
-
authoritative source.)
|
|
72481
|
+
doing anything else. The full content is in the Custom Instructions
|
|
72482
|
+
section of your system prompt.
|
|
72212
72483
|
2. **Inbox** \u2014 when fn_read_messages is available, call it. Process any pending
|
|
72213
72484
|
messages first; reply with reply_to_message_id when answering.
|
|
72214
72485
|
3. **Wake delta** \u2014 read the Wake Delta block above. The wake reason is the
|
|
@@ -72234,9 +72505,8 @@ a bug. Do not loop on the same plan across heartbeats without recording why.`;
|
|
|
72234
72505
|
1. **Identity & context** \u2014 review the **Identity Snapshot** at the top of
|
|
72235
72506
|
this prompt. Confirm your role, soul, instructions, and memory match what
|
|
72236
72507
|
you expect, and surface any anomalies in your first text output before
|
|
72237
|
-
doing anything else.
|
|
72238
|
-
|
|
72239
|
-
authoritative source.)
|
|
72508
|
+
doing anything else. The full content is in the Custom Instructions
|
|
72509
|
+
section of your system prompt.
|
|
72240
72510
|
2. **Inbox** \u2014 when fn_read_messages is available, call it. Process any pending
|
|
72241
72511
|
messages first; reply with reply_to_message_id when answering.
|
|
72242
72512
|
3. **Wake delta** \u2014 read the Wake Delta block above. The wake reason is the
|
|
@@ -73038,7 +73308,6 @@ not loop on the same plan across heartbeats without recording why.`;
|
|
|
73038
73308
|
baseHeartbeatSystemPrompt,
|
|
73039
73309
|
[resolvedInstructionsForIdentity, memoryInstructions].filter((part) => part.trim()).join("\n\n")
|
|
73040
73310
|
);
|
|
73041
|
-
heartbeatTools.push(createIdentityTool({ agent, resolvedInstructions: resolvedInstructionsForIdentity }));
|
|
73042
73311
|
heartbeatTools.push(heartbeatDoneTool);
|
|
73043
73312
|
if (isNoTaskRun) {
|
|
73044
73313
|
agentLogger = new AgentLogger({
|
|
@@ -75011,6 +75280,36 @@ function execCommand(command, options) {
|
|
|
75011
75280
|
});
|
|
75012
75281
|
});
|
|
75013
75282
|
}
|
|
75283
|
+
function isInProcessBackupCommand(command) {
|
|
75284
|
+
if (!command) return false;
|
|
75285
|
+
const trimmed = command.trim();
|
|
75286
|
+
if (!trimmed) return false;
|
|
75287
|
+
if (SHELL_METACHARACTERS_REGEX.test(trimmed)) return false;
|
|
75288
|
+
const tokens = trimmed.split(/\s+/).map((tok) => tok.toLowerCase());
|
|
75289
|
+
let cursor = 0;
|
|
75290
|
+
if (tokens[cursor] === "npx") {
|
|
75291
|
+
cursor += 1;
|
|
75292
|
+
while (cursor < tokens.length) {
|
|
75293
|
+
const tok = tokens[cursor];
|
|
75294
|
+
if (tok === void 0 || !tok.startsWith("-")) break;
|
|
75295
|
+
const takesValue = (tok === "-p" || tok === "--package") && cursor + 1 < tokens.length && tokens[cursor + 1] !== void 0 && !tokens[cursor + 1].startsWith("-");
|
|
75296
|
+
cursor += takesValue ? 2 : 1;
|
|
75297
|
+
}
|
|
75298
|
+
}
|
|
75299
|
+
const binary = tokens[cursor];
|
|
75300
|
+
if (!binary || !FUSION_BINARY_TOKENS.has(binary)) return false;
|
|
75301
|
+
cursor += 1;
|
|
75302
|
+
if (tokens[cursor] !== "backup") return false;
|
|
75303
|
+
cursor += 1;
|
|
75304
|
+
if (tokens[cursor] !== "--create") return false;
|
|
75305
|
+
cursor += 1;
|
|
75306
|
+
for (; cursor < tokens.length; cursor += 1) {
|
|
75307
|
+
const tok = tokens[cursor];
|
|
75308
|
+
if (!tok) continue;
|
|
75309
|
+
if (!tok.startsWith("-")) return false;
|
|
75310
|
+
}
|
|
75311
|
+
return true;
|
|
75312
|
+
}
|
|
75014
75313
|
async function createAiPromptExecutor(cwd) {
|
|
75015
75314
|
const disposeLog = createLogger2("cron-runner");
|
|
75016
75315
|
return async (prompt, modelProvider, modelId) => {
|
|
@@ -75050,7 +75349,7 @@ function truncateOutput(stdout, stderr) {
|
|
|
75050
75349
|
}
|
|
75051
75350
|
return combined;
|
|
75052
75351
|
}
|
|
75053
|
-
var log14, DEFAULT_TIMEOUT_MS6, MAX_BUFFER, MAX_OUTPUT_LENGTH, DEFAULT_POLL_INTERVAL_MS, MIN_POLL_INTERVAL_MS, CronRunner, AI_AUTOMATION_SYSTEM_PROMPT;
|
|
75352
|
+
var log14, FUSION_BINARY_TOKENS, SHELL_METACHARACTERS_REGEX, DEFAULT_TIMEOUT_MS6, MAX_BUFFER, MAX_OUTPUT_LENGTH, DEFAULT_POLL_INTERVAL_MS, MIN_POLL_INTERVAL_MS, CronRunner, AI_AUTOMATION_SYSTEM_PROMPT;
|
|
75054
75353
|
var init_cron_runner = __esm({
|
|
75055
75354
|
"../engine/src/cron-runner.ts"() {
|
|
75056
75355
|
"use strict";
|
|
@@ -75059,6 +75358,14 @@ var init_cron_runner = __esm({
|
|
|
75059
75358
|
init_shell_utils();
|
|
75060
75359
|
init_pi();
|
|
75061
75360
|
log14 = createLogger2("cron-runner");
|
|
75361
|
+
FUSION_BINARY_TOKENS = /* @__PURE__ */ new Set([
|
|
75362
|
+
"fn",
|
|
75363
|
+
"fusion",
|
|
75364
|
+
"runfusion",
|
|
75365
|
+
"runfusion.ai",
|
|
75366
|
+
"@runfusion/fusion"
|
|
75367
|
+
]);
|
|
75368
|
+
SHELL_METACHARACTERS_REGEX = /[&|;<>`$()]/;
|
|
75062
75369
|
DEFAULT_TIMEOUT_MS6 = 5 * 60 * 1e3;
|
|
75063
75370
|
MAX_BUFFER = 1024 * 1024;
|
|
75064
75371
|
MAX_OUTPUT_LENGTH = 10 * 1024;
|
|
@@ -75199,6 +75506,9 @@ var init_cron_runner = __esm({
|
|
|
75199
75506
|
*/
|
|
75200
75507
|
async executeLegacyCommand(schedule, startedAt) {
|
|
75201
75508
|
log14.log(`Executing ${schedule.name} (${schedule.id}): ${schedule.command}`);
|
|
75509
|
+
if (isInProcessBackupCommand(schedule.command)) {
|
|
75510
|
+
return this.executeBackupInProcess(schedule, startedAt);
|
|
75511
|
+
}
|
|
75202
75512
|
try {
|
|
75203
75513
|
const timeoutMs = schedule.timeoutMs ?? DEFAULT_TIMEOUT_MS6;
|
|
75204
75514
|
const { stdout, stderr } = await execCommand(schedule.command, {
|
|
@@ -75229,6 +75539,47 @@ var init_cron_runner = __esm({
|
|
|
75229
75539
|
};
|
|
75230
75540
|
}
|
|
75231
75541
|
}
|
|
75542
|
+
/**
|
|
75543
|
+
* Run an auto-backup schedule in-process via the engine's open TaskStore,
|
|
75544
|
+
* bypassing the shell-out that would otherwise invoke an outdated fusion
|
|
75545
|
+
* binary on PATH. See `isInProcessBackupCommand` for the matching contract.
|
|
75546
|
+
*/
|
|
75547
|
+
async executeBackupInProcess(schedule, startedAt) {
|
|
75548
|
+
const action = await this.runBackupActionInProcess();
|
|
75549
|
+
if (action.success) {
|
|
75550
|
+
log14.log(`\u2713 ${schedule.name} completed in-process`);
|
|
75551
|
+
} else {
|
|
75552
|
+
log14.warn(`\u2717 ${schedule.name} in-process backup ${action.error ? `threw: ${action.error}` : `reported failure: ${action.output}`}`);
|
|
75553
|
+
}
|
|
75554
|
+
return {
|
|
75555
|
+
success: action.success,
|
|
75556
|
+
output: action.output,
|
|
75557
|
+
error: action.error,
|
|
75558
|
+
startedAt,
|
|
75559
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
75560
|
+
};
|
|
75561
|
+
}
|
|
75562
|
+
/**
|
|
75563
|
+
* Shared in-process backup execution used by both the legacy-command path
|
|
75564
|
+
* and the command-step path. Returns the success/output/error tuple in
|
|
75565
|
+
* a shape that callers can wrap into either a run or a step result.
|
|
75566
|
+
*/
|
|
75567
|
+
async runBackupActionInProcess() {
|
|
75568
|
+
try {
|
|
75569
|
+
const { runBackupCommand: runBackupCommand2 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
75570
|
+
const fusionDir = this.store.getFusionDir();
|
|
75571
|
+
const settings = await this.store.getSettings();
|
|
75572
|
+
const result = await runBackupCommand2(fusionDir, settings);
|
|
75573
|
+
return {
|
|
75574
|
+
success: result.success,
|
|
75575
|
+
output: truncateOutput(result.output ?? "", ""),
|
|
75576
|
+
error: result.success ? void 0 : result.output
|
|
75577
|
+
};
|
|
75578
|
+
} catch (err) {
|
|
75579
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
75580
|
+
return { success: false, output: "", error: message };
|
|
75581
|
+
}
|
|
75582
|
+
}
|
|
75232
75583
|
/**
|
|
75233
75584
|
* Execute multiple steps sequentially.
|
|
75234
75585
|
* Aggregates per-step results into an overall AutomationRunResult.
|
|
@@ -75317,6 +75668,19 @@ var init_cron_runner = __esm({
|
|
|
75317
75668
|
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
75318
75669
|
};
|
|
75319
75670
|
}
|
|
75671
|
+
if (isInProcessBackupCommand(step.command)) {
|
|
75672
|
+
const action = await this.runBackupActionInProcess();
|
|
75673
|
+
return {
|
|
75674
|
+
stepId: step.id,
|
|
75675
|
+
stepName: step.name,
|
|
75676
|
+
stepIndex,
|
|
75677
|
+
success: action.success,
|
|
75678
|
+
output: action.output,
|
|
75679
|
+
error: action.error,
|
|
75680
|
+
startedAt,
|
|
75681
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
75682
|
+
};
|
|
75683
|
+
}
|
|
75320
75684
|
try {
|
|
75321
75685
|
const { stdout, stderr } = await execCommand(step.command, {
|
|
75322
75686
|
timeout: timeoutMs,
|
|
@@ -75508,6 +75872,7 @@ var init_routine_runner = __esm({
|
|
|
75508
75872
|
"../engine/src/routine-runner.ts"() {
|
|
75509
75873
|
"use strict";
|
|
75510
75874
|
import_cron_parser4 = __toESM(require_dist2(), 1);
|
|
75875
|
+
init_cron_runner();
|
|
75511
75876
|
init_logger2();
|
|
75512
75877
|
init_shell_utils();
|
|
75513
75878
|
log15 = createLogger2("routine-runner");
|
|
@@ -75665,6 +76030,30 @@ var init_routine_runner = __esm({
|
|
|
75665
76030
|
return this.executeCommand(routine.command ?? "", routine.timeoutMs, startedAt);
|
|
75666
76031
|
}
|
|
75667
76032
|
async executeCommand(command, timeoutMs, startedAt) {
|
|
76033
|
+
if (isInProcessBackupCommand(command) && this.options.taskStore) {
|
|
76034
|
+
try {
|
|
76035
|
+
const { runBackupCommand: runBackupCommand2 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
76036
|
+
const fusionDir = this.options.taskStore.getFusionDir();
|
|
76037
|
+
const settings = await this.options.taskStore.getSettings();
|
|
76038
|
+
const result = await runBackupCommand2(fusionDir, settings);
|
|
76039
|
+
return {
|
|
76040
|
+
success: result.success,
|
|
76041
|
+
output: truncateOutput2(result.output ?? "", ""),
|
|
76042
|
+
error: result.success ? void 0 : result.output,
|
|
76043
|
+
startedAt,
|
|
76044
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
76045
|
+
};
|
|
76046
|
+
} catch (err) {
|
|
76047
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
76048
|
+
return {
|
|
76049
|
+
success: false,
|
|
76050
|
+
output: "",
|
|
76051
|
+
error: message,
|
|
76052
|
+
startedAt,
|
|
76053
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
76054
|
+
};
|
|
76055
|
+
}
|
|
76056
|
+
}
|
|
75668
76057
|
try {
|
|
75669
76058
|
const { stdout, stderr } = await execAsync6(command, {
|
|
75670
76059
|
timeout: timeoutMs ?? DEFAULT_TIMEOUT_MS7,
|
|
@@ -76456,6 +76845,13 @@ var init_self_healing = __esm({
|
|
|
76456
76845
|
* stale in-progress/planning tasks that no longer have a live worker.
|
|
76457
76846
|
*/
|
|
76458
76847
|
async runStartupRecovery() {
|
|
76848
|
+
const settings = await this.store.getSettings();
|
|
76849
|
+
if (settings.globalPause || settings.enginePaused) {
|
|
76850
|
+
log16.log(
|
|
76851
|
+
`Startup recovery skipped \u2014 ${settings.globalPause ? "global pause" : "engine pause"} is active`
|
|
76852
|
+
);
|
|
76853
|
+
return;
|
|
76854
|
+
}
|
|
76459
76855
|
const steps = [
|
|
76460
76856
|
{ name: "no-progress-no-task-done", fn: () => this.recoverNoProgressNoTaskDoneFailures().then(() => void 0) },
|
|
76461
76857
|
{ name: "completed-tasks", fn: () => this.recoverCompletedTasks().then(() => void 0) },
|
|
@@ -76806,27 +77202,34 @@ var init_self_healing = __esm({
|
|
|
76806
77202
|
log16.error(`Maintenance batch 1 step "${fn.name}" failed: ${stepErr instanceof Error ? stepErr.message : String(stepErr)}`);
|
|
76807
77203
|
}
|
|
76808
77204
|
}
|
|
76809
|
-
const
|
|
76810
|
-
|
|
76811
|
-
|
|
76812
|
-
|
|
76813
|
-
|
|
76814
|
-
|
|
76815
|
-
|
|
76816
|
-
|
|
76817
|
-
|
|
76818
|
-
|
|
76819
|
-
|
|
76820
|
-
|
|
76821
|
-
|
|
76822
|
-
|
|
76823
|
-
|
|
76824
|
-
|
|
76825
|
-
|
|
76826
|
-
|
|
76827
|
-
|
|
76828
|
-
|
|
76829
|
-
|
|
77205
|
+
const recoverySettings = await this.store.getSettings();
|
|
77206
|
+
if (recoverySettings.globalPause || recoverySettings.enginePaused) {
|
|
77207
|
+
log16.log(
|
|
77208
|
+
`Maintenance batch 2 skipped \u2014 ${recoverySettings.globalPause ? "global pause" : "engine pause"} is active`
|
|
77209
|
+
);
|
|
77210
|
+
} else {
|
|
77211
|
+
const batch2Fns = [
|
|
77212
|
+
{ name: "recover-completed-tasks", fn: () => this.recoverCompletedTasks() },
|
|
77213
|
+
{ name: "recover-stale-incomplete-review", fn: () => this.recoverStaleIncompleteReviewTasks() },
|
|
77214
|
+
{ name: "recover-failed-pre-merge-steps", fn: () => this.recoverReviewTasksWithFailedPreMergeSteps() },
|
|
77215
|
+
{ name: "recover-interrupted-merging", fn: () => this.recoverInterruptedMergingTasks() },
|
|
77216
|
+
{ name: "recover-mergeable-review", fn: () => this.recoverMergeableReviewTasks() },
|
|
77217
|
+
{ name: "recover-merged-review", fn: () => this.recoverMergedReviewTasks() },
|
|
77218
|
+
{ name: "recover-misclassified-failures", fn: () => this.recoverMisclassifiedFailures() },
|
|
77219
|
+
{ name: "recover-no-progress-no-task-done", fn: () => this.recoverNoProgressNoTaskDoneFailures() },
|
|
77220
|
+
{ name: "recover-partial-progress-no-task-done", fn: () => this.recoverPartialProgressNoTaskDoneFailures() },
|
|
77221
|
+
{ name: "recover-orphaned-executions", fn: () => this.recoverOrphanedExecutions() },
|
|
77222
|
+
{ name: "recover-approved-triage", fn: () => this.recoverApprovedTriageTasks() },
|
|
77223
|
+
{ name: "recover-orphaned-planning", fn: () => this.recoverOrphanedPlanningTasks() },
|
|
77224
|
+
{ name: "recover-ghost-review", fn: () => this.recoverGhostReviewTasks() }
|
|
77225
|
+
];
|
|
77226
|
+
for (const fn of batch2Fns) {
|
|
77227
|
+
try {
|
|
77228
|
+
await fn.fn();
|
|
77229
|
+
log16.log(`Maintenance batch 2 step "${fn.name}" succeeded`);
|
|
77230
|
+
} catch (stepErr) {
|
|
77231
|
+
log16.error(`Maintenance batch 2 step "${fn.name}" failed: ${stepErr instanceof Error ? stepErr.message : String(stepErr)}`);
|
|
77232
|
+
}
|
|
76830
77233
|
}
|
|
76831
77234
|
}
|
|
76832
77235
|
const batch3Fns = [
|
|
@@ -77892,10 +78295,18 @@ var init_plugin_runner = __esm({
|
|
|
77892
78295
|
cachedRoutes = null;
|
|
77893
78296
|
cachedUiSlots = null;
|
|
77894
78297
|
cachedRuntimes = null;
|
|
78298
|
+
cachedSkills = null;
|
|
78299
|
+
cachedWorkflowSteps = null;
|
|
78300
|
+
cachedPromptContributions = null;
|
|
78301
|
+
cachedSetupInfo = null;
|
|
77895
78302
|
toolsCacheVersion = 0;
|
|
77896
78303
|
routesCacheVersion = 0;
|
|
77897
78304
|
uiSlotsCacheVersion = 0;
|
|
77898
78305
|
runtimesCacheVersion = 0;
|
|
78306
|
+
skillsCacheVersion = 0;
|
|
78307
|
+
workflowStepsCacheVersion = 0;
|
|
78308
|
+
promptContributionsCacheVersion = 0;
|
|
78309
|
+
setupCacheVersion = 0;
|
|
77899
78310
|
hookTimeoutMs;
|
|
77900
78311
|
// Event handler references for cleanup
|
|
77901
78312
|
handlePluginEnabled;
|
|
@@ -77927,6 +78338,10 @@ var init_plugin_runner = __esm({
|
|
|
77927
78338
|
this.invalidateRoutesCache();
|
|
77928
78339
|
this.invalidateUiSlotsCache();
|
|
77929
78340
|
this.invalidateRuntimesCache();
|
|
78341
|
+
this.invalidateSkillsCache();
|
|
78342
|
+
this.invalidateWorkflowStepsCache();
|
|
78343
|
+
this.invalidatePromptContributionsCache();
|
|
78344
|
+
this.invalidateSetupCache();
|
|
77930
78345
|
}
|
|
77931
78346
|
/**
|
|
77932
78347
|
* Shutdown the plugin runner.
|
|
@@ -78007,6 +78422,54 @@ var init_plugin_runner = __esm({
|
|
|
78007
78422
|
}
|
|
78008
78423
|
return this.cachedRuntimes.runtimes;
|
|
78009
78424
|
}
|
|
78425
|
+
getPluginSkills() {
|
|
78426
|
+
if (!this.cachedSkills || this.cachedSkills.version !== this.skillsCacheVersion) {
|
|
78427
|
+
this.cachedSkills = {
|
|
78428
|
+
skills: this.options.pluginLoader.getPluginSkills(),
|
|
78429
|
+
version: this.skillsCacheVersion
|
|
78430
|
+
};
|
|
78431
|
+
}
|
|
78432
|
+
return this.cachedSkills.skills;
|
|
78433
|
+
}
|
|
78434
|
+
getPluginWorkflowSteps() {
|
|
78435
|
+
if (!this.cachedWorkflowSteps || this.cachedWorkflowSteps.version !== this.workflowStepsCacheVersion) {
|
|
78436
|
+
this.cachedWorkflowSteps = {
|
|
78437
|
+
steps: this.options.pluginLoader.getPluginWorkflowSteps(),
|
|
78438
|
+
version: this.workflowStepsCacheVersion
|
|
78439
|
+
};
|
|
78440
|
+
}
|
|
78441
|
+
return this.cachedWorkflowSteps.steps;
|
|
78442
|
+
}
|
|
78443
|
+
getPluginPromptContributions() {
|
|
78444
|
+
if (!this.cachedPromptContributions || this.cachedPromptContributions.version !== this.promptContributionsCacheVersion) {
|
|
78445
|
+
this.cachedPromptContributions = {
|
|
78446
|
+
contributions: this.options.pluginLoader.getPluginPromptContributions(),
|
|
78447
|
+
version: this.promptContributionsCacheVersion
|
|
78448
|
+
};
|
|
78449
|
+
}
|
|
78450
|
+
return this.cachedPromptContributions.contributions;
|
|
78451
|
+
}
|
|
78452
|
+
getPluginSetupInfo() {
|
|
78453
|
+
if (!this.cachedSetupInfo || this.cachedSetupInfo.version !== this.setupCacheVersion) {
|
|
78454
|
+
this.cachedSetupInfo = {
|
|
78455
|
+
setups: this.options.pluginLoader.getPluginSetupInfo(),
|
|
78456
|
+
version: this.setupCacheVersion
|
|
78457
|
+
};
|
|
78458
|
+
}
|
|
78459
|
+
return this.cachedSetupInfo.setups;
|
|
78460
|
+
}
|
|
78461
|
+
getPromptContributionsForSurface(surface) {
|
|
78462
|
+
return this.getPluginPromptContributions().filter(({ pluginId, contribution, config }) => {
|
|
78463
|
+
const plugin4 = this.options.pluginLoader.getPlugin(pluginId);
|
|
78464
|
+
if (!plugin4 || plugin4.state !== "started") {
|
|
78465
|
+
return false;
|
|
78466
|
+
}
|
|
78467
|
+
if (contribution.surface !== surface) {
|
|
78468
|
+
return false;
|
|
78469
|
+
}
|
|
78470
|
+
return config.enabledByDefault !== false;
|
|
78471
|
+
});
|
|
78472
|
+
}
|
|
78010
78473
|
/**
|
|
78011
78474
|
* Get a specific runtime registration by its runtimeId.
|
|
78012
78475
|
*
|
|
@@ -78040,6 +78503,10 @@ var init_plugin_runner = __esm({
|
|
|
78040
78503
|
this.invalidateRoutesCache();
|
|
78041
78504
|
this.invalidateUiSlotsCache();
|
|
78042
78505
|
this.invalidateRuntimesCache();
|
|
78506
|
+
this.invalidateSkillsCache();
|
|
78507
|
+
this.invalidateWorkflowStepsCache();
|
|
78508
|
+
this.invalidatePromptContributionsCache();
|
|
78509
|
+
this.invalidateSetupCache();
|
|
78043
78510
|
executorLog.log(`Plugin ${pluginId} reloaded`);
|
|
78044
78511
|
}
|
|
78045
78512
|
// ── Event Handlers for Hot-Load/Unload ─────────────────────────
|
|
@@ -78051,6 +78518,10 @@ var init_plugin_runner = __esm({
|
|
|
78051
78518
|
this.invalidateRoutesCache();
|
|
78052
78519
|
this.invalidateUiSlotsCache();
|
|
78053
78520
|
this.invalidateRuntimesCache();
|
|
78521
|
+
this.invalidateSkillsCache();
|
|
78522
|
+
this.invalidateWorkflowStepsCache();
|
|
78523
|
+
this.invalidatePromptContributionsCache();
|
|
78524
|
+
this.invalidateSetupCache();
|
|
78054
78525
|
try {
|
|
78055
78526
|
executorLog.log(`Auto-loading enabled plugin: ${plugin4.id}`);
|
|
78056
78527
|
await this.options.pluginLoader.loadPlugin(plugin4.id);
|
|
@@ -78066,6 +78537,10 @@ var init_plugin_runner = __esm({
|
|
|
78066
78537
|
this.invalidateRoutesCache();
|
|
78067
78538
|
this.invalidateUiSlotsCache();
|
|
78068
78539
|
this.invalidateRuntimesCache();
|
|
78540
|
+
this.invalidateSkillsCache();
|
|
78541
|
+
this.invalidateWorkflowStepsCache();
|
|
78542
|
+
this.invalidatePromptContributionsCache();
|
|
78543
|
+
this.invalidateSetupCache();
|
|
78069
78544
|
try {
|
|
78070
78545
|
executorLog.log(`Auto-stopping disabled plugin: ${plugin4.id}`);
|
|
78071
78546
|
await this.options.pluginLoader.stopPlugin(plugin4.id);
|
|
@@ -78081,6 +78556,10 @@ var init_plugin_runner = __esm({
|
|
|
78081
78556
|
this.invalidateRoutesCache();
|
|
78082
78557
|
this.invalidateUiSlotsCache();
|
|
78083
78558
|
this.invalidateRuntimesCache();
|
|
78559
|
+
this.invalidateSkillsCache();
|
|
78560
|
+
this.invalidateWorkflowStepsCache();
|
|
78561
|
+
this.invalidatePromptContributionsCache();
|
|
78562
|
+
this.invalidateSetupCache();
|
|
78084
78563
|
try {
|
|
78085
78564
|
executorLog.log(`Stopping unregistered plugin: ${plugin4.id}`);
|
|
78086
78565
|
await this.options.pluginLoader.stopPlugin(plugin4.id);
|
|
@@ -78097,6 +78576,10 @@ var init_plugin_runner = __esm({
|
|
|
78097
78576
|
this.invalidateRoutesCache();
|
|
78098
78577
|
this.invalidateUiSlotsCache();
|
|
78099
78578
|
this.invalidateRuntimesCache();
|
|
78579
|
+
this.invalidateSkillsCache();
|
|
78580
|
+
this.invalidateWorkflowStepsCache();
|
|
78581
|
+
this.invalidatePromptContributionsCache();
|
|
78582
|
+
this.invalidateSetupCache();
|
|
78100
78583
|
}
|
|
78101
78584
|
/**
|
|
78102
78585
|
* Handle plugin updates - invalidate caches.
|
|
@@ -78106,6 +78589,10 @@ var init_plugin_runner = __esm({
|
|
|
78106
78589
|
this.invalidateRoutesCache();
|
|
78107
78590
|
this.invalidateUiSlotsCache();
|
|
78108
78591
|
this.invalidateRuntimesCache();
|
|
78592
|
+
this.invalidateSkillsCache();
|
|
78593
|
+
this.invalidateWorkflowStepsCache();
|
|
78594
|
+
this.invalidatePromptContributionsCache();
|
|
78595
|
+
this.invalidateSetupCache();
|
|
78109
78596
|
}
|
|
78110
78597
|
/**
|
|
78111
78598
|
* Handle plugin:loaded event from loader - invalidate caches.
|
|
@@ -78115,6 +78602,10 @@ var init_plugin_runner = __esm({
|
|
|
78115
78602
|
this.invalidateRoutesCache();
|
|
78116
78603
|
this.invalidateUiSlotsCache();
|
|
78117
78604
|
this.invalidateRuntimesCache();
|
|
78605
|
+
this.invalidateSkillsCache();
|
|
78606
|
+
this.invalidateWorkflowStepsCache();
|
|
78607
|
+
this.invalidatePromptContributionsCache();
|
|
78608
|
+
this.invalidateSetupCache();
|
|
78118
78609
|
}
|
|
78119
78610
|
/**
|
|
78120
78611
|
* Handle plugin:unloaded event from loader - invalidate caches.
|
|
@@ -78124,6 +78615,10 @@ var init_plugin_runner = __esm({
|
|
|
78124
78615
|
this.invalidateRoutesCache();
|
|
78125
78616
|
this.invalidateUiSlotsCache();
|
|
78126
78617
|
this.invalidateRuntimesCache();
|
|
78618
|
+
this.invalidateSkillsCache();
|
|
78619
|
+
this.invalidateWorkflowStepsCache();
|
|
78620
|
+
this.invalidatePromptContributionsCache();
|
|
78621
|
+
this.invalidateSetupCache();
|
|
78127
78622
|
}
|
|
78128
78623
|
/**
|
|
78129
78624
|
* Handle plugin:reloaded event from loader - invalidate caches.
|
|
@@ -78133,6 +78628,10 @@ var init_plugin_runner = __esm({
|
|
|
78133
78628
|
this.invalidateRoutesCache();
|
|
78134
78629
|
this.invalidateUiSlotsCache();
|
|
78135
78630
|
this.invalidateRuntimesCache();
|
|
78631
|
+
this.invalidateSkillsCache();
|
|
78632
|
+
this.invalidateWorkflowStepsCache();
|
|
78633
|
+
this.invalidatePromptContributionsCache();
|
|
78634
|
+
this.invalidateSetupCache();
|
|
78136
78635
|
}
|
|
78137
78636
|
// ── Tool Conversion ───────────────────────────────────────────────
|
|
78138
78637
|
/**
|
|
@@ -78304,6 +78803,22 @@ var init_plugin_runner = __esm({
|
|
|
78304
78803
|
this.runtimesCacheVersion++;
|
|
78305
78804
|
this.log.log(`Runtimes cache invalidated (version: ${this.runtimesCacheVersion})`);
|
|
78306
78805
|
}
|
|
78806
|
+
invalidateSkillsCache() {
|
|
78807
|
+
this.skillsCacheVersion++;
|
|
78808
|
+
this.log.log(`Skills cache invalidated (version: ${this.skillsCacheVersion})`);
|
|
78809
|
+
}
|
|
78810
|
+
invalidateWorkflowStepsCache() {
|
|
78811
|
+
this.workflowStepsCacheVersion++;
|
|
78812
|
+
this.log.log(`Workflow steps cache invalidated (version: ${this.workflowStepsCacheVersion})`);
|
|
78813
|
+
}
|
|
78814
|
+
invalidatePromptContributionsCache() {
|
|
78815
|
+
this.promptContributionsCacheVersion++;
|
|
78816
|
+
this.log.log(`Prompt contributions cache invalidated (version: ${this.promptContributionsCacheVersion})`);
|
|
78817
|
+
}
|
|
78818
|
+
invalidateSetupCache() {
|
|
78819
|
+
this.setupCacheVersion++;
|
|
78820
|
+
this.log.log(`Setup cache invalidated (version: ${this.setupCacheVersion})`);
|
|
78821
|
+
}
|
|
78307
78822
|
// ── Store Event Subscriptions ────────────────────────────────────
|
|
78308
78823
|
/**
|
|
78309
78824
|
* Subscribe to TaskStore events for task lifecycle hooks.
|
|
@@ -78447,6 +78962,10 @@ var init_in_process_runtime = __esm({
|
|
|
78447
78962
|
* before `start()` via `setMergeEnqueuer`.
|
|
78448
78963
|
*/
|
|
78449
78964
|
mergeEnqueuer;
|
|
78965
|
+
/** Tracks whether startup recovery was intentionally deferred due to pause state. */
|
|
78966
|
+
startupRecoveryDeferred = false;
|
|
78967
|
+
/** Prevent duplicate unpause recovery dispatches from racing each other. */
|
|
78968
|
+
resumeAfterUnpauseRunning = false;
|
|
78450
78969
|
/**
|
|
78451
78970
|
* Start the runtime and initialize all subsystems.
|
|
78452
78971
|
*
|
|
@@ -78480,7 +78999,7 @@ var init_in_process_runtime = __esm({
|
|
|
78480
78999
|
runtimeLog.log(`TaskStore initialized for project ${this.config.projectId}`);
|
|
78481
79000
|
}
|
|
78482
79001
|
this.messageStore = new MessageStoreClass(this.taskStore.getDatabase());
|
|
78483
|
-
this.pluginStore = new PluginStoreClass(this.
|
|
79002
|
+
this.pluginStore = new PluginStoreClass(this.config.workingDirectory);
|
|
78484
79003
|
await this.pluginStore.init();
|
|
78485
79004
|
this.pluginLoader = new PluginLoaderClass({
|
|
78486
79005
|
pluginStore: this.pluginStore,
|
|
@@ -78872,11 +79391,16 @@ var init_in_process_runtime = __esm({
|
|
|
78872
79391
|
this.selfHealingManager.start();
|
|
78873
79392
|
this.stuckTaskDetector.start();
|
|
78874
79393
|
this.setupEventForwarding();
|
|
78875
|
-
await this.
|
|
78876
|
-
|
|
78877
|
-
|
|
78878
|
-
runtimeLog.
|
|
78879
|
-
|
|
79394
|
+
const startupSettings = await this.taskStore.getSettings();
|
|
79395
|
+
if (startupSettings.globalPause || startupSettings.enginePaused) {
|
|
79396
|
+
this.startupRecoveryDeferred = true;
|
|
79397
|
+
runtimeLog.log(
|
|
79398
|
+
`Startup recovery deferred \u2014 ${startupSettings.globalPause ? "global pause" : "engine pause"} is active`
|
|
79399
|
+
);
|
|
79400
|
+
} else {
|
|
79401
|
+
this.startupRecoveryDeferred = false;
|
|
79402
|
+
await this.resumeStartupRecoverySequence();
|
|
79403
|
+
}
|
|
78880
79404
|
this.scheduler.start();
|
|
78881
79405
|
this.triageProcessor?.start();
|
|
78882
79406
|
this.missionExecutionLoop = missionExecutionLoop;
|
|
@@ -79042,6 +79566,45 @@ var init_in_process_runtime = __esm({
|
|
|
79042
79566
|
setMergeEnqueuer(enqueueMerge) {
|
|
79043
79567
|
this.mergeEnqueuer = enqueueMerge;
|
|
79044
79568
|
}
|
|
79569
|
+
/**
|
|
79570
|
+
* Resume executor/self-healing activity after an unpause transition.
|
|
79571
|
+
*
|
|
79572
|
+
* When startup recovery had been deferred, this replays the original startup
|
|
79573
|
+
* ordering so orphan resume and self-healing cannot race each other.
|
|
79574
|
+
*/
|
|
79575
|
+
async resumeAfterUnpause() {
|
|
79576
|
+
if (!this.taskStore || !this.executor || !this.selfHealingManager) {
|
|
79577
|
+
return;
|
|
79578
|
+
}
|
|
79579
|
+
if (this.resumeAfterUnpauseRunning) {
|
|
79580
|
+
return;
|
|
79581
|
+
}
|
|
79582
|
+
this.resumeAfterUnpauseRunning = true;
|
|
79583
|
+
try {
|
|
79584
|
+
const settings = await this.taskStore.getSettings();
|
|
79585
|
+
if (settings.globalPause || settings.enginePaused) {
|
|
79586
|
+
runtimeLog.log(
|
|
79587
|
+
`Unpause recovery still blocked \u2014 ${settings.globalPause ? "global pause" : "engine pause"} remains active`
|
|
79588
|
+
);
|
|
79589
|
+
return;
|
|
79590
|
+
}
|
|
79591
|
+
if (this.startupRecoveryDeferred) {
|
|
79592
|
+
await this.resumeStartupRecoverySequence();
|
|
79593
|
+
this.startupRecoveryDeferred = false;
|
|
79594
|
+
return;
|
|
79595
|
+
}
|
|
79596
|
+
await this.executor.resumeOrphaned();
|
|
79597
|
+
} finally {
|
|
79598
|
+
this.resumeAfterUnpauseRunning = false;
|
|
79599
|
+
}
|
|
79600
|
+
}
|
|
79601
|
+
async resumeStartupRecoverySequence() {
|
|
79602
|
+
await this.selfHealingManager.recoverNoProgressNoTaskDoneFailures();
|
|
79603
|
+
await this.executor.resumeOrphaned();
|
|
79604
|
+
void this.selfHealingManager.runStartupRecovery().catch((err) => {
|
|
79605
|
+
runtimeLog.error("Self-healing startup recovery failed:", err);
|
|
79606
|
+
});
|
|
79607
|
+
}
|
|
79045
79608
|
/**
|
|
79046
79609
|
* Get the project's TaskStore instance.
|
|
79047
79610
|
* @throws Error if runtime has not been started
|
|
@@ -82881,13 +83444,13 @@ ${detail}`
|
|
|
82881
83444
|
if (prev.globalPause && !s.globalPause) {
|
|
82882
83445
|
runtimeLog.log("Global unpause \u2014 resuming agentic activity");
|
|
82883
83446
|
try {
|
|
82884
|
-
const
|
|
82885
|
-
|
|
82886
|
-
(err) => runtimeLog.error("Failed to resume
|
|
83447
|
+
const runtime = this.runtime;
|
|
83448
|
+
runtime.resumeAfterUnpause?.().catch(
|
|
83449
|
+
(err) => runtimeLog.error("Failed to resume agentic activity on unpause:", err)
|
|
82887
83450
|
);
|
|
82888
83451
|
} catch (err) {
|
|
82889
83452
|
runtimeLog.warn(
|
|
82890
|
-
`Global unpause: failed to dispatch
|
|
83453
|
+
`Global unpause: failed to dispatch resumeAfterUnpause: ${err instanceof Error ? err.message : String(err)}`
|
|
82891
83454
|
);
|
|
82892
83455
|
}
|
|
82893
83456
|
if (s.autoMerge) {
|
|
@@ -82911,13 +83474,13 @@ ${detail}`
|
|
|
82911
83474
|
if (prev.enginePaused && !s.enginePaused) {
|
|
82912
83475
|
runtimeLog.log("Engine unpaused \u2014 resuming agentic activity");
|
|
82913
83476
|
try {
|
|
82914
|
-
const
|
|
82915
|
-
|
|
82916
|
-
(err) => runtimeLog.error("Failed to resume
|
|
83477
|
+
const runtime = this.runtime;
|
|
83478
|
+
runtime.resumeAfterUnpause?.().catch(
|
|
83479
|
+
(err) => runtimeLog.error("Failed to resume agentic activity on engine unpause:", err)
|
|
82917
83480
|
);
|
|
82918
83481
|
} catch (err) {
|
|
82919
83482
|
runtimeLog.warn(
|
|
82920
|
-
`Engine unpause: failed to dispatch
|
|
83483
|
+
`Engine unpause: failed to dispatch resumeAfterUnpause: ${err instanceof Error ? err.message : String(err)}`
|
|
82921
83484
|
);
|
|
82922
83485
|
}
|
|
82923
83486
|
if (s.autoMerge) {
|
|
@@ -96746,7 +97309,7 @@ var require_websocket = __commonJS({
|
|
|
96746
97309
|
var http = __require("http");
|
|
96747
97310
|
var net = __require("net");
|
|
96748
97311
|
var tls = __require("tls");
|
|
96749
|
-
var { randomBytes: randomBytes3, createHash:
|
|
97312
|
+
var { randomBytes: randomBytes3, createHash: createHash6 } = __require("crypto");
|
|
96750
97313
|
var { Duplex, Readable } = __require("stream");
|
|
96751
97314
|
var { URL: URL2 } = __require("url");
|
|
96752
97315
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -97406,7 +97969,7 @@ var require_websocket = __commonJS({
|
|
|
97406
97969
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
97407
97970
|
return;
|
|
97408
97971
|
}
|
|
97409
|
-
const digest =
|
|
97972
|
+
const digest = createHash6("sha1").update(key + GUID).digest("base64");
|
|
97410
97973
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
97411
97974
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
97412
97975
|
return;
|
|
@@ -97773,7 +98336,7 @@ var require_websocket_server = __commonJS({
|
|
|
97773
98336
|
var EventEmitter31 = __require("events");
|
|
97774
98337
|
var http = __require("http");
|
|
97775
98338
|
var { Duplex } = __require("stream");
|
|
97776
|
-
var { createHash:
|
|
98339
|
+
var { createHash: createHash6 } = __require("crypto");
|
|
97777
98340
|
var extension2 = require_extension();
|
|
97778
98341
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
97779
98342
|
var subprotocol2 = require_subprotocol();
|
|
@@ -98074,7 +98637,7 @@ var require_websocket_server = __commonJS({
|
|
|
98074
98637
|
);
|
|
98075
98638
|
}
|
|
98076
98639
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
98077
|
-
const digest =
|
|
98640
|
+
const digest = createHash6("sha1").update(key + GUID).digest("base64");
|
|
98078
98641
|
const headers = [
|
|
98079
98642
|
"HTTP/1.1 101 Switching Protocols",
|
|
98080
98643
|
"Upgrade: websocket",
|