@runfusion/fusion 0.74.0-beta.7 → 0.74.0-beta.9
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 +367 -485
- package/dist/child-process-worker.js +172 -290
- package/dist/client/.vite/manifest.json +266 -266
- package/dist/client/assets/{AgentDetailView-CTdyQL11.js → AgentDetailView-DC3B06sE.js} +1 -1
- package/dist/client/assets/{AgentPermissionPolicyEditor-DBa7nIQV.js → AgentPermissionPolicyEditor-BtKWfG2h.js} +1 -1
- package/dist/client/assets/{AgentsView-B5tss2oK.js → AgentsView-4DiJ2Htx.js} +3 -3
- package/dist/client/assets/{ChatView-DAKt1a2L.js → ChatView-1nqZiDRk.js} +1 -1
- package/dist/client/assets/{CommandCenter-yPvRo9F6.js → CommandCenter-BHZN2tf0.js} +1 -1
- package/dist/client/assets/{DevServerView-BTyS2owH.js → DevServerView-BwPjQxR_.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-BjGIupNU.js → DirectoryPicker-40vH29Sy.js} +1 -1
- package/dist/client/assets/{DocumentsView-CuxfbpSZ.js → DocumentsView-DI2mQkGF.js} +1 -1
- package/dist/client/assets/{EvalsView-DGuy8SHR.js → EvalsView-CTSt1-CF.js} +1 -1
- package/dist/client/assets/{ExperimentalAgentOnboardingModal-lK407ZAq.js → ExperimentalAgentOnboardingModal-Z1DJ2xFw.js} +1 -1
- package/dist/client/assets/{GoalsView-DAVN0ObR.js → GoalsView-BNyoKq27.js} +1 -1
- package/dist/client/assets/{InsightsView-BXQKcNof.js → InsightsView-zSwsbTfk.js} +1 -1
- package/dist/client/assets/{MemoryView-D7RKEtV7.js → MemoryView-e7R4rcQY.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-CrOJ57R2.js → PiExtensionsManager-DuZzMGuy.js} +1 -1
- package/dist/client/assets/{PluginManager-D7_evt4j.js → PluginManager--lgPTCei.js} +1 -1
- package/dist/client/assets/{PullRequestView-C0lRUbth.js → PullRequestView-C9KOlfV-.js} +1 -1
- package/dist/client/assets/ReportModal-BiXAfHbg.js +21 -0
- package/dist/client/assets/ReportModal-M3uh98sc.css +1 -0
- package/dist/client/assets/{ResearchView-e8st2Sxu.js → ResearchView-N4N7-_7C.js} +1 -1
- package/dist/client/assets/{SecretsView-BLzckrzb.js → SecretsView-GPt8Mw9d.js} +1 -1
- package/dist/client/assets/{SessionTerminal-F_GIj4gh.js → SessionTerminal-D2bnTrLK.js} +1 -1
- package/dist/client/assets/SettingsModal-B30rPfYC.css +1 -0
- package/dist/client/assets/{SettingsModal-eQbxbkLU.js → SettingsModal-D42Cph4Z.js} +4 -4
- package/dist/client/assets/{SettingsModal-XAddgWkF.js → SettingsModal-DLKu3CYU.js} +1 -1
- package/dist/client/assets/{SettingsTextareaRow-DVjUHNQp.js → SettingsTextareaRow-terwvp1e.js} +1 -1
- package/dist/client/assets/{SetupWizardModal-xID9yIff.js → SetupWizardModal-C-ApHZiL.js} +2 -2
- package/dist/client/assets/{SkillsView-BNdMGu6E.js → SkillsView-GYBeq0B-.js} +1 -1
- package/dist/client/assets/{TodoView-xcOjHZm1.js → TodoView-_1AmNwaZ.js} +1 -1
- package/dist/client/assets/{WorkflowNodeEditor-DZ2WZ-ve.js → WorkflowNodeEditor-CYf2R0ap.js} +1 -1
- package/dist/client/assets/{agent-import-generation-0tkW9WMt.js → agent-import-generation-BZPb1nmV.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-DP9_UvPn.js → architectureDiagram-3BPJPVTR-C_wwNBnV.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-EgKwYMgQ.js → blockDiagram-GPEHLZMM-C7URdbgi.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-Dzv0-_xt.js → c4Diagram-AAUBKEIU-BBc8CXBz.js} +1 -1
- package/dist/client/assets/channel-M95yBImf.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-CNmFmJlQ.js → chunk-2J33WTMH-KfVf5U4u.js} +1 -1
- package/dist/client/assets/{chunk-4BX2VUAB-DwtF2sl5.js → chunk-4BX2VUAB-BYzFvVsE.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-DoDurT6F.js → chunk-55IACEB6-B-sxSeny.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-DB87A9uH.js → chunk-727SXJPM-B0xJsLsd.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-ClTDkMp1.js → chunk-AQP2D5EJ-BQ9rJQCA.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-BhY2wlYr.js → chunk-FMBD7UC4-DR-KABew.js} +1 -1
- package/dist/client/assets/{chunk-ND2GUHAM-BB8mzlmk.js → chunk-ND2GUHAM-C6ZnAzm4.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-D81qQMGf.js → chunk-QZHKN3VN-zs4tZGnv.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-DU8poSst.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DU8poSst.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-CCFUHBJX.js → cose-bilkent-S5V4N54A-DnljjIm-.js} +1 -1
- package/dist/client/assets/{dagre-BM42HDAG-xr9MLhRA.js → dagre-BM42HDAG-CEX8DHCo.js} +1 -1
- package/dist/client/assets/{dashboard-view-RXKFv3QV.js → dashboard-view-Chxgvuq4.js} +1 -1
- package/dist/client/assets/{dashboard-view-lqwQ-pMo.js → dashboard-view-DPCI6MD3.js} +1 -1
- package/dist/client/assets/{dashboard-view-oTFt91I3.js → dashboard-view-D_xtIayp.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-mN_tYnBs.js → diagram-2AECGRRQ-Dl9VFNxu.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-xznlq-5C.js → diagram-5GNKFQAL-BPvDRIKP.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-ClRlj1ZA.js → diagram-KO2AKTUF-c1v9YI9G.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-CNiPIQqT.js → diagram-LMA3HP47-ChVDgN1K.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-DwQD-W0P.js → diagram-OG6HWLK6-Cns2RBoA.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-ZXkiCm8S.js → erDiagram-TEJ5UH35-D33nn5Lx.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-DI5haEH9.js → flowDiagram-I6XJVG4X-BluS50at.js} +1 -1
- package/dist/client/assets/{folder-open-NenyCkrb.js → folder-open-oeYf8Ijc.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-BRHJpfOZ.js → ganttDiagram-6RSMTGT7-D78LznXX.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-iXT_YBAZ.js → gitGraphDiagram-PVQCEYII-Cz-VVeuo.js} +1 -1
- package/dist/client/assets/index-Clr90mLV.js +2675 -0
- package/dist/client/assets/index-DRZtPb3i.css +1 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-BzkuQtqZ.js → infoDiagram-5YYISTIA-DW64QGM7.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-5hnPG_98.js → ishikawaDiagram-YF4QCWOH-zB3QANvt.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-Co3fnxbr.js → journeyDiagram-JHISSGLW-nVRvkAiF.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-PZFl_y-h.js → kanban-definition-UN3LZRKU-DIsRSNcB.js} +1 -1
- package/dist/client/assets/{mermaid.core-CJRKeU9s.js → mermaid.core-ByWbtMdM.js} +4 -4
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-B15e2rkx.js → mindmap-definition-RKZ34NQL-BbZZGyk5.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-kGF592D_.js → pieDiagram-4H26LBE5-xEuGzir-.js} +1 -1
- package/dist/client/assets/{puzzle-Dgc4yzjO.js → puzzle-DfKZ6p_i.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-CUShcj70.js → quadrantDiagram-W4KKPZXB-CXU0exeD.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-D2k4nLqQ.js → requirementDiagram-4Y6WPE33-xrqjvySl.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-CA03BxhT.js → sankeyDiagram-5OEKKPKP-B_XL-dlB.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-DDuFN2Pi.js → sequenceDiagram-3UESZ5HK-yPNpJSyq.js} +1 -1
- package/dist/client/assets/{shield-alert-BlYWqolM.js → shield-alert-C0mvrTVY.js} +1 -1
- package/dist/client/assets/{standing-instructions-template-ujl7UARV.js → standing-instructions-template-BA-Y897i.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-yJOkHK4Q.js → stateDiagram-AJRCARHV-B3WacriB.js} +1 -1
- package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-BgErHdAN.js → stateDiagram-v2-BHNVJYJU-C2J3lqDw.js} +1 -1
- package/dist/client/assets/{timeline-definition-PNZ67QCA-BUiDQw21.js → timeline-definition-PNZ67QCA-BMDzGW-H.js} +1 -1
- package/dist/client/assets/{upload-DmlZvpMp.js → upload-BcE2JLKs.js} +1 -1
- package/dist/client/assets/{users-Cx6ACt-W.js → users-CG9A3bIX.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-DqyIjBY8.js → vennDiagram-CIIHVFJN-C7ZUUi6G.js} +1 -1
- package/dist/client/assets/{wardley-L42UT6IY-C93tXAKH.js → wardley-L42UT6IY-zpz98dmH.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-DmH6-GJV.js → wardleyDiagram-YWT4CUSO-D4TOrUW4.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-BPwjE4Su.js → xychartDiagram-2RQKCTM6-CDfiiyNj.js} +1 -1
- package/dist/client/index.html +4 -3
- package/dist/client/theme-data.css +85 -1
- package/dist/client/version.json +1 -1
- package/dist/extension.js +244 -362
- package/package.json +1 -1
- package/dist/client/assets/ReportModal-Bg-XvWay.css +0 -1
- package/dist/client/assets/ReportModal-Cy5fRNDK.js +0 -21
- 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/client/assets/index-CrAJA2v0.js +0 -2675
package/dist/bin.js
CHANGED
|
@@ -867,6 +867,11 @@ var init_execution_and_ui = __esm({
|
|
|
867
867
|
"dawn",
|
|
868
868
|
// FNXC:DashboardTheming 2026-07-31-21:28: Sage must stay order-synchronized across core, selector metadata, and both first-paint validators so saved preferences survive pre-hydration validation.
|
|
869
869
|
"sage",
|
|
870
|
+
/*
|
|
871
|
+
FNXC:MidnightTheme 2026-08-03-02:05:
|
|
872
|
+
Midnight is a persisted selectable dashboard theme. Keep its id and order synchronized with selector metadata and both web/Electron first-paint validators so saved choices survive before hydration, while shadcn-ember remains the unset default.
|
|
873
|
+
*/
|
|
874
|
+
"midnight",
|
|
870
875
|
// FNXC:DashboardTheming 2026-07-31-20:39: Factory Dark must stay order-synchronized across core, selector metadata, and both first-paint validators so saved preferences survive pre-hydration validation.
|
|
871
876
|
"factory-dark",
|
|
872
877
|
// FNXC:DashboardTheming 2026-07-31-23:51: Factory Light must stay order-synchronized across core, selector metadata, and both first-paint validators so saved preferences survive pre-hydration validation.
|
|
@@ -96698,15 +96703,20 @@ async function updateTaskUnlockedImpl(store, id, updates, runContext) {
|
|
|
96698
96703
|
task.workspaceWorktrees = updates.workspaceWorktrees;
|
|
96699
96704
|
}
|
|
96700
96705
|
let movedToTriage = false;
|
|
96706
|
+
let respecifyFromColumn;
|
|
96707
|
+
let respecifyMoveLanes;
|
|
96701
96708
|
if (updates.dependencies !== void 0) {
|
|
96702
96709
|
const oldDeps = new Set((task.dependencies ?? []).map((dependency) => dependency.trim()).filter(Boolean));
|
|
96703
96710
|
const normalizedDependencies = updates.dependencies.map((dependency) => dependency.trim()).filter(Boolean);
|
|
96704
96711
|
const hasNewDeps = normalizedDependencies.some((d) => !oldDeps.has(d));
|
|
96705
96712
|
task.dependencies = normalizedDependencies;
|
|
96706
|
-
const
|
|
96713
|
+
const respecifyIr = hasNewDeps ? await resolveWorkflowIrForTask(store, id).catch(() => void 0) : void 0;
|
|
96714
|
+
respecifyMoveLanes = toTaskMoveLanes(respecifyIr);
|
|
96715
|
+
const depLanes = respecifyIr ? resolveLifecycleColumns(respecifyIr) : void 0;
|
|
96707
96716
|
const holdLane = depLanes === void 0 ? "todo" : depLanes.hold;
|
|
96708
96717
|
if (hasNewDeps && holdLane !== void 0 && task.column === holdLane) {
|
|
96709
96718
|
const intakeLane = depLanes?.intake;
|
|
96719
|
+
respecifyFromColumn = task.column;
|
|
96710
96720
|
const relocating = intakeLane !== void 0 && intakeLane !== task.column;
|
|
96711
96721
|
if (relocating) {
|
|
96712
96722
|
task.column = intakeLane;
|
|
@@ -97384,10 +97394,15 @@ async function updateTaskUnlockedImpl(store, id, updates, runContext) {
|
|
|
97384
97394
|
storeLog.warn(`[task-detail] failed to sync PROMPT.md heading for ${task.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
97385
97395
|
}
|
|
97386
97396
|
}
|
|
97387
|
-
if (movedToTriage) {
|
|
97388
|
-
|
|
97389
|
-
store.
|
|
97390
|
-
|
|
97397
|
+
if (movedToTriage && respecifyFromColumn !== void 0 && respecifyFromColumn !== task.column && respecifyMoveLanes) {
|
|
97398
|
+
store.laneCache.set(task.id, respecifyMoveLanes);
|
|
97399
|
+
store.emit("task:moved", {
|
|
97400
|
+
task,
|
|
97401
|
+
from: respecifyFromColumn,
|
|
97402
|
+
to: task.column,
|
|
97403
|
+
source: "engine",
|
|
97404
|
+
lanes: respecifyMoveLanes
|
|
97405
|
+
});
|
|
97391
97406
|
}
|
|
97392
97407
|
store.emitTaskLifecycleEventSafely("task:updated", [task]);
|
|
97393
97408
|
return task;
|
|
@@ -97399,7 +97414,6 @@ var init_task_update = __esm({
|
|
|
97399
97414
|
init_store();
|
|
97400
97415
|
init_workflow_lifecycle_traits();
|
|
97401
97416
|
init_workflow_ir_resolver();
|
|
97402
|
-
init_workflow_lifecycle_traits();
|
|
97403
97417
|
init_errors3();
|
|
97404
97418
|
init_task_fields();
|
|
97405
97419
|
init_builtin_traits();
|
|
@@ -136278,7 +136292,8 @@ function wrapPluginRuntime(instance, runtimeId, runtimeName) {
|
|
|
136278
136292
|
const result2 = await adapter.createSession(options);
|
|
136279
136293
|
return {
|
|
136280
136294
|
session: result2.session ?? result2,
|
|
136281
|
-
sessionFile: result2.sessionFile
|
|
136295
|
+
sessionFile: result2.sessionFile,
|
|
136296
|
+
settleFallbackDispatch: result2.settleFallbackDispatch
|
|
136282
136297
|
};
|
|
136283
136298
|
}
|
|
136284
136299
|
throw new Error(`Plugin runtime "${runtimeId}" does not implement createSession`);
|
|
@@ -136387,11 +136402,15 @@ var init_runtime_resolution = __esm({
|
|
|
136387
136402
|
name = "Default PI Runtime";
|
|
136388
136403
|
async createSession(options) {
|
|
136389
136404
|
const { toolOutputMaxChars, mcpServers, ...agentOptions } = options;
|
|
136390
|
-
|
|
136405
|
+
const result2 = await createFnAgent2({
|
|
136391
136406
|
...agentOptions,
|
|
136392
136407
|
toolOutputMaxChars,
|
|
136393
136408
|
mcpServers: normalizeAgentRuntimeMcpServers(mcpServers)
|
|
136394
136409
|
});
|
|
136410
|
+
return {
|
|
136411
|
+
...result2,
|
|
136412
|
+
settleFallbackDispatch: result2.settleFallbackDispatch ?? (async () => void 0)
|
|
136413
|
+
};
|
|
136395
136414
|
}
|
|
136396
136415
|
async promptWithFallback(session, prompt, options) {
|
|
136397
136416
|
return promptWithFallback(session, prompt, options);
|
|
@@ -137273,6 +137292,7 @@ async function createResolvedAgentSession(options) {
|
|
|
137273
137292
|
return {
|
|
137274
137293
|
session: result2.session,
|
|
137275
137294
|
sessionFile: result2.sessionFile,
|
|
137295
|
+
settleFallbackDispatch: result2.settleFallbackDispatch,
|
|
137276
137296
|
runtimeId: resolved.runtimeId,
|
|
137277
137297
|
wasConfigured: resolved.wasConfigured
|
|
137278
137298
|
};
|
|
@@ -159268,7 +159288,11 @@ async function createFnAgent2(options) {
|
|
|
159268
159288
|
}
|
|
159269
159289
|
});
|
|
159270
159290
|
attachSessionIdentity(promptableSession);
|
|
159271
|
-
return {
|
|
159291
|
+
return {
|
|
159292
|
+
session: promptableSession,
|
|
159293
|
+
sessionFile: promptableSession.sessionFile,
|
|
159294
|
+
settleFallbackDispatch: async () => void 0
|
|
159295
|
+
};
|
|
159272
159296
|
}
|
|
159273
159297
|
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;
|
|
159274
159298
|
var init_pi = __esm({
|
|
@@ -185757,6 +185781,25 @@ var init_scheduler = __esm({
|
|
|
185757
185781
|
});
|
|
185758
185782
|
}
|
|
185759
185783
|
}
|
|
185784
|
+
if (from === parked.wip && to2 === parked.hold) {
|
|
185785
|
+
if (source === "engine") {
|
|
185786
|
+
this.recentEngineTodoRequeues.set(task.id, task.columnMovedAt ?? (/* @__PURE__ */ new Date()).toISOString());
|
|
185787
|
+
} else {
|
|
185788
|
+
this.recentEngineTodoRequeues.delete(task.id);
|
|
185789
|
+
}
|
|
185790
|
+
} else if (to2 === parked.review || parked.terminal.has(to2)) {
|
|
185791
|
+
this.recentEngineTodoRequeues.delete(task.id);
|
|
185792
|
+
if (task.dispatchStormCount != null || task.lastDispatchAt != null || task.executeRequeueLoopCount != null || task.executeRequeueLoopSignature != null) {
|
|
185793
|
+
void this.store.updateTask(task.id, {
|
|
185794
|
+
dispatchStormCount: null,
|
|
185795
|
+
lastDispatchAt: null,
|
|
185796
|
+
executeRequeueLoopCount: null,
|
|
185797
|
+
executeRequeueLoopSignature: null
|
|
185798
|
+
}).catch((error3) => {
|
|
185799
|
+
schedulerLog.warn(`Failed to reset dispatch oscillation state for ${task.id} on move to ${to2}: ${error3 instanceof Error ? error3.message : String(error3)}`);
|
|
185800
|
+
});
|
|
185801
|
+
}
|
|
185802
|
+
}
|
|
185760
185803
|
const resolvedParked = mergeParkedColumns(await resolveTaskParkedColumns(this.store, task.id), lanes);
|
|
185761
185804
|
if (resolvedParked.terminal.has(to2)) {
|
|
185762
185805
|
try {
|
|
@@ -185817,25 +185860,6 @@ var init_scheduler = __esm({
|
|
|
185817
185860
|
schedulerLog.error(`Failed event-driven blocker reconciliation for ${task.id}`, error3);
|
|
185818
185861
|
}
|
|
185819
185862
|
}
|
|
185820
|
-
if (from === resolvedParked.wip && to2 === resolvedParked.hold) {
|
|
185821
|
-
if (source === "engine") {
|
|
185822
|
-
this.recentEngineTodoRequeues.set(task.id, task.columnMovedAt ?? (/* @__PURE__ */ new Date()).toISOString());
|
|
185823
|
-
} else {
|
|
185824
|
-
this.recentEngineTodoRequeues.delete(task.id);
|
|
185825
|
-
}
|
|
185826
|
-
} else if (to2 === resolvedParked.review || resolvedParked.terminal.has(to2)) {
|
|
185827
|
-
this.recentEngineTodoRequeues.delete(task.id);
|
|
185828
|
-
if (task.dispatchStormCount != null || task.lastDispatchAt != null || task.executeRequeueLoopCount != null || task.executeRequeueLoopSignature != null) {
|
|
185829
|
-
void this.store.updateTask(task.id, {
|
|
185830
|
-
dispatchStormCount: null,
|
|
185831
|
-
lastDispatchAt: null,
|
|
185832
|
-
executeRequeueLoopCount: null,
|
|
185833
|
-
executeRequeueLoopSignature: null
|
|
185834
|
-
}).catch((error3) => {
|
|
185835
|
-
schedulerLog.warn(`Failed to reset dispatch oscillation state for ${task.id} on move to ${to2}: ${error3 instanceof Error ? error3.message : String(error3)}`);
|
|
185836
|
-
});
|
|
185837
|
-
}
|
|
185838
|
-
}
|
|
185839
185863
|
if (resolvedParked.terminal.has(to2) || to2 === resolvedParked.hold) {
|
|
185840
185864
|
schedulerLog.log(`Task moved to ${to2} \u2014 triggering scheduling`);
|
|
185841
185865
|
this.schedule();
|
|
@@ -204093,7 +204117,6 @@ var init_self_healing = __esm({
|
|
|
204093
204117
|
{ name: "reconcile-done-task-integrity", fn: () => this.reconcileDoneTaskIntegrity() },
|
|
204094
204118
|
{ name: "reconcile-stale-merger-status", fn: () => this.reconcileStaleMergerStatus() },
|
|
204095
204119
|
{ name: "reconcile-stale-duplicate-decision", fn: () => this.reconcileStaleDuplicateDecisionPause() },
|
|
204096
|
-
{ name: "reconcile-external-pr-blockers", fn: () => this.reconcileExternalPrBlockers() },
|
|
204097
204120
|
// FNXC:OrphanedPendingSteps 2026-07-22-16:35 (FN-8492 review follow-up): also
|
|
204098
204121
|
// steady-state — a step session can die without an engine restart, and startup-only
|
|
204099
204122
|
// cadence left that case riding the 3×30-min stall escalator to a deadlock park.
|
|
@@ -205597,6 +205620,7 @@ var init_self_healing = __esm({
|
|
|
205597
205620
|
}
|
|
205598
205621
|
async reclaimStaleActiveBranches() {
|
|
205599
205622
|
const reclaimArchivedColumns = await resolveProjectColumnsForRoles(this.store, ["archived"]);
|
|
205623
|
+
const reclaimCompleteColumns = await resolveProjectColumnsForRoles(this.store, ["complete"]);
|
|
205600
205624
|
try {
|
|
205601
205625
|
const settings = await this.store.getSettings();
|
|
205602
205626
|
if (settings.globalPause || settings.enginePaused) return 0;
|
|
@@ -205694,10 +205718,12 @@ var init_self_healing = __esm({
|
|
|
205694
205718
|
if (task.worktree && await isUsableTaskWorktree(this.options.rootDir, task.worktree)) continue;
|
|
205695
205719
|
const inspection = await this.inspectOrphanedBranch(branch);
|
|
205696
205720
|
if (!inspection) continue;
|
|
205697
|
-
|
|
205721
|
+
const isCompleteColumn2 = reclaimCompleteColumns.has(task.column);
|
|
205722
|
+
if (inspection.uniqueCommitCount > 0 && !isCompleteColumn2) {
|
|
205698
205723
|
log33.warn(`[recovery] stale-active-branch-rescue-needed ${task.id} branch=${branch} unique=${inspection.uniqueCommitCount} tip=${inspection.tipSha.slice(0, 12)}`);
|
|
205699
205724
|
continue;
|
|
205700
205725
|
}
|
|
205726
|
+
const reclaimReason = inspection.uniqueCommitCount > 0 ? "complete-column-unique-commits-force" : "zero-unique-commits-no-worktree";
|
|
205701
205727
|
await execAsync18(`git branch -D ${JSON.stringify(branch)}`, {
|
|
205702
205728
|
cwd: this.options.rootDir,
|
|
205703
205729
|
timeout: 12e4,
|
|
@@ -205715,7 +205741,7 @@ var init_self_healing = __esm({
|
|
|
205715
205741
|
});
|
|
205716
205742
|
await this.store.logEntry(
|
|
205717
205743
|
task.id,
|
|
205718
|
-
`[recovery] stale-active-branch-reclaim ${task.id} branch=${branch} reason
|
|
205744
|
+
`[recovery] stale-active-branch-reclaim ${task.id} branch=${branch} reason=${reclaimReason}`
|
|
205719
205745
|
);
|
|
205720
205746
|
try {
|
|
205721
205747
|
const auditor = createRunAuditor(this.store, {
|
|
@@ -205733,7 +205759,7 @@ var init_self_healing = __esm({
|
|
|
205733
205759
|
branch,
|
|
205734
205760
|
tipSha: inspection.tipSha,
|
|
205735
205761
|
uniqueCommitCount: inspection.uniqueCommitCount,
|
|
205736
|
-
reason:
|
|
205762
|
+
reason: reclaimReason
|
|
205737
205763
|
}
|
|
205738
205764
|
});
|
|
205739
205765
|
} catch (auditErr) {
|
|
@@ -205780,10 +205806,9 @@ var init_self_healing = __esm({
|
|
|
205780
205806
|
const baseBranch = task.baseBranch || await resolveIntegrationBranch(this.options.rootDir, void 0);
|
|
205781
205807
|
const comparison = await listUniqueBranchCommits(this.options.rootDir, baseBranch, branchName);
|
|
205782
205808
|
if (comparison.commits.length > 0) {
|
|
205783
|
-
log33.
|
|
205784
|
-
`[self-healing] reconcileCompletedTask ${task.id}: branch ${branchName} has ${comparison.commits.length} unique commit(s) vs ${comparison.mainRef};
|
|
205809
|
+
log33.log(
|
|
205810
|
+
`[self-healing] reconcileCompletedTask ${task.id}: branch ${branchName} has ${comparison.commits.length} unique commit(s) vs ${comparison.mainRef}; force-deleting post-completion (squash-safe)`
|
|
205785
205811
|
);
|
|
205786
|
-
return false;
|
|
205787
205812
|
}
|
|
205788
205813
|
try {
|
|
205789
205814
|
await execAsync18(`git branch -D ${shellQuote2(branchName)}`, {
|
|
@@ -212990,71 +213015,12 @@ var init_self_healing = __esm({
|
|
|
212990
213015
|
}
|
|
212991
213016
|
}
|
|
212992
213017
|
/*
|
|
212993
|
-
FNXC:HonestBlockedExit 2026-08-02-
|
|
212994
|
-
|
|
212995
|
-
|
|
212996
|
-
|
|
213018
|
+
FNXC:HonestBlockedExit 2026-08-02-23:59 (operator decision — FN-8728 vs PR #2398):
|
|
213019
|
+
The FN-8700 `reconcile-external-pr-blockers` sweep (gh-backed clearing of PR-claim parks)
|
|
213020
|
+
is REMOVED with the whole PR/file-claim blocking mechanism. Open PRs are never blockers;
|
|
213021
|
+
file-scope conflicts are arbitrated only by Fusion's own board. Legacy PR-claim parks are
|
|
213022
|
+
no longer honored by isDurableBlockedTask, so normal recovery paths reclaim them.
|
|
212997
213023
|
*/
|
|
212998
|
-
async reconcileExternalPrBlockers() {
|
|
212999
|
-
try {
|
|
213000
|
-
if (!await isGhAvailable()) {
|
|
213001
|
-
log33.debug("reconcile-external-pr-blockers skipped \u2014 gh unavailable");
|
|
213002
|
-
return 0;
|
|
213003
|
-
}
|
|
213004
|
-
const tasks2 = await this.store.listTasks({ slim: true, includeArchived: false, limit: 500 });
|
|
213005
|
-
let cleared = 0;
|
|
213006
|
-
for (const task of tasks2.slice(0, 80)) {
|
|
213007
|
-
if (task.status !== "failed" || !task.error?.startsWith("BLOCKED:")) continue;
|
|
213008
|
-
const meta2 = task.sourceMetadata;
|
|
213009
|
-
const blockers = meta2?.externalBlockers;
|
|
213010
|
-
if (!Array.isArray(blockers) || blockers.length === 0) continue;
|
|
213011
|
-
const prNumbers = blockers.map((b3) => b3 && typeof b3 === "object" && b3.kind === "github-pr" ? Number(b3.number) : NaN).filter((n) => Number.isFinite(n) && n > 0);
|
|
213012
|
-
if (prNumbers.length === 0) continue;
|
|
213013
|
-
let allResolved = true;
|
|
213014
|
-
for (const n of prNumbers) {
|
|
213015
|
-
try {
|
|
213016
|
-
const pr2 = await runGhJsonAsync(
|
|
213017
|
-
["pr", "view", String(n), "--json", "state,mergedAt"],
|
|
213018
|
-
{ timeoutMs: 15e3 }
|
|
213019
|
-
);
|
|
213020
|
-
const state = String(pr2?.state ?? "").toUpperCase();
|
|
213021
|
-
const merged = Boolean(pr2?.mergedAt) || state === "MERGED";
|
|
213022
|
-
const closed = state === "CLOSED" || state === "MERGED";
|
|
213023
|
-
if (!merged && !closed) {
|
|
213024
|
-
allResolved = false;
|
|
213025
|
-
break;
|
|
213026
|
-
}
|
|
213027
|
-
} catch {
|
|
213028
|
-
allResolved = false;
|
|
213029
|
-
break;
|
|
213030
|
-
}
|
|
213031
|
-
}
|
|
213032
|
-
if (!allResolved) continue;
|
|
213033
|
-
await this.store.updateTask(task.id, {
|
|
213034
|
-
status: null,
|
|
213035
|
-
error: null,
|
|
213036
|
-
sourceMetadataPatch: {
|
|
213037
|
-
externalBlockers: [],
|
|
213038
|
-
blockedClass: null,
|
|
213039
|
-
blockedThrashSignature: null,
|
|
213040
|
-
blockedThrashCount: null,
|
|
213041
|
-
externalPrBlockersClearedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
213042
|
-
externalPrBlockersCleared: prNumbers
|
|
213043
|
-
}
|
|
213044
|
-
});
|
|
213045
|
-
await this.store.logEntry(
|
|
213046
|
-
task.id,
|
|
213047
|
-
`Auto-recovered: external PR blocker(s) ${prNumbers.map((n) => `#${n}`).join(", ")} merged/closed \u2014 cleared durable BLOCKED park for re-dispatch`
|
|
213048
|
-
);
|
|
213049
|
-
log33.log(`Cleared durable PR block for ${task.id} (prs=${prNumbers.join(",")})`);
|
|
213050
|
-
cleared += 1;
|
|
213051
|
-
}
|
|
213052
|
-
return cleared;
|
|
213053
|
-
} catch (error3) {
|
|
213054
|
-
log33.warn(`reconcile-external-pr-blockers failed: ${error3 instanceof Error ? error3.message : String(error3)}`);
|
|
213055
|
-
return 0;
|
|
213056
|
-
}
|
|
213057
|
-
}
|
|
213058
213024
|
async resolveExplicitDuplicateMarkerTasks() {
|
|
213059
213025
|
try {
|
|
213060
213026
|
const settings = await this.store.getSettings();
|
|
@@ -213808,6 +213774,7 @@ var init_self_healing = __esm({
|
|
|
213808
213774
|
// ../engine/src/triage.ts
|
|
213809
213775
|
import { Type as Type5 } from "@earendil-works/pi-ai";
|
|
213810
213776
|
import { exec as exec34 } from "node:child_process";
|
|
213777
|
+
import { existsSync as existsSync60 } from "node:fs";
|
|
213811
213778
|
import { readFile as readFile38, writeFile as writeFile27, rm as rm8 } from "node:fs/promises";
|
|
213812
213779
|
import { join as join72 } from "node:path";
|
|
213813
213780
|
import { promisify as promisify48 } from "node:util";
|
|
@@ -214314,6 +214281,8 @@ var init_triage = __esm({
|
|
|
214314
214281
|
unregisterAdmissionProvider = null;
|
|
214315
214282
|
/** Timestamps when tasks entered the `processing` set, for staleness detection. */
|
|
214316
214283
|
processingSince = /* @__PURE__ */ new Map();
|
|
214284
|
+
/** Monotonic provenance token for attempt-local planner fallback observation. */
|
|
214285
|
+
planningAttemptSequence = 0;
|
|
214317
214286
|
wasGlobalPaused = false;
|
|
214318
214287
|
wasEnginePaused = false;
|
|
214319
214288
|
idleSemaphoreLeakCandidateSince = null;
|
|
@@ -215609,7 +215578,28 @@ You are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.
|
|
|
215609
215578
|
}
|
|
215610
215579
|
await this.store.logEntry(task.id, `Planning session running in task worktree ${planningCwd}`).catch(() => void 0);
|
|
215611
215580
|
}
|
|
215612
|
-
const
|
|
215581
|
+
const authoritativePromptPath = join72(this.rootDir, promptPath);
|
|
215582
|
+
const planningAttemptBaseline = existsSync60(authoritativePromptPath) ? await readFile38(authoritativePromptPath, "utf-8").catch(() => void 0) : void 0;
|
|
215583
|
+
const planningAttempt = {
|
|
215584
|
+
id: `${task.id}:${++this.planningAttemptSequence}`,
|
|
215585
|
+
baseline: planningAttemptBaseline,
|
|
215586
|
+
fallbackEngaged: false,
|
|
215587
|
+
fallbackSettlements: []
|
|
215588
|
+
};
|
|
215589
|
+
const fallbackObserver = createFallbackModelObserver({
|
|
215590
|
+
agent: "triage",
|
|
215591
|
+
label: "triage",
|
|
215592
|
+
store: this.store,
|
|
215593
|
+
taskId: task.id,
|
|
215594
|
+
taskTitle: task.title
|
|
215595
|
+
});
|
|
215596
|
+
const onFallbackModelUsed = (payload) => {
|
|
215597
|
+
planningAttempt.fallbackEngaged = true;
|
|
215598
|
+
const settlement = Promise.resolve(fallbackObserver(payload));
|
|
215599
|
+
planningAttempt.fallbackSettlements.push(settlement);
|
|
215600
|
+
return settlement;
|
|
215601
|
+
};
|
|
215602
|
+
const { session, settleFallbackDispatch, runtimeId } = await createResolvedAgentSession({
|
|
215613
215603
|
sessionPurpose: "triage",
|
|
215614
215604
|
runtimeHint: triageRuntimeHint,
|
|
215615
215605
|
pluginRunner: this.options.pluginRunner,
|
|
@@ -215648,13 +215638,7 @@ You are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.
|
|
|
215648
215638
|
taskTitle: task.title,
|
|
215649
215639
|
actionGateContext: this.buildActionGateContext(task.id, triageRunContext.runId, assignedAgent, settings.defaultAgentPermissionPolicy),
|
|
215650
215640
|
permanentAgentGating: this.buildPermanentAgentGatingContext(task.id, triageRunContext.runId, assignedAgent, settings.defaultAgentPermissionPolicy),
|
|
215651
|
-
onFallbackModelUsed
|
|
215652
|
-
agent: "triage",
|
|
215653
|
-
label: "triage",
|
|
215654
|
-
store: this.store,
|
|
215655
|
-
taskId: task.id,
|
|
215656
|
-
taskTitle: task.title
|
|
215657
|
-
})
|
|
215641
|
+
onFallbackModelUsed
|
|
215658
215642
|
});
|
|
215659
215643
|
const modelDesc = formatModelMarkerDetails(describeModel(session), resolvePlanningThinkingLevel(settings, task.planningThinkingLevel ?? task.thinkingLevel));
|
|
215660
215644
|
planLog.debug(`${task.id}: using model ${modelDesc}`);
|
|
@@ -215724,6 +215708,10 @@ You are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.
|
|
|
215724
215708
|
agentPrompt,
|
|
215725
215709
|
imageContents.length > 0 ? { images: imageContents } : void 0
|
|
215726
215710
|
);
|
|
215711
|
+
const fallbackDispatchBoundaryMissing = typeof settleFallbackDispatch !== "function";
|
|
215712
|
+
if (!fallbackDispatchBoundaryMissing) {
|
|
215713
|
+
await settleFallbackDispatch();
|
|
215714
|
+
}
|
|
215727
215715
|
checkSessionError(session);
|
|
215728
215716
|
if (this.pauseAborted.has(task.id)) {
|
|
215729
215717
|
this.pauseAborted.delete(task.id);
|
|
@@ -215816,12 +215804,42 @@ You are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.
|
|
|
215816
215804
|
}
|
|
215817
215805
|
}
|
|
215818
215806
|
}
|
|
215819
|
-
|
|
215820
|
-
|
|
215821
|
-
|
|
215822
|
-
|
|
215823
|
-
|
|
215824
|
-
|
|
215807
|
+
let settledFallbackCount = 0;
|
|
215808
|
+
while (settledFallbackCount < planningAttempt.fallbackSettlements.length) {
|
|
215809
|
+
const pendingSettlements = planningAttempt.fallbackSettlements.slice(settledFallbackCount);
|
|
215810
|
+
settledFallbackCount = planningAttempt.fallbackSettlements.length;
|
|
215811
|
+
await Promise.all(pendingSettlements);
|
|
215812
|
+
}
|
|
215813
|
+
const artifactChangedByAttempt = planningAttempt.baseline !== written;
|
|
215814
|
+
if (fallbackDispatchBoundaryMissing || planningAttempt.fallbackEngaged || !artifactChangedByAttempt) {
|
|
215815
|
+
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}`;
|
|
215816
|
+
const decision = computeRecoveryDecision({
|
|
215817
|
+
recoveryRetryCount: task.recoveryRetryCount,
|
|
215818
|
+
nextRecoveryAt: task.nextRecoveryAt
|
|
215819
|
+
});
|
|
215820
|
+
if (decision.shouldRetry) {
|
|
215821
|
+
const retryMessage = `${failure} \u2014 retry ${decision.nextState.recoveryRetryCount}/${MAX_RECOVERY_RETRIES} in ${formatDelay(decision.delayMs)}.`;
|
|
215822
|
+
planLog.warn(`${task.id} ${retryMessage}`);
|
|
215823
|
+
await this.store.logEntry(task.id, retryMessage);
|
|
215824
|
+
await this.updatePlanningStateIfStillCurrent(task, {
|
|
215825
|
+
status: this.restoreStatusAfterInterruptedTriageWork(task),
|
|
215826
|
+
error: null,
|
|
215827
|
+
recoveryRetryCount: decision.nextState.recoveryRetryCount,
|
|
215828
|
+
nextRecoveryAt: decision.nextState.nextRecoveryAt
|
|
215829
|
+
});
|
|
215830
|
+
return;
|
|
215831
|
+
}
|
|
215832
|
+
const failureMessage = `${failure} after ${MAX_RECOVERY_RETRIES} retries. Retry after adjusting the task prompt or model.`;
|
|
215833
|
+
planLog.error(`${task.id} clean planning attempt retry budget exhausted`);
|
|
215834
|
+
await this.store.logEntry(task.id, failureMessage);
|
|
215835
|
+
if (await this.updatePlanningStateIfStillCurrent(task, {
|
|
215836
|
+
status: "failed",
|
|
215837
|
+
error: failureMessage,
|
|
215838
|
+
recoveryRetryCount: null,
|
|
215839
|
+
nextRecoveryAt: null
|
|
215840
|
+
})) {
|
|
215841
|
+
await this.backfillBlankTitleAfterTerminalTriageFailure(task);
|
|
215842
|
+
}
|
|
215825
215843
|
return;
|
|
215826
215844
|
}
|
|
215827
215845
|
const deterministicSpecFailure = await this.validateGeneratedPrompt(task.id, written);
|
|
@@ -215863,6 +215881,21 @@ You are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.
|
|
|
215863
215881
|
}
|
|
215864
215882
|
return;
|
|
215865
215883
|
}
|
|
215884
|
+
const duplicateReport = { outcome: "parked" };
|
|
215885
|
+
if (await this.tryFinalizeExplicitDuplicateMarker(task, written, settings, {
|
|
215886
|
+
isReplan,
|
|
215887
|
+
feedback
|
|
215888
|
+
}, duplicateReport)) {
|
|
215889
|
+
this.options.onSpecifyComplete?.(task, duplicateReport);
|
|
215890
|
+
return;
|
|
215891
|
+
}
|
|
215892
|
+
if (task.recoveryRetryCount != null || task.nextRecoveryAt != null) {
|
|
215893
|
+
await this.updatePlanningStateIfStillCurrent(task, {
|
|
215894
|
+
error: null,
|
|
215895
|
+
recoveryRetryCount: null,
|
|
215896
|
+
nextRecoveryAt: null
|
|
215897
|
+
});
|
|
215898
|
+
}
|
|
215866
215899
|
const finalizeReport = await this.finalizeApprovedTask(task, written, settings, {
|
|
215867
215900
|
isReplan,
|
|
215868
215901
|
feedback
|
|
@@ -216899,103 +216932,35 @@ Remove or replace these ids and call fn_task_create again.`
|
|
|
216899
216932
|
// ../engine/src/execution-block-classifier.ts
|
|
216900
216933
|
function partitionBlockedByRefs(blockedBy) {
|
|
216901
216934
|
const taskIds = [];
|
|
216902
|
-
const prNumbers = [];
|
|
216903
216935
|
for (const raw of blockedBy) {
|
|
216904
216936
|
const id = raw.trim();
|
|
216905
216937
|
if (!id) continue;
|
|
216906
|
-
|
|
216907
|
-
if (prMatch) {
|
|
216908
|
-
prNumbers.push(Number(prMatch[1]));
|
|
216909
|
-
continue;
|
|
216910
|
-
}
|
|
216938
|
+
if (LEGACY_PR_REF_RE.test(id)) continue;
|
|
216911
216939
|
if (TASK_ID_RE.test(id)) {
|
|
216912
216940
|
const m2 = id.toUpperCase().match(/^([A-Z][A-Z0-9]*)-(\d+)$/);
|
|
216913
216941
|
taskIds.push(m2 ? `${m2[1]}-${m2[2]}` : id.toUpperCase());
|
|
216914
|
-
continue;
|
|
216915
216942
|
}
|
|
216916
216943
|
}
|
|
216917
|
-
return {
|
|
216918
|
-
taskIds: [...new Set(taskIds)],
|
|
216919
|
-
prNumbers: [...new Set(prNumbers.filter((n) => Number.isFinite(n) && n > 0))]
|
|
216920
|
-
};
|
|
216944
|
+
return { taskIds: [...new Set(taskIds)] };
|
|
216921
216945
|
}
|
|
216922
|
-
function
|
|
216923
|
-
const
|
|
216924
|
-
|
|
216925
|
-
const n = Number(match[1]);
|
|
216926
|
-
if (Number.isFinite(n) && n > 0) found.push(n);
|
|
216927
|
-
}
|
|
216928
|
-
return [...new Set(found)];
|
|
216929
|
-
}
|
|
216930
|
-
function isFileClaimBlockedReason(reason) {
|
|
216931
|
-
return CLAIM_REASON_RE.test(reason);
|
|
216932
|
-
}
|
|
216933
|
-
function classifyBlockedExit(reason, blockedBy = []) {
|
|
216934
|
-
const trimmed = reason.trim();
|
|
216935
|
-
const partitioned = partitionBlockedByRefs(blockedBy);
|
|
216936
|
-
const prFromText = extractPrNumbersFromText(trimmed);
|
|
216937
|
-
const prNumbers = [.../* @__PURE__ */ new Set([...partitioned.prNumbers, ...prFromText])];
|
|
216938
|
-
const isClaim = isFileClaimBlockedReason(trimmed) || prNumbers.length > 0 && /claim/i.test(trimmed);
|
|
216939
|
-
if (isClaim || prNumbers.length > 0 && isFileClaimBlockedReason(trimmed)) {
|
|
216940
|
-
const externalBlockers = [
|
|
216941
|
-
...prNumbers.map((number4) => ({ kind: "github-pr", number: number4 }))
|
|
216942
|
-
];
|
|
216943
|
-
if (externalBlockers.length === 0 && isClaim) {
|
|
216944
|
-
externalBlockers.push({
|
|
216945
|
-
kind: "file-claim",
|
|
216946
|
-
prNumber: prNumbers[0]
|
|
216947
|
-
});
|
|
216948
|
-
} else if (isClaim) {
|
|
216949
|
-
for (const n of prNumbers) {
|
|
216950
|
-
if (!externalBlockers.some((b3) => b3.kind === "github-pr" && b3.number === n)) {
|
|
216951
|
-
externalBlockers.push({ kind: "github-pr", number: n });
|
|
216952
|
-
}
|
|
216953
|
-
}
|
|
216954
|
-
if (prNumbers.length === 0) {
|
|
216955
|
-
externalBlockers.push({ kind: "file-claim" });
|
|
216956
|
-
}
|
|
216957
|
-
}
|
|
216958
|
-
const thrashSignature = [
|
|
216959
|
-
"file-claim",
|
|
216960
|
-
...prNumbers.map((n) => `pr:${n}`).sort(),
|
|
216961
|
-
...partitioned.taskIds.slice().sort()
|
|
216962
|
-
].join("|");
|
|
216963
|
-
return {
|
|
216964
|
-
allowAutoReplan: false,
|
|
216965
|
-
class: "file-claim",
|
|
216966
|
-
externalBlockers,
|
|
216967
|
-
thrashSignature: thrashSignature || "file-claim",
|
|
216968
|
-
prNumbers
|
|
216969
|
-
};
|
|
216970
|
-
}
|
|
216971
|
-
if (partitioned.taskIds.length > 0) {
|
|
216946
|
+
function classifyBlockedExit(_reason, blockedBy = []) {
|
|
216947
|
+
const { taskIds } = partitionBlockedByRefs(blockedBy);
|
|
216948
|
+
if (taskIds.length > 0) {
|
|
216972
216949
|
return {
|
|
216973
216950
|
allowAutoReplan: false,
|
|
216974
216951
|
class: "external",
|
|
216975
|
-
|
|
216976
|
-
thrashSignature: `tasks:${partitioned.taskIds.slice().sort().join(",")}`,
|
|
216977
|
-
prNumbers
|
|
216978
|
-
};
|
|
216979
|
-
}
|
|
216980
|
-
if (prNumbers.length > 0) {
|
|
216981
|
-
return {
|
|
216982
|
-
allowAutoReplan: false,
|
|
216983
|
-
class: "external",
|
|
216984
|
-
externalBlockers: prNumbers.map((number4) => ({ kind: "github-pr", number: number4 })),
|
|
216985
|
-
thrashSignature: prNumbers.map((n) => `pr:${n}`).sort().join("|"),
|
|
216986
|
-
prNumbers
|
|
216952
|
+
thrashSignature: `tasks:${taskIds.slice().sort().join(",")}`
|
|
216987
216953
|
};
|
|
216988
216954
|
}
|
|
216989
216955
|
return {
|
|
216990
216956
|
allowAutoReplan: true,
|
|
216991
216957
|
class: "plan-defect",
|
|
216992
|
-
|
|
216993
|
-
thrashSignature: "plan-defect",
|
|
216994
|
-
prNumbers: []
|
|
216958
|
+
thrashSignature: "plan-defect"
|
|
216995
216959
|
};
|
|
216996
216960
|
}
|
|
216997
216961
|
function countBlockedThrashHits(log43, signature, nowMs = Date.now(), windowMs = BLOCKED_THRASH_WINDOW_MS) {
|
|
216998
216962
|
if (!log43?.length) return 0;
|
|
216963
|
+
if (signature === "plan-defect") return 0;
|
|
216999
216964
|
const cutoff = nowMs - windowMs;
|
|
217000
216965
|
let count2 = 0;
|
|
217001
216966
|
for (const entry of log43) {
|
|
@@ -217007,18 +216972,7 @@ function countBlockedThrashHits(log43, signature, nowMs = Date.now(), windowMs =
|
|
|
217007
216972
|
continue;
|
|
217008
216973
|
}
|
|
217009
216974
|
}
|
|
217010
|
-
if (signature === "plan-defect") continue;
|
|
217011
|
-
if (signature.includes("file-claim") || signature.startsWith("pr:") || signature.includes("|pr:")) {
|
|
217012
|
-
if (isFileClaimBlockedReason(action) || /PR\s*#?\s*\d+/i.test(action) || action.includes("durable external block")) {
|
|
217013
|
-
count2 += 1;
|
|
217014
|
-
continue;
|
|
217015
|
-
}
|
|
217016
|
-
}
|
|
217017
216975
|
for (const part of signature.split("|")) {
|
|
217018
|
-
if (part.startsWith("pr:") && action.includes(`PR #${part.slice(3)}`)) {
|
|
217019
|
-
count2 += 1;
|
|
217020
|
-
break;
|
|
217021
|
-
}
|
|
217022
216976
|
if (part.startsWith("tasks:") && part.slice(6).split(",").some((id) => id && action.includes(id))) {
|
|
217023
216977
|
count2 += 1;
|
|
217024
216978
|
break;
|
|
@@ -217027,38 +216981,26 @@ function countBlockedThrashHits(log43, signature, nowMs = Date.now(), windowMs =
|
|
|
217027
216981
|
}
|
|
217028
216982
|
return count2;
|
|
217029
216983
|
}
|
|
217030
|
-
function isDurableBlockedError(error3) {
|
|
217031
|
-
if (!error3?.startsWith("BLOCKED:")) return false;
|
|
217032
|
-
const reason = error3.slice("BLOCKED:".length).trim();
|
|
217033
|
-
const classification = classifyBlockedExit(reason, []);
|
|
217034
|
-
return !classification.allowAutoReplan;
|
|
217035
|
-
}
|
|
217036
216984
|
function isDurableBlockedTask(task) {
|
|
217037
|
-
if (task.status === "failed" && isDurableBlockedError(task.error)) return true;
|
|
217038
216985
|
const meta2 = task.sourceMetadata;
|
|
217039
216986
|
if (!meta2 || typeof meta2 !== "object") return false;
|
|
217040
|
-
if (meta2.blockedClass
|
|
217041
|
-
|
|
217042
|
-
}
|
|
217043
|
-
const blockers = meta2.externalBlockers;
|
|
217044
|
-
return Array.isArray(blockers) && blockers.length > 0 && task.status === "failed";
|
|
216987
|
+
if (meta2.blockedClass !== "external") return false;
|
|
216988
|
+
return task.status === "failed" || task.status === "needs-replan";
|
|
217045
216989
|
}
|
|
217046
216990
|
function buildExternalBlockMetadataPatch(classification, thrashCount) {
|
|
217047
216991
|
return {
|
|
217048
216992
|
blockedClass: classification.class,
|
|
217049
216993
|
blockedThrashSignature: classification.thrashSignature,
|
|
217050
216994
|
blockedThrashCount: thrashCount,
|
|
217051
|
-
externalBlockers:
|
|
216995
|
+
externalBlockers: []
|
|
217052
216996
|
};
|
|
217053
216997
|
}
|
|
217054
|
-
var TASK_ID_RE,
|
|
216998
|
+
var TASK_ID_RE, LEGACY_PR_REF_RE, BLOCKED_THRASH_LIMIT, BLOCKED_THRASH_WINDOW_MS;
|
|
217055
216999
|
var init_execution_block_classifier = __esm({
|
|
217056
217000
|
"../engine/src/execution-block-classifier.ts"() {
|
|
217057
217001
|
"use strict";
|
|
217058
217002
|
TASK_ID_RE = /^[A-Z][A-Z0-9]*-\d+$/i;
|
|
217059
|
-
|
|
217060
|
-
PR_IN_TEXT_RE = /\bPR\s*#?\s*(\d+)\b/gi;
|
|
217061
|
-
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;
|
|
217003
|
+
LEGACY_PR_REF_RE = /^(?:pr[:#-]|#|PR-)(\d+)$/i;
|
|
217062
217004
|
BLOCKED_THRASH_LIMIT = 3;
|
|
217063
217005
|
BLOCKED_THRASH_WINDOW_MS = 60 * 60 * 1e3;
|
|
217064
217006
|
}
|
|
@@ -219876,7 +219818,7 @@ var init_workflow_completion_summary = __esm({
|
|
|
219876
219818
|
|
|
219877
219819
|
// ../engine/src/review-checkout.ts
|
|
219878
219820
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
219879
|
-
import { existsSync as
|
|
219821
|
+
import { existsSync as existsSync61, realpathSync as realpathSync9, statSync as statSync11 } from "node:fs";
|
|
219880
219822
|
import { isAbsolute as isAbsolute15 } from "node:path";
|
|
219881
219823
|
function readMetadataPath(value) {
|
|
219882
219824
|
if (!value || typeof value !== "object") return void 0;
|
|
@@ -219900,7 +219842,7 @@ function resolveReviewCheckoutCwd(task, fallbackCwd) {
|
|
|
219900
219842
|
const candidate = getTaskReviewCheckoutPath(task);
|
|
219901
219843
|
if (!candidate || !isAbsolute15(candidate)) return fallbackCwd;
|
|
219902
219844
|
try {
|
|
219903
|
-
if (!
|
|
219845
|
+
if (!existsSync61(candidate) || !statSync11(candidate).isDirectory()) return fallbackCwd;
|
|
219904
219846
|
const realCandidate = realpathSync9(candidate);
|
|
219905
219847
|
const topLevel = execFileSync3("git", ["rev-parse", "--show-toplevel"], {
|
|
219906
219848
|
cwd: realCandidate,
|
|
@@ -222506,7 +222448,7 @@ var init_external_integration_evidence = __esm({
|
|
|
222506
222448
|
|
|
222507
222449
|
// ../engine/src/step-runner.ts
|
|
222508
222450
|
import { exec as exec35 } from "node:child_process";
|
|
222509
|
-
import { existsSync as
|
|
222451
|
+
import { existsSync as existsSync63, statSync as statSync12 } from "node:fs";
|
|
222510
222452
|
import { promisify as promisify50 } from "node:util";
|
|
222511
222453
|
async function runTaskStep(deps, task, stepIndex, opts = {}) {
|
|
222512
222454
|
const { store, worktreePath } = deps;
|
|
@@ -222660,7 +222602,7 @@ function makeAncestryBlastRadiusGuard(opts) {
|
|
|
222660
222602
|
function isUsableWorktreeDirectory(candidate) {
|
|
222661
222603
|
if (!candidate) return false;
|
|
222662
222604
|
try {
|
|
222663
|
-
return
|
|
222605
|
+
return existsSync63(candidate) && statSync12(candidate).isDirectory();
|
|
222664
222606
|
} catch {
|
|
222665
222607
|
return false;
|
|
222666
222608
|
}
|
|
@@ -222697,7 +222639,7 @@ var init_step_runner = __esm({
|
|
|
222697
222639
|
|
|
222698
222640
|
// ../engine/src/auto-recovery-handlers/branch-worktree.ts
|
|
222699
222641
|
import { exec as exec36 } from "node:child_process";
|
|
222700
|
-
import { existsSync as
|
|
222642
|
+
import { existsSync as existsSync64 } from "node:fs";
|
|
222701
222643
|
import { promisify as promisify51 } from "node:util";
|
|
222702
222644
|
var execAsync33, baseLog2, GIT_TIMEOUT_MS8, GIT_MAX_BUFFER6, BranchWorktreeAutoRecoveryHandler;
|
|
222703
222645
|
var init_branch_worktree = __esm({
|
|
@@ -222888,7 +222830,7 @@ var init_branch_worktree = __esm({
|
|
|
222888
222830
|
if (inspection.kind === "stale-resolved" || inspection.kind === "fully-subsumed" || inspection.kind === "tip-already-merged") {
|
|
222889
222831
|
await this.requeueAfterRecovery(ctx.task, failure, inspection.kind, {
|
|
222890
222832
|
branchExists: await this.hasBranchRef(repoDir, branchName),
|
|
222891
|
-
worktreePresent:
|
|
222833
|
+
worktreePresent: existsSync64(conflictingWorktreePath),
|
|
222892
222834
|
tipSha: "tipSha" in inspection ? inspection.tipSha : void 0,
|
|
222893
222835
|
inspectionKind: inspection.kind
|
|
222894
222836
|
});
|
|
@@ -222958,7 +222900,7 @@ var init_branch_worktree = __esm({
|
|
|
222958
222900
|
let branchDeleted = false;
|
|
222959
222901
|
let worktreeRemoved = false;
|
|
222960
222902
|
if (!isLiveOwned) {
|
|
222961
|
-
if (
|
|
222903
|
+
if (existsSync64(conflictingWorktreePath)) {
|
|
222962
222904
|
try {
|
|
222963
222905
|
await execAsync33(`git worktree remove --force ${this.quote(conflictingWorktreePath)}`, {
|
|
222964
222906
|
cwd: repoDir,
|
|
@@ -223006,7 +222948,7 @@ var init_branch_worktree = __esm({
|
|
|
223006
222948
|
});
|
|
223007
222949
|
await this.requeueAfterRecovery(ctx.task, failure, "live-foreign-discard-and-recreate", {
|
|
223008
222950
|
branchExists: !branchDeleted,
|
|
223009
|
-
worktreePresent: !worktreeRemoved &&
|
|
222951
|
+
worktreePresent: !worktreeRemoved && existsSync64(conflictingWorktreePath),
|
|
223010
222952
|
tipSha: tipSha2,
|
|
223011
222953
|
inspectionKind: inspection.kind
|
|
223012
222954
|
});
|
|
@@ -223019,7 +222961,7 @@ var init_branch_worktree = __esm({
|
|
|
223019
222961
|
conflictingWorktreePath,
|
|
223020
222962
|
inspectionKind: inspection.kind,
|
|
223021
222963
|
branchExists,
|
|
223022
|
-
worktreePresent:
|
|
222964
|
+
worktreePresent: existsSync64(conflictingWorktreePath),
|
|
223023
222965
|
tipSha
|
|
223024
222966
|
});
|
|
223025
222967
|
}
|
|
@@ -223180,7 +223122,7 @@ var init_file_scope2 = __esm({
|
|
|
223180
223122
|
});
|
|
223181
223123
|
|
|
223182
223124
|
// ../engine/src/run-verification-tool.ts
|
|
223183
|
-
import { existsSync as
|
|
223125
|
+
import { existsSync as existsSync65, readdirSync as readdirSync11, readFileSync as readFileSync23 } from "node:fs";
|
|
223184
223126
|
import { isAbsolute as isAbsolute16, join as join77, relative as relative14 } from "node:path";
|
|
223185
223127
|
import { Type as Type6 } from "@earendil-works/pi-ai";
|
|
223186
223128
|
function shellSplit(input) {
|
|
@@ -223740,7 +223682,7 @@ function createRunVerificationTool(opts) {
|
|
|
223740
223682
|
}
|
|
223741
223683
|
if (effectiveCommand.trimStart().startsWith("pnpm --filter")) {
|
|
223742
223684
|
const modulesYaml = join77(rootDir, "node_modules", ".modules.yaml");
|
|
223743
|
-
if (!
|
|
223685
|
+
if (!existsSync65(modulesYaml)) {
|
|
223744
223686
|
const installCmd = "pnpm install --prefer-offline";
|
|
223745
223687
|
const msg = `node_modules/.modules.yaml not found in workspace root \u2014 auto-prepending \`${installCmd}\` before running the command.`;
|
|
223746
223688
|
warnings.push(msg);
|
|
@@ -224101,7 +224043,7 @@ import { exec as exec39, execFile as execFile26, execSync as execSync7 } from "n
|
|
|
224101
224043
|
import { promisify as promisify54 } from "node:util";
|
|
224102
224044
|
import { setImmediate as setImmediateCb3 } from "node:timers";
|
|
224103
224045
|
import { basename as basename19, delimiter as delimiter2, isAbsolute as isAbsolute18, join as join78, relative as relative16, resolve as resolvePath3 } from "node:path";
|
|
224104
|
-
import { existsSync as
|
|
224046
|
+
import { existsSync as existsSync66, lstatSync as lstatSync3, realpathSync as realpathSync10 } from "node:fs";
|
|
224105
224047
|
import { readFile as readFile40, rm as rm12, writeFile as writeFile29 } from "node:fs/promises";
|
|
224106
224048
|
import { Type as Type7 } from "@earendil-works/pi-ai";
|
|
224107
224049
|
import { SessionManager as SessionManager2 } from "@earendil-works/pi-coding-agent";
|
|
@@ -224119,7 +224061,7 @@ function isWorkflowStepSkillDiscoverable(skillName, additionalSkillPaths, ceSkil
|
|
|
224119
224061
|
return false;
|
|
224120
224062
|
}
|
|
224121
224063
|
return (additionalSkillPaths ?? []).some(
|
|
224122
|
-
(skillPath) => basename19(skillPath) === bareSkillName2 &&
|
|
224064
|
+
(skillPath) => basename19(skillPath) === bareSkillName2 && existsSync66(join78(skillPath, "SKILL.md")) || existsSync66(join78(skillPath, bareSkillName2, "SKILL.md"))
|
|
224123
224065
|
);
|
|
224124
224066
|
}
|
|
224125
224067
|
function getPromptSection(prompt, heading) {
|
|
@@ -225092,7 +225034,7 @@ If you have just finished a step's work, immediately call \`fn_task_update\` to
|
|
|
225092
225034
|
|
|
225093
225035
|
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.
|
|
225094
225036
|
|
|
225095
|
-
**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
|
|
225037
|
+
**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.
|
|
225096
225038
|
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.
|
|
225097
225039
|
|
|
225098
225040
|
## How to work
|
|
@@ -227681,7 +227623,7 @@ The tool prevents your session from being killed by the inactivity watchdog duri
|
|
|
227681
227623
|
);
|
|
227682
227624
|
return false;
|
|
227683
227625
|
}
|
|
227684
|
-
if (task.worktree &&
|
|
227626
|
+
if (task.worktree && existsSync66(task.worktree)) {
|
|
227685
227627
|
const modifiedFiles = await this.captureModifiedFiles(task.worktree, task.baseCommitSha, task.id, void 0, "recovery");
|
|
227686
227628
|
if (modifiedFiles.length > 0) {
|
|
227687
227629
|
await this.store.updateTask(task.id, { modifiedFiles });
|
|
@@ -230643,7 +230585,7 @@ ${info.feedback}`, revisionKey),
|
|
|
230643
230585
|
if (live.firstExecutionAt || live.executionStartedAt) return false;
|
|
230644
230586
|
if (activeSessionRegistry.isPathActive(live.worktree) || activeSessionRegistry.isPathActive(resolvePath3(live.worktree))) return false;
|
|
230645
230587
|
if (this.hasLiveTaskSessionSurface(taskId) || executingTaskLock.has(taskId)) return false;
|
|
230646
|
-
if (
|
|
230588
|
+
if (existsSync66(live.worktree)) {
|
|
230647
230589
|
if (await this.preExecutionWorktreeHasWork(live.worktree)) {
|
|
230648
230590
|
executorLog.log(`${taskId}: keeping pre-execution worktree ${live.worktree} \u2014 it carries commits or uncommitted changes`);
|
|
230649
230591
|
return false;
|
|
@@ -230685,7 +230627,7 @@ ${info.feedback}`, revisionKey),
|
|
|
230685
230627
|
}
|
|
230686
230628
|
if (this.workspaceConfig && (this.workspaceConfig.repos.length ?? 0) > 0) return null;
|
|
230687
230629
|
const live = await this.store.getTask(taskId);
|
|
230688
|
-
if (live.worktree &&
|
|
230630
|
+
if (live.worktree && existsSync66(live.worktree)) return live.worktree;
|
|
230689
230631
|
const settings = await this.store.getSettings();
|
|
230690
230632
|
const acquisitionTask = live.worktree ? { ...live, worktree: void 0, sessionFile: void 0 } : live;
|
|
230691
230633
|
const acquired = await this.ensureGraphCustomNodeWorktree(acquisitionTask, settings, "planning");
|
|
@@ -230699,8 +230641,8 @@ ${info.feedback}`, revisionKey),
|
|
|
230699
230641
|
if (!requirement.requiresWorktree) return;
|
|
230700
230642
|
const live = await this.store.getTask(nodeTask.id);
|
|
230701
230643
|
const executionCodeNode = node.kind === "code";
|
|
230702
|
-
if (live.worktree &&
|
|
230703
|
-
const taskForAcquisition = live.worktree && !
|
|
230644
|
+
if (live.worktree && existsSync66(live.worktree) && !executionCodeNode) return;
|
|
230645
|
+
const taskForAcquisition = live.worktree && !existsSync66(live.worktree) ? { ...live, worktree: void 0, sessionFile: void 0 } : live;
|
|
230704
230646
|
if (live.worktree) {
|
|
230705
230647
|
await this.store.logEntry(
|
|
230706
230648
|
live.id,
|
|
@@ -230826,7 +230768,7 @@ ${info.feedback}`, revisionKey),
|
|
|
230826
230768
|
const nodeDisplayName = typeof cfg.name === "string" && cfg.name.trim() ? cfg.name.trim() : node.id;
|
|
230827
230769
|
const isPlanReviewNode = node.id === "plan-review-step" || nodeDisplayName === "Plan Review" || optionalGroupId === "plan-review";
|
|
230828
230770
|
if (!this.workspaceConfig) {
|
|
230829
|
-
const recordedWorktreeMissing = Boolean(executionTarget.worktree) && !
|
|
230771
|
+
const recordedWorktreeMissing = Boolean(executionTarget.worktree) && !existsSync66(executionTarget.worktree);
|
|
230830
230772
|
const shouldAcquire = !executionTarget.worktree || recordedWorktreeMissing && isPlanReviewNode;
|
|
230831
230773
|
if (shouldAcquire) {
|
|
230832
230774
|
if (recordedWorktreeMissing) {
|
|
@@ -232500,75 +232442,16 @@ Graph value: ${failureValue}` : ""}`, budget.key),
|
|
|
232500
232442
|
);
|
|
232501
232443
|
}
|
|
232502
232444
|
}
|
|
232503
|
-
/*
|
|
232504
|
-
FNXC:HonestBlockedExit 2026-08-02-01:30:
|
|
232505
|
-
Agents often log `BLOCKED: … actively claimed by PR #N` without calling fn_task_done.
|
|
232506
|
-
Without promotion, incomplete-step graph resume requeues the card and thrash restarts
|
|
232507
|
-
(FN-8700). Promote claim/external blocks to a durable failed park here.
|
|
232508
|
-
*/
|
|
232509
|
-
async parkDurableBlockedFromRecentLog(live) {
|
|
232510
|
-
const recent = [...live.log ?? []].reverse().find((entry) => {
|
|
232511
|
-
const action = entry.action ?? "";
|
|
232512
|
-
return action.startsWith("BLOCKED:") || action.includes("durable external block");
|
|
232513
|
-
});
|
|
232514
|
-
if (!recent?.action) return false;
|
|
232515
|
-
const reason = recent.action.startsWith("BLOCKED:") ? recent.action.slice("BLOCKED:".length).trim() : recent.action;
|
|
232516
|
-
const classification = classifyBlockedExit(reason, []);
|
|
232517
|
-
if (classification.allowAutoReplan) return false;
|
|
232518
|
-
const thrashCount = countBlockedThrashHits(live.log, classification.thrashSignature) + 1;
|
|
232519
|
-
const thrashExhausted = thrashCount >= BLOCKED_THRASH_LIMIT;
|
|
232520
|
-
const parkError = thrashExhausted ? `BLOCKED: ${reason} [thrash-exhausted after ${thrashCount} identical durable blocks]` : `BLOCKED: ${reason}`;
|
|
232521
|
-
const metaPatch = buildExternalBlockMetadataPatch(classification, thrashCount);
|
|
232522
|
-
await this.store.updateTask(live.id, {
|
|
232523
|
-
status: "failed",
|
|
232524
|
-
error: parkError,
|
|
232525
|
-
paused: false,
|
|
232526
|
-
pausedByAgentId: null,
|
|
232527
|
-
sourceMetadataPatch: metaPatch
|
|
232528
|
-
}, this.getRunContextFor(live.id));
|
|
232529
|
-
await this.store.logEntry(
|
|
232530
|
-
live.id,
|
|
232531
|
-
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})`,
|
|
232532
|
-
void 0,
|
|
232533
|
-
this.getRunContextFor(live.id)
|
|
232534
|
-
);
|
|
232535
|
-
await this.store.recordRunAuditEvent?.({
|
|
232536
|
-
taskId: live.id,
|
|
232537
|
-
agentId: "executor",
|
|
232538
|
-
runId: generateSyntheticRunId("execution-blocked-log-promote", live.id),
|
|
232539
|
-
domain: "database",
|
|
232540
|
-
mutationType: "task:execution-blocked-parked",
|
|
232541
|
-
target: live.id,
|
|
232542
|
-
metadata: {
|
|
232543
|
-
taskId: live.id,
|
|
232544
|
-
blockedBy: [],
|
|
232545
|
-
hasReason: true,
|
|
232546
|
-
parkedAs: "failed",
|
|
232547
|
-
blockedClass: classification.class,
|
|
232548
|
-
thrashCount,
|
|
232549
|
-
thrashExhausted,
|
|
232550
|
-
prNumbers: classification.prNumbers,
|
|
232551
|
-
source: "session-log-promote"
|
|
232552
|
-
}
|
|
232553
|
-
});
|
|
232554
|
-
executorLog.warn(
|
|
232555
|
-
`${live.id}: promoted durable BLOCKED from session log (class=${classification.class}; thrash=${thrashCount})`
|
|
232556
|
-
);
|
|
232557
|
-
return true;
|
|
232558
|
-
}
|
|
232559
232445
|
async routeGraphFailureToExecutionResume(live, failedNode, failureValue, resumeLanesMemo) {
|
|
232560
232446
|
if (live.deletedAt) return false;
|
|
232561
232447
|
if (live.paused || live.userPaused === true) return false;
|
|
232562
232448
|
if ((await resolveTerminalColumnsFor(this.store, live.id)).includes(live.column)) return false;
|
|
232563
|
-
if (isDurableBlockedTask(live)
|
|
232449
|
+
if (isDurableBlockedTask(live)) {
|
|
232564
232450
|
executorLog.log(
|
|
232565
|
-
`${live.id}: graph failure resume skipped \u2014 durable BLOCKED park honored (
|
|
232451
|
+
`${live.id}: graph failure resume skipped \u2014 durable BLOCKED park honored (task-dependency block)`
|
|
232566
232452
|
);
|
|
232567
232453
|
return false;
|
|
232568
232454
|
}
|
|
232569
|
-
if (await this.parkDurableBlockedFromRecentLog(live)) {
|
|
232570
|
-
return false;
|
|
232571
|
-
}
|
|
232572
232455
|
if (failedNode === COMPLETION_SUMMARY_NODE_ID) return false;
|
|
232573
232456
|
const incompleteSteps = hasNonTerminalWorkflowSteps(live);
|
|
232574
232457
|
const implementationIncompleteMergeFailure = this.isMergeGraphFailure(failedNode) && failureValue === "implementation-incomplete";
|
|
@@ -233749,7 +233632,7 @@ ${summary}`,
|
|
|
233749
233632
|
executorLog.warn(`\u26A1 ${task.id} transient error \u2014 retry ${attempt}/${MAX_RECOVERY_RETRIES} in ${delay6}: ${errorMessage5}`);
|
|
233750
233633
|
await this.store.logEntry(task.id, `Transient error (retry ${attempt}/${MAX_RECOVERY_RETRIES} in ${delay6}): ${errorMessage5}`, void 0, this.getRunContextFor(task.id));
|
|
233751
233634
|
}
|
|
233752
|
-
if (worktreePath &&
|
|
233635
|
+
if (worktreePath && existsSync66(worktreePath)) {
|
|
233753
233636
|
try {
|
|
233754
233637
|
const settings2 = await this.store.getSettings();
|
|
233755
233638
|
await removeWorktree({
|
|
@@ -233830,7 +233713,7 @@ ${summary}`,
|
|
|
233830
233713
|
const settings2 = await this.store.getSettings();
|
|
233831
233714
|
const preserveProgress = settings2.preserveProgressOnStuckRequeue !== false;
|
|
233832
233715
|
await this.resetStepsIfWorkLost(latestTask);
|
|
233833
|
-
if (worktreePath &&
|
|
233716
|
+
if (worktreePath && existsSync66(worktreePath)) {
|
|
233834
233717
|
try {
|
|
233835
233718
|
await removeWorktree({
|
|
233836
233719
|
worktreePath,
|
|
@@ -234113,7 +233996,7 @@ ${summary}`,
|
|
|
234113
233996
|
nodeId: detail.effectiveNodeId ?? detail.nodeId ?? null,
|
|
234114
233997
|
agentId: engineRunContext.agentId ?? null
|
|
234115
233998
|
});
|
|
234116
|
-
let isResuming = !!task.sessionFile &&
|
|
233999
|
+
let isResuming = !!task.sessionFile && existsSync66(task.sessionFile);
|
|
234117
234000
|
if (isResuming) {
|
|
234118
234001
|
const persistedWorktreePath = await extractPersistedSessionWorktreePath(task.sessionFile, this.rootDir, settings);
|
|
234119
234002
|
if (!isSessionWorktreeCompatible(persistedWorktreePath, worktreePath)) {
|
|
@@ -234894,7 +234777,7 @@ ${summary}`,
|
|
|
234894
234777
|
return;
|
|
234895
234778
|
} else {
|
|
234896
234779
|
executorLog.log(`${task.id} paused \u2014 moving to todo`);
|
|
234897
|
-
if (worktreePath &&
|
|
234780
|
+
if (worktreePath && existsSync66(worktreePath)) {
|
|
234898
234781
|
try {
|
|
234899
234782
|
const settings2 = await this.store.getSettings();
|
|
234900
234783
|
await removeWorktree({
|
|
@@ -235291,7 +235174,7 @@ ${summary}`,
|
|
|
235291
235174
|
executorLog.warn(`\u26A1 ${task.id} transient error \u2014 retry ${attempt}/${MAX_RECOVERY_RETRIES} in ${delay6}: ${errorMessage5}`);
|
|
235292
235175
|
await this.store.logEntry(task.id, `Transient error (retry ${attempt}/${MAX_RECOVERY_RETRIES} in ${delay6}): ${errorMessage5}`, void 0, this.getRunContextFor(task.id));
|
|
235293
235176
|
}
|
|
235294
|
-
if (worktreePath &&
|
|
235177
|
+
if (worktreePath && existsSync66(worktreePath)) {
|
|
235295
235178
|
try {
|
|
235296
235179
|
const settings2 = await this.store.getSettings();
|
|
235297
235180
|
await removeWorktree({
|
|
@@ -235427,7 +235310,7 @@ ${summary}`,
|
|
|
235427
235310
|
const settings2 = await this.store.getSettings();
|
|
235428
235311
|
const preserveProgress = settings2.preserveProgressOnStuckRequeue !== false;
|
|
235429
235312
|
await this.resetStepsIfWorkLost(latestTask);
|
|
235430
|
-
if (worktreePath &&
|
|
235313
|
+
if (worktreePath && existsSync66(worktreePath)) {
|
|
235431
235314
|
try {
|
|
235432
235315
|
await removeWorktree({
|
|
235433
235316
|
worktreePath,
|
|
@@ -235854,7 +235737,7 @@ ${summary}`,
|
|
|
235854
235737
|
for (const repoRel of Object.keys(workspaceWorktrees).sort()) {
|
|
235855
235738
|
const repo = workspaceWorktrees[repoRel];
|
|
235856
235739
|
const expectedBranch = repo.branch || canonicalFusionBranchName(task.id);
|
|
235857
|
-
if (!
|
|
235740
|
+
if (!existsSync66(repo.worktreePath)) {
|
|
235858
235741
|
executorLog.log(`${task.id}: workspace worktree for ${repoRel} not found at ${repo.worktreePath} \u2014 skipping git validation`);
|
|
235859
235742
|
continue;
|
|
235860
235743
|
}
|
|
@@ -235986,7 +235869,7 @@ ${summary}`,
|
|
|
235986
235869
|
expected: `resolvable task worktree under ${resolveWorktreesDir(this.rootDir, settings)}/*`
|
|
235987
235870
|
};
|
|
235988
235871
|
}
|
|
235989
|
-
if (!
|
|
235872
|
+
if (!existsSync66(worktreePath)) {
|
|
235990
235873
|
executorLog.log(
|
|
235991
235874
|
`${task.id}: worktree directory not found at ${worktreePath} \u2014 skipping git validation for task completion`
|
|
235992
235875
|
);
|
|
@@ -236315,10 +236198,10 @@ ${summary}`,
|
|
|
236315
236198
|
{ 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.' }
|
|
236316
236199
|
)),
|
|
236317
236200
|
blockedBy: Type7.Optional(Type7.Array(Type7.String(), {
|
|
236318
|
-
description: 'When outcome="blocked": task IDs (e.g. ["FN-8145"])
|
|
236201
|
+
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.'
|
|
236319
236202
|
})),
|
|
236320
236203
|
reason: Type7.Optional(Type7.String({
|
|
236321
|
-
description: 'Required when outcome="blocked": concrete explanation of what is blocking the work and what is needed to unblock it.
|
|
236204
|
+
description: 'Required when outcome="blocked": concrete explanation of what is blocking the work and what is needed to unblock it.'
|
|
236322
236205
|
}))
|
|
236323
236206
|
}),
|
|
236324
236207
|
execute: async (_id, params) => {
|
|
@@ -236377,7 +236260,7 @@ ${summary}`,
|
|
|
236377
236260
|
}, this.getRunContextFor(taskId));
|
|
236378
236261
|
await store.logEntry(
|
|
236379
236262
|
taskId,
|
|
236380
|
-
thrashExhausted ? `${parkError} \u2014 durable external block thrash-exhausted (signature=${classification.thrashSignature}); parked failed, no auto-requeue` :
|
|
236263
|
+
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)`,
|
|
236381
236264
|
void 0,
|
|
236382
236265
|
this.getRunContextFor(taskId)
|
|
236383
236266
|
);
|
|
@@ -236396,18 +236279,17 @@ ${summary}`,
|
|
|
236396
236279
|
parkedAs: autoReplanPark ? "auto-replan" : "failed",
|
|
236397
236280
|
blockedClass: classification.class,
|
|
236398
236281
|
thrashCount,
|
|
236399
|
-
thrashExhausted
|
|
236400
|
-
prNumbers: classification.prNumbers
|
|
236282
|
+
thrashExhausted
|
|
236401
236283
|
}
|
|
236402
236284
|
});
|
|
236403
236285
|
await this.persistTokenUsage(taskId);
|
|
236404
236286
|
executorLog.log(
|
|
236405
|
-
`\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"}
|
|
236287
|
+
`\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"})`}`
|
|
236406
236288
|
);
|
|
236407
236289
|
return {
|
|
236408
236290
|
content: [{
|
|
236409
236291
|
type: "text",
|
|
236410
|
-
text: autoReplanPark ? "Task parked as blocked with no
|
|
236292
|
+
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.`
|
|
236411
236293
|
}],
|
|
236412
236294
|
details: {}
|
|
236413
236295
|
};
|
|
@@ -238465,7 +238347,7 @@ ${detectedQuestion}
|
|
|
238465
238347
|
* rather than fail the task permanently.
|
|
238466
238348
|
*/
|
|
238467
238349
|
async resolveWorktreeStartPoint(startPoint, taskId) {
|
|
238468
|
-
const command = isAbsolute18(startPoint) &&
|
|
238350
|
+
const command = isAbsolute18(startPoint) && existsSync66(startPoint) ? `git -C "${startPoint}" rev-parse --verify HEAD^{commit}` : `git rev-parse --verify "${startPoint}^{commit}"`;
|
|
238469
238351
|
try {
|
|
238470
238352
|
const { stdout } = await execAsync36(command, { cwd: this.rootDir });
|
|
238471
238353
|
return stdout.trim() || startPoint;
|
|
@@ -238688,7 +238570,7 @@ ${detectedQuestion}
|
|
|
238688
238570
|
throw error3;
|
|
238689
238571
|
}
|
|
238690
238572
|
};
|
|
238691
|
-
if (
|
|
238573
|
+
if (existsSync66(path14)) {
|
|
238692
238574
|
const isRegistered = await this.isRegisteredWorktree(path14);
|
|
238693
238575
|
if (!isRegistered) {
|
|
238694
238576
|
await this.store.logEntry(
|
|
@@ -239304,7 +239186,7 @@ ${detectedQuestion}
|
|
|
239304
239186
|
const stillRegistered = await isRegisteredGitWorktree2(this.rootDir, worktreePath).catch(() => true);
|
|
239305
239187
|
const activeOwner2 = await this.findActiveWorktreeOwner(worktreePath, taskId).catch(() => "unknown");
|
|
239306
239188
|
let safeToRemove = isInsideWorktreesDir(this.rootDir, worktreePath, settings) && !stillRegistered && activeOwner2 === null;
|
|
239307
|
-
if (safeToRemove &&
|
|
239189
|
+
if (safeToRemove && existsSync66(worktreePath)) {
|
|
239308
239190
|
try {
|
|
239309
239191
|
if (lstatSync3(worktreePath).isSymbolicLink()) {
|
|
239310
239192
|
safeToRemove = false;
|
|
@@ -239332,7 +239214,7 @@ ${detectedQuestion}
|
|
|
239332
239214
|
const pruneMsg = pruneErr instanceof Error ? pruneErr.message : String(pruneErr);
|
|
239333
239215
|
executorLog.warn(`${taskId}: git worktree prune failed during stale-path cleanup of ${worktreePath}: ${pruneMsg}`);
|
|
239334
239216
|
}
|
|
239335
|
-
if (
|
|
239217
|
+
if (existsSync66(worktreePath)) {
|
|
239336
239218
|
try {
|
|
239337
239219
|
await rm12(worktreePath, { recursive: true, force: true });
|
|
239338
239220
|
} catch (rmErr) {
|
|
@@ -239779,7 +239661,7 @@ ${detectedQuestion}
|
|
|
239779
239661
|
this.clearPausedAborted(taskId);
|
|
239780
239662
|
await this.resetStepsIfWorkLost(latestTask);
|
|
239781
239663
|
let cleanupFailed = false;
|
|
239782
|
-
if (worktreePath &&
|
|
239664
|
+
if (worktreePath && existsSync66(worktreePath)) {
|
|
239783
239665
|
try {
|
|
239784
239666
|
await removeWorktree({
|
|
239785
239667
|
worktreePath,
|
|
@@ -243866,7 +243748,7 @@ var init_overseer_noop_finalize_veto = __esm({
|
|
|
243866
243748
|
|
|
243867
243749
|
// ../engine/src/merger-ai-worktree.ts
|
|
243868
243750
|
import { execFile as execFile27 } from "node:child_process";
|
|
243869
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
243751
|
+
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";
|
|
243870
243752
|
import { rm as rm13 } from "node:fs/promises";
|
|
243871
243753
|
import { tmpdir as tmpdir10 } from "node:os";
|
|
243872
243754
|
import { isAbsolute as isAbsolute19, join as join79, relative as relative17 } from "node:path";
|
|
@@ -243901,7 +243783,7 @@ function isBenignAbsentWorktreeError(err) {
|
|
|
243901
243783
|
}
|
|
243902
243784
|
function ensureAiMergeRootIgnored(projectRootDir, settings) {
|
|
243903
243785
|
const excludePath = join79(projectRootDir, ".git", "info", "exclude");
|
|
243904
|
-
if (!
|
|
243786
|
+
if (!existsSync67(excludePath)) return;
|
|
243905
243787
|
try {
|
|
243906
243788
|
const current = readFileSync24(excludePath, "utf-8");
|
|
243907
243789
|
const legacyAiMergeRoot = resolveLegacyAiMergeRootPath(projectRootDir);
|
|
@@ -244032,7 +243914,7 @@ async function cleanupAiMergeWorktree(input) {
|
|
|
244032
243914
|
const cleanupMetadata = { taskId, mergeRoot: canonicalRoot, requestedMergeRoot: mergeRoot };
|
|
244033
243915
|
let alreadyAbsent = false;
|
|
244034
243916
|
if (worktreeAdded) {
|
|
244035
|
-
if (!
|
|
243917
|
+
if (!existsSync67(canonicalRoot) && !existsSync67(mergeRoot)) {
|
|
244036
243918
|
alreadyAbsent = true;
|
|
244037
243919
|
await log43(`AI merge cleanup: worktree ${canonicalRoot} was already absent before git removal; treating cleanup as idempotent`);
|
|
244038
243920
|
await audit.git({ type: "merge:ai-worktree-cleanup", target: canonicalRoot, metadata: { ...cleanupMetadata, phase: "git-remove", success: true, alreadyAbsent: true, idempotent: true, code: "ENOENT" } });
|
|
@@ -250354,12 +250236,12 @@ The note must be specific (what/where/why). Prefer citing File Scope, PROMPT, a
|
|
|
250354
250236
|
});
|
|
250355
250237
|
|
|
250356
250238
|
// ../engine/src/overseer-watchdog.ts
|
|
250357
|
-
import { existsSync as
|
|
250239
|
+
import { existsSync as existsSync68, readFileSync as readFileSync25 } from "node:fs";
|
|
250358
250240
|
import { dirname as dirname34, join as join82, relative as relative18, resolve as resolve40, sep as sep11 } from "node:path";
|
|
250359
250241
|
import { homedir as homedir12 } from "node:os";
|
|
250360
250242
|
function defaultReadText(path14) {
|
|
250361
250243
|
try {
|
|
250362
|
-
if (!
|
|
250244
|
+
if (!existsSync68(path14)) return null;
|
|
250363
250245
|
return readFileSync25(path14, "utf8");
|
|
250364
250246
|
} catch {
|
|
250365
250247
|
return null;
|
|
@@ -256160,7 +256042,7 @@ var init_adapters = __esm({
|
|
|
256160
256042
|
});
|
|
256161
256043
|
|
|
256162
256044
|
// ../engine/src/cli-agent/resume-coordinator.ts
|
|
256163
|
-
import { existsSync as
|
|
256045
|
+
import { existsSync as existsSync69 } from "node:fs";
|
|
256164
256046
|
import { execFile as execFile30 } from "node:child_process";
|
|
256165
256047
|
import { promisify as promisify62 } from "node:util";
|
|
256166
256048
|
async function defaultIsWorktreeDirty(worktreePath) {
|
|
@@ -256205,7 +256087,7 @@ var init_resume_coordinator = __esm({
|
|
|
256205
256087
|
this.reattachTelemetry = opts.reattachTelemetry;
|
|
256206
256088
|
this.maxResumeAttempts = opts.maxResumeAttempts ?? DEFAULT_MAX_RESUME_ATTEMPTS;
|
|
256207
256089
|
this.resumeBackoffBaseMs = opts.resumeBackoffBaseMs ?? DEFAULT_RESUME_BACKOFF_BASE_MS;
|
|
256208
|
-
this.worktreeExists = opts.worktreeExists ?? ((p2) =>
|
|
256090
|
+
this.worktreeExists = opts.worktreeExists ?? ((p2) => existsSync69(p2));
|
|
256209
256091
|
this.isWorktreeDirty = opts.isWorktreeDirty ?? defaultIsWorktreeDirty;
|
|
256210
256092
|
this.log = opts.log ?? (() => {
|
|
256211
256093
|
});
|
|
@@ -280583,11 +280465,11 @@ var init_task_lookup_error = __esm({
|
|
|
280583
280465
|
});
|
|
280584
280466
|
|
|
280585
280467
|
// ../dashboard/src/cli-package-version.ts
|
|
280586
|
-
import { existsSync as
|
|
280468
|
+
import { existsSync as existsSync70, readFileSync as readFileSync26 } from "node:fs";
|
|
280587
280469
|
import { dirname as dirname37, resolve as resolve43 } from "node:path";
|
|
280588
280470
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
280589
280471
|
function readPackageVersion(pkgPath, packageNames) {
|
|
280590
|
-
if (!
|
|
280472
|
+
if (!existsSync70(pkgPath)) {
|
|
280591
280473
|
return null;
|
|
280592
280474
|
}
|
|
280593
280475
|
try {
|
|
@@ -294043,7 +293925,7 @@ See \`GET /api/tasks/${task.id}/diff\` for the landed diff being reverted.
|
|
|
294043
293925
|
};
|
|
294044
293926
|
router.get("/tasks/:id/stranded-refinement", async (req, res) => {
|
|
294045
293927
|
try {
|
|
294046
|
-
const { existsSync:
|
|
293928
|
+
const { existsSync: existsSync119 } = await import("node:fs");
|
|
294047
293929
|
const { join: join153 } = await import("node:path");
|
|
294048
293930
|
const { store: scopedStore } = await getProjectContext2(req);
|
|
294049
293931
|
const task = await scopedStore.getTask(req.params.id);
|
|
@@ -294062,7 +293944,7 @@ See \`GET /api/tasks/${task.id}/diff\` for the landed diff being reverted.
|
|
|
294062
293944
|
ageMs: Math.max(0, Date.now() - Date.parse(task.createdAt))
|
|
294063
293945
|
};
|
|
294064
293946
|
const promptPath = join153(scopedStore.getRootDir(), ".fusion", "tasks", task.id, "PROMPT.md");
|
|
294065
|
-
const promptExists =
|
|
293947
|
+
const promptExists = existsSync119(promptPath);
|
|
294066
293948
|
const dependencyDetails = await Promise.all((task.dependencies ?? []).map(async (dependencyId) => {
|
|
294067
293949
|
try {
|
|
294068
293950
|
const depTask = await scopedStore.getTask(dependencyId);
|
|
@@ -298823,7 +298705,7 @@ __export(chat_exports, {
|
|
|
298823
298705
|
});
|
|
298824
298706
|
import { EventEmitter as EventEmitter40 } from "node:events";
|
|
298825
298707
|
import { randomUUID as randomUUID50 } from "node:crypto";
|
|
298826
|
-
import { existsSync as
|
|
298708
|
+
import { existsSync as existsSync71 } from "node:fs";
|
|
298827
298709
|
import { join as join90, resolve as resolve48, relative as relative20 } from "node:path";
|
|
298828
298710
|
import { SessionManager as SessionManager3 } from "@earendil-works/pi-coding-agent";
|
|
298829
298711
|
function __getChatDiagnostics() {
|
|
@@ -299030,7 +298912,7 @@ function createTaskVerificationTools(taskStore, actionGateContext) {
|
|
|
299030
298912
|
const profile = typeof raw.profile === "string" ? raw.profile : "verify:fast";
|
|
299031
298913
|
if (!taskId || !profiles.has(profile)) return { content: [{ type: "text", text: "ERROR: task_id and an allowlisted profile are required; raw commands are not accepted." }], isError: true, details: {} };
|
|
299032
298914
|
const task = await taskStore.getTask(taskId);
|
|
299033
|
-
if (!task || !(await wipColumnsForTask(taskStore, taskId)).has(task.column) || !task.worktree || !
|
|
298915
|
+
if (!task || !(await wipColumnsForTask(taskStore, taskId)).has(task.column) || !task.worktree || !existsSync71(task.worktree)) return { content: [{ type: "text", text: "ERROR: verification requires an in-progress task with a live executor worktree." }], isError: true, details: {} };
|
|
299034
298916
|
const settings = await taskStore.getSettings();
|
|
299035
298917
|
const command = profile === "verify:fast" ? "pnpm verify:fast" : typeof settings.testCommand === "string" ? settings.testCommand : "";
|
|
299036
298918
|
if (!command) return { content: [{ type: "text", text: "ERROR: the selected verification profile is not configured." }], isError: true, details: {} };
|
|
@@ -299861,7 +299743,7 @@ When you need structured input, or whenever you present options, choices, or a d
|
|
|
299861
299743
|
* keep the CLI session stable across user messages.
|
|
299862
299744
|
*/
|
|
299863
299745
|
async resolveCliSessionManager(session) {
|
|
299864
|
-
if (session.cliSessionFile &&
|
|
299746
|
+
if (session.cliSessionFile && existsSync71(session.cliSessionFile)) {
|
|
299865
299747
|
try {
|
|
299866
299748
|
return SessionManager3.open(session.cliSessionFile);
|
|
299867
299749
|
} catch (err) {
|
|
@@ -351746,7 +351628,7 @@ var init_cli_spawn = __esm({
|
|
|
351746
351628
|
// ../../plugins/fusion-plugin-hermes-runtime/src/fusion-skill-install.ts
|
|
351747
351629
|
import {
|
|
351748
351630
|
cpSync as cpSync2,
|
|
351749
|
-
existsSync as
|
|
351631
|
+
existsSync as existsSync73,
|
|
351750
351632
|
lstatSync as lstatSync4,
|
|
351751
351633
|
mkdirSync as mkdirSync13,
|
|
351752
351634
|
readFileSync as readFileSync28,
|
|
@@ -351776,7 +351658,7 @@ function getFusionSkillSourceCandidates(moduleUrl = import.meta.url) {
|
|
|
351776
351658
|
function resolveBundledFusionSkillSource() {
|
|
351777
351659
|
const candidates = getFusionSkillSourceCandidates();
|
|
351778
351660
|
for (const candidate of candidates) {
|
|
351779
|
-
if (
|
|
351661
|
+
if (existsSync73(join97(candidate, "SKILL.md"))) return candidate;
|
|
351780
351662
|
}
|
|
351781
351663
|
return null;
|
|
351782
351664
|
}
|
|
@@ -351794,7 +351676,7 @@ function installFusionSkillIntoHermesHome(options = {}) {
|
|
|
351794
351676
|
try {
|
|
351795
351677
|
mkdirSync13(dirname40(targetDir), { recursive: true });
|
|
351796
351678
|
let replaced = false;
|
|
351797
|
-
if (
|
|
351679
|
+
if (existsSync73(targetDir) || isBrokenSymlink(targetDir)) {
|
|
351798
351680
|
const stat20 = lstatSync4(targetDir);
|
|
351799
351681
|
if (stat20.isSymbolicLink()) {
|
|
351800
351682
|
const currentTarget = safeReadlink(targetDir);
|
|
@@ -351865,14 +351747,14 @@ function safeReadlink(path14) {
|
|
|
351865
351747
|
function isBrokenSymlink(path14) {
|
|
351866
351748
|
try {
|
|
351867
351749
|
const stat20 = lstatSync4(path14);
|
|
351868
|
-
return stat20.isSymbolicLink() && !
|
|
351750
|
+
return stat20.isSymbolicLink() && !existsSync73(path14);
|
|
351869
351751
|
} catch {
|
|
351870
351752
|
return false;
|
|
351871
351753
|
}
|
|
351872
351754
|
}
|
|
351873
351755
|
function looksLikePriorFusionInstall(path14) {
|
|
351874
351756
|
const skillMd = join97(path14, "SKILL.md");
|
|
351875
|
-
if (!
|
|
351757
|
+
if (!existsSync73(skillMd)) return false;
|
|
351876
351758
|
try {
|
|
351877
351759
|
const body = readFileSync28(skillMd, "utf-8");
|
|
351878
351760
|
return /\bfusion\b/i.test(body) && /\bskill\b/i.test(body);
|
|
@@ -351883,7 +351765,7 @@ function looksLikePriorFusionInstall(path14) {
|
|
|
351883
351765
|
function looksLikeFusionSkillTarget(path14) {
|
|
351884
351766
|
if (!path14) return false;
|
|
351885
351767
|
if (basename28(path14).toLowerCase() === FUSION_SKILL_NAME) return true;
|
|
351886
|
-
return
|
|
351768
|
+
return existsSync73(join97(path14, "SKILL.md"));
|
|
351887
351769
|
}
|
|
351888
351770
|
var FUSION_SKILL_NAME;
|
|
351889
351771
|
var init_fusion_skill_install = __esm({
|
|
@@ -354906,7 +354788,7 @@ var init_provider2 = __esm({
|
|
|
354906
354788
|
});
|
|
354907
354789
|
|
|
354908
354790
|
// ../../plugins/fusion-plugin-grok-runtime/src/acp/cli-spawn.ts
|
|
354909
|
-
import { existsSync as
|
|
354791
|
+
import { existsSync as existsSync75 } from "node:fs";
|
|
354910
354792
|
import { dirname as dirname42, isAbsolute as isAbsolute28, join as join101, resolve as resolve59 } from "node:path";
|
|
354911
354793
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
354912
354794
|
function asTrimmedString(value) {
|
|
@@ -354929,7 +354811,7 @@ function bundledClaudeBridgeBinPath(pluginRoot = pluginRootDir()) {
|
|
|
354929
354811
|
}
|
|
354930
354812
|
function resolveBundledClaudeBridgeBinary(options = {}) {
|
|
354931
354813
|
const root = options.pluginRoot ?? pluginRootDir();
|
|
354932
|
-
const exists2 = options.exists ??
|
|
354814
|
+
const exists2 = options.exists ?? existsSync75;
|
|
354933
354815
|
const candidate = bundledClaudeBridgeBinPath(root);
|
|
354934
354816
|
if (!exists2(candidate)) {
|
|
354935
354817
|
return {
|
|
@@ -356278,7 +356160,7 @@ var init_mcp_forwarding = __esm({
|
|
|
356278
356160
|
// ../../plugins/fusion-plugin-grok-runtime/src/skill-loader.ts
|
|
356279
356161
|
import {
|
|
356280
356162
|
cpSync as cpSync3,
|
|
356281
|
-
existsSync as
|
|
356163
|
+
existsSync as existsSync76,
|
|
356282
356164
|
mkdirSync as mkdirSync14,
|
|
356283
356165
|
mkdtempSync as mkdtempSync3,
|
|
356284
356166
|
readdirSync as readdirSync14,
|
|
@@ -356291,7 +356173,7 @@ import { tmpdir as tmpdir16 } from "node:os";
|
|
|
356291
356173
|
import { basename as basename30, dirname as dirname44, join as join103, resolve as resolve61 } from "node:path";
|
|
356292
356174
|
import { fileURLToPath as fileURLToPath10 } from "node:url";
|
|
356293
356175
|
function isSkillDir(dir2) {
|
|
356294
|
-
return
|
|
356176
|
+
return existsSync76(join103(dir2, "SKILL.md"));
|
|
356295
356177
|
}
|
|
356296
356178
|
function pushUnique(out, candidate) {
|
|
356297
356179
|
if (!candidate) return;
|
|
@@ -356355,7 +356237,7 @@ function resolveBundledFusionSkillSource2(moduleUrl = import.meta.url) {
|
|
|
356355
356237
|
function installSkillDir(sourceDir, targetDir) {
|
|
356356
356238
|
if (!isSkillDir(sourceDir)) return false;
|
|
356357
356239
|
mkdirSync14(dirname44(targetDir), { recursive: true });
|
|
356358
|
-
if (
|
|
356240
|
+
if (existsSync76(targetDir)) {
|
|
356359
356241
|
rmSync11(targetDir, { recursive: true, force: true });
|
|
356360
356242
|
}
|
|
356361
356243
|
try {
|
|
@@ -356371,7 +356253,7 @@ function installSkillDir(sourceDir, targetDir) {
|
|
|
356371
356253
|
}
|
|
356372
356254
|
}
|
|
356373
356255
|
function collectSkillsFromRoot(root, out) {
|
|
356374
|
-
if (!
|
|
356256
|
+
if (!existsSync76(root)) return;
|
|
356375
356257
|
if (isSkillDir(root)) {
|
|
356376
356258
|
out.set(basename30(root), root);
|
|
356377
356259
|
return;
|
|
@@ -356410,7 +356292,7 @@ function stageGrokSessionSkills(options = {}) {
|
|
|
356410
356292
|
installSkillDir(source, join103(skillsDir, name2));
|
|
356411
356293
|
}
|
|
356412
356294
|
for (const [name2, source] of installed) {
|
|
356413
|
-
if (!
|
|
356295
|
+
if (!existsSync76(join103(skillsDir, name2))) {
|
|
356414
356296
|
installSkillDir(source, join103(skillsDir, name2));
|
|
356415
356297
|
}
|
|
356416
356298
|
}
|
|
@@ -356479,7 +356361,7 @@ var init_skill_loader = __esm({
|
|
|
356479
356361
|
|
|
356480
356362
|
// ../../plugins/fusion-plugin-grok-runtime/src/tool-bridge.ts
|
|
356481
356363
|
import { createServer as createServer2 } from "node:http";
|
|
356482
|
-
import { existsSync as
|
|
356364
|
+
import { existsSync as existsSync77, writeFileSync as writeFileSync15 } from "node:fs";
|
|
356483
356365
|
import { tmpdir as tmpdir17 } from "node:os";
|
|
356484
356366
|
import { dirname as dirname45, join as join104 } from "node:path";
|
|
356485
356367
|
import { fileURLToPath as fileURLToPath11 } from "node:url";
|
|
@@ -356525,7 +356407,7 @@ async function startFusionToolBridge(tools) {
|
|
|
356525
356407
|
const defs = toolsToMcpToolDefs2(tools);
|
|
356526
356408
|
if (defs.length === 0) return null;
|
|
356527
356409
|
const serverPath = fusionToolsMcpServerPath();
|
|
356528
|
-
if (!
|
|
356410
|
+
if (!existsSync77(serverPath)) {
|
|
356529
356411
|
throw missingMcpSchemaServerError(serverPath);
|
|
356530
356412
|
}
|
|
356531
356413
|
const byName = /* @__PURE__ */ new Map();
|
|
@@ -356966,7 +356848,7 @@ var init_src11 = __esm({
|
|
|
356966
356848
|
});
|
|
356967
356849
|
|
|
356968
356850
|
// ../../plugins/fusion-plugin-claude-runtime/src/acp/cli-spawn.ts
|
|
356969
|
-
import { existsSync as
|
|
356851
|
+
import { existsSync as existsSync78 } from "node:fs";
|
|
356970
356852
|
import { dirname as dirname46, isAbsolute as isAbsolute29, join as join105, resolve as resolve62 } from "node:path";
|
|
356971
356853
|
import { fileURLToPath as fileURLToPath12 } from "node:url";
|
|
356972
356854
|
function asTrimmedString2(value) {
|
|
@@ -356989,7 +356871,7 @@ function bundledClaudeBridgeBinPath2(pluginRoot = pluginRootDir2()) {
|
|
|
356989
356871
|
}
|
|
356990
356872
|
function resolveBundledClaudeBridgeBinary2(options = {}) {
|
|
356991
356873
|
const root = options.pluginRoot ?? pluginRootDir2();
|
|
356992
|
-
const exists2 = options.exists ??
|
|
356874
|
+
const exists2 = options.exists ?? existsSync78;
|
|
356993
356875
|
const candidate = bundledClaudeBridgeBinPath2(root);
|
|
356994
356876
|
if (!exists2(candidate)) {
|
|
356995
356877
|
return {
|
|
@@ -358224,7 +358106,7 @@ var init_acp2 = __esm({
|
|
|
358224
358106
|
|
|
358225
358107
|
// ../../plugins/fusion-plugin-claude-runtime/src/cli-spawn.ts
|
|
358226
358108
|
import { spawn as spawn21 } from "node:child_process";
|
|
358227
|
-
import { existsSync as
|
|
358109
|
+
import { existsSync as existsSync79 } from "node:fs";
|
|
358228
358110
|
import { basename as basename32, dirname as dirname48, isAbsolute as isAbsolute30, join as join107, resolve as resolve64 } from "node:path";
|
|
358229
358111
|
import { fileURLToPath as fileURLToPath13 } from "node:url";
|
|
358230
358112
|
function pluginRootDir3() {
|
|
@@ -358236,7 +358118,7 @@ function bundledClaudeBridgeBinPath3(pluginRoot = pluginRootDir3()) {
|
|
|
358236
358118
|
}
|
|
358237
358119
|
function resolveBundledClaudeBridgeBinary3(options = {}) {
|
|
358238
358120
|
const candidate = bundledClaudeBridgeBinPath3(options.pluginRoot ?? pluginRootDir3());
|
|
358239
|
-
const exists2 = options.exists ??
|
|
358121
|
+
const exists2 = options.exists ?? existsSync79;
|
|
358240
358122
|
if (!exists2(candidate) || !isAbsolute30(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}` };
|
|
358241
358123
|
return { kind: "resolved", requested: CLAUDE_CODE_CLI_ACP_BINARY3, path: candidate };
|
|
358242
358124
|
}
|
|
@@ -358399,7 +358281,7 @@ var init_mcp_forwarding2 = __esm({
|
|
|
358399
358281
|
// ../../plugins/fusion-plugin-claude-runtime/src/skill-loader.ts
|
|
358400
358282
|
import {
|
|
358401
358283
|
cpSync as cpSync4,
|
|
358402
|
-
existsSync as
|
|
358284
|
+
existsSync as existsSync80,
|
|
358403
358285
|
mkdirSync as mkdirSync15,
|
|
358404
358286
|
mkdtempSync as mkdtempSync4,
|
|
358405
358287
|
readdirSync as readdirSync15,
|
|
@@ -358412,7 +358294,7 @@ import { tmpdir as tmpdir18 } from "node:os";
|
|
|
358412
358294
|
import { basename as basename33, dirname as dirname49, join as join108, resolve as resolve65 } from "node:path";
|
|
358413
358295
|
import { fileURLToPath as fileURLToPath14 } from "node:url";
|
|
358414
358296
|
function isSkillDir2(dir2) {
|
|
358415
|
-
return
|
|
358297
|
+
return existsSync80(join108(dir2, "SKILL.md"));
|
|
358416
358298
|
}
|
|
358417
358299
|
function pushUnique2(out, candidate) {
|
|
358418
358300
|
if (!candidate) return;
|
|
@@ -358476,7 +358358,7 @@ function resolveBundledFusionSkillSource3(moduleUrl = import.meta.url) {
|
|
|
358476
358358
|
function installSkillDir2(sourceDir, targetDir) {
|
|
358477
358359
|
if (!isSkillDir2(sourceDir)) return false;
|
|
358478
358360
|
mkdirSync15(dirname49(targetDir), { recursive: true });
|
|
358479
|
-
if (
|
|
358361
|
+
if (existsSync80(targetDir)) {
|
|
358480
358362
|
rmSync12(targetDir, { recursive: true, force: true });
|
|
358481
358363
|
}
|
|
358482
358364
|
try {
|
|
@@ -358492,7 +358374,7 @@ function installSkillDir2(sourceDir, targetDir) {
|
|
|
358492
358374
|
}
|
|
358493
358375
|
}
|
|
358494
358376
|
function collectSkillsFromRoot2(root, out) {
|
|
358495
|
-
if (!
|
|
358377
|
+
if (!existsSync80(root)) return;
|
|
358496
358378
|
if (isSkillDir2(root)) {
|
|
358497
358379
|
out.set(basename33(root), root);
|
|
358498
358380
|
return;
|
|
@@ -358531,7 +358413,7 @@ function stageClaudeSessionSkills(options = {}) {
|
|
|
358531
358413
|
installSkillDir2(source, join108(skillsDir, name2));
|
|
358532
358414
|
}
|
|
358533
358415
|
for (const [name2, source] of installed) {
|
|
358534
|
-
if (!
|
|
358416
|
+
if (!existsSync80(join108(skillsDir, name2))) {
|
|
358535
358417
|
installSkillDir2(source, join108(skillsDir, name2));
|
|
358536
358418
|
}
|
|
358537
358419
|
}
|
|
@@ -358600,7 +358482,7 @@ var init_skill_loader2 = __esm({
|
|
|
358600
358482
|
|
|
358601
358483
|
// ../../plugins/fusion-plugin-claude-runtime/src/tool-bridge.ts
|
|
358602
358484
|
import { createServer as createServer3 } from "node:http";
|
|
358603
|
-
import { existsSync as
|
|
358485
|
+
import { existsSync as existsSync81, rmSync as rmSync13, writeFileSync as writeFileSync17 } from "node:fs";
|
|
358604
358486
|
import { tmpdir as tmpdir19 } from "node:os";
|
|
358605
358487
|
import { dirname as dirname50, join as join109 } from "node:path";
|
|
358606
358488
|
import { fileURLToPath as fileURLToPath15 } from "node:url";
|
|
@@ -358646,7 +358528,7 @@ async function startFusionToolBridge2(tools, options = {}) {
|
|
|
358646
358528
|
const defs = toolsToMcpToolDefs3(tools);
|
|
358647
358529
|
if (defs.length === 0) return null;
|
|
358648
358530
|
const serverPath = fusionToolsMcpServerPath2();
|
|
358649
|
-
if (!
|
|
358531
|
+
if (!existsSync81(serverPath)) {
|
|
358650
358532
|
throw missingMcpSchemaServerError2(serverPath);
|
|
358651
358533
|
}
|
|
358652
358534
|
const byName = /* @__PURE__ */ new Map();
|
|
@@ -359458,7 +359340,7 @@ var init_provider6 = __esm({
|
|
|
359458
359340
|
});
|
|
359459
359341
|
|
|
359460
359342
|
// ../../plugins/fusion-plugin-omp-runtime/src/acp/cli-spawn.ts
|
|
359461
|
-
import { existsSync as
|
|
359343
|
+
import { existsSync as existsSync82 } from "node:fs";
|
|
359462
359344
|
import { dirname as dirname51, isAbsolute as isAbsolute31, join as join110, resolve as resolve66 } from "node:path";
|
|
359463
359345
|
import { fileURLToPath as fileURLToPath16 } from "node:url";
|
|
359464
359346
|
function asTrimmedString3(value) {
|
|
@@ -359481,7 +359363,7 @@ function bundledClaudeBridgeBinPath4(pluginRoot = pluginRootDir4()) {
|
|
|
359481
359363
|
}
|
|
359482
359364
|
function resolveBundledClaudeBridgeBinary4(options = {}) {
|
|
359483
359365
|
const root = options.pluginRoot ?? pluginRootDir4();
|
|
359484
|
-
const exists2 = options.exists ??
|
|
359366
|
+
const exists2 = options.exists ?? existsSync82;
|
|
359485
359367
|
const candidate = bundledClaudeBridgeBinPath4(root);
|
|
359486
359368
|
if (!exists2(candidate)) {
|
|
359487
359369
|
return {
|
|
@@ -360793,7 +360675,7 @@ var init_mcp_forwarding3 = __esm({
|
|
|
360793
360675
|
|
|
360794
360676
|
// ../../plugins/fusion-plugin-omp-runtime/src/tool-bridge.ts
|
|
360795
360677
|
import { createServer as createServer4 } from "node:http";
|
|
360796
|
-
import { existsSync as
|
|
360678
|
+
import { existsSync as existsSync83, unlinkSync as unlinkSync5, writeFileSync as writeFileSync18 } from "node:fs";
|
|
360797
360679
|
import { tmpdir as tmpdir20 } from "node:os";
|
|
360798
360680
|
import { dirname as dirname53, join as join112 } from "node:path";
|
|
360799
360681
|
import { fileURLToPath as fileURLToPath17 } from "node:url";
|
|
@@ -360820,7 +360702,7 @@ function fusionToolsMcpServerPath3() {
|
|
|
360820
360702
|
join112(here, "..", "mcp-schema-server.cjs")
|
|
360821
360703
|
];
|
|
360822
360704
|
for (const candidate of candidates) {
|
|
360823
|
-
if (
|
|
360705
|
+
if (existsSync83(candidate)) return candidate;
|
|
360824
360706
|
}
|
|
360825
360707
|
return null;
|
|
360826
360708
|
}
|
|
@@ -360958,7 +360840,7 @@ var init_tool_bridge3 = __esm({
|
|
|
360958
360840
|
});
|
|
360959
360841
|
|
|
360960
360842
|
// ../../plugins/fusion-plugin-omp-runtime/src/runtime-adapter.ts
|
|
360961
|
-
import { existsSync as
|
|
360843
|
+
import { existsSync as existsSync84 } from "node:fs";
|
|
360962
360844
|
function compactDiagnostic3(value) {
|
|
360963
360845
|
return value.replace(/\s+/g, " ").trim();
|
|
360964
360846
|
}
|
|
@@ -361149,7 +361031,7 @@ var init_runtime_adapter9 = __esm({
|
|
|
361149
361031
|
const command = server.command.trim();
|
|
361150
361032
|
if (!command) return false;
|
|
361151
361033
|
if (command.includes("/") || command.includes("\\")) {
|
|
361152
|
-
return
|
|
361034
|
+
return existsSync84(command);
|
|
361153
361035
|
}
|
|
361154
361036
|
return true;
|
|
361155
361037
|
});
|
|
@@ -368063,7 +367945,7 @@ var init_auth_provider_catalog = __esm({
|
|
|
368063
367945
|
// ../dashboard/src/routes/register-auth-routes.ts
|
|
368064
367946
|
import { tmpdir as tmpdir21 } from "node:os";
|
|
368065
367947
|
import { join as join116 } from "node:path";
|
|
368066
|
-
import { existsSync as
|
|
367948
|
+
import { existsSync as existsSync85, readFileSync as readFileSync29 } from "node:fs";
|
|
368067
367949
|
function parseGitHubCopilotDeviceCode(instructions) {
|
|
368068
367950
|
const match = instructions.match(/Enter code:\s*([A-Z0-9-]+)\b/i);
|
|
368069
367951
|
return match?.[1];
|
|
@@ -368821,7 +368703,7 @@ var init_register_auth_routes = __esm({
|
|
|
368821
368703
|
let acpAuthReason;
|
|
368822
368704
|
try {
|
|
368823
368705
|
const signalPath = join116(tmpdir21(), "fusion-acp-bridge-auth.json");
|
|
368824
|
-
if (
|
|
368706
|
+
if (existsSync85(signalPath)) {
|
|
368825
368707
|
const sig = JSON.parse(readFileSync29(signalPath, "utf8"));
|
|
368826
368708
|
if (sig?.authFailed) {
|
|
368827
368709
|
acpAuthFailed = true;
|
|
@@ -370920,7 +370802,7 @@ import { spawn as spawn27 } from "node:child_process";
|
|
|
370920
370802
|
import {
|
|
370921
370803
|
chmodSync as chmodSync4,
|
|
370922
370804
|
cpSync as cpSync5,
|
|
370923
|
-
existsSync as
|
|
370805
|
+
existsSync as existsSync86,
|
|
370924
370806
|
lstatSync as lstatSync5,
|
|
370925
370807
|
mkdirSync as mkdirSync16,
|
|
370926
370808
|
readlinkSync as readlinkSync3,
|
|
@@ -371035,20 +370917,20 @@ function runStreamingCommand(command, args, options) {
|
|
|
371035
370917
|
function resolveBunExecutable() {
|
|
371036
370918
|
if (process.env.BUN_INSTALL) {
|
|
371037
370919
|
const candidate = join119(process.env.BUN_INSTALL, "bin", process.platform === "win32" ? "bun.exe" : "bun");
|
|
371038
|
-
if (
|
|
370920
|
+
if (existsSync86(candidate)) return candidate;
|
|
371039
370921
|
}
|
|
371040
370922
|
const homeBun = join119(homedir19(), ".bun", "bin", process.platform === "win32" ? "bun.exe" : "bun");
|
|
371041
|
-
if (
|
|
370923
|
+
if (existsSync86(homeBun)) return homeBun;
|
|
371042
370924
|
return "bun";
|
|
371043
370925
|
}
|
|
371044
370926
|
function installLocalFnBinary(distDir, onLog, paths2 = resolveFnBinaryLocalPaths()) {
|
|
371045
370927
|
const srcBinary = join119(distDir, process.platform === "win32" ? "fn.exe" : "fn");
|
|
371046
370928
|
const srcClient = join119(distDir, "client");
|
|
371047
370929
|
const srcRuntime = join119(distDir, "runtime");
|
|
371048
|
-
if (!
|
|
370930
|
+
if (!existsSync86(srcBinary)) {
|
|
371049
370931
|
throw new Error(`Built binary missing at ${srcBinary}. Did the Bun compile step fail?`);
|
|
371050
370932
|
}
|
|
371051
|
-
if (!
|
|
370933
|
+
if (!existsSync86(srcClient)) {
|
|
371052
370934
|
throw new Error(`Dashboard client assets missing at ${srcClient}.`);
|
|
371053
370935
|
}
|
|
371054
370936
|
mkdirSync16(paths2.installDir, { recursive: true });
|
|
@@ -371062,14 +370944,14 @@ function installLocalFnBinary(distDir, onLog, paths2 = resolveFnBinaryLocalPaths
|
|
|
371062
370944
|
onLog("system", `Installing client assets \u2192 ${join119(paths2.installDir, "client")}`);
|
|
371063
370945
|
rmSync14(join119(paths2.installDir, "client"), { recursive: true, force: true });
|
|
371064
370946
|
cpSync5(srcClient, join119(paths2.installDir, "client"), { recursive: true });
|
|
371065
|
-
if (
|
|
370947
|
+
if (existsSync86(srcRuntime)) {
|
|
371066
370948
|
onLog("system", `Installing runtime assets \u2192 ${join119(paths2.installDir, "runtime")}`);
|
|
371067
370949
|
rmSync14(join119(paths2.installDir, "runtime"), { recursive: true, force: true });
|
|
371068
370950
|
cpSync5(srcRuntime, join119(paths2.installDir, "runtime"), { recursive: true });
|
|
371069
370951
|
}
|
|
371070
370952
|
for (const shim of [paths2.fnShimPath, paths2.fusionShimPath]) {
|
|
371071
370953
|
try {
|
|
371072
|
-
if (
|
|
370954
|
+
if (existsSync86(shim) || isSymlink(shim)) {
|
|
371073
370955
|
unlinkSync6(shim);
|
|
371074
370956
|
}
|
|
371075
370957
|
} catch {
|
|
@@ -371091,7 +370973,7 @@ function removeLocalFnShims(onLog, paths2 = resolveFnBinaryLocalPaths()) {
|
|
|
371091
370973
|
const installReal = resolve69(paths2.binaryPath);
|
|
371092
370974
|
for (const shim of [paths2.fnShimPath, paths2.fusionShimPath]) {
|
|
371093
370975
|
try {
|
|
371094
|
-
if (!
|
|
370976
|
+
if (!existsSync86(shim) && !isSymlink(shim)) {
|
|
371095
370977
|
onLog("system", `No shim at ${shim}`);
|
|
371096
370978
|
continue;
|
|
371097
370979
|
}
|
|
@@ -371123,10 +371005,10 @@ async function runLinkLocalFnBinary(sourceRoot, onLog) {
|
|
|
371123
371005
|
const buildScript = join119(sourceRoot, "scripts", "build-workspace.mjs");
|
|
371124
371006
|
const cliBuild = join119(sourceRoot, "packages", "cli", "build.ts");
|
|
371125
371007
|
const distDir = join119(sourceRoot, "packages", "cli", "dist");
|
|
371126
|
-
if (!
|
|
371008
|
+
if (!existsSync86(buildScript)) {
|
|
371127
371009
|
return { success: false, error: `Build script missing: ${buildScript}` };
|
|
371128
371010
|
}
|
|
371129
|
-
if (!
|
|
371011
|
+
if (!existsSync86(cliBuild)) {
|
|
371130
371012
|
return { success: false, error: `CLI build entry missing: ${cliBuild}` };
|
|
371131
371013
|
}
|
|
371132
371014
|
onLog("system", "Step 1/3 \u2014 full workspace package build\u2026");
|
|
@@ -371202,7 +371084,7 @@ var init_fn_binary_local_install = __esm({
|
|
|
371202
371084
|
|
|
371203
371085
|
// ../dashboard/src/routes/register-system-routes.ts
|
|
371204
371086
|
import { randomUUID as randomUUID66 } from "node:crypto";
|
|
371205
|
-
import { existsSync as
|
|
371087
|
+
import { existsSync as existsSync87 } from "node:fs";
|
|
371206
371088
|
import { join as join120 } from "node:path";
|
|
371207
371089
|
function rejectCrossOrigin(req, res) {
|
|
371208
371090
|
const origin = req.headers.origin;
|
|
@@ -371394,7 +371276,7 @@ function registerSystemRoutes(ctx, deps) {
|
|
|
371394
371276
|
const restartAfter = body.restart !== false && scope !== "plugins";
|
|
371395
371277
|
const { args, label } = rebuildScopes[scope];
|
|
371396
371278
|
const scriptPath = join120(root, args[0]);
|
|
371397
|
-
if (!
|
|
371279
|
+
if (!existsSync87(scriptPath)) {
|
|
371398
371280
|
throw new ApiError(409, `Build script missing: ${scriptPath}`);
|
|
371399
371281
|
}
|
|
371400
371282
|
const job = {
|
|
@@ -382634,7 +382516,7 @@ var init_reliability_metrics = __esm({
|
|
|
382634
382516
|
});
|
|
382635
382517
|
|
|
382636
382518
|
// ../dashboard/src/view-chunk-manifest.ts
|
|
382637
|
-
import { existsSync as
|
|
382519
|
+
import { existsSync as existsSync88, readFileSync as readFileSync31, statSync as statSync15 } from "node:fs";
|
|
382638
382520
|
import { join as join124, resolve as resolve73 } from "node:path";
|
|
382639
382521
|
function warnOnce(set, key, message) {
|
|
382640
382522
|
if (set.has(key)) {
|
|
@@ -382656,7 +382538,7 @@ function loadViewChunkManifest(clientDir) {
|
|
|
382656
382538
|
if (cached2 && cached2.mtimeMs === mtimeMs) {
|
|
382657
382539
|
return cached2.entries;
|
|
382658
382540
|
}
|
|
382659
|
-
if (!
|
|
382541
|
+
if (!existsSync88(manifestPath)) {
|
|
382660
382542
|
warnOnce(warnedMissingManifest, cacheKey, `[dashboard] View chunk manifest missing: ${manifestPath}`);
|
|
382661
382543
|
const empty = {};
|
|
382662
382544
|
manifestCache.set(cacheKey, { entries: empty, mtimeMs });
|
|
@@ -383234,7 +383116,7 @@ var init_provider_health_monitor = __esm({
|
|
|
383234
383116
|
import express3 from "express";
|
|
383235
383117
|
import { randomUUID as randomUUID67 } from "node:crypto";
|
|
383236
383118
|
import { join as join125, dirname as dirname57 } from "node:path";
|
|
383237
|
-
import { existsSync as
|
|
383119
|
+
import { existsSync as existsSync89, readFileSync as readFileSync32, statSync as statSync16 } from "node:fs";
|
|
383238
383120
|
import { fileURLToPath as fileURLToPath18 } from "node:url";
|
|
383239
383121
|
import { createSecureServer as createHttp2SecureServer } from "node:http2";
|
|
383240
383122
|
import { WebSocketServer as WebSocketServer2 } from "ws";
|
|
@@ -383556,7 +383438,7 @@ function createServer5(store, options) {
|
|
|
383556
383438
|
getTerminalService(store.getRootDir());
|
|
383557
383439
|
const isHeadless = options?.headless === true;
|
|
383558
383440
|
const execDir = dirname57(process.execPath);
|
|
383559
|
-
const clientDir = process.env.FUSION_CLIENT_DIR ? process.env.FUSION_CLIENT_DIR :
|
|
383441
|
+
const clientDir = process.env.FUSION_CLIENT_DIR ? process.env.FUSION_CLIENT_DIR : existsSync89(join125(execDir, "client", "index.html")) ? join125(execDir, "client") : existsSync89(join125(__dirname2, "..", "dist", "client")) ? join125(__dirname2, "..", "dist", "client") : join125(__dirname2, "..", "client");
|
|
383560
383442
|
let cachedIndexClientDir = null;
|
|
383561
383443
|
let cachedIndexHtml = null;
|
|
383562
383444
|
let cachedIndexMtimeMs = null;
|
|
@@ -383611,7 +383493,7 @@ ${injection}`) : cachedIndexHtml.replace("</head>", `${injection}</head>`);
|
|
|
383611
383493
|
}
|
|
383612
383494
|
});
|
|
383613
383495
|
});
|
|
383614
|
-
if (
|
|
383496
|
+
if (existsSync89(join125(clientDir, "index.html"))) {
|
|
383615
383497
|
app.get(["/", "/index.html"], serveIndexHtml);
|
|
383616
383498
|
app.use(express3.static(clientDir, { index: false }));
|
|
383617
383499
|
}
|
|
@@ -385670,7 +385552,7 @@ var init_src15 = __esm({
|
|
|
385670
385552
|
import { Type as Type9 } from "typebox";
|
|
385671
385553
|
import { StringEnum } from "@earendil-works/pi-ai";
|
|
385672
385554
|
import { resolve as resolve75, relative as relative25, isAbsolute as isAbsolute33, sep as sep22, basename as basename36, extname as extname5, join as join127 } from "node:path";
|
|
385673
|
-
import { existsSync as
|
|
385555
|
+
import { existsSync as existsSync90 } from "node:fs";
|
|
385674
385556
|
import { AsyncLocalStorage as AsyncLocalStorage8 } from "node:async_hooks";
|
|
385675
385557
|
function resolveProjectRoot2(cwd) {
|
|
385676
385558
|
const worktreeProjectRoot = typeof getProjectRootFromWorktree === "function" ? getProjectRootFromWorktree(cwd) : null;
|
|
@@ -385678,12 +385560,12 @@ function resolveProjectRoot2(cwd) {
|
|
|
385678
385560
|
warnedMissingProjectRootResolver = true;
|
|
385679
385561
|
console.warn("[fusion-extension] @fusion/core.getProjectRootFromWorktree is unavailable; using filesystem fallback resolution.");
|
|
385680
385562
|
}
|
|
385681
|
-
if (worktreeProjectRoot &&
|
|
385563
|
+
if (worktreeProjectRoot && existsSync90(join127(worktreeProjectRoot, ".fusion"))) {
|
|
385682
385564
|
return worktreeProjectRoot;
|
|
385683
385565
|
}
|
|
385684
385566
|
let current = resolve75(cwd);
|
|
385685
385567
|
while (true) {
|
|
385686
|
-
if (
|
|
385568
|
+
if (existsSync90(join127(current, ".fusion"))) {
|
|
385687
385569
|
return current;
|
|
385688
385570
|
}
|
|
385689
385571
|
const parent2 = resolve75(current, "..");
|
|
@@ -386568,7 +386450,7 @@ var init_migration_holding_server = __esm({
|
|
|
386568
386450
|
|
|
386569
386451
|
// src/commands/ensure-project-registered.ts
|
|
386570
386452
|
import { exec as exec49 } from "node:child_process";
|
|
386571
|
-
import { existsSync as
|
|
386453
|
+
import { existsSync as existsSync91, mkdirSync as mkdirSync17 } from "node:fs";
|
|
386572
386454
|
import { basename as basename37, join as join128 } from "node:path";
|
|
386573
386455
|
import { promisify as promisify74 } from "node:util";
|
|
386574
386456
|
function stampProjectIdentityBestEffort(cwd, project, logPrefix) {
|
|
@@ -386596,7 +386478,7 @@ async function ensureCwdProjectRegistered(options) {
|
|
|
386596
386478
|
}
|
|
386597
386479
|
try {
|
|
386598
386480
|
const fusionDir = join128(cwd, ".fusion");
|
|
386599
|
-
if (!
|
|
386481
|
+
if (!existsSync91(fusionDir)) {
|
|
386600
386482
|
mkdirSync17(fusionDir, { recursive: true });
|
|
386601
386483
|
}
|
|
386602
386484
|
const projectName = await detectProjectName(cwd);
|
|
@@ -386626,7 +386508,7 @@ async function ensureCwdProjectRegistered(options) {
|
|
|
386626
386508
|
}
|
|
386627
386509
|
}
|
|
386628
386510
|
async function detectProjectName(dir2) {
|
|
386629
|
-
if (!
|
|
386511
|
+
if (!existsSync91(join128(dir2, ".git"))) {
|
|
386630
386512
|
return basename37(dir2) || "my-project";
|
|
386631
386513
|
}
|
|
386632
386514
|
try {
|
|
@@ -386658,7 +386540,7 @@ var init_ensure_project_registered = __esm({
|
|
|
386658
386540
|
});
|
|
386659
386541
|
|
|
386660
386542
|
// src/commands/provider-settings.ts
|
|
386661
|
-
import { existsSync as
|
|
386543
|
+
import { existsSync as existsSync92, readFileSync as readFileSync33, writeFileSync as writeFileSync19, mkdirSync as mkdirSync18 } from "node:fs";
|
|
386662
386544
|
import { join as join129, dirname as dirname59, basename as basename38 } from "node:path";
|
|
386663
386545
|
function siblingAgentDir2(agentDir, siblingRoot) {
|
|
386664
386546
|
if (basename38(agentDir) !== "agent") {
|
|
@@ -386667,7 +386549,7 @@ function siblingAgentDir2(agentDir, siblingRoot) {
|
|
|
386667
386549
|
return join129(dirname59(dirname59(agentDir)), siblingRoot, "agent");
|
|
386668
386550
|
}
|
|
386669
386551
|
function readJsonObject4(path14) {
|
|
386670
|
-
if (!
|
|
386552
|
+
if (!existsSync92(path14)) {
|
|
386671
386553
|
return {};
|
|
386672
386554
|
}
|
|
386673
386555
|
try {
|
|
@@ -386712,7 +386594,7 @@ var init_provider_auth2 = __esm({
|
|
|
386712
386594
|
|
|
386713
386595
|
// src/commands/auth-paths.ts
|
|
386714
386596
|
import { homedir as homedir20 } from "node:os";
|
|
386715
|
-
import { existsSync as
|
|
386597
|
+
import { existsSync as existsSync93, readFileSync as readFileSync34 } from "node:fs";
|
|
386716
386598
|
import { join as join130 } from "node:path";
|
|
386717
386599
|
function getFusionAgentDir2(home = process.env.HOME || process.env.USERPROFILE || homedir20()) {
|
|
386718
386600
|
return join130(home, ".fusion", "agent");
|
|
@@ -386731,13 +386613,13 @@ function getLegacyModelsPaths2(home = process.env.HOME || process.env.USERPROFIL
|
|
|
386731
386613
|
}
|
|
386732
386614
|
function getModelRegistryModelsPath2(home = process.env.HOME || process.env.USERPROFILE || homedir20()) {
|
|
386733
386615
|
const fusionModelsPath = getFusionModelsPath2(home);
|
|
386734
|
-
if (
|
|
386616
|
+
if (existsSync93(fusionModelsPath)) {
|
|
386735
386617
|
return fusionModelsPath;
|
|
386736
386618
|
}
|
|
386737
|
-
return getLegacyModelsPaths2(home).find((modelsPath) =>
|
|
386619
|
+
return getLegacyModelsPaths2(home).find((modelsPath) => existsSync93(modelsPath)) ?? fusionModelsPath;
|
|
386738
386620
|
}
|
|
386739
386621
|
function readJsonObject5(path14) {
|
|
386740
|
-
if (!
|
|
386622
|
+
if (!existsSync93(path14)) {
|
|
386741
386623
|
return {};
|
|
386742
386624
|
}
|
|
386743
386625
|
try {
|
|
@@ -386755,13 +386637,13 @@ function getPackageManagerAgentDir2(home = process.env.HOME || process.env.USERP
|
|
|
386755
386637
|
const legacyAgentDir = getLegacyAgentDir(home);
|
|
386756
386638
|
const fusionSettings = readJsonObject5(join130(fusionAgentDir, "settings.json"));
|
|
386757
386639
|
const legacySettings = readJsonObject5(join130(legacyAgentDir, "settings.json"));
|
|
386758
|
-
if (hasPackageManagerSettings3(fusionSettings) || !
|
|
386640
|
+
if (hasPackageManagerSettings3(fusionSettings) || !existsSync93(legacyAgentDir)) {
|
|
386759
386641
|
return fusionAgentDir;
|
|
386760
386642
|
}
|
|
386761
386643
|
if (hasPackageManagerSettings3(legacySettings)) {
|
|
386762
386644
|
return legacyAgentDir;
|
|
386763
386645
|
}
|
|
386764
|
-
return
|
|
386646
|
+
return existsSync93(fusionAgentDir) ? fusionAgentDir : legacyAgentDir;
|
|
386765
386647
|
}
|
|
386766
386648
|
var init_auth_paths2 = __esm({
|
|
386767
386649
|
"src/commands/auth-paths.ts"() {
|
|
@@ -387008,7 +386890,7 @@ var init_project_context = __esm({
|
|
|
387008
386890
|
// src/commands/claude-skills.ts
|
|
387009
386891
|
import {
|
|
387010
386892
|
cpSync as cpSync6,
|
|
387011
|
-
existsSync as
|
|
386893
|
+
existsSync as existsSync94,
|
|
387012
386894
|
lstatSync as lstatSync6,
|
|
387013
386895
|
mkdirSync as mkdirSync19,
|
|
387014
386896
|
readlinkSync as readlinkSync4,
|
|
@@ -387037,7 +386919,7 @@ function isPiClaudeCliConfigured(globalSettings) {
|
|
|
387037
386919
|
function resolveFusionSkillSource() {
|
|
387038
386920
|
const here = fileURLToPath19(import.meta.url);
|
|
387039
386921
|
const candidate = resolve77(dirname61(here), "..", "..", "skill", FUSION_SKILL_NAME4);
|
|
387040
|
-
return
|
|
386922
|
+
return existsSync94(candidate) ? candidate : null;
|
|
387041
386923
|
}
|
|
387042
386924
|
function installFusionSkillIntoProject(projectPath, options = {}) {
|
|
387043
386925
|
const target = join131(projectPath, ".claude", "skills", FUSION_SKILL_NAME4);
|
|
@@ -387055,7 +386937,7 @@ function installFusionSkillIntoProject(projectPath, options = {}) {
|
|
|
387055
386937
|
try {
|
|
387056
386938
|
mkdirSync19(dirname61(target), { recursive: true });
|
|
387057
386939
|
let replaced = false;
|
|
387058
|
-
if (
|
|
386940
|
+
if (existsSync94(target) || isBrokenSymlink2(target)) {
|
|
387059
386941
|
const stat20 = lstatSync6(target);
|
|
387060
386942
|
if (stat20.isSymbolicLink()) {
|
|
387061
386943
|
const current = safeReadlink2(target);
|
|
@@ -387066,7 +386948,7 @@ function installFusionSkillIntoProject(projectPath, options = {}) {
|
|
|
387066
386948
|
replaced = true;
|
|
387067
386949
|
} else {
|
|
387068
386950
|
const skillMd = join131(target, "SKILL.md");
|
|
387069
|
-
if (!
|
|
386951
|
+
if (!existsSync94(skillMd)) {
|
|
387070
386952
|
return {
|
|
387071
386953
|
outcome: "failed",
|
|
387072
386954
|
target,
|
|
@@ -387125,7 +387007,7 @@ function isBrokenSymlink2(path14) {
|
|
|
387125
387007
|
try {
|
|
387126
387008
|
const stat20 = lstatSync6(path14);
|
|
387127
387009
|
if (!stat20.isSymbolicLink()) return false;
|
|
387128
|
-
return !
|
|
387010
|
+
return !existsSync94(path14);
|
|
387129
387011
|
} catch {
|
|
387130
387012
|
return false;
|
|
387131
387013
|
}
|
|
@@ -387222,7 +387104,7 @@ var init_claude_skills_runner = __esm({
|
|
|
387222
387104
|
});
|
|
387223
387105
|
|
|
387224
387106
|
// src/commands/claude-cli-extension.ts
|
|
387225
|
-
import { existsSync as
|
|
387107
|
+
import { existsSync as existsSync95, readFileSync as readFileSync35 } from "node:fs";
|
|
387226
387108
|
import { createRequire as createRequire10 } from "node:module";
|
|
387227
387109
|
import { dirname as dirname62, resolve as resolve78 } from "node:path";
|
|
387228
387110
|
import { fileURLToPath as fileURLToPath20 } from "node:url";
|
|
@@ -387231,7 +387113,7 @@ function resolveClaudeCliExtensionFromModuleUrl(moduleUrl) {
|
|
|
387231
387113
|
const here = dirname62(fileURLToPath20(moduleUrl));
|
|
387232
387114
|
for (const rel of ["pi-claude-cli", "../pi-claude-cli", "../../pi-claude-cli"]) {
|
|
387233
387115
|
const candidate = resolve78(here, rel, "package.json");
|
|
387234
|
-
if (
|
|
387116
|
+
if (existsSync95(candidate)) {
|
|
387235
387117
|
pkgJsonPath = candidate;
|
|
387236
387118
|
break;
|
|
387237
387119
|
}
|
|
@@ -387267,7 +387149,7 @@ function resolveClaudeCliExtensionFromModuleUrl(moduleUrl) {
|
|
|
387267
387149
|
};
|
|
387268
387150
|
}
|
|
387269
387151
|
const entryPath = resolve78(dirname62(pkgJsonPath), rawEntry);
|
|
387270
|
-
if (!
|
|
387152
|
+
if (!existsSync95(entryPath)) {
|
|
387271
387153
|
return {
|
|
387272
387154
|
status: "missing-entry",
|
|
387273
387155
|
reason: `@fusion/pi-claude-cli extension file not found at ${entryPath}`
|
|
@@ -387318,7 +387200,7 @@ var init_claude_cli_extension = __esm({
|
|
|
387318
387200
|
});
|
|
387319
387201
|
|
|
387320
387202
|
// src/commands/droid-cli-extension.ts
|
|
387321
|
-
import { existsSync as
|
|
387203
|
+
import { existsSync as existsSync96, readFileSync as readFileSync36 } from "node:fs";
|
|
387322
387204
|
import { createRequire as createRequire11 } from "node:module";
|
|
387323
387205
|
import { dirname as dirname63, resolve as resolve79 } from "node:path";
|
|
387324
387206
|
import { fileURLToPath as fileURLToPath21 } from "node:url";
|
|
@@ -387327,7 +387209,7 @@ function resolveDroidCliExtensionFromModuleUrl(moduleUrl) {
|
|
|
387327
387209
|
const here = dirname63(fileURLToPath21(moduleUrl));
|
|
387328
387210
|
for (const rel of ["droid-cli", "../droid-cli", "../../droid-cli"]) {
|
|
387329
387211
|
const candidate = resolve79(here, rel, "package.json");
|
|
387330
|
-
if (
|
|
387212
|
+
if (existsSync96(candidate)) {
|
|
387331
387213
|
pkgJsonPath = candidate;
|
|
387332
387214
|
break;
|
|
387333
387215
|
}
|
|
@@ -387363,7 +387245,7 @@ function resolveDroidCliExtensionFromModuleUrl(moduleUrl) {
|
|
|
387363
387245
|
};
|
|
387364
387246
|
}
|
|
387365
387247
|
const entryPath = resolve79(dirname63(pkgJsonPath), rawEntry);
|
|
387366
|
-
if (!
|
|
387248
|
+
if (!existsSync96(entryPath)) {
|
|
387367
387249
|
return {
|
|
387368
387250
|
status: "missing-entry",
|
|
387369
387251
|
reason: `@fusion/droid-cli extension file not found at ${entryPath}`
|
|
@@ -387414,7 +387296,7 @@ var init_droid_cli_extension = __esm({
|
|
|
387414
387296
|
});
|
|
387415
387297
|
|
|
387416
387298
|
// src/commands/llama-cpp-extension.ts
|
|
387417
|
-
import { existsSync as
|
|
387299
|
+
import { existsSync as existsSync97, readFileSync as readFileSync37 } from "node:fs";
|
|
387418
387300
|
import { createRequire as createRequire12 } from "node:module";
|
|
387419
387301
|
import { dirname as dirname64, resolve as resolve80 } from "node:path";
|
|
387420
387302
|
import { fileURLToPath as fileURLToPath22 } from "node:url";
|
|
@@ -387423,7 +387305,7 @@ function resolveLlamaCppExtensionFromModuleUrl(moduleUrl) {
|
|
|
387423
387305
|
const here = dirname64(fileURLToPath22(moduleUrl));
|
|
387424
387306
|
for (const rel of ["pi-llama-cpp", "../pi-llama-cpp", "../../pi-llama-cpp", "../../../pi-llama-cpp"]) {
|
|
387425
387307
|
const candidate = resolve80(here, rel, "package.json");
|
|
387426
|
-
if (
|
|
387308
|
+
if (existsSync97(candidate)) {
|
|
387427
387309
|
pkgJsonPath = candidate;
|
|
387428
387310
|
break;
|
|
387429
387311
|
}
|
|
@@ -387459,7 +387341,7 @@ function resolveLlamaCppExtensionFromModuleUrl(moduleUrl) {
|
|
|
387459
387341
|
};
|
|
387460
387342
|
}
|
|
387461
387343
|
const entryPath = resolve80(dirname64(pkgJsonPath), rawEntry);
|
|
387462
|
-
if (!
|
|
387344
|
+
if (!existsSync97(entryPath)) {
|
|
387463
387345
|
return {
|
|
387464
387346
|
status: "missing-entry",
|
|
387465
387347
|
reason: `@fusion/pi-llama-cpp extension file not found at ${entryPath}`
|
|
@@ -387558,7 +387440,7 @@ var init_update_cache = __esm({
|
|
|
387558
387440
|
});
|
|
387559
387441
|
|
|
387560
387442
|
// src/commands/self-extension.ts
|
|
387561
|
-
import { existsSync as
|
|
387443
|
+
import { existsSync as existsSync98, readFileSync as readFileSync39 } from "node:fs";
|
|
387562
387444
|
import { dirname as dirname65, resolve as resolve81 } from "node:path";
|
|
387563
387445
|
import { fileURLToPath as fileURLToPath23 } from "node:url";
|
|
387564
387446
|
function resolveSelfExtension() {
|
|
@@ -387566,7 +387448,7 @@ function resolveSelfExtension() {
|
|
|
387566
387448
|
let pkgDir;
|
|
387567
387449
|
let cur = here;
|
|
387568
387450
|
for (let i = 0; i < 5; i++) {
|
|
387569
|
-
if (
|
|
387451
|
+
if (existsSync98(resolve81(cur, "package.json"))) {
|
|
387570
387452
|
try {
|
|
387571
387453
|
const parsed = JSON.parse(readFileSync39(resolve81(cur, "package.json"), "utf-8"));
|
|
387572
387454
|
if (parsed.name === "@runfusion/fusion") {
|
|
@@ -387590,7 +387472,7 @@ function resolveSelfExtension() {
|
|
|
387590
387472
|
return { status: "missing", reason: `Failed to read @runfusion/fusion package.json: ${err instanceof Error ? err.message : String(err)}` };
|
|
387591
387473
|
}
|
|
387592
387474
|
const srcEntry = resolve81(pkgDir, "src", "extension.ts");
|
|
387593
|
-
if (
|
|
387475
|
+
if (existsSync98(srcEntry)) {
|
|
387594
387476
|
return { status: "ok", path: srcEntry, packageVersion: pkgJson.version ?? "unknown" };
|
|
387595
387477
|
}
|
|
387596
387478
|
const extensions = pkgJson.pi?.extensions;
|
|
@@ -387602,7 +387484,7 @@ function resolveSelfExtension() {
|
|
|
387602
387484
|
return { status: "missing", reason: "@runfusion/fusion pi.extensions[0] is not a valid path string" };
|
|
387603
387485
|
}
|
|
387604
387486
|
const entryPath = resolve81(pkgDir, rawEntry);
|
|
387605
|
-
if (!
|
|
387487
|
+
if (!existsSync98(entryPath)) {
|
|
387606
387488
|
return { status: "missing", reason: `@runfusion/fusion extension file not found at ${entryPath}` };
|
|
387607
387489
|
}
|
|
387608
387490
|
return { status: "ok", path: entryPath, packageVersion: pkgJson.version ?? "unknown" };
|
|
@@ -396064,7 +395946,7 @@ import { join as join134, resolve as pathResolve2 } from "node:path";
|
|
|
396064
395946
|
import { execFile as execFileCb, spawn as spawn31 } from "node:child_process";
|
|
396065
395947
|
import { promisify as promisify75 } from "node:util";
|
|
396066
395948
|
import { stat as stat18, readdir as readdir16, readFile as fsReadFile4 } from "node:fs/promises";
|
|
396067
|
-
import { existsSync as
|
|
395949
|
+
import { existsSync as existsSync99, readFileSync as readFileSync40 } from "node:fs";
|
|
396068
395950
|
import { fileURLToPath as fileURLToPath25 } from "node:url";
|
|
396069
395951
|
import { DefaultPackageManager as DefaultPackageManager2, discoverAndLoadExtensions as discoverAndLoadExtensions2, createExtensionRuntime as createExtensionRuntime2 } from "@earendil-works/pi-coding-agent";
|
|
396070
395952
|
async function countActiveTasks(store, tasks2) {
|
|
@@ -398366,7 +398248,7 @@ function resolveFusionSourceWorkspaceRoot() {
|
|
|
398366
398248
|
try {
|
|
398367
398249
|
let dir2 = pathResolve2(fileURLToPath25(import.meta.url), "..");
|
|
398368
398250
|
for (let i = 0; i < 10; i++) {
|
|
398369
|
-
if (
|
|
398251
|
+
if (existsSync99(join134(dir2, "pnpm-workspace.yaml"))) {
|
|
398370
398252
|
try {
|
|
398371
398253
|
const pkg = JSON.parse(readFileSync40(join134(dir2, "package.json"), "utf8"));
|
|
398372
398254
|
return pkg?.name === "fusion-workspace" ? dir2 : void 0;
|
|
@@ -400768,7 +400650,7 @@ __export(desktop_exports, {
|
|
|
400768
400650
|
});
|
|
400769
400651
|
import { spawn as spawn32 } from "node:child_process";
|
|
400770
400652
|
import { once as once2 } from "node:events";
|
|
400771
|
-
import { existsSync as
|
|
400653
|
+
import { existsSync as existsSync100 } from "node:fs";
|
|
400772
400654
|
import { dirname as dirname67, isAbsolute as isAbsolute34, join as join137, resolve as resolve83 } from "node:path";
|
|
400773
400655
|
import { createRequire as createRequire13 } from "node:module";
|
|
400774
400656
|
import { fileURLToPath as fileURLToPath26 } from "node:url";
|
|
@@ -400877,7 +400759,7 @@ function terminateProcess(child, signal = "SIGTERM") {
|
|
|
400877
400759
|
}
|
|
400878
400760
|
function resolveDevDesktopEntry(rootDir) {
|
|
400879
400761
|
const desktopEntry = join137(rootDir, "packages", "desktop", "dist", "main.js");
|
|
400880
|
-
if (
|
|
400762
|
+
if (existsSync100(desktopEntry)) {
|
|
400881
400763
|
return desktopEntry;
|
|
400882
400764
|
}
|
|
400883
400765
|
throw new Error(
|
|
@@ -400888,17 +400770,17 @@ function resolvePackagedDesktopEntry() {
|
|
|
400888
400770
|
const override = process.env.FUSION_DESKTOP_ENTRY;
|
|
400889
400771
|
if (override) {
|
|
400890
400772
|
const resolvedOverride = isAbsolute34(override) ? override : resolve83(process.cwd(), override);
|
|
400891
|
-
if (
|
|
400773
|
+
if (existsSync100(resolvedOverride)) {
|
|
400892
400774
|
return resolvedOverride;
|
|
400893
400775
|
}
|
|
400894
400776
|
throw new Error(`Fusion desktop runtime override is missing: ${resolvedOverride}`);
|
|
400895
400777
|
}
|
|
400896
400778
|
const packagedEntry = resolve83(cliModuleDir, "desktop", "main.js");
|
|
400897
|
-
if (
|
|
400779
|
+
if (existsSync100(packagedEntry)) {
|
|
400898
400780
|
return packagedEntry;
|
|
400899
400781
|
}
|
|
400900
400782
|
const sourceCheckoutEntry = resolve83(cliModuleDir, "..", "..", "dist", "desktop", "main.js");
|
|
400901
|
-
if (
|
|
400783
|
+
if (existsSync100(sourceCheckoutEntry)) {
|
|
400902
400784
|
return sourceCheckoutEntry;
|
|
400903
400785
|
}
|
|
400904
400786
|
throw new Error(
|
|
@@ -401530,7 +401412,7 @@ __export(task_exports, {
|
|
|
401530
401412
|
runTaskUpdate: () => runTaskUpdate
|
|
401531
401413
|
});
|
|
401532
401414
|
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
401533
|
-
import { watchFile, unwatchFile, statSync as statSync17, existsSync as
|
|
401415
|
+
import { watchFile, unwatchFile, statSync as statSync17, existsSync as existsSync101, readFileSync as readFileSync41 } from "node:fs";
|
|
401534
401416
|
import { basename as basename40, join as join138 } from "node:path";
|
|
401535
401417
|
function columnLabel2(column) {
|
|
401536
401418
|
return COLUMN_LABELS[column] ?? column;
|
|
@@ -402104,7 +401986,7 @@ async function runTaskLogs(id, options = {}, projectName) {
|
|
|
402104
401986
|
if (options.follow) {
|
|
402105
401987
|
const projectPath = context.projectPath ?? process.cwd();
|
|
402106
401988
|
const logPath = join138(projectPath, ".fusion", "tasks", id, "agent.log");
|
|
402107
|
-
if (!
|
|
401989
|
+
if (!existsSync101(logPath)) {
|
|
402108
401990
|
console.log(`
|
|
402109
401991
|
Waiting for log file to be created...`);
|
|
402110
401992
|
}
|
|
@@ -403788,7 +403670,7 @@ var settings_import_exports = {};
|
|
|
403788
403670
|
__export(settings_import_exports, {
|
|
403789
403671
|
runSettingsImport: () => runSettingsImport
|
|
403790
403672
|
});
|
|
403791
|
-
import { existsSync as
|
|
403673
|
+
import { existsSync as existsSync102 } from "node:fs";
|
|
403792
403674
|
import { resolve as resolve85 } from "node:path";
|
|
403793
403675
|
async function runSettingsImport(filePath, options = {}) {
|
|
403794
403676
|
const scope = options.scope ?? "both";
|
|
@@ -403807,7 +403689,7 @@ async function runSettingsImport(filePath, options = {}) {
|
|
|
403807
403689
|
};
|
|
403808
403690
|
try {
|
|
403809
403691
|
const resolvedPath = resolve85(filePath);
|
|
403810
|
-
if (!
|
|
403692
|
+
if (!existsSync102(resolvedPath)) {
|
|
403811
403693
|
console.error(`Error: File not found: ${filePath}`);
|
|
403812
403694
|
await exitWithStore(1);
|
|
403813
403695
|
return;
|
|
@@ -403915,7 +403797,7 @@ __export(mcp_exports, {
|
|
|
403915
403797
|
runMcpRemove: () => runMcpRemove,
|
|
403916
403798
|
runMcpValidate: () => runMcpValidate
|
|
403917
403799
|
});
|
|
403918
|
-
import { existsSync as
|
|
403800
|
+
import { existsSync as existsSync103 } from "node:fs";
|
|
403919
403801
|
import { readFile as readFile60, writeFile as writeFile41 } from "node:fs/promises";
|
|
403920
403802
|
import { resolve as resolve86 } from "node:path";
|
|
403921
403803
|
async function createGlobalSettingsStore() {
|
|
@@ -404253,7 +404135,7 @@ async function runMcpImport(filePath, opts = {}) {
|
|
|
404253
404135
|
const scope = normalizeScope(opts.scope);
|
|
404254
404136
|
context = await loadContext(opts.projectName, scope === "project");
|
|
404255
404137
|
const resolvedPath = resolve86(filePath);
|
|
404256
|
-
if (!
|
|
404138
|
+
if (!existsSync103(resolvedPath)) throw new Error(`File not found: ${filePath}`);
|
|
404257
404139
|
const imported = importMcpServersJson(await readFile60(resolvedPath, "utf-8"), { scope });
|
|
404258
404140
|
if (imported.errors.length > 0) throw new Error(`Invalid MCP import file:
|
|
404259
404141
|
${imported.errors.map((error3) => ` - ${error3}`).join("\n")}`);
|
|
@@ -404370,7 +404252,7 @@ var init_mcp = __esm({
|
|
|
404370
404252
|
});
|
|
404371
404253
|
|
|
404372
404254
|
// src/project-resolver.ts
|
|
404373
|
-
import { existsSync as
|
|
404255
|
+
import { existsSync as existsSync104, statSync as statSync18 } from "node:fs";
|
|
404374
404256
|
import { basename as basename41, dirname as dirname68, join as join140, normalize as normalize9, resolve as resolve87 } from "node:path";
|
|
404375
404257
|
import { createInterface as createInterface4 } from "node:readline/promises";
|
|
404376
404258
|
async function getCentralCore() {
|
|
@@ -404453,7 +404335,7 @@ async function resolveProject2(options = {}) {
|
|
|
404453
404335
|
{ searchedName: options.project, availableProjects: projects2.map((p2) => p2.name) }
|
|
404454
404336
|
);
|
|
404455
404337
|
}
|
|
404456
|
-
if (!
|
|
404338
|
+
if (!existsSync104(match.path)) {
|
|
404457
404339
|
throw new ProjectResolutionError(
|
|
404458
404340
|
`Project "${match.name}" is registered but the directory no longer exists: ${match.path}
|
|
404459
404341
|
|
|
@@ -404471,7 +404353,7 @@ Run \`fn project remove ` + match.name + "` to clean up the registry entry.",
|
|
|
404471
404353
|
const normalizedKbDir = normalize9(fusionDir);
|
|
404472
404354
|
const match = allProjects2.find((p2) => normalize9(p2.path) === normalizedKbDir);
|
|
404473
404355
|
if (match) {
|
|
404474
|
-
if (!
|
|
404356
|
+
if (!existsSync104(match.path)) {
|
|
404475
404357
|
throw new ProjectResolutionError(
|
|
404476
404358
|
`Project "${match.name}" is registered but the directory no longer exists: ${match.path}
|
|
404477
404359
|
|
|
@@ -404597,7 +404479,7 @@ Run \`fn project add ` + fusionDir + "` to register it, or use --project <name>.
|
|
|
404597
404479
|
}
|
|
404598
404480
|
if (allProjects.length === 1) {
|
|
404599
404481
|
const project = allProjects[0];
|
|
404600
|
-
if (!
|
|
404482
|
+
if (!existsSync104(project.path)) {
|
|
404601
404483
|
throw new ProjectResolutionError(
|
|
404602
404484
|
`The only registered project "${project.name}" has a missing directory: ${project.path}
|
|
404603
404485
|
|
|
@@ -405587,7 +405469,7 @@ __export(db_exports, {
|
|
|
405587
405469
|
runDbMigrate: () => runDbMigrate,
|
|
405588
405470
|
runDbVacuum: () => runDbVacuum
|
|
405589
405471
|
});
|
|
405590
|
-
import { existsSync as
|
|
405472
|
+
import { existsSync as existsSync105 } from "node:fs";
|
|
405591
405473
|
import { copyFile as copyFile3, mkdir as mkdir41 } from "node:fs/promises";
|
|
405592
405474
|
import { join as join141 } from "node:path";
|
|
405593
405475
|
function formatBytes9(bytes) {
|
|
@@ -405668,7 +405550,7 @@ async function runDbMigrate(projectName, opts = {}) {
|
|
|
405668
405550
|
const fusionDir = join141(projectRoot, ".fusion");
|
|
405669
405551
|
const globalDir = resolveGlobalDir();
|
|
405670
405552
|
const sources = defaultMigrationSources(fusionDir, globalDir);
|
|
405671
|
-
const presentSources = sources.filter((s3) =>
|
|
405553
|
+
const presentSources = sources.filter((s3) => existsSync105(s3.sqlitePath));
|
|
405672
405554
|
if (presentSources.length === 0) {
|
|
405673
405555
|
console.error(
|
|
405674
405556
|
`fn db migrate: no legacy SQLite files found under ${fusionDir} (or ${globalDir}). Nothing to migrate.`
|
|
@@ -405795,7 +405677,7 @@ async function createPreMigrationBackup(fusionDir, globalDir, sources) {
|
|
|
405795
405677
|
const backupDir = join141(globalDir, "migration-backups", `pre-migrate-${ts2}`);
|
|
405796
405678
|
await mkdir41(backupDir, { recursive: true });
|
|
405797
405679
|
for (const s3 of sources) {
|
|
405798
|
-
if (
|
|
405680
|
+
if (existsSync105(s3.sqlitePath)) {
|
|
405799
405681
|
const dest = join141(backupDir, s3.sqlitePath.split("/").pop() ?? "source.db");
|
|
405800
405682
|
await copyFile3(s3.sqlitePath, dest);
|
|
405801
405683
|
}
|
|
@@ -406691,7 +406573,7 @@ __export(project_exports2, {
|
|
|
406691
406573
|
runProjectShow: () => runProjectShow
|
|
406692
406574
|
});
|
|
406693
406575
|
import { resolve as resolve89, isAbsolute as isAbsolute35, relative as relative26, basename as basename42, join as join142 } from "node:path";
|
|
406694
|
-
import { existsSync as
|
|
406576
|
+
import { existsSync as existsSync106, statSync as statSync19 } from "node:fs";
|
|
406695
406577
|
import { createInterface as createInterface8 } from "node:readline/promises";
|
|
406696
406578
|
function formatDisplayPath(projectPath) {
|
|
406697
406579
|
const rel = relative26(process.cwd(), projectPath);
|
|
@@ -406845,7 +406727,7 @@ async function runProjectAdd(name2, path14, options = {}) {
|
|
|
406845
406727
|
projectPath = pathInput.trim() || defaultPath;
|
|
406846
406728
|
}
|
|
406847
406729
|
const absolutePath2 = isAbsolute35(projectPath) ? projectPath : resolve89(process.cwd(), projectPath);
|
|
406848
|
-
if (!
|
|
406730
|
+
if (!existsSync106(absolutePath2)) {
|
|
406849
406731
|
console.error(`
|
|
406850
406732
|
\u2717 Path does not exist: ${projectPath}`);
|
|
406851
406733
|
rl.close();
|
|
@@ -406895,7 +406777,7 @@ async function runProjectAdd(name2, path14, options = {}) {
|
|
|
406895
406777
|
process.exit(1);
|
|
406896
406778
|
}
|
|
406897
406779
|
const absolutePath = isAbsolute35(projectPath) ? projectPath : resolve89(process.cwd(), projectPath);
|
|
406898
|
-
if (!
|
|
406780
|
+
if (!existsSync106(absolutePath)) {
|
|
406899
406781
|
console.error(`
|
|
406900
406782
|
\u2717 Path does not exist: ${projectPath}
|
|
406901
406783
|
`);
|
|
@@ -407180,7 +407062,7 @@ var init_project2 = __esm({
|
|
|
407180
407062
|
});
|
|
407181
407063
|
|
|
407182
407064
|
// src/commands/skill-installation.ts
|
|
407183
|
-
import { cpSync as cpSync7, existsSync as
|
|
407065
|
+
import { cpSync as cpSync7, existsSync as existsSync107, mkdirSync as mkdirSync20 } from "node:fs";
|
|
407184
407066
|
import { homedir as homedir21 } from "node:os";
|
|
407185
407067
|
import { dirname as dirname69, join as join143, resolve as resolve90 } from "node:path";
|
|
407186
407068
|
import { fileURLToPath as fileURLToPath27 } from "node:url";
|
|
@@ -407194,7 +407076,7 @@ function getSupportedSkillInstallTargets(homeDir = process.env.HOME || process.e
|
|
|
407194
407076
|
function resolveBundledFusionSkillSource4() {
|
|
407195
407077
|
const here = fileURLToPath27(import.meta.url);
|
|
407196
407078
|
const source = resolve90(dirname69(here), "..", "..", "skill", FUSION_SKILL_NAME5);
|
|
407197
|
-
return
|
|
407079
|
+
return existsSync107(source) ? source : null;
|
|
407198
407080
|
}
|
|
407199
407081
|
function installBundledFusionSkill(options = {}) {
|
|
407200
407082
|
const sourceDir = options.sourceDir ?? resolveBundledFusionSkillSource4();
|
|
@@ -407212,7 +407094,7 @@ function installBundledFusionSkill(options = {}) {
|
|
|
407212
407094
|
}
|
|
407213
407095
|
const results = targets.map((target) => {
|
|
407214
407096
|
try {
|
|
407215
|
-
if (
|
|
407097
|
+
if (existsSync107(target.targetDir)) {
|
|
407216
407098
|
return {
|
|
407217
407099
|
client: target.client,
|
|
407218
407100
|
targetDir: target.targetDir,
|
|
@@ -407251,7 +407133,7 @@ var init_exports = {};
|
|
|
407251
407133
|
__export(init_exports, {
|
|
407252
407134
|
runInit: () => runInit
|
|
407253
407135
|
});
|
|
407254
|
-
import { existsSync as
|
|
407136
|
+
import { existsSync as existsSync108, mkdirSync as mkdirSync21, writeFileSync as writeFileSync20, readFileSync as readFileSync42 } from "node:fs";
|
|
407255
407137
|
import { join as join144, resolve as resolve91, basename as basename43 } from "node:path";
|
|
407256
407138
|
import { exec as exec51 } from "node:child_process";
|
|
407257
407139
|
import { promisify as promisify77 } from "node:util";
|
|
@@ -407259,10 +407141,10 @@ async function runInit(options = {}) {
|
|
|
407259
407141
|
const cwd = options.path ? resolve91(options.path) : process.cwd();
|
|
407260
407142
|
const fusionDir = join144(cwd, ".fusion");
|
|
407261
407143
|
const dbPath = join144(fusionDir, "fusion.db");
|
|
407262
|
-
const hasDbPath =
|
|
407144
|
+
const hasDbPath = existsSync108(dbPath);
|
|
407263
407145
|
const hasValidDb = hasDbPath && isValidSqliteDatabaseFile(dbPath);
|
|
407264
407146
|
const hasIdentity = hasProjectIdentity(fusionDir);
|
|
407265
|
-
if (
|
|
407147
|
+
if (existsSync108(fusionDir) && (hasIdentity || hasValidDb)) {
|
|
407266
407148
|
const central2 = new CentralCore();
|
|
407267
407149
|
await central2.init();
|
|
407268
407150
|
const existing = await central2.getProjectByPath(cwd);
|
|
@@ -407291,7 +407173,7 @@ async function runInit(options = {}) {
|
|
|
407291
407173
|
await central2.close();
|
|
407292
407174
|
return;
|
|
407293
407175
|
}
|
|
407294
|
-
if (
|
|
407176
|
+
if (existsSync108(fusionDir) && !hasIdentity && hasDbPath && !hasValidDb) {
|
|
407295
407177
|
throw new Error(
|
|
407296
407178
|
`Existing database at ${dbPath} is not a valid SQLite database. Restore it from .fusion/backups or move it aside before re-running fn init.`
|
|
407297
407179
|
);
|
|
@@ -407299,7 +407181,7 @@ async function runInit(options = {}) {
|
|
|
407299
407181
|
const projectName = options.name ?? await detectProjectName2(cwd);
|
|
407300
407182
|
console.log(`Initializing fn project: "${projectName}"`);
|
|
407301
407183
|
console.log(` Path: ${cwd}`);
|
|
407302
|
-
if (!
|
|
407184
|
+
if (!existsSync108(fusionDir)) {
|
|
407303
407185
|
mkdirSync21(fusionDir, { recursive: true });
|
|
407304
407186
|
console.log(` \u2713 Created .fusion/ directory`);
|
|
407305
407187
|
}
|
|
@@ -407380,7 +407262,7 @@ async function runInit(options = {}) {
|
|
|
407380
407262
|
}
|
|
407381
407263
|
}
|
|
407382
407264
|
async function detectProjectName2(dir2) {
|
|
407383
|
-
if (!
|
|
407265
|
+
if (!existsSync108(join144(dir2, ".git"))) {
|
|
407384
407266
|
return basename43(dir2) || "my-project";
|
|
407385
407267
|
}
|
|
407386
407268
|
try {
|
|
@@ -407402,7 +407284,7 @@ async function detectProjectName2(dir2) {
|
|
|
407402
407284
|
async function addLocalStorageToGitignore(cwd) {
|
|
407403
407285
|
const gitignorePath = join144(cwd, ".gitignore");
|
|
407404
407286
|
let content = "";
|
|
407405
|
-
if (
|
|
407287
|
+
if (existsSync108(gitignorePath)) {
|
|
407406
407288
|
try {
|
|
407407
407289
|
content = readFileSync42(gitignorePath, "utf-8");
|
|
407408
407290
|
} catch {
|
|
@@ -407444,7 +407326,7 @@ async function initializeGitRepo(cwd) {
|
|
|
407444
407326
|
await ensureGitConfig(cwd, "user.name", "Fusion");
|
|
407445
407327
|
await ensureGitConfig(cwd, "user.email", "noreply@runfusion.ai");
|
|
407446
407328
|
const gitkeepPath = join144(cwd, ".gitkeep");
|
|
407447
|
-
if (!
|
|
407329
|
+
if (!existsSync108(gitkeepPath)) {
|
|
407448
407330
|
writeFileSync20(gitkeepPath, "\n");
|
|
407449
407331
|
}
|
|
407450
407332
|
await execAsync48("git add .gitkeep", { cwd, timeout: 1e4 });
|
|
@@ -407510,7 +407392,7 @@ __export(onboard_exports, {
|
|
|
407510
407392
|
persistLocalProviderRegistry: () => persistLocalProviderRegistry,
|
|
407511
407393
|
runOnboard: () => runOnboard
|
|
407512
407394
|
});
|
|
407513
|
-
import { existsSync as
|
|
407395
|
+
import { existsSync as existsSync109, mkdirSync as mkdirSync22, readFileSync as readFileSync43, renameSync as renameSync6, unlinkSync as unlinkSync8, writeFileSync as writeFileSync21 } from "node:fs";
|
|
407514
407396
|
import { dirname as dirname70 } from "node:path";
|
|
407515
407397
|
import { createInterface as createInterface9 } from "node:readline";
|
|
407516
407398
|
function createPromptSession(input = process.stdin) {
|
|
@@ -407639,7 +407521,7 @@ function composeLocalProviderRegistry(existing, config3) {
|
|
|
407639
407521
|
return { ...existing, providers };
|
|
407640
407522
|
}
|
|
407641
407523
|
function registryHasProvider(path14, providerId) {
|
|
407642
|
-
if (!
|
|
407524
|
+
if (!existsSync109(path14)) return false;
|
|
407643
407525
|
try {
|
|
407644
407526
|
const registry3 = JSON.parse(readFileSync43(path14, "utf8"));
|
|
407645
407527
|
return isObject2(registry3) && isObject2(registry3.providers) && isObject2(registry3.providers[providerId]);
|
|
@@ -407649,7 +407531,7 @@ function registryHasProvider(path14, providerId) {
|
|
|
407649
407531
|
}
|
|
407650
407532
|
function persistLocalProviderRegistry(path14, config3) {
|
|
407651
407533
|
let existing = {};
|
|
407652
|
-
if (
|
|
407534
|
+
if (existsSync109(path14)) {
|
|
407653
407535
|
try {
|
|
407654
407536
|
existing = JSON.parse(readFileSync43(path14, "utf8"));
|
|
407655
407537
|
} catch {
|
|
@@ -407664,7 +407546,7 @@ function persistLocalProviderRegistry(path14, config3) {
|
|
|
407664
407546
|
`, { mode: 384 });
|
|
407665
407547
|
renameSync6(tempPath, path14);
|
|
407666
407548
|
} finally {
|
|
407667
|
-
if (
|
|
407549
|
+
if (existsSync109(tempPath)) unlinkSync8(tempPath);
|
|
407668
407550
|
}
|
|
407669
407551
|
}
|
|
407670
407552
|
function validateMaxConcurrent(input) {
|
|
@@ -407699,7 +407581,7 @@ async function runOnboard(options = {}) {
|
|
|
407699
407581
|
const prompts = createPromptSession(options.input);
|
|
407700
407582
|
try {
|
|
407701
407583
|
const centralDbPath = getDefaultCentralDbPath();
|
|
407702
|
-
if (
|
|
407584
|
+
if (existsSync109(centralDbPath)) {
|
|
407703
407585
|
console.log(`\u2713 Central DB already exists: ${centralDbPath}`);
|
|
407704
407586
|
} else {
|
|
407705
407587
|
const ranCentralDb = await runSkippableStep(prompts, "Central DB", async () => {
|
|
@@ -407996,7 +407878,7 @@ var agent_import_exports = {};
|
|
|
407996
407878
|
__export(agent_import_exports, {
|
|
407997
407879
|
runAgentImport: () => runAgentImport
|
|
407998
407880
|
});
|
|
407999
|
-
import { existsSync as
|
|
407881
|
+
import { existsSync as existsSync110, mkdirSync as mkdirSync23, readFileSync as readFileSync44, statSync as statSync20, writeFileSync as writeFileSync22 } from "node:fs";
|
|
408000
407882
|
import { resolve as resolve92 } from "node:path";
|
|
408001
407883
|
function slugifyPathSegment(input) {
|
|
408002
407884
|
if (!input || typeof input !== "string") {
|
|
@@ -408055,7 +407937,7 @@ async function importSkillsToProject(projectPath, skills, companySlug, dryRun) {
|
|
|
408055
407937
|
const skillSlug = slugifyPathSegment(skill.name);
|
|
408056
407938
|
const skillDir = resolve92(baseSkillsDir, skillSlug);
|
|
408057
407939
|
const skillPath = resolve92(skillDir, "SKILL.md");
|
|
408058
|
-
if (
|
|
407940
|
+
if (existsSync110(skillPath)) {
|
|
408059
407941
|
result2.skipped.push(skill.name);
|
|
408060
407942
|
continue;
|
|
408061
407943
|
}
|
|
@@ -408116,7 +407998,7 @@ async function runAgentImport(source, options) {
|
|
|
408116
407998
|
const dryRun = options?.dryRun ?? false;
|
|
408117
407999
|
const skipExisting = options?.skipExisting ?? false;
|
|
408118
408000
|
const sourcePath = resolve92(source);
|
|
408119
|
-
if (!
|
|
408001
|
+
if (!existsSync110(sourcePath)) {
|
|
408120
408002
|
console.error(`Path not found: ${sourcePath}`);
|
|
408121
408003
|
process.exit(1);
|
|
408122
408004
|
}
|
|
@@ -408990,7 +408872,7 @@ __export(plugin_exports2, {
|
|
|
408990
408872
|
runPluginSetupStatus: () => runPluginSetupStatus,
|
|
408991
408873
|
runPluginUninstall: () => runPluginUninstall
|
|
408992
408874
|
});
|
|
408993
|
-
import { existsSync as
|
|
408875
|
+
import { existsSync as existsSync111 } from "node:fs";
|
|
408994
408876
|
import { dirname as dirname71, extname as extname6, join as join145, resolve as resolve96 } from "node:path";
|
|
408995
408877
|
import { readFile as readFile63, stat as stat19 } from "node:fs/promises";
|
|
408996
408878
|
import * as readline from "node:readline";
|
|
@@ -409085,7 +408967,7 @@ async function resolvePluginEntryFile(pluginDir) {
|
|
|
409085
408967
|
}
|
|
409086
408968
|
const packageJsonPath = join145(absoluteInputPath, "package.json");
|
|
409087
408969
|
let selectedCandidate;
|
|
409088
|
-
if (
|
|
408970
|
+
if (existsSync111(packageJsonPath)) {
|
|
409089
408971
|
const packageJson = JSON.parse(await readFile63(packageJsonPath, "utf-8"));
|
|
409090
408972
|
const exportsRecord = asRecord6(packageJson.exports);
|
|
409091
408973
|
const dotExport = exportsRecord?.["."];
|
|
@@ -409134,7 +409016,7 @@ async function loadManifestFromPath(pluginPath) {
|
|
|
409134
409016
|
const inputStats = await statPath(absoluteInputPath);
|
|
409135
409017
|
const manifestDir = inputStats?.isFile() ? dirname71(absoluteInputPath) : absoluteInputPath;
|
|
409136
409018
|
const manifestPath = join145(manifestDir, "manifest.json");
|
|
409137
|
-
if (!
|
|
409019
|
+
if (!existsSync111(manifestPath)) {
|
|
409138
409020
|
throw new Error(`Plugin manifest not found at: ${manifestPath}`);
|
|
409139
409021
|
}
|
|
409140
409022
|
const content = await readFile63(manifestPath, "utf-8");
|
|
@@ -409192,7 +409074,7 @@ async function runPluginInstall(source, options) {
|
|
|
409192
409074
|
console.error("Please provide a local path to the plugin directory.");
|
|
409193
409075
|
process.exit(1);
|
|
409194
409076
|
}
|
|
409195
|
-
if (!
|
|
409077
|
+
if (!existsSync111(source)) {
|
|
409196
409078
|
console.error(`Plugin path does not exist: ${source}`);
|
|
409197
409079
|
process.exit(1);
|
|
409198
409080
|
}
|
|
@@ -409515,7 +409397,7 @@ __export(plugin_scaffold_exports, {
|
|
|
409515
409397
|
runPluginCreate: () => runPluginCreate,
|
|
409516
409398
|
runPluginNew: () => runPluginNew
|
|
409517
409399
|
});
|
|
409518
|
-
import { mkdirSync as mkdirSync24, writeFileSync as writeFileSync23, existsSync as
|
|
409400
|
+
import { mkdirSync as mkdirSync24, writeFileSync as writeFileSync23, existsSync as existsSync112, readFileSync as readFileSync45 } from "node:fs";
|
|
409519
409401
|
import { join as join146, dirname as dirname72, resolve as resolve97 } from "node:path";
|
|
409520
409402
|
import { fileURLToPath as fileURLToPath28 } from "node:url";
|
|
409521
409403
|
function toTitleCase(str) {
|
|
@@ -409536,7 +409418,7 @@ function resolveTargetPath(name2, output) {
|
|
|
409536
409418
|
};
|
|
409537
409419
|
}
|
|
409538
409420
|
function ensureTargetPathAvailable(targetDir, targetPath) {
|
|
409539
|
-
if (
|
|
409421
|
+
if (existsSync112(targetPath)) {
|
|
409540
409422
|
console.error(`Error: Directory '${targetDir}' already exists.`);
|
|
409541
409423
|
console.error("Please choose a different name or remove the existing directory.");
|
|
409542
409424
|
process.exit(1);
|
|
@@ -409551,7 +409433,7 @@ function readOwnCliVersion() {
|
|
|
409551
409433
|
}
|
|
409552
409434
|
for (let i = 0; i < 8; i += 1) {
|
|
409553
409435
|
const pkgPath = resolve97(currentDir, "package.json");
|
|
409554
|
-
if (
|
|
409436
|
+
if (existsSync112(pkgPath)) {
|
|
409555
409437
|
try {
|
|
409556
409438
|
const parsed = JSON.parse(readFileSync45(pkgPath, "utf-8"));
|
|
409557
409439
|
if (parsed.name === "@runfusion/fusion" && typeof parsed.version === "string") {
|
|
@@ -409913,7 +409795,7 @@ var plugin_dev_exports = {};
|
|
|
409913
409795
|
__export(plugin_dev_exports, {
|
|
409914
409796
|
runPluginDev: () => runPluginDev
|
|
409915
409797
|
});
|
|
409916
|
-
import { existsSync as
|
|
409798
|
+
import { existsSync as existsSync113, watch as watch2 } from "node:fs";
|
|
409917
409799
|
import { join as join147, resolve as resolve98 } from "node:path";
|
|
409918
409800
|
async function runSupervisedCommand(command, cwd, timeoutMs = 12e4) {
|
|
409919
409801
|
await new Promise((resolvePromise, rejectPromise) => {
|
|
@@ -409959,7 +409841,7 @@ async function defaultBuildFn(pluginDir) {
|
|
|
409959
409841
|
await runSupervisedCommand("npm run build", pluginDir);
|
|
409960
409842
|
}
|
|
409961
409843
|
function defaultWatchFn(pluginDir, onChange) {
|
|
409962
|
-
const watchPath =
|
|
409844
|
+
const watchPath = existsSync113(join147(pluginDir, "src")) ? join147(pluginDir, "src") : pluginDir;
|
|
409963
409845
|
try {
|
|
409964
409846
|
const watcher = watch2(watchPath, { recursive: true }, onChange);
|
|
409965
409847
|
return { close: () => watcher.close() };
|
|
@@ -409975,7 +409857,7 @@ function shouldUseWatcher(options) {
|
|
|
409975
409857
|
return Boolean(process.stdout.isTTY && process.stdin.isTTY);
|
|
409976
409858
|
}
|
|
409977
409859
|
async function runPluginDev(source, options) {
|
|
409978
|
-
if (!
|
|
409860
|
+
if (!existsSync113(source)) {
|
|
409979
409861
|
console.error(`Plugin path does not exist: ${source}`);
|
|
409980
409862
|
process.exit(1);
|
|
409981
409863
|
}
|
|
@@ -410095,7 +409977,7 @@ __export(plugin_publish_exports, {
|
|
|
410095
409977
|
collectPluginPreflight: () => collectPluginPreflight,
|
|
410096
409978
|
runPluginPublish: () => runPluginPublish
|
|
410097
409979
|
});
|
|
410098
|
-
import { existsSync as
|
|
409980
|
+
import { existsSync as existsSync114 } from "node:fs";
|
|
410099
409981
|
import { readFile as readFile64 } from "node:fs/promises";
|
|
410100
409982
|
import { join as join148, resolve as resolve99 } from "node:path";
|
|
410101
409983
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
@@ -410256,7 +410138,7 @@ function statusIcon(status) {
|
|
|
410256
410138
|
return "\u2717";
|
|
410257
410139
|
}
|
|
410258
410140
|
async function runPluginPublish(source, options) {
|
|
410259
|
-
if (!
|
|
410141
|
+
if (!existsSync114(source)) {
|
|
410260
410142
|
console.error(`Plugin path does not exist: ${source}`);
|
|
410261
410143
|
process.exit(1);
|
|
410262
410144
|
}
|
|
@@ -410825,7 +410707,7 @@ __export(update_exports, {
|
|
|
410825
410707
|
runUpdate: () => runUpdate
|
|
410826
410708
|
});
|
|
410827
410709
|
import { exec as exec52 } from "node:child_process";
|
|
410828
|
-
import { existsSync as
|
|
410710
|
+
import { existsSync as existsSync115, readFileSync as readFileSync46 } from "node:fs";
|
|
410829
410711
|
import { promisify as promisify78 } from "node:util";
|
|
410830
410712
|
import { dirname as dirname73, resolve as resolve102 } from "node:path";
|
|
410831
410713
|
import { fileURLToPath as fileURLToPath29 } from "node:url";
|
|
@@ -410888,7 +410770,7 @@ function readOwnCliVersion2() {
|
|
|
410888
410770
|
}
|
|
410889
410771
|
for (let i = 0; i < 8; i += 1) {
|
|
410890
410772
|
const pkgPath = resolve102(currentDir, "package.json");
|
|
410891
|
-
if (
|
|
410773
|
+
if (existsSync115(pkgPath)) {
|
|
410892
410774
|
try {
|
|
410893
410775
|
const parsed = JSON.parse(readFileSync46(pkgPath, "utf-8"));
|
|
410894
410776
|
if (parsed.name === "@runfusion/fusion" && typeof parsed.version === "string") {
|
|
@@ -411169,7 +411051,7 @@ __export(onboard_autolaunch_exports, {
|
|
|
411169
411051
|
maybeAutoLaunchOnboarding: () => maybeAutoLaunchOnboarding,
|
|
411170
411052
|
shouldAutoLaunchOnboarding: () => shouldAutoLaunchOnboarding
|
|
411171
411053
|
});
|
|
411172
|
-
import { existsSync as
|
|
411054
|
+
import { existsSync as existsSync116 } from "node:fs";
|
|
411173
411055
|
import { join as join150 } from "node:path";
|
|
411174
411056
|
function shouldAutoLaunchOnboarding(input) {
|
|
411175
411057
|
const env = input.env ?? process.env;
|
|
@@ -411234,7 +411116,7 @@ async function maybeAutoLaunchOnboarding(deps) {
|
|
|
411234
411116
|
let centralDbExists = true;
|
|
411235
411117
|
let projectInitialized = false;
|
|
411236
411118
|
try {
|
|
411237
|
-
const pathExists4 = deps.pathExists ??
|
|
411119
|
+
const pathExists4 = deps.pathExists ?? existsSync116;
|
|
411238
411120
|
const centralDbPath = deps.centralDbPath ?? getDefaultCentralDbPath();
|
|
411239
411121
|
const cwd = deps.cwd ?? process.cwd();
|
|
411240
411122
|
const projectMarkerPath = join150(cwd, ".fusion", "project.json");
|
|
@@ -411295,7 +411177,7 @@ __export(native_patch_exports, {
|
|
|
411295
411177
|
setupNativeResolution: () => setupNativeResolution
|
|
411296
411178
|
});
|
|
411297
411179
|
import { join as join151, basename as basename44, dirname as dirname74 } from "node:path";
|
|
411298
|
-
import { existsSync as
|
|
411180
|
+
import { existsSync as existsSync117, copyFileSync as copyFileSync2, mkdirSync as mkdirSync25, symlinkSync as symlinkSync7, rmSync as rmSync16, lstatSync as lstatSync7, readlinkSync as readlinkSync5 } from "node:fs";
|
|
411299
411181
|
import { tmpdir as tmpdir22 } from "node:os";
|
|
411300
411182
|
function findStagedNativeDir2() {
|
|
411301
411183
|
const platform6 = process.platform === "darwin" ? "darwin" : process.platform === "linux" ? "linux" : process.platform === "win32" ? "win32" : "unknown";
|
|
@@ -411303,12 +411185,12 @@ function findStagedNativeDir2() {
|
|
|
411303
411185
|
const prebuildName = `${platform6}-${arch}`;
|
|
411304
411186
|
const execDir = dirname74(process.execPath);
|
|
411305
411187
|
const nextToBinary = join151(execDir, "runtime", prebuildName);
|
|
411306
|
-
if (
|
|
411188
|
+
if (existsSync117(join151(nextToBinary, "pty.node"))) {
|
|
411307
411189
|
return nextToBinary;
|
|
411308
411190
|
}
|
|
411309
411191
|
if (process.env.FUSION_RUNTIME_DIR) {
|
|
411310
411192
|
const envPath = join151(process.env.FUSION_RUNTIME_DIR, prebuildName);
|
|
411311
|
-
if (
|
|
411193
|
+
if (existsSync117(join151(envPath, "pty.node"))) {
|
|
411312
411194
|
return envPath;
|
|
411313
411195
|
}
|
|
411314
411196
|
}
|
|
@@ -411318,11 +411200,11 @@ function cleanupStaleBunfsLinks() {
|
|
|
411318
411200
|
if (process.platform === "win32") return;
|
|
411319
411201
|
const bunfsRoot = "/$bunfs/root";
|
|
411320
411202
|
try {
|
|
411321
|
-
if (
|
|
411203
|
+
if (existsSync117(bunfsRoot)) {
|
|
411322
411204
|
const stats = lstatSync7(bunfsRoot);
|
|
411323
411205
|
if (stats.isSymbolicLink()) {
|
|
411324
411206
|
const target = readlinkSync5(bunfsRoot);
|
|
411325
|
-
if (target.includes("fn-bunfs-") && !
|
|
411207
|
+
if (target.includes("fn-bunfs-") && !existsSync117(target)) {
|
|
411326
411208
|
rmSync16(bunfsRoot);
|
|
411327
411209
|
console.log("[fn-native-patch] Cleaned up stale /$bunfs/root symlink");
|
|
411328
411210
|
}
|
|
@@ -411350,14 +411232,14 @@ function setupNativeResolution() {
|
|
|
411350
411232
|
mkdirSync25(platformDir, { recursive: true });
|
|
411351
411233
|
const ptyNodeDest = join151(platformDir, "pty.node");
|
|
411352
411234
|
copyFileSync2(join151(nativeDir, "pty.node"), ptyNodeDest);
|
|
411353
|
-
if (
|
|
411235
|
+
if (existsSync117(join151(nativeDir, "spawn-helper"))) {
|
|
411354
411236
|
copyFileSync2(join151(nativeDir, "spawn-helper"), join151(platformDir, "spawn-helper"));
|
|
411355
411237
|
}
|
|
411356
411238
|
process.env.FUSION_FAKE_BUNFS_ROOT = tmpRoot;
|
|
411357
411239
|
if (process.platform !== "win32") {
|
|
411358
411240
|
const bunfsRoot = "/$bunfs/root";
|
|
411359
411241
|
try {
|
|
411360
|
-
if (
|
|
411242
|
+
if (existsSync117(bunfsRoot)) {
|
|
411361
411243
|
const stats = lstatSync7(bunfsRoot);
|
|
411362
411244
|
if (stats.isSymbolicLink()) {
|
|
411363
411245
|
rmSync16(bunfsRoot);
|
|
@@ -411380,7 +411262,7 @@ function setupNativeResolution() {
|
|
|
411380
411262
|
function cleanupNativeResolution() {
|
|
411381
411263
|
if (bunfsSymlinkPath && process.platform !== "win32") {
|
|
411382
411264
|
try {
|
|
411383
|
-
if (
|
|
411265
|
+
if (existsSync117(bunfsSymlinkPath)) {
|
|
411384
411266
|
const stats = lstatSync7(bunfsSymlinkPath);
|
|
411385
411267
|
if (stats.isSymbolicLink()) {
|
|
411386
411268
|
rmSync16(bunfsSymlinkPath);
|
|
@@ -411427,7 +411309,7 @@ var init_native_patch = __esm({
|
|
|
411427
411309
|
|
|
411428
411310
|
// src/bin.ts
|
|
411429
411311
|
init_output();
|
|
411430
|
-
import { existsSync as
|
|
411312
|
+
import { existsSync as existsSync118, mkdtempSync as mkdtempSync5, readFileSync as readFileSync47, symlinkSync as symlinkSync8, writeFileSync as writeFileSync24 } from "node:fs";
|
|
411431
411313
|
import { createRequire as createRequire14 } from "node:module";
|
|
411432
411314
|
import { join as join152, dirname as dirname75, resolve as resolve103 } from "node:path";
|
|
411433
411315
|
import { tmpdir as tmpdir23 } from "node:os";
|
|
@@ -411452,7 +411334,7 @@ function configurePiPackage() {
|
|
|
411452
411334
|
packageJson = JSON.parse(readFileSync47(piPackagePath, "utf-8"));
|
|
411453
411335
|
for (const entry of ["dist", "docs", "examples", "README.md", "CHANGELOG.md"]) {
|
|
411454
411336
|
const source = join152(piPackageDir, entry);
|
|
411455
|
-
if (
|
|
411337
|
+
if (existsSync118(source)) {
|
|
411456
411338
|
symlinkSync8(source, join152(tmp, entry));
|
|
411457
411339
|
}
|
|
411458
411340
|
}
|
|
@@ -411472,7 +411354,7 @@ setInterval(() => {
|
|
|
411472
411354
|
performance4.clearResourceTimings();
|
|
411473
411355
|
}, 1e3).unref();
|
|
411474
411356
|
function loadEnvFile(path14) {
|
|
411475
|
-
if (!
|
|
411357
|
+
if (!existsSync118(path14)) return;
|
|
411476
411358
|
const contents = readFileSync47(path14, "utf-8");
|
|
411477
411359
|
for (const rawLine of contents.split(/\r?\n/)) {
|
|
411478
411360
|
const line2 = rawLine.trim();
|
|
@@ -411995,7 +411877,7 @@ function readOwnCliVersion3() {
|
|
|
411995
411877
|
}
|
|
411996
411878
|
for (let i = 0; i < 8; i += 1) {
|
|
411997
411879
|
const pkgPath = resolve103(currentDir, "package.json");
|
|
411998
|
-
if (
|
|
411880
|
+
if (existsSync118(pkgPath)) {
|
|
411999
411881
|
try {
|
|
412000
411882
|
const parsed = JSON.parse(readFileSync47(pkgPath, "utf-8"));
|
|
412001
411883
|
if (parsed.name === "@runfusion/fusion" && typeof parsed.version === "string") {
|