@runfusion/fusion 0.74.0-beta.7 → 0.74.0-beta.8
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 +339 -473
- package/dist/child-process-worker.js +144 -278
- package/dist/client/.vite/manifest.json +254 -254
- package/dist/client/assets/{AgentDetailView-CTdyQL11.js → AgentDetailView-CnzGIxqj.js} +1 -1
- package/dist/client/assets/{AgentPermissionPolicyEditor-DBa7nIQV.js → AgentPermissionPolicyEditor-DMnyR96M.js} +1 -1
- package/dist/client/assets/{AgentsView-B5tss2oK.js → AgentsView-CzFtICwM.js} +3 -3
- package/dist/client/assets/{ChatView-DAKt1a2L.js → ChatView-Cs6B3fNf.js} +1 -1
- package/dist/client/assets/{CommandCenter-yPvRo9F6.js → CommandCenter-DADvho3z.js} +1 -1
- package/dist/client/assets/{DevServerView-BTyS2owH.js → DevServerView-Bzrzfs8Z.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-BjGIupNU.js → DirectoryPicker-rmip5GcI.js} +1 -1
- package/dist/client/assets/{DocumentsView-CuxfbpSZ.js → DocumentsView-BEM4nmJT.js} +1 -1
- package/dist/client/assets/{EvalsView-DGuy8SHR.js → EvalsView-Du7NaYMJ.js} +1 -1
- package/dist/client/assets/{ExperimentalAgentOnboardingModal-lK407ZAq.js → ExperimentalAgentOnboardingModal-BpIMiZOi.js} +1 -1
- package/dist/client/assets/{GoalsView-DAVN0ObR.js → GoalsView-BxKRyXM3.js} +1 -1
- package/dist/client/assets/{InsightsView-BXQKcNof.js → InsightsView-Dauq6b3M.js} +1 -1
- package/dist/client/assets/{MemoryView-D7RKEtV7.js → MemoryView-DRD9Xvwx.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-CrOJ57R2.js → PiExtensionsManager-DJKE1iAX.js} +1 -1
- package/dist/client/assets/{PluginManager-D7_evt4j.js → PluginManager-CScwY-Ib.js} +1 -1
- package/dist/client/assets/{PullRequestView-C0lRUbth.js → PullRequestView-uAu5_4__.js} +1 -1
- package/dist/client/assets/{ReportModal-Cy5fRNDK.js → ReportModal-nNUcGxYj.js} +1 -1
- package/dist/client/assets/{ResearchView-e8st2Sxu.js → ResearchView-BX1kGbWP.js} +1 -1
- package/dist/client/assets/{SecretsView-BLzckrzb.js → SecretsView-U_itETHx.js} +1 -1
- package/dist/client/assets/{SessionTerminal-F_GIj4gh.js → SessionTerminal-_b15vcd9.js} +1 -1
- package/dist/client/assets/SettingsModal-B30rPfYC.css +1 -0
- package/dist/client/assets/{SettingsModal-XAddgWkF.js → SettingsModal-DkpUKf4k.js} +1 -1
- package/dist/client/assets/{SettingsModal-eQbxbkLU.js → SettingsModal-DpbYR3Co.js} +4 -4
- package/dist/client/assets/{SettingsTextareaRow-DVjUHNQp.js → SettingsTextareaRow-Dbv-oqsF.js} +1 -1
- package/dist/client/assets/{SetupWizardModal-xID9yIff.js → SetupWizardModal-n_kcJfIP.js} +2 -2
- package/dist/client/assets/{SkillsView-BNdMGu6E.js → SkillsView-Bv2uqBre.js} +1 -1
- package/dist/client/assets/{TodoView-xcOjHZm1.js → TodoView-y11oUvjw.js} +1 -1
- package/dist/client/assets/{WorkflowNodeEditor-DZ2WZ-ve.js → WorkflowNodeEditor-DwY4XzNB.js} +1 -1
- package/dist/client/assets/{agent-import-generation-0tkW9WMt.js → agent-import-generation-B_UNOAWY.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-DP9_UvPn.js → architectureDiagram-3BPJPVTR-BpA9_eoq.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-EgKwYMgQ.js → blockDiagram-GPEHLZMM-DFFA8tCG.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-Dzv0-_xt.js → c4Diagram-AAUBKEIU-Fzhn0dG7.js} +1 -1
- package/dist/client/assets/channel-C9C9Rxgn.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-CNmFmJlQ.js → chunk-2J33WTMH-Bi3oPWBJ.js} +1 -1
- package/dist/client/assets/{chunk-4BX2VUAB-DwtF2sl5.js → chunk-4BX2VUAB-UmeI_To2.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-DoDurT6F.js → chunk-55IACEB6-BvNWeThd.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-DB87A9uH.js → chunk-727SXJPM-OHmjSQwz.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-ClTDkMp1.js → chunk-AQP2D5EJ-DCi9eQaE.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-BhY2wlYr.js → chunk-FMBD7UC4-CelGyE3R.js} +1 -1
- package/dist/client/assets/{chunk-ND2GUHAM-BB8mzlmk.js → chunk-ND2GUHAM-DespM-6E.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-D81qQMGf.js → chunk-QZHKN3VN-DLkr_Pz0.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-BGVE_u03.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BGVE_u03.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-CCFUHBJX.js → cose-bilkent-S5V4N54A-I7MlbwDq.js} +1 -1
- package/dist/client/assets/{dagre-BM42HDAG-xr9MLhRA.js → dagre-BM42HDAG-DRwLRj5m.js} +1 -1
- package/dist/client/assets/{dashboard-view-oTFt91I3.js → dashboard-view-CIwO3ODB.js} +1 -1
- package/dist/client/assets/{dashboard-view-RXKFv3QV.js → dashboard-view-CSxVzmpI.js} +1 -1
- package/dist/client/assets/{dashboard-view-lqwQ-pMo.js → dashboard-view-Gb436HIO.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-mN_tYnBs.js → diagram-2AECGRRQ-BuWGDbh_.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-xznlq-5C.js → diagram-5GNKFQAL-hG6N6ArX.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-ClRlj1ZA.js → diagram-KO2AKTUF-BSXKqQJA.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-CNiPIQqT.js → diagram-LMA3HP47-wNefeM2W.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-DwQD-W0P.js → diagram-OG6HWLK6-nA8v_k_H.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-ZXkiCm8S.js → erDiagram-TEJ5UH35-Dwnvvp2x.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-DI5haEH9.js → flowDiagram-I6XJVG4X-FS4W3U0O.js} +1 -1
- package/dist/client/assets/{folder-open-NenyCkrb.js → folder-open-C3GXrzUo.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-BRHJpfOZ.js → ganttDiagram-6RSMTGT7-D95bgKFE.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-iXT_YBAZ.js → gitGraphDiagram-PVQCEYII-zqFbK6on.js} +1 -1
- package/dist/client/assets/{index-CrAJA2v0.js → index-BWRNl9tu.js} +274 -274
- package/dist/client/assets/index-DRZtPb3i.css +1 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-BzkuQtqZ.js → infoDiagram-5YYISTIA-BBELQBNE.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-5hnPG_98.js → ishikawaDiagram-YF4QCWOH-bSZkIXd-.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-Co3fnxbr.js → journeyDiagram-JHISSGLW-8wIimXRT.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-PZFl_y-h.js → kanban-definition-UN3LZRKU-DMj6kFc5.js} +1 -1
- package/dist/client/assets/{mermaid.core-CJRKeU9s.js → mermaid.core-UDKENpfo.js} +4 -4
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-B15e2rkx.js → mindmap-definition-RKZ34NQL-CJGH0VYQ.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-kGF592D_.js → pieDiagram-4H26LBE5-B3cZLcOe.js} +1 -1
- package/dist/client/assets/{puzzle-Dgc4yzjO.js → puzzle-D85LM19g.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-CUShcj70.js → quadrantDiagram-W4KKPZXB-bR1CBrVi.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-D2k4nLqQ.js → requirementDiagram-4Y6WPE33-DnyJ74cE.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-CA03BxhT.js → sankeyDiagram-5OEKKPKP-ttv4kq0z.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-DDuFN2Pi.js → sequenceDiagram-3UESZ5HK-FiUBFoWw.js} +1 -1
- package/dist/client/assets/{shield-alert-BlYWqolM.js → shield-alert-D3IVOJV1.js} +1 -1
- package/dist/client/assets/{standing-instructions-template-ujl7UARV.js → standing-instructions-template-CWY_pFh6.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-yJOkHK4Q.js → stateDiagram-AJRCARHV-BcsYRB77.js} +1 -1
- package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-BgErHdAN.js → stateDiagram-v2-BHNVJYJU-DsBPFwnG.js} +1 -1
- package/dist/client/assets/{timeline-definition-PNZ67QCA-BUiDQw21.js → timeline-definition-PNZ67QCA-B8rOOxEj.js} +1 -1
- package/dist/client/assets/{upload-DmlZvpMp.js → upload-WqSaqC__.js} +1 -1
- package/dist/client/assets/{users-Cx6ACt-W.js → users-CPP-3wxQ.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-DqyIjBY8.js → vennDiagram-CIIHVFJN-CO0LSFj2.js} +1 -1
- package/dist/client/assets/{wardley-L42UT6IY-C93tXAKH.js → wardley-L42UT6IY-QHbclXGi.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DmH6-GJV.js → wardleyDiagram-YWT4CUSO-DAsnTuM9.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-BPwjE4Su.js → xychartDiagram-2RQKCTM6-BmG5EEoO.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/version.json +1 -1
- package/dist/extension.js +216 -350
- package/package.json +1 -1
- package/dist/client/assets/SettingsModal-KnUd0942.css +0 -1
- package/dist/client/assets/channel-BdTAZBkX.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-CuoGzmwo.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-CuoGzmwo.js +0 -1
- package/dist/client/assets/index-CITV-wDq.css +0 -1
package/dist/extension.js
CHANGED
|
@@ -135461,7 +135461,8 @@ function wrapPluginRuntime(instance, runtimeId, runtimeName) {
|
|
|
135461
135461
|
const result2 = await adapter.createSession(options);
|
|
135462
135462
|
return {
|
|
135463
135463
|
session: result2.session ?? result2,
|
|
135464
|
-
sessionFile: result2.sessionFile
|
|
135464
|
+
sessionFile: result2.sessionFile,
|
|
135465
|
+
settleFallbackDispatch: result2.settleFallbackDispatch
|
|
135465
135466
|
};
|
|
135466
135467
|
}
|
|
135467
135468
|
throw new Error(`Plugin runtime "${runtimeId}" does not implement createSession`);
|
|
@@ -135570,11 +135571,15 @@ var init_runtime_resolution = __esm({
|
|
|
135570
135571
|
name = "Default PI Runtime";
|
|
135571
135572
|
async createSession(options) {
|
|
135572
135573
|
const { toolOutputMaxChars, mcpServers, ...agentOptions } = options;
|
|
135573
|
-
|
|
135574
|
+
const result2 = await createFnAgent2({
|
|
135574
135575
|
...agentOptions,
|
|
135575
135576
|
toolOutputMaxChars,
|
|
135576
135577
|
mcpServers: normalizeAgentRuntimeMcpServers(mcpServers)
|
|
135577
135578
|
});
|
|
135579
|
+
return {
|
|
135580
|
+
...result2,
|
|
135581
|
+
settleFallbackDispatch: result2.settleFallbackDispatch ?? (async () => void 0)
|
|
135582
|
+
};
|
|
135578
135583
|
}
|
|
135579
135584
|
async promptWithFallback(session, prompt, options) {
|
|
135580
135585
|
return promptWithFallback(session, prompt, options);
|
|
@@ -136456,6 +136461,7 @@ async function createResolvedAgentSession(options) {
|
|
|
136456
136461
|
return {
|
|
136457
136462
|
session: result2.session,
|
|
136458
136463
|
sessionFile: result2.sessionFile,
|
|
136464
|
+
settleFallbackDispatch: result2.settleFallbackDispatch,
|
|
136459
136465
|
runtimeId: resolved.runtimeId,
|
|
136460
136466
|
wasConfigured: resolved.wasConfigured
|
|
136461
136467
|
};
|
|
@@ -158451,7 +158457,11 @@ async function createFnAgent2(options) {
|
|
|
158451
158457
|
}
|
|
158452
158458
|
});
|
|
158453
158459
|
attachSessionIdentity(promptableSession);
|
|
158454
|
-
return {
|
|
158460
|
+
return {
|
|
158461
|
+
session: promptableSession,
|
|
158462
|
+
sessionFile: promptableSession.sessionFile,
|
|
158463
|
+
settleFallbackDispatch: async () => void 0
|
|
158464
|
+
};
|
|
158455
158465
|
}
|
|
158456
158466
|
var execAsync, RTK_ACCEPTED_REWRITE_EXIT_CODES, RTK_EXPECTED_PASSTHROUGH_EXIT_CODES, RTK_EXPECTED_FAIL_OPEN_ERROR_CODES, RTK_REWRITE_MAX_BUFFER_BYTES, hostExtensionPaths, FN_MEMORY_APPEND_TOOL_NAME, FUSION_SHUTDOWN_WRAP_FLAG, promptWithFallbackInFlight, COMPACTION_FALLBACK_INSTRUCTIONS, MAX_COMPACTED_PROMPT_MEMORY_CHARS, MAX_COMPACTED_SUBTASK_GUIDANCE_CHARS, MAX_COMPACTED_ATTACHMENTS_CHARS, MAX_COMPACTED_EXISTING_SPEC_CHARS, MAX_COMPACTED_TASK_PROMPT_CHARS, MAX_COMPACTED_USER_COMMENTS_CHARS, ModelFallbackExhaustedError, GATE_BYPASS_TOOL_NAMES, TOOL_OUTPUT_BUDGET_OVERRIDES;
|
|
158457
158467
|
var init_pi = __esm({
|
|
@@ -184940,6 +184950,25 @@ var init_scheduler = __esm({
|
|
|
184940
184950
|
});
|
|
184941
184951
|
}
|
|
184942
184952
|
}
|
|
184953
|
+
if (from === parked.wip && to2 === parked.hold) {
|
|
184954
|
+
if (source === "engine") {
|
|
184955
|
+
this.recentEngineTodoRequeues.set(task.id, task.columnMovedAt ?? (/* @__PURE__ */ new Date()).toISOString());
|
|
184956
|
+
} else {
|
|
184957
|
+
this.recentEngineTodoRequeues.delete(task.id);
|
|
184958
|
+
}
|
|
184959
|
+
} else if (to2 === parked.review || parked.terminal.has(to2)) {
|
|
184960
|
+
this.recentEngineTodoRequeues.delete(task.id);
|
|
184961
|
+
if (task.dispatchStormCount != null || task.lastDispatchAt != null || task.executeRequeueLoopCount != null || task.executeRequeueLoopSignature != null) {
|
|
184962
|
+
void this.store.updateTask(task.id, {
|
|
184963
|
+
dispatchStormCount: null,
|
|
184964
|
+
lastDispatchAt: null,
|
|
184965
|
+
executeRequeueLoopCount: null,
|
|
184966
|
+
executeRequeueLoopSignature: null
|
|
184967
|
+
}).catch((error3) => {
|
|
184968
|
+
schedulerLog.warn(`Failed to reset dispatch oscillation state for ${task.id} on move to ${to2}: ${error3 instanceof Error ? error3.message : String(error3)}`);
|
|
184969
|
+
});
|
|
184970
|
+
}
|
|
184971
|
+
}
|
|
184943
184972
|
const resolvedParked = mergeParkedColumns(await resolveTaskParkedColumns(this.store, task.id), lanes);
|
|
184944
184973
|
if (resolvedParked.terminal.has(to2)) {
|
|
184945
184974
|
try {
|
|
@@ -185000,25 +185029,6 @@ var init_scheduler = __esm({
|
|
|
185000
185029
|
schedulerLog.error(`Failed event-driven blocker reconciliation for ${task.id}`, error3);
|
|
185001
185030
|
}
|
|
185002
185031
|
}
|
|
185003
|
-
if (from === resolvedParked.wip && to2 === resolvedParked.hold) {
|
|
185004
|
-
if (source === "engine") {
|
|
185005
|
-
this.recentEngineTodoRequeues.set(task.id, task.columnMovedAt ?? (/* @__PURE__ */ new Date()).toISOString());
|
|
185006
|
-
} else {
|
|
185007
|
-
this.recentEngineTodoRequeues.delete(task.id);
|
|
185008
|
-
}
|
|
185009
|
-
} else if (to2 === resolvedParked.review || resolvedParked.terminal.has(to2)) {
|
|
185010
|
-
this.recentEngineTodoRequeues.delete(task.id);
|
|
185011
|
-
if (task.dispatchStormCount != null || task.lastDispatchAt != null || task.executeRequeueLoopCount != null || task.executeRequeueLoopSignature != null) {
|
|
185012
|
-
void this.store.updateTask(task.id, {
|
|
185013
|
-
dispatchStormCount: null,
|
|
185014
|
-
lastDispatchAt: null,
|
|
185015
|
-
executeRequeueLoopCount: null,
|
|
185016
|
-
executeRequeueLoopSignature: null
|
|
185017
|
-
}).catch((error3) => {
|
|
185018
|
-
schedulerLog.warn(`Failed to reset dispatch oscillation state for ${task.id} on move to ${to2}: ${error3 instanceof Error ? error3.message : String(error3)}`);
|
|
185019
|
-
});
|
|
185020
|
-
}
|
|
185021
|
-
}
|
|
185022
185032
|
if (resolvedParked.terminal.has(to2) || to2 === resolvedParked.hold) {
|
|
185023
185033
|
schedulerLog.log(`Task moved to ${to2} \u2014 triggering scheduling`);
|
|
185024
185034
|
this.schedule();
|
|
@@ -203276,7 +203286,6 @@ var init_self_healing = __esm({
|
|
|
203276
203286
|
{ name: "reconcile-done-task-integrity", fn: () => this.reconcileDoneTaskIntegrity() },
|
|
203277
203287
|
{ name: "reconcile-stale-merger-status", fn: () => this.reconcileStaleMergerStatus() },
|
|
203278
203288
|
{ name: "reconcile-stale-duplicate-decision", fn: () => this.reconcileStaleDuplicateDecisionPause() },
|
|
203279
|
-
{ name: "reconcile-external-pr-blockers", fn: () => this.reconcileExternalPrBlockers() },
|
|
203280
203289
|
// FNXC:OrphanedPendingSteps 2026-07-22-16:35 (FN-8492 review follow-up): also
|
|
203281
203290
|
// steady-state — a step session can die without an engine restart, and startup-only
|
|
203282
203291
|
// cadence left that case riding the 3×30-min stall escalator to a deadlock park.
|
|
@@ -212173,71 +212182,12 @@ var init_self_healing = __esm({
|
|
|
212173
212182
|
}
|
|
212174
212183
|
}
|
|
212175
212184
|
/*
|
|
212176
|
-
FNXC:HonestBlockedExit 2026-08-02-
|
|
212177
|
-
|
|
212178
|
-
|
|
212179
|
-
|
|
212185
|
+
FNXC:HonestBlockedExit 2026-08-02-23:59 (operator decision — FN-8728 vs PR #2398):
|
|
212186
|
+
The FN-8700 `reconcile-external-pr-blockers` sweep (gh-backed clearing of PR-claim parks)
|
|
212187
|
+
is REMOVED with the whole PR/file-claim blocking mechanism. Open PRs are never blockers;
|
|
212188
|
+
file-scope conflicts are arbitrated only by Fusion's own board. Legacy PR-claim parks are
|
|
212189
|
+
no longer honored by isDurableBlockedTask, so normal recovery paths reclaim them.
|
|
212180
212190
|
*/
|
|
212181
|
-
async reconcileExternalPrBlockers() {
|
|
212182
|
-
try {
|
|
212183
|
-
if (!await isGhAvailable()) {
|
|
212184
|
-
log33.debug("reconcile-external-pr-blockers skipped \u2014 gh unavailable");
|
|
212185
|
-
return 0;
|
|
212186
|
-
}
|
|
212187
|
-
const tasks2 = await this.store.listTasks({ slim: true, includeArchived: false, limit: 500 });
|
|
212188
|
-
let cleared = 0;
|
|
212189
|
-
for (const task of tasks2.slice(0, 80)) {
|
|
212190
|
-
if (task.status !== "failed" || !task.error?.startsWith("BLOCKED:")) continue;
|
|
212191
|
-
const meta2 = task.sourceMetadata;
|
|
212192
|
-
const blockers = meta2?.externalBlockers;
|
|
212193
|
-
if (!Array.isArray(blockers) || blockers.length === 0) continue;
|
|
212194
|
-
const prNumbers = blockers.map((b3) => b3 && typeof b3 === "object" && b3.kind === "github-pr" ? Number(b3.number) : NaN).filter((n) => Number.isFinite(n) && n > 0);
|
|
212195
|
-
if (prNumbers.length === 0) continue;
|
|
212196
|
-
let allResolved = true;
|
|
212197
|
-
for (const n of prNumbers) {
|
|
212198
|
-
try {
|
|
212199
|
-
const pr2 = await runGhJsonAsync(
|
|
212200
|
-
["pr", "view", String(n), "--json", "state,mergedAt"],
|
|
212201
|
-
{ timeoutMs: 15e3 }
|
|
212202
|
-
);
|
|
212203
|
-
const state = String(pr2?.state ?? "").toUpperCase();
|
|
212204
|
-
const merged = Boolean(pr2?.mergedAt) || state === "MERGED";
|
|
212205
|
-
const closed = state === "CLOSED" || state === "MERGED";
|
|
212206
|
-
if (!merged && !closed) {
|
|
212207
|
-
allResolved = false;
|
|
212208
|
-
break;
|
|
212209
|
-
}
|
|
212210
|
-
} catch {
|
|
212211
|
-
allResolved = false;
|
|
212212
|
-
break;
|
|
212213
|
-
}
|
|
212214
|
-
}
|
|
212215
|
-
if (!allResolved) continue;
|
|
212216
|
-
await this.store.updateTask(task.id, {
|
|
212217
|
-
status: null,
|
|
212218
|
-
error: null,
|
|
212219
|
-
sourceMetadataPatch: {
|
|
212220
|
-
externalBlockers: [],
|
|
212221
|
-
blockedClass: null,
|
|
212222
|
-
blockedThrashSignature: null,
|
|
212223
|
-
blockedThrashCount: null,
|
|
212224
|
-
externalPrBlockersClearedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
212225
|
-
externalPrBlockersCleared: prNumbers
|
|
212226
|
-
}
|
|
212227
|
-
});
|
|
212228
|
-
await this.store.logEntry(
|
|
212229
|
-
task.id,
|
|
212230
|
-
`Auto-recovered: external PR blocker(s) ${prNumbers.map((n) => `#${n}`).join(", ")} merged/closed \u2014 cleared durable BLOCKED park for re-dispatch`
|
|
212231
|
-
);
|
|
212232
|
-
log33.log(`Cleared durable PR block for ${task.id} (prs=${prNumbers.join(",")})`);
|
|
212233
|
-
cleared += 1;
|
|
212234
|
-
}
|
|
212235
|
-
return cleared;
|
|
212236
|
-
} catch (error3) {
|
|
212237
|
-
log33.warn(`reconcile-external-pr-blockers failed: ${error3 instanceof Error ? error3.message : String(error3)}`);
|
|
212238
|
-
return 0;
|
|
212239
|
-
}
|
|
212240
|
-
}
|
|
212241
212191
|
async resolveExplicitDuplicateMarkerTasks() {
|
|
212242
212192
|
try {
|
|
212243
212193
|
const settings = await this.store.getSettings();
|
|
@@ -212991,6 +212941,7 @@ var init_self_healing = __esm({
|
|
|
212991
212941
|
// ../engine/src/triage.ts
|
|
212992
212942
|
import { Type as Type5 } from "@earendil-works/pi-ai";
|
|
212993
212943
|
import { exec as exec34 } from "node:child_process";
|
|
212944
|
+
import { existsSync as existsSync60 } from "node:fs";
|
|
212994
212945
|
import { readFile as readFile38, writeFile as writeFile27, rm as rm8 } from "node:fs/promises";
|
|
212995
212946
|
import { join as join72 } from "node:path";
|
|
212996
212947
|
import { promisify as promisify48 } from "node:util";
|
|
@@ -213497,6 +213448,8 @@ var init_triage = __esm({
|
|
|
213497
213448
|
unregisterAdmissionProvider = null;
|
|
213498
213449
|
/** Timestamps when tasks entered the `processing` set, for staleness detection. */
|
|
213499
213450
|
processingSince = /* @__PURE__ */ new Map();
|
|
213451
|
+
/** Monotonic provenance token for attempt-local planner fallback observation. */
|
|
213452
|
+
planningAttemptSequence = 0;
|
|
213500
213453
|
wasGlobalPaused = false;
|
|
213501
213454
|
wasEnginePaused = false;
|
|
213502
213455
|
idleSemaphoreLeakCandidateSince = null;
|
|
@@ -214792,7 +214745,28 @@ You are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.
|
|
|
214792
214745
|
}
|
|
214793
214746
|
await this.store.logEntry(task.id, `Planning session running in task worktree ${planningCwd}`).catch(() => void 0);
|
|
214794
214747
|
}
|
|
214795
|
-
const
|
|
214748
|
+
const authoritativePromptPath = join72(this.rootDir, promptPath);
|
|
214749
|
+
const planningAttemptBaseline = existsSync60(authoritativePromptPath) ? await readFile38(authoritativePromptPath, "utf-8").catch(() => void 0) : void 0;
|
|
214750
|
+
const planningAttempt = {
|
|
214751
|
+
id: `${task.id}:${++this.planningAttemptSequence}`,
|
|
214752
|
+
baseline: planningAttemptBaseline,
|
|
214753
|
+
fallbackEngaged: false,
|
|
214754
|
+
fallbackSettlements: []
|
|
214755
|
+
};
|
|
214756
|
+
const fallbackObserver = createFallbackModelObserver({
|
|
214757
|
+
agent: "triage",
|
|
214758
|
+
label: "triage",
|
|
214759
|
+
store: this.store,
|
|
214760
|
+
taskId: task.id,
|
|
214761
|
+
taskTitle: task.title
|
|
214762
|
+
});
|
|
214763
|
+
const onFallbackModelUsed = (payload) => {
|
|
214764
|
+
planningAttempt.fallbackEngaged = true;
|
|
214765
|
+
const settlement = Promise.resolve(fallbackObserver(payload));
|
|
214766
|
+
planningAttempt.fallbackSettlements.push(settlement);
|
|
214767
|
+
return settlement;
|
|
214768
|
+
};
|
|
214769
|
+
const { session, settleFallbackDispatch, runtimeId } = await createResolvedAgentSession({
|
|
214796
214770
|
sessionPurpose: "triage",
|
|
214797
214771
|
runtimeHint: triageRuntimeHint,
|
|
214798
214772
|
pluginRunner: this.options.pluginRunner,
|
|
@@ -214831,13 +214805,7 @@ You are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.
|
|
|
214831
214805
|
taskTitle: task.title,
|
|
214832
214806
|
actionGateContext: this.buildActionGateContext(task.id, triageRunContext.runId, assignedAgent, settings.defaultAgentPermissionPolicy),
|
|
214833
214807
|
permanentAgentGating: this.buildPermanentAgentGatingContext(task.id, triageRunContext.runId, assignedAgent, settings.defaultAgentPermissionPolicy),
|
|
214834
|
-
onFallbackModelUsed
|
|
214835
|
-
agent: "triage",
|
|
214836
|
-
label: "triage",
|
|
214837
|
-
store: this.store,
|
|
214838
|
-
taskId: task.id,
|
|
214839
|
-
taskTitle: task.title
|
|
214840
|
-
})
|
|
214808
|
+
onFallbackModelUsed
|
|
214841
214809
|
});
|
|
214842
214810
|
const modelDesc = formatModelMarkerDetails(describeModel(session), resolvePlanningThinkingLevel(settings, task.planningThinkingLevel ?? task.thinkingLevel));
|
|
214843
214811
|
planLog.debug(`${task.id}: using model ${modelDesc}`);
|
|
@@ -214907,6 +214875,10 @@ You are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.
|
|
|
214907
214875
|
agentPrompt,
|
|
214908
214876
|
imageContents.length > 0 ? { images: imageContents } : void 0
|
|
214909
214877
|
);
|
|
214878
|
+
const fallbackDispatchBoundaryMissing = typeof settleFallbackDispatch !== "function";
|
|
214879
|
+
if (!fallbackDispatchBoundaryMissing) {
|
|
214880
|
+
await settleFallbackDispatch();
|
|
214881
|
+
}
|
|
214910
214882
|
checkSessionError(session);
|
|
214911
214883
|
if (this.pauseAborted.has(task.id)) {
|
|
214912
214884
|
this.pauseAborted.delete(task.id);
|
|
@@ -214999,12 +214971,42 @@ You are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.
|
|
|
214999
214971
|
}
|
|
215000
214972
|
}
|
|
215001
214973
|
}
|
|
215002
|
-
|
|
215003
|
-
|
|
215004
|
-
|
|
215005
|
-
|
|
215006
|
-
|
|
215007
|
-
|
|
214974
|
+
let settledFallbackCount = 0;
|
|
214975
|
+
while (settledFallbackCount < planningAttempt.fallbackSettlements.length) {
|
|
214976
|
+
const pendingSettlements = planningAttempt.fallbackSettlements.slice(settledFallbackCount);
|
|
214977
|
+
settledFallbackCount = planningAttempt.fallbackSettlements.length;
|
|
214978
|
+
await Promise.all(pendingSettlements);
|
|
214979
|
+
}
|
|
214980
|
+
const artifactChangedByAttempt = planningAttempt.baseline !== written;
|
|
214981
|
+
if (fallbackDispatchBoundaryMissing || planningAttempt.fallbackEngaged || !artifactChangedByAttempt) {
|
|
214982
|
+
const failure = fallbackDispatchBoundaryMissing ? `Planner runtime ${runtimeId} did not provide a fallback-dispatch settlement boundary for attempt ${planningAttempt.id}` : planningAttempt.fallbackEngaged ? `Planner fallback engaged during attempt ${planningAttempt.id}` : `Planner did not update the authoritative PROMPT.md during attempt ${planningAttempt.id}`;
|
|
214983
|
+
const decision = computeRecoveryDecision({
|
|
214984
|
+
recoveryRetryCount: task.recoveryRetryCount,
|
|
214985
|
+
nextRecoveryAt: task.nextRecoveryAt
|
|
214986
|
+
});
|
|
214987
|
+
if (decision.shouldRetry) {
|
|
214988
|
+
const retryMessage = `${failure} \u2014 retry ${decision.nextState.recoveryRetryCount}/${MAX_RECOVERY_RETRIES} in ${formatDelay(decision.delayMs)}.`;
|
|
214989
|
+
planLog.warn(`${task.id} ${retryMessage}`);
|
|
214990
|
+
await this.store.logEntry(task.id, retryMessage);
|
|
214991
|
+
await this.updatePlanningStateIfStillCurrent(task, {
|
|
214992
|
+
status: this.restoreStatusAfterInterruptedTriageWork(task),
|
|
214993
|
+
error: null,
|
|
214994
|
+
recoveryRetryCount: decision.nextState.recoveryRetryCount,
|
|
214995
|
+
nextRecoveryAt: decision.nextState.nextRecoveryAt
|
|
214996
|
+
});
|
|
214997
|
+
return;
|
|
214998
|
+
}
|
|
214999
|
+
const failureMessage = `${failure} after ${MAX_RECOVERY_RETRIES} retries. Retry after adjusting the task prompt or model.`;
|
|
215000
|
+
planLog.error(`${task.id} clean planning attempt retry budget exhausted`);
|
|
215001
|
+
await this.store.logEntry(task.id, failureMessage);
|
|
215002
|
+
if (await this.updatePlanningStateIfStillCurrent(task, {
|
|
215003
|
+
status: "failed",
|
|
215004
|
+
error: failureMessage,
|
|
215005
|
+
recoveryRetryCount: null,
|
|
215006
|
+
nextRecoveryAt: null
|
|
215007
|
+
})) {
|
|
215008
|
+
await this.backfillBlankTitleAfterTerminalTriageFailure(task);
|
|
215009
|
+
}
|
|
215008
215010
|
return;
|
|
215009
215011
|
}
|
|
215010
215012
|
const deterministicSpecFailure = await this.validateGeneratedPrompt(task.id, written);
|
|
@@ -215046,6 +215048,21 @@ You are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.
|
|
|
215046
215048
|
}
|
|
215047
215049
|
return;
|
|
215048
215050
|
}
|
|
215051
|
+
const duplicateReport = { outcome: "parked" };
|
|
215052
|
+
if (await this.tryFinalizeExplicitDuplicateMarker(task, written, settings, {
|
|
215053
|
+
isReplan,
|
|
215054
|
+
feedback
|
|
215055
|
+
}, duplicateReport)) {
|
|
215056
|
+
this.options.onSpecifyComplete?.(task, duplicateReport);
|
|
215057
|
+
return;
|
|
215058
|
+
}
|
|
215059
|
+
if (task.recoveryRetryCount != null || task.nextRecoveryAt != null) {
|
|
215060
|
+
await this.updatePlanningStateIfStillCurrent(task, {
|
|
215061
|
+
error: null,
|
|
215062
|
+
recoveryRetryCount: null,
|
|
215063
|
+
nextRecoveryAt: null
|
|
215064
|
+
});
|
|
215065
|
+
}
|
|
215049
215066
|
const finalizeReport = await this.finalizeApprovedTask(task, written, settings, {
|
|
215050
215067
|
isReplan,
|
|
215051
215068
|
feedback
|
|
@@ -216082,103 +216099,35 @@ Remove or replace these ids and call fn_task_create again.`
|
|
|
216082
216099
|
// ../engine/src/execution-block-classifier.ts
|
|
216083
216100
|
function partitionBlockedByRefs(blockedBy) {
|
|
216084
216101
|
const taskIds = [];
|
|
216085
|
-
const prNumbers = [];
|
|
216086
216102
|
for (const raw of blockedBy) {
|
|
216087
216103
|
const id = raw.trim();
|
|
216088
216104
|
if (!id) continue;
|
|
216089
|
-
|
|
216090
|
-
if (prMatch) {
|
|
216091
|
-
prNumbers.push(Number(prMatch[1]));
|
|
216092
|
-
continue;
|
|
216093
|
-
}
|
|
216105
|
+
if (LEGACY_PR_REF_RE.test(id)) continue;
|
|
216094
216106
|
if (TASK_ID_RE.test(id)) {
|
|
216095
216107
|
const m2 = id.toUpperCase().match(/^([A-Z][A-Z0-9]*)-(\d+)$/);
|
|
216096
216108
|
taskIds.push(m2 ? `${m2[1]}-${m2[2]}` : id.toUpperCase());
|
|
216097
|
-
continue;
|
|
216098
216109
|
}
|
|
216099
216110
|
}
|
|
216100
|
-
return {
|
|
216101
|
-
taskIds: [...new Set(taskIds)],
|
|
216102
|
-
prNumbers: [...new Set(prNumbers.filter((n) => Number.isFinite(n) && n > 0))]
|
|
216103
|
-
};
|
|
216111
|
+
return { taskIds: [...new Set(taskIds)] };
|
|
216104
216112
|
}
|
|
216105
|
-
function
|
|
216106
|
-
const
|
|
216107
|
-
|
|
216108
|
-
const n = Number(match[1]);
|
|
216109
|
-
if (Number.isFinite(n) && n > 0) found.push(n);
|
|
216110
|
-
}
|
|
216111
|
-
return [...new Set(found)];
|
|
216112
|
-
}
|
|
216113
|
-
function isFileClaimBlockedReason(reason) {
|
|
216114
|
-
return CLAIM_REASON_RE.test(reason);
|
|
216115
|
-
}
|
|
216116
|
-
function classifyBlockedExit(reason, blockedBy = []) {
|
|
216117
|
-
const trimmed = reason.trim();
|
|
216118
|
-
const partitioned = partitionBlockedByRefs(blockedBy);
|
|
216119
|
-
const prFromText = extractPrNumbersFromText(trimmed);
|
|
216120
|
-
const prNumbers = [.../* @__PURE__ */ new Set([...partitioned.prNumbers, ...prFromText])];
|
|
216121
|
-
const isClaim = isFileClaimBlockedReason(trimmed) || prNumbers.length > 0 && /claim/i.test(trimmed);
|
|
216122
|
-
if (isClaim || prNumbers.length > 0 && isFileClaimBlockedReason(trimmed)) {
|
|
216123
|
-
const externalBlockers = [
|
|
216124
|
-
...prNumbers.map((number4) => ({ kind: "github-pr", number: number4 }))
|
|
216125
|
-
];
|
|
216126
|
-
if (externalBlockers.length === 0 && isClaim) {
|
|
216127
|
-
externalBlockers.push({
|
|
216128
|
-
kind: "file-claim",
|
|
216129
|
-
prNumber: prNumbers[0]
|
|
216130
|
-
});
|
|
216131
|
-
} else if (isClaim) {
|
|
216132
|
-
for (const n of prNumbers) {
|
|
216133
|
-
if (!externalBlockers.some((b3) => b3.kind === "github-pr" && b3.number === n)) {
|
|
216134
|
-
externalBlockers.push({ kind: "github-pr", number: n });
|
|
216135
|
-
}
|
|
216136
|
-
}
|
|
216137
|
-
if (prNumbers.length === 0) {
|
|
216138
|
-
externalBlockers.push({ kind: "file-claim" });
|
|
216139
|
-
}
|
|
216140
|
-
}
|
|
216141
|
-
const thrashSignature = [
|
|
216142
|
-
"file-claim",
|
|
216143
|
-
...prNumbers.map((n) => `pr:${n}`).sort(),
|
|
216144
|
-
...partitioned.taskIds.slice().sort()
|
|
216145
|
-
].join("|");
|
|
216146
|
-
return {
|
|
216147
|
-
allowAutoReplan: false,
|
|
216148
|
-
class: "file-claim",
|
|
216149
|
-
externalBlockers,
|
|
216150
|
-
thrashSignature: thrashSignature || "file-claim",
|
|
216151
|
-
prNumbers
|
|
216152
|
-
};
|
|
216153
|
-
}
|
|
216154
|
-
if (partitioned.taskIds.length > 0) {
|
|
216113
|
+
function classifyBlockedExit(_reason, blockedBy = []) {
|
|
216114
|
+
const { taskIds } = partitionBlockedByRefs(blockedBy);
|
|
216115
|
+
if (taskIds.length > 0) {
|
|
216155
216116
|
return {
|
|
216156
216117
|
allowAutoReplan: false,
|
|
216157
216118
|
class: "external",
|
|
216158
|
-
|
|
216159
|
-
thrashSignature: `tasks:${partitioned.taskIds.slice().sort().join(",")}`,
|
|
216160
|
-
prNumbers
|
|
216161
|
-
};
|
|
216162
|
-
}
|
|
216163
|
-
if (prNumbers.length > 0) {
|
|
216164
|
-
return {
|
|
216165
|
-
allowAutoReplan: false,
|
|
216166
|
-
class: "external",
|
|
216167
|
-
externalBlockers: prNumbers.map((number4) => ({ kind: "github-pr", number: number4 })),
|
|
216168
|
-
thrashSignature: prNumbers.map((n) => `pr:${n}`).sort().join("|"),
|
|
216169
|
-
prNumbers
|
|
216119
|
+
thrashSignature: `tasks:${taskIds.slice().sort().join(",")}`
|
|
216170
216120
|
};
|
|
216171
216121
|
}
|
|
216172
216122
|
return {
|
|
216173
216123
|
allowAutoReplan: true,
|
|
216174
216124
|
class: "plan-defect",
|
|
216175
|
-
|
|
216176
|
-
thrashSignature: "plan-defect",
|
|
216177
|
-
prNumbers: []
|
|
216125
|
+
thrashSignature: "plan-defect"
|
|
216178
216126
|
};
|
|
216179
216127
|
}
|
|
216180
216128
|
function countBlockedThrashHits(log41, signature, nowMs = Date.now(), windowMs = BLOCKED_THRASH_WINDOW_MS) {
|
|
216181
216129
|
if (!log41?.length) return 0;
|
|
216130
|
+
if (signature === "plan-defect") return 0;
|
|
216182
216131
|
const cutoff = nowMs - windowMs;
|
|
216183
216132
|
let count2 = 0;
|
|
216184
216133
|
for (const entry of log41) {
|
|
@@ -216190,18 +216139,7 @@ function countBlockedThrashHits(log41, signature, nowMs = Date.now(), windowMs =
|
|
|
216190
216139
|
continue;
|
|
216191
216140
|
}
|
|
216192
216141
|
}
|
|
216193
|
-
if (signature === "plan-defect") continue;
|
|
216194
|
-
if (signature.includes("file-claim") || signature.startsWith("pr:") || signature.includes("|pr:")) {
|
|
216195
|
-
if (isFileClaimBlockedReason(action) || /PR\s*#?\s*\d+/i.test(action) || action.includes("durable external block")) {
|
|
216196
|
-
count2 += 1;
|
|
216197
|
-
continue;
|
|
216198
|
-
}
|
|
216199
|
-
}
|
|
216200
216142
|
for (const part of signature.split("|")) {
|
|
216201
|
-
if (part.startsWith("pr:") && action.includes(`PR #${part.slice(3)}`)) {
|
|
216202
|
-
count2 += 1;
|
|
216203
|
-
break;
|
|
216204
|
-
}
|
|
216205
216143
|
if (part.startsWith("tasks:") && part.slice(6).split(",").some((id) => id && action.includes(id))) {
|
|
216206
216144
|
count2 += 1;
|
|
216207
216145
|
break;
|
|
@@ -216210,38 +216148,26 @@ function countBlockedThrashHits(log41, signature, nowMs = Date.now(), windowMs =
|
|
|
216210
216148
|
}
|
|
216211
216149
|
return count2;
|
|
216212
216150
|
}
|
|
216213
|
-
function isDurableBlockedError(error3) {
|
|
216214
|
-
if (!error3?.startsWith("BLOCKED:")) return false;
|
|
216215
|
-
const reason = error3.slice("BLOCKED:".length).trim();
|
|
216216
|
-
const classification = classifyBlockedExit(reason, []);
|
|
216217
|
-
return !classification.allowAutoReplan;
|
|
216218
|
-
}
|
|
216219
216151
|
function isDurableBlockedTask(task) {
|
|
216220
|
-
if (task.status === "failed" && isDurableBlockedError(task.error)) return true;
|
|
216221
216152
|
const meta2 = task.sourceMetadata;
|
|
216222
216153
|
if (!meta2 || typeof meta2 !== "object") return false;
|
|
216223
|
-
if (meta2.blockedClass
|
|
216224
|
-
|
|
216225
|
-
}
|
|
216226
|
-
const blockers = meta2.externalBlockers;
|
|
216227
|
-
return Array.isArray(blockers) && blockers.length > 0 && task.status === "failed";
|
|
216154
|
+
if (meta2.blockedClass !== "external") return false;
|
|
216155
|
+
return task.status === "failed" || task.status === "needs-replan";
|
|
216228
216156
|
}
|
|
216229
216157
|
function buildExternalBlockMetadataPatch(classification, thrashCount) {
|
|
216230
216158
|
return {
|
|
216231
216159
|
blockedClass: classification.class,
|
|
216232
216160
|
blockedThrashSignature: classification.thrashSignature,
|
|
216233
216161
|
blockedThrashCount: thrashCount,
|
|
216234
|
-
externalBlockers:
|
|
216162
|
+
externalBlockers: []
|
|
216235
216163
|
};
|
|
216236
216164
|
}
|
|
216237
|
-
var TASK_ID_RE,
|
|
216165
|
+
var TASK_ID_RE, LEGACY_PR_REF_RE, BLOCKED_THRASH_LIMIT, BLOCKED_THRASH_WINDOW_MS;
|
|
216238
216166
|
var init_execution_block_classifier = __esm({
|
|
216239
216167
|
"../engine/src/execution-block-classifier.ts"() {
|
|
216240
216168
|
"use strict";
|
|
216241
216169
|
TASK_ID_RE = /^[A-Z][A-Z0-9]*-\d+$/i;
|
|
216242
|
-
|
|
216243
|
-
PR_IN_TEXT_RE = /\bPR\s*#?\s*(\d+)\b/gi;
|
|
216244
|
-
CLAIM_REASON_RE = /check-file-claimed|actively claimed|file[- ]claim|claimed by (?:open )?pr|open pr\s*#?\s*\d+|collision policy|claimed paths?|file claims?/i;
|
|
216170
|
+
LEGACY_PR_REF_RE = /^(?:pr[:#-]|#|PR-)(\d+)$/i;
|
|
216245
216171
|
BLOCKED_THRASH_LIMIT = 3;
|
|
216246
216172
|
BLOCKED_THRASH_WINDOW_MS = 60 * 60 * 1e3;
|
|
216247
216173
|
}
|
|
@@ -219059,7 +218985,7 @@ var init_workflow_completion_summary = __esm({
|
|
|
219059
218985
|
|
|
219060
218986
|
// ../engine/src/review-checkout.ts
|
|
219061
218987
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
219062
|
-
import { existsSync as
|
|
218988
|
+
import { existsSync as existsSync61, realpathSync as realpathSync9, statSync as statSync11 } from "node:fs";
|
|
219063
218989
|
import { isAbsolute as isAbsolute15 } from "node:path";
|
|
219064
218990
|
function readMetadataPath(value) {
|
|
219065
218991
|
if (!value || typeof value !== "object") return void 0;
|
|
@@ -219083,7 +219009,7 @@ function resolveReviewCheckoutCwd(task, fallbackCwd) {
|
|
|
219083
219009
|
const candidate = getTaskReviewCheckoutPath(task);
|
|
219084
219010
|
if (!candidate || !isAbsolute15(candidate)) return fallbackCwd;
|
|
219085
219011
|
try {
|
|
219086
|
-
if (!
|
|
219012
|
+
if (!existsSync61(candidate) || !statSync11(candidate).isDirectory()) return fallbackCwd;
|
|
219087
219013
|
const realCandidate = realpathSync9(candidate);
|
|
219088
219014
|
const topLevel = execFileSync3("git", ["rev-parse", "--show-toplevel"], {
|
|
219089
219015
|
cwd: realCandidate,
|
|
@@ -221689,7 +221615,7 @@ var init_external_integration_evidence = __esm({
|
|
|
221689
221615
|
|
|
221690
221616
|
// ../engine/src/step-runner.ts
|
|
221691
221617
|
import { exec as exec35 } from "node:child_process";
|
|
221692
|
-
import { existsSync as
|
|
221618
|
+
import { existsSync as existsSync63, statSync as statSync12 } from "node:fs";
|
|
221693
221619
|
import { promisify as promisify50 } from "node:util";
|
|
221694
221620
|
async function runTaskStep(deps, task, stepIndex, opts = {}) {
|
|
221695
221621
|
const { store, worktreePath } = deps;
|
|
@@ -221843,7 +221769,7 @@ function makeAncestryBlastRadiusGuard(opts) {
|
|
|
221843
221769
|
function isUsableWorktreeDirectory(candidate) {
|
|
221844
221770
|
if (!candidate) return false;
|
|
221845
221771
|
try {
|
|
221846
|
-
return
|
|
221772
|
+
return existsSync63(candidate) && statSync12(candidate).isDirectory();
|
|
221847
221773
|
} catch {
|
|
221848
221774
|
return false;
|
|
221849
221775
|
}
|
|
@@ -221880,7 +221806,7 @@ var init_step_runner = __esm({
|
|
|
221880
221806
|
|
|
221881
221807
|
// ../engine/src/auto-recovery-handlers/branch-worktree.ts
|
|
221882
221808
|
import { exec as exec36 } from "node:child_process";
|
|
221883
|
-
import { existsSync as
|
|
221809
|
+
import { existsSync as existsSync64 } from "node:fs";
|
|
221884
221810
|
import { promisify as promisify51 } from "node:util";
|
|
221885
221811
|
var execAsync33, baseLog2, GIT_TIMEOUT_MS8, GIT_MAX_BUFFER6, BranchWorktreeAutoRecoveryHandler;
|
|
221886
221812
|
var init_branch_worktree = __esm({
|
|
@@ -222071,7 +221997,7 @@ var init_branch_worktree = __esm({
|
|
|
222071
221997
|
if (inspection.kind === "stale-resolved" || inspection.kind === "fully-subsumed" || inspection.kind === "tip-already-merged") {
|
|
222072
221998
|
await this.requeueAfterRecovery(ctx.task, failure, inspection.kind, {
|
|
222073
221999
|
branchExists: await this.hasBranchRef(repoDir, branchName),
|
|
222074
|
-
worktreePresent:
|
|
222000
|
+
worktreePresent: existsSync64(conflictingWorktreePath),
|
|
222075
222001
|
tipSha: "tipSha" in inspection ? inspection.tipSha : void 0,
|
|
222076
222002
|
inspectionKind: inspection.kind
|
|
222077
222003
|
});
|
|
@@ -222141,7 +222067,7 @@ var init_branch_worktree = __esm({
|
|
|
222141
222067
|
let branchDeleted = false;
|
|
222142
222068
|
let worktreeRemoved = false;
|
|
222143
222069
|
if (!isLiveOwned) {
|
|
222144
|
-
if (
|
|
222070
|
+
if (existsSync64(conflictingWorktreePath)) {
|
|
222145
222071
|
try {
|
|
222146
222072
|
await execAsync33(`git worktree remove --force ${this.quote(conflictingWorktreePath)}`, {
|
|
222147
222073
|
cwd: repoDir,
|
|
@@ -222189,7 +222115,7 @@ var init_branch_worktree = __esm({
|
|
|
222189
222115
|
});
|
|
222190
222116
|
await this.requeueAfterRecovery(ctx.task, failure, "live-foreign-discard-and-recreate", {
|
|
222191
222117
|
branchExists: !branchDeleted,
|
|
222192
|
-
worktreePresent: !worktreeRemoved &&
|
|
222118
|
+
worktreePresent: !worktreeRemoved && existsSync64(conflictingWorktreePath),
|
|
222193
222119
|
tipSha: tipSha2,
|
|
222194
222120
|
inspectionKind: inspection.kind
|
|
222195
222121
|
});
|
|
@@ -222202,7 +222128,7 @@ var init_branch_worktree = __esm({
|
|
|
222202
222128
|
conflictingWorktreePath,
|
|
222203
222129
|
inspectionKind: inspection.kind,
|
|
222204
222130
|
branchExists,
|
|
222205
|
-
worktreePresent:
|
|
222131
|
+
worktreePresent: existsSync64(conflictingWorktreePath),
|
|
222206
222132
|
tipSha
|
|
222207
222133
|
});
|
|
222208
222134
|
}
|
|
@@ -222363,7 +222289,7 @@ var init_file_scope2 = __esm({
|
|
|
222363
222289
|
});
|
|
222364
222290
|
|
|
222365
222291
|
// ../engine/src/run-verification-tool.ts
|
|
222366
|
-
import { existsSync as
|
|
222292
|
+
import { existsSync as existsSync65, readdirSync as readdirSync11, readFileSync as readFileSync23 } from "node:fs";
|
|
222367
222293
|
import { isAbsolute as isAbsolute16, join as join77, relative as relative14 } from "node:path";
|
|
222368
222294
|
import { Type as Type6 } from "@earendil-works/pi-ai";
|
|
222369
222295
|
function shellSplit(input) {
|
|
@@ -222923,7 +222849,7 @@ function createRunVerificationTool(opts) {
|
|
|
222923
222849
|
}
|
|
222924
222850
|
if (effectiveCommand.trimStart().startsWith("pnpm --filter")) {
|
|
222925
222851
|
const modulesYaml = join77(rootDir, "node_modules", ".modules.yaml");
|
|
222926
|
-
if (!
|
|
222852
|
+
if (!existsSync65(modulesYaml)) {
|
|
222927
222853
|
const installCmd = "pnpm install --prefer-offline";
|
|
222928
222854
|
const msg = `node_modules/.modules.yaml not found in workspace root \u2014 auto-prepending \`${installCmd}\` before running the command.`;
|
|
222929
222855
|
warnings.push(msg);
|
|
@@ -223284,7 +223210,7 @@ import { exec as exec39, execFile as execFile26, execSync as execSync7 } from "n
|
|
|
223284
223210
|
import { promisify as promisify54 } from "node:util";
|
|
223285
223211
|
import { setImmediate as setImmediateCb3 } from "node:timers";
|
|
223286
223212
|
import { basename as basename19, delimiter as delimiter2, isAbsolute as isAbsolute18, join as join78, relative as relative16, resolve as resolvePath3 } from "node:path";
|
|
223287
|
-
import { existsSync as
|
|
223213
|
+
import { existsSync as existsSync66, lstatSync as lstatSync3, realpathSync as realpathSync10 } from "node:fs";
|
|
223288
223214
|
import { readFile as readFile40, rm as rm12, writeFile as writeFile29 } from "node:fs/promises";
|
|
223289
223215
|
import { Type as Type7 } from "@earendil-works/pi-ai";
|
|
223290
223216
|
import { SessionManager as SessionManager2 } from "@earendil-works/pi-coding-agent";
|
|
@@ -223302,7 +223228,7 @@ function isWorkflowStepSkillDiscoverable(skillName, additionalSkillPaths, ceSkil
|
|
|
223302
223228
|
return false;
|
|
223303
223229
|
}
|
|
223304
223230
|
return (additionalSkillPaths ?? []).some(
|
|
223305
|
-
(skillPath) => basename19(skillPath) === bareSkillName &&
|
|
223231
|
+
(skillPath) => basename19(skillPath) === bareSkillName && existsSync66(join78(skillPath, "SKILL.md")) || existsSync66(join78(skillPath, bareSkillName, "SKILL.md"))
|
|
223306
223232
|
);
|
|
223307
223233
|
}
|
|
223308
223234
|
function getPromptSection(prompt, heading) {
|
|
@@ -224275,7 +224201,7 @@ If you have just finished a step's work, immediately call \`fn_task_update\` to
|
|
|
224275
224201
|
|
|
224276
224202
|
The user is not watching this conversation in real-time. They will read the final result. Asking permission wastes a full retry cycle and may orphan committed work.
|
|
224277
224203
|
|
|
224278
|
-
**Cannot proceed \u2014 the honest blocked exit.** If the work genuinely cannot be finished (an upstream API break, a missing prerequisite task, an unresolvable external error
|
|
224204
|
+
**Cannot proceed \u2014 the honest blocked exit.** If the work genuinely cannot be finished (an upstream API break, a missing prerequisite task, or an unresolvable external error), call \`fn_task_done(outcome="blocked", reason="<concrete blocker + what would unblock it>", blockedBy=["FN-XXXX"])\`. That parks durable failed WITHOUT auto-replan so the engine does not thrash; task IDs requeue when those tasks complete. Blockers must be Fusion board tasks \u2014 do NOT treat open GitHub PRs touching the same files as blockers; other PRs are not claims on your file scope. Do NOT skip remaining steps to fake completion.
|
|
224279
224205
|
This is THE correct action when you are stuck \u2014 do NOT instead mark the remaining steps \`skipped\` and call \`fn_task_done\` to make the task look finished. Skipping steps to escape a blocker launders a failure into \`done\` and is never the right move. (\`skipped\` remains valid only for the stale-premise path below, when the requested work is already present on HEAD.) Never write the blocker as plain prose.
|
|
224280
224206
|
|
|
224281
224207
|
## How to work
|
|
@@ -226864,7 +226790,7 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
226864
226790
|
);
|
|
226865
226791
|
return false;
|
|
226866
226792
|
}
|
|
226867
|
-
if (task.worktree &&
|
|
226793
|
+
if (task.worktree && existsSync66(task.worktree)) {
|
|
226868
226794
|
const modifiedFiles = await this.captureModifiedFiles(task.worktree, task.baseCommitSha, task.id, void 0, "recovery");
|
|
226869
226795
|
if (modifiedFiles.length > 0) {
|
|
226870
226796
|
await this.store.updateTask(task.id, { modifiedFiles });
|
|
@@ -229826,7 +229752,7 @@ ${info.feedback}`, revisionKey),
|
|
|
229826
229752
|
if (live.firstExecutionAt || live.executionStartedAt) return false;
|
|
229827
229753
|
if (activeSessionRegistry.isPathActive(live.worktree) || activeSessionRegistry.isPathActive(resolvePath3(live.worktree))) return false;
|
|
229828
229754
|
if (this.hasLiveTaskSessionSurface(taskId) || executingTaskLock.has(taskId)) return false;
|
|
229829
|
-
if (
|
|
229755
|
+
if (existsSync66(live.worktree)) {
|
|
229830
229756
|
if (await this.preExecutionWorktreeHasWork(live.worktree)) {
|
|
229831
229757
|
executorLog.log(`${taskId}: keeping pre-execution worktree ${live.worktree} \u2014 it carries commits or uncommitted changes`);
|
|
229832
229758
|
return false;
|
|
@@ -229868,7 +229794,7 @@ ${info.feedback}`, revisionKey),
|
|
|
229868
229794
|
}
|
|
229869
229795
|
if (this.workspaceConfig && (this.workspaceConfig.repos.length ?? 0) > 0) return null;
|
|
229870
229796
|
const live = await this.store.getTask(taskId);
|
|
229871
|
-
if (live.worktree &&
|
|
229797
|
+
if (live.worktree && existsSync66(live.worktree)) return live.worktree;
|
|
229872
229798
|
const settings = await this.store.getSettings();
|
|
229873
229799
|
const acquisitionTask = live.worktree ? { ...live, worktree: void 0, sessionFile: void 0 } : live;
|
|
229874
229800
|
const acquired = await this.ensureGraphCustomNodeWorktree(acquisitionTask, settings, "planning");
|
|
@@ -229882,8 +229808,8 @@ ${info.feedback}`, revisionKey),
|
|
|
229882
229808
|
if (!requirement.requiresWorktree) return;
|
|
229883
229809
|
const live = await this.store.getTask(nodeTask.id);
|
|
229884
229810
|
const executionCodeNode = node.kind === "code";
|
|
229885
|
-
if (live.worktree &&
|
|
229886
|
-
const taskForAcquisition = live.worktree && !
|
|
229811
|
+
if (live.worktree && existsSync66(live.worktree) && !executionCodeNode) return;
|
|
229812
|
+
const taskForAcquisition = live.worktree && !existsSync66(live.worktree) ? { ...live, worktree: void 0, sessionFile: void 0 } : live;
|
|
229887
229813
|
if (live.worktree) {
|
|
229888
229814
|
await this.store.logEntry(
|
|
229889
229815
|
live.id,
|
|
@@ -230009,7 +229935,7 @@ ${info.feedback}`, revisionKey),
|
|
|
230009
229935
|
const nodeDisplayName = typeof cfg.name === "string" && cfg.name.trim() ? cfg.name.trim() : node.id;
|
|
230010
229936
|
const isPlanReviewNode = node.id === "plan-review-step" || nodeDisplayName === "Plan Review" || optionalGroupId === "plan-review";
|
|
230011
229937
|
if (!this.workspaceConfig) {
|
|
230012
|
-
const recordedWorktreeMissing = Boolean(executionTarget.worktree) && !
|
|
229938
|
+
const recordedWorktreeMissing = Boolean(executionTarget.worktree) && !existsSync66(executionTarget.worktree);
|
|
230013
229939
|
const shouldAcquire = !executionTarget.worktree || recordedWorktreeMissing && isPlanReviewNode;
|
|
230014
229940
|
if (shouldAcquire) {
|
|
230015
229941
|
if (recordedWorktreeMissing) {
|
|
@@ -231683,75 +231609,16 @@ Graph value: ${failureValue}` : ""}`, budget.key),
|
|
|
231683
231609
|
);
|
|
231684
231610
|
}
|
|
231685
231611
|
}
|
|
231686
|
-
/*
|
|
231687
|
-
FNXC:HonestBlockedExit 2026-08-02-01:30:
|
|
231688
|
-
Agents often log `BLOCKED: … actively claimed by PR #N` without calling fn_task_done.
|
|
231689
|
-
Without promotion, incomplete-step graph resume requeues the card and thrash restarts
|
|
231690
|
-
(FN-8700). Promote claim/external blocks to a durable failed park here.
|
|
231691
|
-
*/
|
|
231692
|
-
async parkDurableBlockedFromRecentLog(live) {
|
|
231693
|
-
const recent = [...live.log ?? []].reverse().find((entry) => {
|
|
231694
|
-
const action = entry.action ?? "";
|
|
231695
|
-
return action.startsWith("BLOCKED:") || action.includes("durable external block");
|
|
231696
|
-
});
|
|
231697
|
-
if (!recent?.action) return false;
|
|
231698
|
-
const reason = recent.action.startsWith("BLOCKED:") ? recent.action.slice("BLOCKED:".length).trim() : recent.action;
|
|
231699
|
-
const classification = classifyBlockedExit(reason, []);
|
|
231700
|
-
if (classification.allowAutoReplan) return false;
|
|
231701
|
-
const thrashCount = countBlockedThrashHits(live.log, classification.thrashSignature) + 1;
|
|
231702
|
-
const thrashExhausted = thrashCount >= BLOCKED_THRASH_LIMIT;
|
|
231703
|
-
const parkError = thrashExhausted ? `BLOCKED: ${reason} [thrash-exhausted after ${thrashCount} identical durable blocks]` : `BLOCKED: ${reason}`;
|
|
231704
|
-
const metaPatch = buildExternalBlockMetadataPatch(classification, thrashCount);
|
|
231705
|
-
await this.store.updateTask(live.id, {
|
|
231706
|
-
status: "failed",
|
|
231707
|
-
error: parkError,
|
|
231708
|
-
paused: false,
|
|
231709
|
-
pausedByAgentId: null,
|
|
231710
|
-
sourceMetadataPatch: metaPatch
|
|
231711
|
-
}, this.getRunContextFor(live.id));
|
|
231712
|
-
await this.store.logEntry(
|
|
231713
|
-
live.id,
|
|
231714
|
-
thrashExhausted ? `${parkError} \u2014 promoted from session log; thrash-exhausted, no auto-requeue` : `${parkError} \u2014 promoted from session log to durable external block park (class=${classification.class})`,
|
|
231715
|
-
void 0,
|
|
231716
|
-
this.getRunContextFor(live.id)
|
|
231717
|
-
);
|
|
231718
|
-
await this.store.recordRunAuditEvent?.({
|
|
231719
|
-
taskId: live.id,
|
|
231720
|
-
agentId: "executor",
|
|
231721
|
-
runId: generateSyntheticRunId("execution-blocked-log-promote", live.id),
|
|
231722
|
-
domain: "database",
|
|
231723
|
-
mutationType: "task:execution-blocked-parked",
|
|
231724
|
-
target: live.id,
|
|
231725
|
-
metadata: {
|
|
231726
|
-
taskId: live.id,
|
|
231727
|
-
blockedBy: [],
|
|
231728
|
-
hasReason: true,
|
|
231729
|
-
parkedAs: "failed",
|
|
231730
|
-
blockedClass: classification.class,
|
|
231731
|
-
thrashCount,
|
|
231732
|
-
thrashExhausted,
|
|
231733
|
-
prNumbers: classification.prNumbers,
|
|
231734
|
-
source: "session-log-promote"
|
|
231735
|
-
}
|
|
231736
|
-
});
|
|
231737
|
-
executorLog.warn(
|
|
231738
|
-
`${live.id}: promoted durable BLOCKED from session log (class=${classification.class}; thrash=${thrashCount})`
|
|
231739
|
-
);
|
|
231740
|
-
return true;
|
|
231741
|
-
}
|
|
231742
231612
|
async routeGraphFailureToExecutionResume(live, failedNode, failureValue, resumeLanesMemo) {
|
|
231743
231613
|
if (live.deletedAt) return false;
|
|
231744
231614
|
if (live.paused || live.userPaused === true) return false;
|
|
231745
231615
|
if ((await resolveTerminalColumnsFor(this.store, live.id)).includes(live.column)) return false;
|
|
231746
|
-
if (isDurableBlockedTask(live)
|
|
231616
|
+
if (isDurableBlockedTask(live)) {
|
|
231747
231617
|
executorLog.log(
|
|
231748
|
-
`${live.id}: graph failure resume skipped \u2014 durable BLOCKED park honored (
|
|
231618
|
+
`${live.id}: graph failure resume skipped \u2014 durable BLOCKED park honored (task-dependency block)`
|
|
231749
231619
|
);
|
|
231750
231620
|
return false;
|
|
231751
231621
|
}
|
|
231752
|
-
if (await this.parkDurableBlockedFromRecentLog(live)) {
|
|
231753
|
-
return false;
|
|
231754
|
-
}
|
|
231755
231622
|
if (failedNode === COMPLETION_SUMMARY_NODE_ID) return false;
|
|
231756
231623
|
const incompleteSteps = hasNonTerminalWorkflowSteps(live);
|
|
231757
231624
|
const implementationIncompleteMergeFailure = this.isMergeGraphFailure(failedNode) && failureValue === "implementation-incomplete";
|
|
@@ -232932,7 +232799,7 @@ ${summary}`,
|
|
|
232932
232799
|
executorLog.warn(`\u26A1 ${task.id} transient error \u2014 retry ${attempt}/${MAX_RECOVERY_RETRIES} in ${delay6}: ${errorMessage2}`);
|
|
232933
232800
|
await this.store.logEntry(task.id, `Transient error (retry ${attempt}/${MAX_RECOVERY_RETRIES} in ${delay6}): ${errorMessage2}`, void 0, this.getRunContextFor(task.id));
|
|
232934
232801
|
}
|
|
232935
|
-
if (worktreePath &&
|
|
232802
|
+
if (worktreePath && existsSync66(worktreePath)) {
|
|
232936
232803
|
try {
|
|
232937
232804
|
const settings2 = await this.store.getSettings();
|
|
232938
232805
|
await removeWorktree({
|
|
@@ -233013,7 +232880,7 @@ ${summary}`,
|
|
|
233013
232880
|
const settings2 = await this.store.getSettings();
|
|
233014
232881
|
const preserveProgress = settings2.preserveProgressOnStuckRequeue !== false;
|
|
233015
232882
|
await this.resetStepsIfWorkLost(latestTask);
|
|
233016
|
-
if (worktreePath &&
|
|
232883
|
+
if (worktreePath && existsSync66(worktreePath)) {
|
|
233017
232884
|
try {
|
|
233018
232885
|
await removeWorktree({
|
|
233019
232886
|
worktreePath,
|
|
@@ -233296,7 +233163,7 @@ ${summary}`,
|
|
|
233296
233163
|
nodeId: detail.effectiveNodeId ?? detail.nodeId ?? null,
|
|
233297
233164
|
agentId: engineRunContext.agentId ?? null
|
|
233298
233165
|
});
|
|
233299
|
-
let isResuming = !!task.sessionFile &&
|
|
233166
|
+
let isResuming = !!task.sessionFile && existsSync66(task.sessionFile);
|
|
233300
233167
|
if (isResuming) {
|
|
233301
233168
|
const persistedWorktreePath = await extractPersistedSessionWorktreePath(task.sessionFile, this.rootDir, settings);
|
|
233302
233169
|
if (!isSessionWorktreeCompatible(persistedWorktreePath, worktreePath)) {
|
|
@@ -234077,7 +233944,7 @@ ${summary}`,
|
|
|
234077
233944
|
return;
|
|
234078
233945
|
} else {
|
|
234079
233946
|
executorLog.log(`${task.id} paused \u2014 moving to todo`);
|
|
234080
|
-
if (worktreePath &&
|
|
233947
|
+
if (worktreePath && existsSync66(worktreePath)) {
|
|
234081
233948
|
try {
|
|
234082
233949
|
const settings2 = await this.store.getSettings();
|
|
234083
233950
|
await removeWorktree({
|
|
@@ -234474,7 +234341,7 @@ ${summary}`,
|
|
|
234474
234341
|
executorLog.warn(`\u26A1 ${task.id} transient error \u2014 retry ${attempt}/${MAX_RECOVERY_RETRIES} in ${delay6}: ${errorMessage2}`);
|
|
234475
234342
|
await this.store.logEntry(task.id, `Transient error (retry ${attempt}/${MAX_RECOVERY_RETRIES} in ${delay6}): ${errorMessage2}`, void 0, this.getRunContextFor(task.id));
|
|
234476
234343
|
}
|
|
234477
|
-
if (worktreePath &&
|
|
234344
|
+
if (worktreePath && existsSync66(worktreePath)) {
|
|
234478
234345
|
try {
|
|
234479
234346
|
const settings2 = await this.store.getSettings();
|
|
234480
234347
|
await removeWorktree({
|
|
@@ -234610,7 +234477,7 @@ ${summary}`,
|
|
|
234610
234477
|
const settings2 = await this.store.getSettings();
|
|
234611
234478
|
const preserveProgress = settings2.preserveProgressOnStuckRequeue !== false;
|
|
234612
234479
|
await this.resetStepsIfWorkLost(latestTask);
|
|
234613
|
-
if (worktreePath &&
|
|
234480
|
+
if (worktreePath && existsSync66(worktreePath)) {
|
|
234614
234481
|
try {
|
|
234615
234482
|
await removeWorktree({
|
|
234616
234483
|
worktreePath,
|
|
@@ -235037,7 +234904,7 @@ ${summary}`,
|
|
|
235037
234904
|
for (const repoRel of Object.keys(workspaceWorktrees).sort()) {
|
|
235038
234905
|
const repo = workspaceWorktrees[repoRel];
|
|
235039
234906
|
const expectedBranch = repo.branch || canonicalFusionBranchName(task.id);
|
|
235040
|
-
if (!
|
|
234907
|
+
if (!existsSync66(repo.worktreePath)) {
|
|
235041
234908
|
executorLog.log(`${task.id}: workspace worktree for ${repoRel} not found at ${repo.worktreePath} \u2014 skipping git validation`);
|
|
235042
234909
|
continue;
|
|
235043
234910
|
}
|
|
@@ -235169,7 +235036,7 @@ ${summary}`,
|
|
|
235169
235036
|
expected: `resolvable task worktree under ${resolveWorktreesDir(this.rootDir, settings)}/*`
|
|
235170
235037
|
};
|
|
235171
235038
|
}
|
|
235172
|
-
if (!
|
|
235039
|
+
if (!existsSync66(worktreePath)) {
|
|
235173
235040
|
executorLog.log(
|
|
235174
235041
|
`${task.id}: worktree directory not found at ${worktreePath} \u2014 skipping git validation for task completion`
|
|
235175
235042
|
);
|
|
@@ -235498,10 +235365,10 @@ ${summary}`,
|
|
|
235498
235365
|
{ description: '"completed" (default) finishes the task; "blocked" honestly parks it as failed because the work cannot proceed. Use "blocked" instead of skipping steps + completing when you are stuck.' }
|
|
235499
235366
|
)),
|
|
235500
235367
|
blockedBy: Type7.Optional(Type7.Array(Type7.String(), {
|
|
235501
|
-
description: 'When outcome="blocked": task IDs (e.g. ["FN-8145"])
|
|
235368
|
+
description: 'When outcome="blocked": Fusion task IDs (e.g. ["FN-8145"]) that must complete before this task can proceed. Task IDs become real dependency edges. Open GitHub PRs are not valid blockers.'
|
|
235502
235369
|
})),
|
|
235503
235370
|
reason: Type7.Optional(Type7.String({
|
|
235504
|
-
description: 'Required when outcome="blocked": concrete explanation of what is blocking the work and what is needed to unblock it.
|
|
235371
|
+
description: 'Required when outcome="blocked": concrete explanation of what is blocking the work and what is needed to unblock it.'
|
|
235505
235372
|
}))
|
|
235506
235373
|
}),
|
|
235507
235374
|
execute: async (_id, params) => {
|
|
@@ -235560,7 +235427,7 @@ ${summary}`,
|
|
|
235560
235427
|
}, this.getRunContextFor(taskId));
|
|
235561
235428
|
await store.logEntry(
|
|
235562
235429
|
taskId,
|
|
235563
|
-
thrashExhausted ? `${parkError} \u2014 durable external block thrash-exhausted (signature=${classification.thrashSignature}); parked failed, no auto-requeue` :
|
|
235430
|
+
thrashExhausted ? `${parkError} \u2014 durable external block thrash-exhausted (signature=${classification.thrashSignature}); parked failed, no auto-requeue` : `${parkError} \u2014 recorded dependencies: ${blockedByIds.join(", ")} \u2014 parked failed (honest blocked exit; steps preserved)`,
|
|
235564
235431
|
void 0,
|
|
235565
235432
|
this.getRunContextFor(taskId)
|
|
235566
235433
|
);
|
|
@@ -235579,18 +235446,17 @@ ${summary}`,
|
|
|
235579
235446
|
parkedAs: autoReplanPark ? "auto-replan" : "failed",
|
|
235580
235447
|
blockedClass: classification.class,
|
|
235581
235448
|
thrashCount,
|
|
235582
|
-
thrashExhausted
|
|
235583
|
-
prNumbers: classification.prNumbers
|
|
235449
|
+
thrashExhausted
|
|
235584
235450
|
}
|
|
235585
235451
|
});
|
|
235586
235452
|
await this.persistTokenUsage(taskId);
|
|
235587
235453
|
executorLog.log(
|
|
235588
|
-
`\u26D4 ${taskId} ${autoReplanPark ? "parked for automatic replan via blocked exit (plan defect, no dependencies)" : thrashExhausted ? `parked failed via blocked thrash-exhaustion (class=${classification.class})` : `parked failed via durable blocked exit (class=${classification.class}; blockedBy tasks: ${blockedByIds.join(", ") || "none"}
|
|
235454
|
+
`\u26D4 ${taskId} ${autoReplanPark ? "parked for automatic replan via blocked exit (plan defect, no dependencies)" : thrashExhausted ? `parked failed via blocked thrash-exhaustion (class=${classification.class})` : `parked failed via durable blocked exit (class=${classification.class}; blockedBy tasks: ${blockedByIds.join(", ") || "none"})`}`
|
|
235589
235455
|
);
|
|
235590
235456
|
return {
|
|
235591
235457
|
content: [{
|
|
235592
235458
|
type: "text",
|
|
235593
|
-
text: autoReplanPark ? "Task parked as blocked with no
|
|
235459
|
+
text: autoReplanPark ? "Task parked as blocked with no blocking task dependencies \u2014 queued for automatic replan so the plan can resolve the conflict. Steps left in their true statuses; no completion recorded." : thrashExhausted ? "Task parked as blocked (failed) after repeated identical durable blocks \u2014 no further automatic retries. Resolve the blocking tasks or replan manually." : `Task parked as blocked (failed). Recorded ${blockedByIds.length} blocking task dependency(ies); it will requeue once they complete. Steps left in their true statuses; no completion recorded.`
|
|
235594
235460
|
}],
|
|
235595
235461
|
details: {}
|
|
235596
235462
|
};
|
|
@@ -237648,7 +237514,7 @@ ${detectedQuestion}
|
|
|
237648
237514
|
* rather than fail the task permanently.
|
|
237649
237515
|
*/
|
|
237650
237516
|
async resolveWorktreeStartPoint(startPoint, taskId) {
|
|
237651
|
-
const command = isAbsolute18(startPoint) &&
|
|
237517
|
+
const command = isAbsolute18(startPoint) && existsSync66(startPoint) ? `git -C "${startPoint}" rev-parse --verify HEAD^{commit}` : `git rev-parse --verify "${startPoint}^{commit}"`;
|
|
237652
237518
|
try {
|
|
237653
237519
|
const { stdout } = await execAsync36(command, { cwd: this.rootDir });
|
|
237654
237520
|
return stdout.trim() || startPoint;
|
|
@@ -237871,7 +237737,7 @@ ${detectedQuestion}
|
|
|
237871
237737
|
throw error3;
|
|
237872
237738
|
}
|
|
237873
237739
|
};
|
|
237874
|
-
if (
|
|
237740
|
+
if (existsSync66(path10)) {
|
|
237875
237741
|
const isRegistered = await this.isRegisteredWorktree(path10);
|
|
237876
237742
|
if (!isRegistered) {
|
|
237877
237743
|
await this.store.logEntry(
|
|
@@ -238487,7 +238353,7 @@ ${detectedQuestion}
|
|
|
238487
238353
|
const stillRegistered = await isRegisteredGitWorktree2(this.rootDir, worktreePath).catch(() => true);
|
|
238488
238354
|
const activeOwner2 = await this.findActiveWorktreeOwner(worktreePath, taskId).catch(() => "unknown");
|
|
238489
238355
|
let safeToRemove = isInsideWorktreesDir(this.rootDir, worktreePath, settings) && !stillRegistered && activeOwner2 === null;
|
|
238490
|
-
if (safeToRemove &&
|
|
238356
|
+
if (safeToRemove && existsSync66(worktreePath)) {
|
|
238491
238357
|
try {
|
|
238492
238358
|
if (lstatSync3(worktreePath).isSymbolicLink()) {
|
|
238493
238359
|
safeToRemove = false;
|
|
@@ -238515,7 +238381,7 @@ ${detectedQuestion}
|
|
|
238515
238381
|
const pruneMsg = pruneErr instanceof Error ? pruneErr.message : String(pruneErr);
|
|
238516
238382
|
executorLog.warn(`${taskId}: git worktree prune failed during stale-path cleanup of ${worktreePath}: ${pruneMsg}`);
|
|
238517
238383
|
}
|
|
238518
|
-
if (
|
|
238384
|
+
if (existsSync66(worktreePath)) {
|
|
238519
238385
|
try {
|
|
238520
238386
|
await rm12(worktreePath, { recursive: true, force: true });
|
|
238521
238387
|
} catch (rmErr) {
|
|
@@ -238962,7 +238828,7 @@ ${detectedQuestion}
|
|
|
238962
238828
|
this.clearPausedAborted(taskId);
|
|
238963
238829
|
await this.resetStepsIfWorkLost(latestTask);
|
|
238964
238830
|
let cleanupFailed = false;
|
|
238965
|
-
if (worktreePath &&
|
|
238831
|
+
if (worktreePath && existsSync66(worktreePath)) {
|
|
238966
238832
|
try {
|
|
238967
238833
|
await removeWorktree({
|
|
238968
238834
|
worktreePath,
|
|
@@ -243049,7 +242915,7 @@ var init_overseer_noop_finalize_veto = __esm({
|
|
|
243049
242915
|
|
|
243050
242916
|
// ../engine/src/merger-ai-worktree.ts
|
|
243051
242917
|
import { execFile as execFile27 } from "node:child_process";
|
|
243052
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
242918
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync67, mkdirSync as mkdirSync11, readdirSync as readdirSync12, readFileSync as readFileSync24, realpathSync as realpathSync11, rmSync as rmSync9, statSync as statSync13 } from "node:fs";
|
|
243053
242919
|
import { rm as rm13 } from "node:fs/promises";
|
|
243054
242920
|
import { tmpdir as tmpdir10 } from "node:os";
|
|
243055
242921
|
import { isAbsolute as isAbsolute19, join as join79, relative as relative17 } from "node:path";
|
|
@@ -243084,7 +242950,7 @@ function isBenignAbsentWorktreeError(err) {
|
|
|
243084
242950
|
}
|
|
243085
242951
|
function ensureAiMergeRootIgnored(projectRootDir, settings) {
|
|
243086
242952
|
const excludePath = join79(projectRootDir, ".git", "info", "exclude");
|
|
243087
|
-
if (!
|
|
242953
|
+
if (!existsSync67(excludePath)) return;
|
|
243088
242954
|
try {
|
|
243089
242955
|
const current = readFileSync24(excludePath, "utf-8");
|
|
243090
242956
|
const legacyAiMergeRoot = resolveLegacyAiMergeRootPath(projectRootDir);
|
|
@@ -243215,7 +243081,7 @@ async function cleanupAiMergeWorktree(input) {
|
|
|
243215
243081
|
const cleanupMetadata = { taskId, mergeRoot: canonicalRoot, requestedMergeRoot: mergeRoot };
|
|
243216
243082
|
let alreadyAbsent = false;
|
|
243217
243083
|
if (worktreeAdded) {
|
|
243218
|
-
if (!
|
|
243084
|
+
if (!existsSync67(canonicalRoot) && !existsSync67(mergeRoot)) {
|
|
243219
243085
|
alreadyAbsent = true;
|
|
243220
243086
|
await log41(`AI merge cleanup: worktree ${canonicalRoot} was already absent before git removal; treating cleanup as idempotent`);
|
|
243221
243087
|
await audit.git({ type: "merge:ai-worktree-cleanup", target: canonicalRoot, metadata: { ...cleanupMetadata, phase: "git-remove", success: true, alreadyAbsent: true, idempotent: true, code: "ENOENT" } });
|
|
@@ -249537,12 +249403,12 @@ The note must be specific (what/where/why). Prefer citing File Scope, PROMPT, a
|
|
|
249537
249403
|
});
|
|
249538
249404
|
|
|
249539
249405
|
// ../engine/src/overseer-watchdog.ts
|
|
249540
|
-
import { existsSync as
|
|
249406
|
+
import { existsSync as existsSync68, readFileSync as readFileSync25 } from "node:fs";
|
|
249541
249407
|
import { dirname as dirname34, join as join82, relative as relative18, resolve as resolve40, sep as sep11 } from "node:path";
|
|
249542
249408
|
import { homedir as homedir12 } from "node:os";
|
|
249543
249409
|
function defaultReadText(path10) {
|
|
249544
249410
|
try {
|
|
249545
|
-
if (!
|
|
249411
|
+
if (!existsSync68(path10)) return null;
|
|
249546
249412
|
return readFileSync25(path10, "utf8");
|
|
249547
249413
|
} catch {
|
|
249548
249414
|
return null;
|
|
@@ -255343,7 +255209,7 @@ var init_adapters = __esm({
|
|
|
255343
255209
|
});
|
|
255344
255210
|
|
|
255345
255211
|
// ../engine/src/cli-agent/resume-coordinator.ts
|
|
255346
|
-
import { existsSync as
|
|
255212
|
+
import { existsSync as existsSync69 } from "node:fs";
|
|
255347
255213
|
import { execFile as execFile30 } from "node:child_process";
|
|
255348
255214
|
import { promisify as promisify62 } from "node:util";
|
|
255349
255215
|
async function defaultIsWorktreeDirty(worktreePath) {
|
|
@@ -255388,7 +255254,7 @@ var init_resume_coordinator = __esm({
|
|
|
255388
255254
|
this.reattachTelemetry = opts.reattachTelemetry;
|
|
255389
255255
|
this.maxResumeAttempts = opts.maxResumeAttempts ?? DEFAULT_MAX_RESUME_ATTEMPTS;
|
|
255390
255256
|
this.resumeBackoffBaseMs = opts.resumeBackoffBaseMs ?? DEFAULT_RESUME_BACKOFF_BASE_MS;
|
|
255391
|
-
this.worktreeExists = opts.worktreeExists ?? ((p2) =>
|
|
255257
|
+
this.worktreeExists = opts.worktreeExists ?? ((p2) => existsSync69(p2));
|
|
255392
255258
|
this.isWorktreeDirty = opts.isWorktreeDirty ?? defaultIsWorktreeDirty;
|
|
255393
255259
|
this.log = opts.log ?? (() => {
|
|
255394
255260
|
});
|
|
@@ -283184,7 +283050,7 @@ var init_cli_spawn = __esm({
|
|
|
283184
283050
|
// ../../plugins/fusion-plugin-hermes-runtime/src/fusion-skill-install.ts
|
|
283185
283051
|
import {
|
|
283186
283052
|
cpSync as cpSync2,
|
|
283187
|
-
existsSync as
|
|
283053
|
+
existsSync as existsSync70,
|
|
283188
283054
|
lstatSync as lstatSync4,
|
|
283189
283055
|
mkdirSync as mkdirSync13,
|
|
283190
283056
|
readFileSync as readFileSync26,
|
|
@@ -283214,7 +283080,7 @@ function getFusionSkillSourceCandidates(moduleUrl = import.meta.url) {
|
|
|
283214
283080
|
function resolveBundledFusionSkillSource() {
|
|
283215
283081
|
const candidates = getFusionSkillSourceCandidates();
|
|
283216
283082
|
for (const candidate of candidates) {
|
|
283217
|
-
if (
|
|
283083
|
+
if (existsSync70(join87(candidate, "SKILL.md"))) return candidate;
|
|
283218
283084
|
}
|
|
283219
283085
|
return null;
|
|
283220
283086
|
}
|
|
@@ -283232,7 +283098,7 @@ function installFusionSkillIntoHermesHome(options = {}) {
|
|
|
283232
283098
|
try {
|
|
283233
283099
|
mkdirSync13(dirname36(targetDir), { recursive: true });
|
|
283234
283100
|
let replaced = false;
|
|
283235
|
-
if (
|
|
283101
|
+
if (existsSync70(targetDir) || isBrokenSymlink(targetDir)) {
|
|
283236
283102
|
const stat13 = lstatSync4(targetDir);
|
|
283237
283103
|
if (stat13.isSymbolicLink()) {
|
|
283238
283104
|
const currentTarget = safeReadlink(targetDir);
|
|
@@ -283303,14 +283169,14 @@ function safeReadlink(path10) {
|
|
|
283303
283169
|
function isBrokenSymlink(path10) {
|
|
283304
283170
|
try {
|
|
283305
283171
|
const stat13 = lstatSync4(path10);
|
|
283306
|
-
return stat13.isSymbolicLink() && !
|
|
283172
|
+
return stat13.isSymbolicLink() && !existsSync70(path10);
|
|
283307
283173
|
} catch {
|
|
283308
283174
|
return false;
|
|
283309
283175
|
}
|
|
283310
283176
|
}
|
|
283311
283177
|
function looksLikePriorFusionInstall(path10) {
|
|
283312
283178
|
const skillMd = join87(path10, "SKILL.md");
|
|
283313
|
-
if (!
|
|
283179
|
+
if (!existsSync70(skillMd)) return false;
|
|
283314
283180
|
try {
|
|
283315
283181
|
const body = readFileSync26(skillMd, "utf-8");
|
|
283316
283182
|
return /\bfusion\b/i.test(body) && /\bskill\b/i.test(body);
|
|
@@ -283321,7 +283187,7 @@ function looksLikePriorFusionInstall(path10) {
|
|
|
283321
283187
|
function looksLikeFusionSkillTarget(path10) {
|
|
283322
283188
|
if (!path10) return false;
|
|
283323
283189
|
if (basename20(path10).toLowerCase() === FUSION_SKILL_NAME) return true;
|
|
283324
|
-
return
|
|
283190
|
+
return existsSync70(join87(path10, "SKILL.md"));
|
|
283325
283191
|
}
|
|
283326
283192
|
var FUSION_SKILL_NAME;
|
|
283327
283193
|
var init_fusion_skill_install = __esm({
|
|
@@ -284677,7 +284543,7 @@ var init_provider2 = __esm({
|
|
|
284677
284543
|
});
|
|
284678
284544
|
|
|
284679
284545
|
// ../../plugins/fusion-plugin-grok-runtime/src/acp/cli-spawn.ts
|
|
284680
|
-
import { existsSync as
|
|
284546
|
+
import { existsSync as existsSync71 } from "node:fs";
|
|
284681
284547
|
import { dirname as dirname38, isAbsolute as isAbsolute22, join as join90, resolve as resolve42 } from "node:path";
|
|
284682
284548
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
284683
284549
|
function asTrimmedString(value) {
|
|
@@ -284700,7 +284566,7 @@ function bundledClaudeBridgeBinPath(pluginRoot = pluginRootDir()) {
|
|
|
284700
284566
|
}
|
|
284701
284567
|
function resolveBundledClaudeBridgeBinary(options = {}) {
|
|
284702
284568
|
const root = options.pluginRoot ?? pluginRootDir();
|
|
284703
|
-
const exists2 = options.exists ??
|
|
284569
|
+
const exists2 = options.exists ?? existsSync71;
|
|
284704
284570
|
const candidate = bundledClaudeBridgeBinPath(root);
|
|
284705
284571
|
if (!exists2(candidate)) {
|
|
284706
284572
|
return {
|
|
@@ -286049,7 +285915,7 @@ var init_mcp_forwarding = __esm({
|
|
|
286049
285915
|
// ../../plugins/fusion-plugin-grok-runtime/src/skill-loader.ts
|
|
286050
285916
|
import {
|
|
286051
285917
|
cpSync as cpSync3,
|
|
286052
|
-
existsSync as
|
|
285918
|
+
existsSync as existsSync72,
|
|
286053
285919
|
mkdirSync as mkdirSync14,
|
|
286054
285920
|
mkdtempSync as mkdtempSync3,
|
|
286055
285921
|
readdirSync as readdirSync14,
|
|
@@ -286062,7 +285928,7 @@ import { tmpdir as tmpdir15 } from "node:os";
|
|
|
286062
285928
|
import { basename as basename22, dirname as dirname40, join as join92, resolve as resolve44 } from "node:path";
|
|
286063
285929
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
286064
285930
|
function isSkillDir(dir) {
|
|
286065
|
-
return
|
|
285931
|
+
return existsSync72(join92(dir, "SKILL.md"));
|
|
286066
285932
|
}
|
|
286067
285933
|
function pushUnique(out, candidate) {
|
|
286068
285934
|
if (!candidate) return;
|
|
@@ -286126,7 +285992,7 @@ function resolveBundledFusionSkillSource2(moduleUrl = import.meta.url) {
|
|
|
286126
285992
|
function installSkillDir(sourceDir, targetDir) {
|
|
286127
285993
|
if (!isSkillDir(sourceDir)) return false;
|
|
286128
285994
|
mkdirSync14(dirname40(targetDir), { recursive: true });
|
|
286129
|
-
if (
|
|
285995
|
+
if (existsSync72(targetDir)) {
|
|
286130
285996
|
rmSync11(targetDir, { recursive: true, force: true });
|
|
286131
285997
|
}
|
|
286132
285998
|
try {
|
|
@@ -286142,7 +286008,7 @@ function installSkillDir(sourceDir, targetDir) {
|
|
|
286142
286008
|
}
|
|
286143
286009
|
}
|
|
286144
286010
|
function collectSkillsFromRoot(root, out) {
|
|
286145
|
-
if (!
|
|
286011
|
+
if (!existsSync72(root)) return;
|
|
286146
286012
|
if (isSkillDir(root)) {
|
|
286147
286013
|
out.set(basename22(root), root);
|
|
286148
286014
|
return;
|
|
@@ -286181,7 +286047,7 @@ function stageGrokSessionSkills(options = {}) {
|
|
|
286181
286047
|
installSkillDir(source, join92(skillsDir, name2));
|
|
286182
286048
|
}
|
|
286183
286049
|
for (const [name2, source] of installed) {
|
|
286184
|
-
if (!
|
|
286050
|
+
if (!existsSync72(join92(skillsDir, name2))) {
|
|
286185
286051
|
installSkillDir(source, join92(skillsDir, name2));
|
|
286186
286052
|
}
|
|
286187
286053
|
}
|
|
@@ -286250,7 +286116,7 @@ var init_skill_loader = __esm({
|
|
|
286250
286116
|
|
|
286251
286117
|
// ../../plugins/fusion-plugin-grok-runtime/src/tool-bridge.ts
|
|
286252
286118
|
import { createServer as createServer2 } from "node:http";
|
|
286253
|
-
import { existsSync as
|
|
286119
|
+
import { existsSync as existsSync73, writeFileSync as writeFileSync15 } from "node:fs";
|
|
286254
286120
|
import { tmpdir as tmpdir16 } from "node:os";
|
|
286255
286121
|
import { dirname as dirname41, join as join93 } from "node:path";
|
|
286256
286122
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
@@ -286296,7 +286162,7 @@ async function startFusionToolBridge(tools) {
|
|
|
286296
286162
|
const defs = toolsToMcpToolDefs2(tools);
|
|
286297
286163
|
if (defs.length === 0) return null;
|
|
286298
286164
|
const serverPath = fusionToolsMcpServerPath();
|
|
286299
|
-
if (!
|
|
286165
|
+
if (!existsSync73(serverPath)) {
|
|
286300
286166
|
throw missingMcpSchemaServerError(serverPath);
|
|
286301
286167
|
}
|
|
286302
286168
|
const byName = /* @__PURE__ */ new Map();
|
|
@@ -286737,7 +286603,7 @@ var init_src11 = __esm({
|
|
|
286737
286603
|
});
|
|
286738
286604
|
|
|
286739
286605
|
// ../../plugins/fusion-plugin-claude-runtime/src/acp/cli-spawn.ts
|
|
286740
|
-
import { existsSync as
|
|
286606
|
+
import { existsSync as existsSync74 } from "node:fs";
|
|
286741
286607
|
import { dirname as dirname42, isAbsolute as isAbsolute23, join as join94, resolve as resolve45 } from "node:path";
|
|
286742
286608
|
import { fileURLToPath as fileURLToPath10 } from "node:url";
|
|
286743
286609
|
function asTrimmedString2(value) {
|
|
@@ -286760,7 +286626,7 @@ function bundledClaudeBridgeBinPath2(pluginRoot = pluginRootDir2()) {
|
|
|
286760
286626
|
}
|
|
286761
286627
|
function resolveBundledClaudeBridgeBinary2(options = {}) {
|
|
286762
286628
|
const root = options.pluginRoot ?? pluginRootDir2();
|
|
286763
|
-
const exists2 = options.exists ??
|
|
286629
|
+
const exists2 = options.exists ?? existsSync74;
|
|
286764
286630
|
const candidate = bundledClaudeBridgeBinPath2(root);
|
|
286765
286631
|
if (!exists2(candidate)) {
|
|
286766
286632
|
return {
|
|
@@ -287995,7 +287861,7 @@ var init_acp2 = __esm({
|
|
|
287995
287861
|
|
|
287996
287862
|
// ../../plugins/fusion-plugin-claude-runtime/src/cli-spawn.ts
|
|
287997
287863
|
import { spawn as spawn19 } from "node:child_process";
|
|
287998
|
-
import { existsSync as
|
|
287864
|
+
import { existsSync as existsSync75 } from "node:fs";
|
|
287999
287865
|
import { basename as basename24, dirname as dirname44, isAbsolute as isAbsolute24, join as join96, resolve as resolve47 } from "node:path";
|
|
288000
287866
|
import { fileURLToPath as fileURLToPath11 } from "node:url";
|
|
288001
287867
|
function pluginRootDir3() {
|
|
@@ -288007,7 +287873,7 @@ function bundledClaudeBridgeBinPath3(pluginRoot = pluginRootDir3()) {
|
|
|
288007
287873
|
}
|
|
288008
287874
|
function resolveBundledClaudeBridgeBinary3(options = {}) {
|
|
288009
287875
|
const candidate = bundledClaudeBridgeBinPath3(options.pluginRoot ?? pluginRootDir3());
|
|
288010
|
-
const exists2 = options.exists ??
|
|
287876
|
+
const exists2 = options.exists ?? existsSync75;
|
|
288011
287877
|
if (!exists2(candidate) || !isAbsolute24(candidate)) return { kind: "not_resolved", requested: CLAUDE_CODE_CLI_ACP_BINARY3, path: candidate, reason: `Staged ${CLAUDE_CODE_CLI_ACP_BINARY3} bridge was not found at ${candidate}` };
|
|
288012
287878
|
return { kind: "resolved", requested: CLAUDE_CODE_CLI_ACP_BINARY3, path: candidate };
|
|
288013
287879
|
}
|
|
@@ -288170,7 +288036,7 @@ var init_mcp_forwarding2 = __esm({
|
|
|
288170
288036
|
// ../../plugins/fusion-plugin-claude-runtime/src/skill-loader.ts
|
|
288171
288037
|
import {
|
|
288172
288038
|
cpSync as cpSync4,
|
|
288173
|
-
existsSync as
|
|
288039
|
+
existsSync as existsSync76,
|
|
288174
288040
|
mkdirSync as mkdirSync15,
|
|
288175
288041
|
mkdtempSync as mkdtempSync4,
|
|
288176
288042
|
readdirSync as readdirSync15,
|
|
@@ -288183,7 +288049,7 @@ import { tmpdir as tmpdir17 } from "node:os";
|
|
|
288183
288049
|
import { basename as basename25, dirname as dirname45, join as join97, resolve as resolve48 } from "node:path";
|
|
288184
288050
|
import { fileURLToPath as fileURLToPath12 } from "node:url";
|
|
288185
288051
|
function isSkillDir2(dir) {
|
|
288186
|
-
return
|
|
288052
|
+
return existsSync76(join97(dir, "SKILL.md"));
|
|
288187
288053
|
}
|
|
288188
288054
|
function pushUnique2(out, candidate) {
|
|
288189
288055
|
if (!candidate) return;
|
|
@@ -288247,7 +288113,7 @@ function resolveBundledFusionSkillSource3(moduleUrl = import.meta.url) {
|
|
|
288247
288113
|
function installSkillDir2(sourceDir, targetDir) {
|
|
288248
288114
|
if (!isSkillDir2(sourceDir)) return false;
|
|
288249
288115
|
mkdirSync15(dirname45(targetDir), { recursive: true });
|
|
288250
|
-
if (
|
|
288116
|
+
if (existsSync76(targetDir)) {
|
|
288251
288117
|
rmSync12(targetDir, { recursive: true, force: true });
|
|
288252
288118
|
}
|
|
288253
288119
|
try {
|
|
@@ -288263,7 +288129,7 @@ function installSkillDir2(sourceDir, targetDir) {
|
|
|
288263
288129
|
}
|
|
288264
288130
|
}
|
|
288265
288131
|
function collectSkillsFromRoot2(root, out) {
|
|
288266
|
-
if (!
|
|
288132
|
+
if (!existsSync76(root)) return;
|
|
288267
288133
|
if (isSkillDir2(root)) {
|
|
288268
288134
|
out.set(basename25(root), root);
|
|
288269
288135
|
return;
|
|
@@ -288302,7 +288168,7 @@ function stageClaudeSessionSkills(options = {}) {
|
|
|
288302
288168
|
installSkillDir2(source, join97(skillsDir, name2));
|
|
288303
288169
|
}
|
|
288304
288170
|
for (const [name2, source] of installed) {
|
|
288305
|
-
if (!
|
|
288171
|
+
if (!existsSync76(join97(skillsDir, name2))) {
|
|
288306
288172
|
installSkillDir2(source, join97(skillsDir, name2));
|
|
288307
288173
|
}
|
|
288308
288174
|
}
|
|
@@ -288371,7 +288237,7 @@ var init_skill_loader2 = __esm({
|
|
|
288371
288237
|
|
|
288372
288238
|
// ../../plugins/fusion-plugin-claude-runtime/src/tool-bridge.ts
|
|
288373
288239
|
import { createServer as createServer3 } from "node:http";
|
|
288374
|
-
import { existsSync as
|
|
288240
|
+
import { existsSync as existsSync77, rmSync as rmSync13, writeFileSync as writeFileSync17 } from "node:fs";
|
|
288375
288241
|
import { tmpdir as tmpdir18 } from "node:os";
|
|
288376
288242
|
import { dirname as dirname46, join as join98 } from "node:path";
|
|
288377
288243
|
import { fileURLToPath as fileURLToPath13 } from "node:url";
|
|
@@ -288417,7 +288283,7 @@ async function startFusionToolBridge2(tools, options = {}) {
|
|
|
288417
288283
|
const defs = toolsToMcpToolDefs3(tools);
|
|
288418
288284
|
if (defs.length === 0) return null;
|
|
288419
288285
|
const serverPath = fusionToolsMcpServerPath2();
|
|
288420
|
-
if (!
|
|
288286
|
+
if (!existsSync77(serverPath)) {
|
|
288421
288287
|
throw missingMcpSchemaServerError2(serverPath);
|
|
288422
288288
|
}
|
|
288423
288289
|
const byName = /* @__PURE__ */ new Map();
|
|
@@ -289229,7 +289095,7 @@ var init_provider6 = __esm({
|
|
|
289229
289095
|
});
|
|
289230
289096
|
|
|
289231
289097
|
// ../../plugins/fusion-plugin-omp-runtime/src/acp/cli-spawn.ts
|
|
289232
|
-
import { existsSync as
|
|
289098
|
+
import { existsSync as existsSync78 } from "node:fs";
|
|
289233
289099
|
import { dirname as dirname47, isAbsolute as isAbsolute25, join as join99, resolve as resolve49 } from "node:path";
|
|
289234
289100
|
import { fileURLToPath as fileURLToPath14 } from "node:url";
|
|
289235
289101
|
function asTrimmedString3(value) {
|
|
@@ -289252,7 +289118,7 @@ function bundledClaudeBridgeBinPath4(pluginRoot = pluginRootDir4()) {
|
|
|
289252
289118
|
}
|
|
289253
289119
|
function resolveBundledClaudeBridgeBinary4(options = {}) {
|
|
289254
289120
|
const root = options.pluginRoot ?? pluginRootDir4();
|
|
289255
|
-
const exists2 = options.exists ??
|
|
289121
|
+
const exists2 = options.exists ?? existsSync78;
|
|
289256
289122
|
const candidate = bundledClaudeBridgeBinPath4(root);
|
|
289257
289123
|
if (!exists2(candidate)) {
|
|
289258
289124
|
return {
|
|
@@ -290564,7 +290430,7 @@ var init_mcp_forwarding3 = __esm({
|
|
|
290564
290430
|
|
|
290565
290431
|
// ../../plugins/fusion-plugin-omp-runtime/src/tool-bridge.ts
|
|
290566
290432
|
import { createServer as createServer4 } from "node:http";
|
|
290567
|
-
import { existsSync as
|
|
290433
|
+
import { existsSync as existsSync79, unlinkSync as unlinkSync5, writeFileSync as writeFileSync18 } from "node:fs";
|
|
290568
290434
|
import { tmpdir as tmpdir19 } from "node:os";
|
|
290569
290435
|
import { dirname as dirname49, join as join101 } from "node:path";
|
|
290570
290436
|
import { fileURLToPath as fileURLToPath15 } from "node:url";
|
|
@@ -290591,7 +290457,7 @@ function fusionToolsMcpServerPath3() {
|
|
|
290591
290457
|
join101(here, "..", "mcp-schema-server.cjs")
|
|
290592
290458
|
];
|
|
290593
290459
|
for (const candidate of candidates) {
|
|
290594
|
-
if (
|
|
290460
|
+
if (existsSync79(candidate)) return candidate;
|
|
290595
290461
|
}
|
|
290596
290462
|
return null;
|
|
290597
290463
|
}
|
|
@@ -290729,7 +290595,7 @@ var init_tool_bridge3 = __esm({
|
|
|
290729
290595
|
});
|
|
290730
290596
|
|
|
290731
290597
|
// ../../plugins/fusion-plugin-omp-runtime/src/runtime-adapter.ts
|
|
290732
|
-
import { existsSync as
|
|
290598
|
+
import { existsSync as existsSync80 } from "node:fs";
|
|
290733
290599
|
function compactDiagnostic3(value) {
|
|
290734
290600
|
return value.replace(/\s+/g, " ").trim();
|
|
290735
290601
|
}
|
|
@@ -290920,7 +290786,7 @@ var init_runtime_adapter9 = __esm({
|
|
|
290920
290786
|
const command = server.command.trim();
|
|
290921
290787
|
if (!command) return false;
|
|
290922
290788
|
if (command.includes("/") || command.includes("\\")) {
|
|
290923
|
-
return
|
|
290789
|
+
return existsSync80(command);
|
|
290924
290790
|
}
|
|
290925
290791
|
return true;
|
|
290926
290792
|
});
|
|
@@ -294142,7 +294008,7 @@ __export(task_exports, {
|
|
|
294142
294008
|
runTaskUpdate: () => runTaskUpdate
|
|
294143
294009
|
});
|
|
294144
294010
|
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
294145
|
-
import { watchFile, unwatchFile, statSync as statSync14, existsSync as
|
|
294011
|
+
import { watchFile, unwatchFile, statSync as statSync14, existsSync as existsSync81, readFileSync as readFileSync27 } from "node:fs";
|
|
294146
294012
|
import { basename as basename28, join as join104 } from "node:path";
|
|
294147
294013
|
function columnLabel(column) {
|
|
294148
294014
|
return COLUMN_LABELS[column] ?? column;
|
|
@@ -294716,7 +294582,7 @@ async function runTaskLogs(id, options = {}, projectName) {
|
|
|
294716
294582
|
if (options.follow) {
|
|
294717
294583
|
const projectPath = context.projectPath ?? process.cwd();
|
|
294718
294584
|
const logPath = join104(projectPath, ".fusion", "tasks", id, "agent.log");
|
|
294719
|
-
if (!
|
|
294585
|
+
if (!existsSync81(logPath)) {
|
|
294720
294586
|
console.log(`
|
|
294721
294587
|
Waiting for log file to be created...`);
|
|
294722
294588
|
}
|
|
@@ -296119,7 +295985,7 @@ import { Type as Type9 } from "typebox";
|
|
|
296119
295985
|
import { StringEnum } from "@earendil-works/pi-ai";
|
|
296120
295986
|
import { resolve as resolve53, relative as relative20, isAbsolute as isAbsolute26, sep as sep16, basename as basename29, extname as extname4, join as join105 } from "node:path";
|
|
296121
295987
|
import { readFile as readFile47 } from "node:fs/promises";
|
|
296122
|
-
import { existsSync as
|
|
295988
|
+
import { existsSync as existsSync82 } from "node:fs";
|
|
296123
295989
|
import { spawn as spawn23 } from "node:child_process";
|
|
296124
295990
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
296125
295991
|
function truncateAgentDiagnosticText(value, maxChars) {
|
|
@@ -296199,12 +296065,12 @@ function resolveProjectRoot2(cwd) {
|
|
|
296199
296065
|
warnedMissingProjectRootResolver = true;
|
|
296200
296066
|
console.warn("[fusion-extension] @fusion/core.getProjectRootFromWorktree is unavailable; using filesystem fallback resolution.");
|
|
296201
296067
|
}
|
|
296202
|
-
if (worktreeProjectRoot &&
|
|
296068
|
+
if (worktreeProjectRoot && existsSync82(join105(worktreeProjectRoot, ".fusion"))) {
|
|
296203
296069
|
return worktreeProjectRoot;
|
|
296204
296070
|
}
|
|
296205
296071
|
let current = resolve53(cwd);
|
|
296206
296072
|
while (true) {
|
|
296207
|
-
if (
|
|
296073
|
+
if (existsSync82(join105(current, ".fusion"))) {
|
|
296208
296074
|
return current;
|
|
296209
296075
|
}
|
|
296210
296076
|
const parent = resolve53(current, "..");
|