@runfusion/fusion 0.74.0-beta.2 → 0.74.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +847 -655
- package/dist/child-process-worker.js +414 -231
- package/dist/client/.vite/manifest.json +268 -268
- package/dist/client/assets/{AgentDetailView-DH4Cn5iG.js → AgentDetailView-D0J_GDct.js} +1 -1
- package/dist/client/assets/{AgentPermissionPolicyEditor-BycC7HhP.js → AgentPermissionPolicyEditor-BBAwprvO.js} +1 -1
- package/dist/client/assets/{AgentsView-Dkij8Sm8.js → AgentsView-DTY5DIav.js} +3 -3
- package/dist/client/assets/{ChatView-DAsZY1We.js → ChatView-CRoW2tRJ.js} +1 -1
- package/dist/client/assets/{CommandCenter-jTzBo-pg.js → CommandCenter-BieyKvKb.js} +1 -1
- package/dist/client/assets/{DevServerView-CxlacYJp.js → DevServerView-CLR1LmhK.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-DsCk3Nsw.js → DirectoryPicker-B-olNAvT.js} +1 -1
- package/dist/client/assets/{DocumentsView-8EI6KNBY.js → DocumentsView-CG_-pnXU.js} +1 -1
- package/dist/client/assets/{EvalsView-kYnaIk11.js → EvalsView-Xp0zCUlr.js} +1 -1
- package/dist/client/assets/{ExperimentalAgentOnboardingModal-ce6DROKD.js → ExperimentalAgentOnboardingModal-z8m5V5yv.js} +1 -1
- package/dist/client/assets/{GoalsView-BVlTtw-u.js → GoalsView-Bd-4g949.js} +1 -1
- package/dist/client/assets/{InsightsView-BKQeROkb.js → InsightsView-tCgg66wJ.js} +1 -1
- package/dist/client/assets/{MemoryView-DCzTnxsV.js → MemoryView-Dqgsd_0E.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-C94HwDz5.js → PiExtensionsManager-GzGoWgb5.js} +1 -1
- package/dist/client/assets/{PluginManager-C3DegklW.js → PluginManager-BWdqEqr9.js} +1 -1
- package/dist/client/assets/{PullRequestView-CrE89UL7.js → PullRequestView-CQq1G1kY.js} +1 -1
- package/dist/client/assets/{ReportModal-BD1ZUDdV.js → ReportModal-C-3rBFhw.js} +1 -1
- package/dist/client/assets/{ResearchView-eMiRw1EM.js → ResearchView-CS1HwDg_.js} +1 -1
- package/dist/client/assets/{SecretsView-6qK8Idb7.js → SecretsView-C6RP9Rkw.js} +1 -1
- package/dist/client/assets/{SessionTerminal-DtFLyUaK.js → SessionTerminal-C9nCSefk.js} +1 -1
- package/dist/client/assets/SettingsModal-C1oEklYy.css +1 -0
- package/dist/client/assets/{SettingsModal-BkOSlfyr.js → SettingsModal-D3DCvCfP.js} +1 -1
- package/dist/client/assets/{SettingsModal-DSq-_qwo.js → SettingsModal-D4mjT8hw.js} +3 -3
- package/dist/client/assets/{SettingsTextareaRow-Btyx5kaR.js → SettingsTextareaRow-zBVXQbcC.js} +1 -1
- package/dist/client/assets/{SetupWizardModal-Blhx-dRt.js → SetupWizardModal-C9r1dd-h.js} +2 -2
- package/dist/client/assets/{SkillsView-DGE5kYc3.js → SkillsView-DFyUBWd8.js} +1 -1
- package/dist/client/assets/{TodoView-YSGI7ATd.js → TodoView-BC8f952m.js} +1 -1
- package/dist/client/assets/{WorkflowNodeEditor-CZiEThu2.js → WorkflowNodeEditor-UTX757WH.js} +1 -1
- package/dist/client/assets/{agent-import-generation-DQeNZMAm.js → agent-import-generation-DN0q1xEo.js} +1 -1
- package/dist/client/assets/{app-DJIiVHdA.js → app-BP57l_5h.js} +1 -1
- package/dist/client/assets/{app-hQw_x2KJ.js → app-D4frL0Ka.js} +1 -1
- package/dist/client/assets/{app-DaikOPcV.js → app-niWDkeV8.js} +3 -3
- package/dist/client/assets/{app-Dn1u7zJ9.js → app-sLOwmHAE.js} +1 -1
- package/dist/client/assets/{app-DMZ_RusZ.js → app-vRWwM-aD.js} +1 -1
- package/dist/client/assets/{app-DxTbBEMH.js → app-zPyey_fg.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-DhaJNKa4.js → architectureDiagram-3BPJPVTR-D-nqJ95-.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-pKpg7gJU.js → blockDiagram-GPEHLZMM--OlkXlyS.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-DVPXKJnr.js → c4Diagram-AAUBKEIU-CH7PaWgs.js} +1 -1
- package/dist/client/assets/channel-FJNMzlkv.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-CHt90T5z.js → chunk-2J33WTMH-CpHDwqg2.js} +1 -1
- package/dist/client/assets/{chunk-4BX2VUAB-DsWFYy0a.js → chunk-4BX2VUAB-BdW4tdnc.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-D8XiXEo8.js → chunk-55IACEB6-b3tBFiuH.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-DlUYBn_Y.js → chunk-727SXJPM-DifknEtv.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-BSdPOr9q.js → chunk-AQP2D5EJ-DHIZNZ4Z.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-B9IAeBld.js → chunk-FMBD7UC4-BLRLYW2y.js} +1 -1
- package/dist/client/assets/{chunk-ND2GUHAM-CmxnYQrR.js → chunk-ND2GUHAM-Dh8f06Ld.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-Dxp6Po_j.js → chunk-QZHKN3VN-CpzUiemt.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-BOenhjVP.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BOenhjVP.js +1 -0
- package/dist/client/assets/common-13IRj_PO.js +1 -0
- package/dist/client/assets/common-BBynATth.js +1 -0
- package/dist/client/assets/common-BG-vw0tL.js +1 -0
- package/dist/client/assets/common-DSo46rnH.js +1 -0
- package/dist/client/assets/common-DbOCE-0i.js +1 -0
- package/dist/client/assets/common-DnXF4Jmj.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-BNl3bhpS.js → cose-bilkent-S5V4N54A-CE2RJ_k0.js} +1 -1
- package/dist/client/assets/{dagre-BM42HDAG-DFs7WCcz.js → dagre-BM42HDAG-CCs_xlYw.js} +1 -1
- package/dist/client/assets/{dashboard-view-vc8kgLMs.js → dashboard-view-D5qv61fP.js} +1 -1
- package/dist/client/assets/{dashboard-view-ZGxLEL9r.js → dashboard-view-Eg7Jyvnm.js} +1 -1
- package/dist/client/assets/{dashboard-view-DnoTcnIo.js → dashboard-view-Z6H-k0uR.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-C2PVozvu.js → diagram-2AECGRRQ-CF60Q-de.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-DFJ5b9H8.js → diagram-5GNKFQAL-DDcGMlua.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-D335CW-c.js → diagram-KO2AKTUF-YgvJ4DQf.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-DSfhroAW.js → diagram-LMA3HP47-Bi-j9nGw.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-8iGveM-Z.js → diagram-OG6HWLK6-DEmMqnwc.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-Xc56MEEi.js → erDiagram-TEJ5UH35-DwmZwhiW.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-DjCU9WbD.js → flowDiagram-I6XJVG4X-B5ITa_HJ.js} +1 -1
- package/dist/client/assets/{folder-open-BRrB44UX.js → folder-open-BVxA7YtM.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-CXQE1bea.js → ganttDiagram-6RSMTGT7-BgAPwh9w.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII--mrSABLC.js → gitGraphDiagram-PVQCEYII-DTtGzZFj.js} +1 -1
- package/dist/client/assets/{index-C2xsZoNG.js → index-idkERMsE.js} +289 -289
- package/dist/client/assets/{infoDiagram-5YYISTIA-CTS_nljP.js → infoDiagram-5YYISTIA-CkSnTje1.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CpV5x3gk.js → ishikawaDiagram-YF4QCWOH-jn5VNpMh.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-BK2QCMnt.js → journeyDiagram-JHISSGLW-BpaqoXaI.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-B4srpspY.js → kanban-definition-UN3LZRKU-CpfjJoBN.js} +1 -1
- package/dist/client/assets/{mermaid.core-B8DVAt21.js → mermaid.core-DZNGPQzF.js} +4 -4
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-CsmmiPpA.js → mindmap-definition-RKZ34NQL-BdbX1EJa.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-BahLDqf4.js → pieDiagram-4H26LBE5-Xn0322tJ.js} +1 -1
- package/dist/client/assets/{puzzle-BFPQsuIa.js → puzzle-CPx1RP2g.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-Bo3u0wTU.js → quadrantDiagram-W4KKPZXB-OOHqqw5y.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-DYkYsz7d.js → requirementDiagram-4Y6WPE33-Dvj6zvaB.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-BCbh0BSY.js → sankeyDiagram-5OEKKPKP-DEkEqthK.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-C2AP9GlE.js → sequenceDiagram-3UESZ5HK-BPc9ncPj.js} +1 -1
- package/dist/client/assets/{shield-alert-tlZOi02c.js → shield-alert-baoKRyU6.js} +1 -1
- package/dist/client/assets/{standing-instructions-template-C0Rzv9Mr.js → standing-instructions-template-CkqsGC1L.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-CARkH0ug.js → stateDiagram-AJRCARHV-DywhjHIx.js} +1 -1
- package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-C2He043y.js → stateDiagram-v2-BHNVJYJU-D7t7x4uT.js} +1 -1
- package/dist/client/assets/{timeline-definition-PNZ67QCA-MvbYneEM.js → timeline-definition-PNZ67QCA-BH3CKgrg.js} +1 -1
- package/dist/client/assets/{upload-DWK0F17Z.js → upload-DtIvOGwM.js} +1 -1
- package/dist/client/assets/{users-1AkDfM14.js → users-DcxsxPlj.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-DOjzzLqc.js → vennDiagram-CIIHVFJN-CCDllBgJ.js} +1 -1
- package/dist/client/assets/{wardley-L42UT6IY-Di70vhu2.js → wardley-L42UT6IY-C43hFLXh.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-nK6ARhDv.js → wardleyDiagram-YWT4CUSO-__f9rI8w.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-C7_y76B7.js → xychartDiagram-2RQKCTM6-DY-fpQ_x.js} +1 -1
- package/dist/client/index.html +1 -1
- package/dist/client/version.json +1 -1
- package/dist/extension.js +551 -368
- package/package.json +1 -1
- package/skill/fusion/references/engine-tools.md +1 -1
- package/dist/client/assets/SettingsModal-BTfZlghk.css +0 -1
- package/dist/client/assets/channel-xFBfK0sX.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-BFBVD968.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BFBVD968.js +0 -1
- package/dist/client/assets/common-BDp2y6CF.js +0 -1
- package/dist/client/assets/common-BnEo5fLN.js +0 -1
- package/dist/client/assets/common-Bzr_Y8h4.js +0 -1
- package/dist/client/assets/common-CvwyFzfv.js +0 -1
- package/dist/client/assets/common-CztCXRkz.js +0 -1
- package/dist/client/assets/common-DPe2mbb7.js +0 -1
package/dist/extension.js
CHANGED
|
@@ -5525,7 +5525,7 @@ var init_sql = __esm({
|
|
|
5525
5525
|
return new SQL([new StringChunk(str)]);
|
|
5526
5526
|
}
|
|
5527
5527
|
sql2.raw = raw;
|
|
5528
|
-
function
|
|
5528
|
+
function join109(chunks, separator) {
|
|
5529
5529
|
const result2 = [];
|
|
5530
5530
|
for (const [i, chunk] of chunks.entries()) {
|
|
5531
5531
|
if (i > 0 && separator !== void 0) {
|
|
@@ -5535,7 +5535,7 @@ var init_sql = __esm({
|
|
|
5535
5535
|
}
|
|
5536
5536
|
return new SQL(result2);
|
|
5537
5537
|
}
|
|
5538
|
-
sql2.join =
|
|
5538
|
+
sql2.join = join109;
|
|
5539
5539
|
function identifier(value) {
|
|
5540
5540
|
return new Name(value);
|
|
5541
5541
|
}
|
|
@@ -10183,7 +10183,7 @@ var init_select2 = __esm({
|
|
|
10183
10183
|
const baseTableName = this.tableName;
|
|
10184
10184
|
const tableName = getTableLikeName(table);
|
|
10185
10185
|
for (const item of extractUsedTable(table)) this.usedTables.add(item);
|
|
10186
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
10186
|
+
if (typeof tableName === "string" && this.config.joins?.some((join109) => join109.alias === tableName)) {
|
|
10187
10187
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
10188
10188
|
}
|
|
10189
10189
|
if (!this.isPartialSelect) {
|
|
@@ -11718,7 +11718,7 @@ var init_update = __esm({
|
|
|
11718
11718
|
createJoin(joinType) {
|
|
11719
11719
|
return (table, on) => {
|
|
11720
11720
|
const tableName = getTableLikeName(table);
|
|
11721
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
11721
|
+
if (typeof tableName === "string" && this.config.joins.some((join109) => join109.alias === tableName)) {
|
|
11722
11722
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
11723
11723
|
}
|
|
11724
11724
|
if (typeof on === "function") {
|
|
@@ -11814,10 +11814,10 @@ var init_update = __esm({
|
|
|
11814
11814
|
const fromFields = this.getTableLikeFields(this.config.from);
|
|
11815
11815
|
fields[tableName] = fromFields;
|
|
11816
11816
|
}
|
|
11817
|
-
for (const
|
|
11818
|
-
const tableName2 = getTableLikeName(
|
|
11819
|
-
if (typeof tableName2 === "string" && !is(
|
|
11820
|
-
const fromFields = this.getTableLikeFields(
|
|
11817
|
+
for (const join109 of this.config.joins) {
|
|
11818
|
+
const tableName2 = getTableLikeName(join109.table);
|
|
11819
|
+
if (typeof tableName2 === "string" && !is(join109.table, SQL)) {
|
|
11820
|
+
const fromFields = this.getTableLikeFields(join109.table);
|
|
11821
11821
|
fields[tableName2] = fromFields;
|
|
11822
11822
|
}
|
|
11823
11823
|
}
|
|
@@ -20421,26 +20421,26 @@ function validateParallelism(nodes2, outgoing, nodesById) {
|
|
|
20421
20421
|
}
|
|
20422
20422
|
const joinsReached = /* @__PURE__ */ new Set();
|
|
20423
20423
|
for (const edge of branchEdges) {
|
|
20424
|
-
const
|
|
20425
|
-
if (!
|
|
20424
|
+
const join110 = walkBranchToJoin(edge.to, split.id, outgoing, nodesById);
|
|
20425
|
+
if (!join110) {
|
|
20426
20426
|
throw new WorkflowIrError(`split '${split.id}' has a branch with no reachable matching join`);
|
|
20427
20427
|
}
|
|
20428
|
-
joinsReached.add(
|
|
20428
|
+
joinsReached.add(join110);
|
|
20429
20429
|
}
|
|
20430
20430
|
if (joinsReached.size !== 1) {
|
|
20431
20431
|
throw new WorkflowIrError(`split '${split.id}' branches converge on more than one join`);
|
|
20432
20432
|
}
|
|
20433
20433
|
const joinId = [...joinsReached][0];
|
|
20434
|
-
const
|
|
20435
|
-
const mode =
|
|
20434
|
+
const join109 = nodesById.get(joinId);
|
|
20435
|
+
const mode = join109.config?.mode;
|
|
20436
20436
|
if (mode && typeof mode === "object" && "quorum" in mode) {
|
|
20437
20437
|
const n = mode.quorum;
|
|
20438
20438
|
if (typeof n !== "number" || !Number.isInteger(n) || n < 1) {
|
|
20439
|
-
throw new WorkflowIrError(`join '${
|
|
20439
|
+
throw new WorkflowIrError(`join '${join109.id}' quorum must be a positive integer`);
|
|
20440
20440
|
}
|
|
20441
20441
|
if (n > branchEdges.length) {
|
|
20442
20442
|
throw new WorkflowIrError(
|
|
20443
|
-
`join '${
|
|
20443
|
+
`join '${join109.id}' quorum(${n}) exceeds the split's ${branchEdges.length} branches`
|
|
20444
20444
|
);
|
|
20445
20445
|
}
|
|
20446
20446
|
}
|
|
@@ -23996,14 +23996,14 @@ async function detectWorkspaceRepos(dir, runner = runGitCommand, timeout = DEFAU
|
|
|
23996
23996
|
return [];
|
|
23997
23997
|
}
|
|
23998
23998
|
const { stat: stat13 } = await import("node:fs/promises");
|
|
23999
|
-
const { join:
|
|
23999
|
+
const { join: join109 } = await import("node:path");
|
|
24000
24000
|
const found = [];
|
|
24001
24001
|
const EXCLUDED_ENTRIES = /* @__PURE__ */ new Set(["node_modules", ".fusion", ".git", ".pi"]);
|
|
24002
24002
|
for (const entry of entries) {
|
|
24003
24003
|
if (EXCLUDED_ENTRIES.has(entry)) continue;
|
|
24004
|
-
const childDir =
|
|
24004
|
+
const childDir = join109(dir, entry);
|
|
24005
24005
|
try {
|
|
24006
|
-
const s3 = await stat13(
|
|
24006
|
+
const s3 = await stat13(join109(childDir, ".git"));
|
|
24007
24007
|
if (!s3.isDirectory() && !s3.isFile()) continue;
|
|
24008
24008
|
} catch {
|
|
24009
24009
|
continue;
|
|
@@ -24016,9 +24016,9 @@ async function detectWorkspaceRepos(dir, runner = runGitCommand, timeout = DEFAU
|
|
|
24016
24016
|
}
|
|
24017
24017
|
async function isWorkspaceModeExplicitlyDisabled(projectPath) {
|
|
24018
24018
|
try {
|
|
24019
|
-
const { readFile:
|
|
24020
|
-
const { join:
|
|
24021
|
-
const raw = await
|
|
24019
|
+
const { readFile: readFile47 } = await import("node:fs/promises");
|
|
24020
|
+
const { join: join109 } = await import("node:path");
|
|
24021
|
+
const raw = await readFile47(join109(projectPath, ".fusion", "config.json"), "utf-8");
|
|
24022
24022
|
const config3 = JSON.parse(raw);
|
|
24023
24023
|
return config3.settings?.workspaceMode === false;
|
|
24024
24024
|
} catch {
|
|
@@ -24026,12 +24026,12 @@ async function isWorkspaceModeExplicitlyDisabled(projectPath) {
|
|
|
24026
24026
|
}
|
|
24027
24027
|
}
|
|
24028
24028
|
async function setWorkspaceModeInConfig(projectPath, value) {
|
|
24029
|
-
const { readFile:
|
|
24030
|
-
const { join:
|
|
24031
|
-
const configPath =
|
|
24029
|
+
const { readFile: readFile47, writeFile: writeFile35, mkdir: mkdir32 } = await import("node:fs/promises");
|
|
24030
|
+
const { join: join109 } = await import("node:path");
|
|
24031
|
+
const configPath = join109(projectPath, ".fusion", "config.json");
|
|
24032
24032
|
let config3 = {};
|
|
24033
24033
|
try {
|
|
24034
|
-
config3 = JSON.parse(await
|
|
24034
|
+
config3 = JSON.parse(await readFile47(configPath, "utf-8"));
|
|
24035
24035
|
} catch (err) {
|
|
24036
24036
|
if (err?.code !== "ENOENT") throw err;
|
|
24037
24037
|
}
|
|
@@ -24040,7 +24040,7 @@ async function setWorkspaceModeInConfig(projectPath, value) {
|
|
|
24040
24040
|
}
|
|
24041
24041
|
const settings = config3.settings;
|
|
24042
24042
|
settings.workspaceMode = value;
|
|
24043
|
-
await mkdir32(
|
|
24043
|
+
await mkdir32(join109(projectPath, ".fusion"), { recursive: true });
|
|
24044
24044
|
await writeFile35(configPath, JSON.stringify(config3, null, 2), "utf-8");
|
|
24045
24045
|
}
|
|
24046
24046
|
function isInRootRelativePath(entry, pathMod) {
|
|
@@ -24053,12 +24053,12 @@ function isInRootRelativePath(entry, pathMod) {
|
|
|
24053
24053
|
return true;
|
|
24054
24054
|
}
|
|
24055
24055
|
async function loadWorkspaceConfig(rootDir) {
|
|
24056
|
-
const { readFile:
|
|
24056
|
+
const { readFile: readFile47 } = await import("node:fs/promises");
|
|
24057
24057
|
const pathMod = await import("node:path");
|
|
24058
|
-
const { join:
|
|
24059
|
-
const configPath =
|
|
24058
|
+
const { join: join109 } = pathMod;
|
|
24059
|
+
const configPath = join109(rootDir, ".fusion", WORKSPACE_CONFIG_FILENAME);
|
|
24060
24060
|
try {
|
|
24061
|
-
const raw = await
|
|
24061
|
+
const raw = await readFile47(configPath, "utf-8");
|
|
24062
24062
|
const parsed = JSON.parse(raw);
|
|
24063
24063
|
if (parsed !== null && typeof parsed === "object" && "repos" in parsed && Array.isArray(parsed.repos) && parsed.repos.every((r) => typeof r === "string")) {
|
|
24064
24064
|
const rawRepos = parsed.repos;
|
|
@@ -24072,11 +24072,11 @@ async function loadWorkspaceConfig(rootDir) {
|
|
|
24072
24072
|
}
|
|
24073
24073
|
async function saveWorkspaceConfig(rootDir, config3) {
|
|
24074
24074
|
const { mkdir: mkdir32, writeFile: writeFile35 } = await import("node:fs/promises");
|
|
24075
|
-
const { join:
|
|
24076
|
-
const fusionDir =
|
|
24075
|
+
const { join: join109 } = await import("node:path");
|
|
24076
|
+
const fusionDir = join109(rootDir, ".fusion");
|
|
24077
24077
|
await mkdir32(fusionDir, { recursive: true });
|
|
24078
24078
|
await writeFile35(
|
|
24079
|
-
|
|
24079
|
+
join109(fusionDir, WORKSPACE_CONFIG_FILENAME),
|
|
24080
24080
|
JSON.stringify(config3, null, 2),
|
|
24081
24081
|
"utf-8"
|
|
24082
24082
|
);
|
|
@@ -38905,11 +38905,11 @@ async function rekeyFallbackProjectPartition(db, fallbackProjectId, registeredPr
|
|
|
38905
38905
|
const parentKey = `${fk.parentSchema}.${fk.parentTable}`;
|
|
38906
38906
|
if (!targetKeys.has(parentKey)) continue;
|
|
38907
38907
|
const childTarget = targetKeys.has(`${fk.childSchema}.${fk.childTable}`);
|
|
38908
|
-
const
|
|
38908
|
+
const join109 = fk.childColumns.map((column, index2) => `child.${quoteIdentifier(column)} IS NOT DISTINCT FROM parent.${quoteIdentifier(fk.parentColumns[index2])}`).join(" AND ");
|
|
38909
38909
|
const registeredChildScope = childTarget ? ` AND child.${quoteIdentifier("project_id")} = ${quoteLiteral(registeredProjectId)}` : "";
|
|
38910
38910
|
const unreplaced = await tx.execute(sql.raw(`SELECT EXISTS (
|
|
38911
38911
|
SELECT 1 FROM ${relationName({ schema: fk.childSchema, table: fk.childTable })} child
|
|
38912
|
-
JOIN ${relationName({ schema: fk.parentSchema, table: fk.parentTable })} parent ON ${
|
|
38912
|
+
JOIN ${relationName({ schema: fk.parentSchema, table: fk.parentTable })} parent ON ${join109}
|
|
38913
38913
|
JOIN fusion_rekey_conflict_candidates parent_candidate
|
|
38914
38914
|
ON parent_candidate.schema_name = ${quoteLiteral(fk.parentSchema)}
|
|
38915
38915
|
AND parent_candidate.table_name = ${quoteLiteral(fk.parentTable)}
|
|
@@ -49746,8 +49746,8 @@ var require_CronFileParser = __commonJS({
|
|
|
49746
49746
|
* @throws If file cannot be read
|
|
49747
49747
|
*/
|
|
49748
49748
|
static async parseFile(filePath) {
|
|
49749
|
-
const { readFile:
|
|
49750
|
-
const data = await
|
|
49749
|
+
const { readFile: readFile47 } = await Promise.resolve().then(() => __importStar(__require("fs/promises")));
|
|
49750
|
+
const data = await readFile47(filePath, "utf8");
|
|
49751
49751
|
return _CronFileParser.#parseContent(data);
|
|
49752
49752
|
}
|
|
49753
49753
|
/**
|
|
@@ -132671,8 +132671,8 @@ var require_graceful_fs = __commonJS({
|
|
|
132671
132671
|
fs10.createReadStream = createReadStream;
|
|
132672
132672
|
fs10.createWriteStream = createWriteStream;
|
|
132673
132673
|
var fs$readFile = fs10.readFile;
|
|
132674
|
-
fs10.readFile =
|
|
132675
|
-
function
|
|
132674
|
+
fs10.readFile = readFile47;
|
|
132675
|
+
function readFile47(path10, options, cb) {
|
|
132676
132676
|
if (typeof options === "function")
|
|
132677
132677
|
cb = options, options = null;
|
|
132678
132678
|
return go$readFile(path10, options, cb);
|
|
@@ -135388,10 +135388,10 @@ async function runHoldReleaseSweep(store, deps) {
|
|
|
135388
135388
|
}
|
|
135389
135389
|
return result2;
|
|
135390
135390
|
}
|
|
135391
|
-
async function issueRelease(store, deps, task, target, ir2) {
|
|
135391
|
+
async function issueRelease(store, deps, task, target, ir2, options = {}) {
|
|
135392
135392
|
const targetColumn = findColumn2(ir2, target);
|
|
135393
135393
|
const targetIsProcessing = targetColumn ? resolveColumnFlags(targetColumn).countsTowardWip === true : false;
|
|
135394
|
-
if (targetIsProcessing && await isUnplannedForExecution(store, task, ir2)) {
|
|
135394
|
+
if (targetIsProcessing && !options.allowUnplanned && await isUnplannedForExecution(store, task, ir2)) {
|
|
135395
135395
|
schedulerLog.log(`Hold release for ${task.id} blocked \u2014 card is unplanned and cannot enter processing column ${target}`);
|
|
135396
135396
|
return false;
|
|
135397
135397
|
}
|
|
@@ -135433,7 +135433,7 @@ async function issueRelease(store, deps, task, target, ir2) {
|
|
|
135433
135433
|
return false;
|
|
135434
135434
|
}
|
|
135435
135435
|
}
|
|
135436
|
-
async function promoteHeldTask(store, taskId, deps = {}) {
|
|
135436
|
+
async function promoteHeldTask(store, taskId, deps = {}, options = {}) {
|
|
135437
135437
|
const task = await store.getTask(taskId);
|
|
135438
135438
|
if (!task) return { released: false, rejection: "task-not-found" };
|
|
135439
135439
|
const ir2 = await resolveWorkflowIrForTask(store, taskId);
|
|
@@ -135444,17 +135444,50 @@ async function promoteHeldTask(store, taskId, deps = {}) {
|
|
|
135444
135444
|
if (!target) return { released: false, rejection: "no-release-target" };
|
|
135445
135445
|
const targetColumn = findColumn2(ir2, target);
|
|
135446
135446
|
const targetIsProcessing = targetColumn ? resolveColumnFlags(targetColumn).countsTowardWip === true : false;
|
|
135447
|
-
|
|
135447
|
+
const unplanned = targetIsProcessing && await isUnplannedForExecution(store, task, ir2);
|
|
135448
|
+
if (unplanned && options.force !== true) {
|
|
135448
135449
|
return { released: false, rejection: "unplanned-for-execution", toColumn: target };
|
|
135449
135450
|
}
|
|
135451
|
+
let promoted = task;
|
|
135452
|
+
if (unplanned) {
|
|
135453
|
+
if (task.status === "needs-replan" || task.status === "plan-review-unavailable") {
|
|
135454
|
+
try {
|
|
135455
|
+
await store.updateTask(task.id, { status: null });
|
|
135456
|
+
promoted = { ...task, status: void 0 };
|
|
135457
|
+
} catch (error3) {
|
|
135458
|
+
schedulerLog.warn(
|
|
135459
|
+
`Force-promote for ${task.id} could not clear replan status: ${error3 instanceof Error ? error3.message : String(error3)}`
|
|
135460
|
+
);
|
|
135461
|
+
}
|
|
135462
|
+
}
|
|
135463
|
+
if (typeof store.recordRunAuditEvent === "function") {
|
|
135464
|
+
try {
|
|
135465
|
+
await store.recordRunAuditEvent({
|
|
135466
|
+
domain: "database",
|
|
135467
|
+
mutationType: "task:promote-forced-unplanned",
|
|
135468
|
+
target: task.id,
|
|
135469
|
+
taskId: task.id,
|
|
135470
|
+
agentId: "system",
|
|
135471
|
+
runId: `promote-force-${task.id}`,
|
|
135472
|
+
metadata: { fromColumn: task.column, toColumn: target, priorStatus: task.status ?? null }
|
|
135473
|
+
});
|
|
135474
|
+
} catch {
|
|
135475
|
+
}
|
|
135476
|
+
}
|
|
135477
|
+
schedulerLog.log(`Force-promote for ${task.id} bypassing unplanned gate into ${target} (operator override)`);
|
|
135478
|
+
}
|
|
135450
135479
|
const released = await issueRelease(
|
|
135451
135480
|
store,
|
|
135452
135481
|
{ now: () => Date.now(), reserveSlot: deps.reserveSlot, allocateWorktree: deps.allocateWorktree },
|
|
135453
|
-
|
|
135482
|
+
promoted,
|
|
135454
135483
|
target,
|
|
135455
|
-
ir2
|
|
135484
|
+
ir2,
|
|
135485
|
+
{ allowUnplanned: unplanned }
|
|
135456
135486
|
);
|
|
135457
|
-
|
|
135487
|
+
if (!released) {
|
|
135488
|
+
return { released: false, rejection: "capacity-exhausted-or-no-slot" };
|
|
135489
|
+
}
|
|
135490
|
+
return { released: true, toColumn: target, forcedUnplanned: unplanned || void 0 };
|
|
135458
135491
|
}
|
|
135459
135492
|
async function releaseHeldTaskByEvent(store, taskId, eventTag, deps = {}) {
|
|
135460
135493
|
const task = await store.getTask(taskId);
|
|
@@ -161627,6 +161660,86 @@ var init_research_step_runner = __esm({
|
|
|
161627
161660
|
}
|
|
161628
161661
|
});
|
|
161629
161662
|
|
|
161663
|
+
// ../engine/src/plan-artifact-writeback.ts
|
|
161664
|
+
import { readFile as readFile29 } from "node:fs/promises";
|
|
161665
|
+
import { join as join61 } from "node:path";
|
|
161666
|
+
function relativePromptPath(taskId) {
|
|
161667
|
+
return `.fusion/tasks/${taskId}/PROMPT.md`;
|
|
161668
|
+
}
|
|
161669
|
+
async function readIfPresent(path10) {
|
|
161670
|
+
try {
|
|
161671
|
+
return await readFile29(path10, "utf-8");
|
|
161672
|
+
} catch {
|
|
161673
|
+
return null;
|
|
161674
|
+
}
|
|
161675
|
+
}
|
|
161676
|
+
async function reconcileWorktreePlanArtifact(options) {
|
|
161677
|
+
const { store, taskId, rootDir, planningCwd, logger: logger3 } = options;
|
|
161678
|
+
const relPath = relativePromptPath(taskId);
|
|
161679
|
+
const rootContent = await readIfPresent(join61(rootDir, relPath));
|
|
161680
|
+
if (planningCwd === rootDir) {
|
|
161681
|
+
return { outcome: "not-worktree", content: rootContent ?? void 0 };
|
|
161682
|
+
}
|
|
161683
|
+
const worktreeContent = await readIfPresent(join61(planningCwd, relPath));
|
|
161684
|
+
if (worktreeContent === null) {
|
|
161685
|
+
return { outcome: "no-worktree-artifact", content: rootContent ?? void 0 };
|
|
161686
|
+
}
|
|
161687
|
+
if (worktreeContent.trim().length === 0) {
|
|
161688
|
+
return { outcome: "worktree-artifact-empty", content: rootContent ?? void 0 };
|
|
161689
|
+
}
|
|
161690
|
+
if (rootContent === worktreeContent) {
|
|
161691
|
+
return { outcome: "already-authoritative", content: rootContent };
|
|
161692
|
+
}
|
|
161693
|
+
try {
|
|
161694
|
+
await store.updateTask(taskId, { prompt: worktreeContent });
|
|
161695
|
+
logger3?.log?.(
|
|
161696
|
+
`${taskId}: recovered a worktree-local PROMPT.md into the project .fusion folder (${planningCwd})`
|
|
161697
|
+
);
|
|
161698
|
+
return { outcome: "recovered", content: worktreeContent };
|
|
161699
|
+
} catch (error3) {
|
|
161700
|
+
const message = error3 instanceof Error ? error3.message : String(error3);
|
|
161701
|
+
logger3?.warn?.(
|
|
161702
|
+
`${taskId}: failed to copy the worktree-local PROMPT.md back into the project .fusion folder: ${message}`
|
|
161703
|
+
);
|
|
161704
|
+
return { outcome: "recovery-failed", content: rootContent ?? void 0 };
|
|
161705
|
+
}
|
|
161706
|
+
}
|
|
161707
|
+
async function mirrorPlanToProjectDb(store, taskId, content, options = {}) {
|
|
161708
|
+
if (content.trim().length === 0) return false;
|
|
161709
|
+
if (typeof store.upsertTaskDocument !== "function") return false;
|
|
161710
|
+
try {
|
|
161711
|
+
if (typeof store.getTaskDocument === "function") {
|
|
161712
|
+
const existing = await store.getTaskDocument(taskId, PLAN_DOCUMENT_KEY);
|
|
161713
|
+
if (typeof existing?.content === "string" && existing.content === content) return false;
|
|
161714
|
+
}
|
|
161715
|
+
await store.upsertTaskDocument(taskId, {
|
|
161716
|
+
key: PLAN_DOCUMENT_KEY,
|
|
161717
|
+
content,
|
|
161718
|
+
author: options.author ?? "agent"
|
|
161719
|
+
});
|
|
161720
|
+
return true;
|
|
161721
|
+
} catch (error3) {
|
|
161722
|
+
const message = error3 instanceof Error ? error3.message : String(error3);
|
|
161723
|
+
options.logger?.warn?.(`${taskId}: failed to mirror the plan into the project database: ${message}`);
|
|
161724
|
+
return false;
|
|
161725
|
+
}
|
|
161726
|
+
}
|
|
161727
|
+
async function persistPlanArtifact(options) {
|
|
161728
|
+
const result2 = await reconcileWorktreePlanArtifact(options);
|
|
161729
|
+
const mirrored = result2.content ? await mirrorPlanToProjectDb(options.store, options.taskId, result2.content, {
|
|
161730
|
+
author: options.author,
|
|
161731
|
+
logger: options.logger
|
|
161732
|
+
}) : false;
|
|
161733
|
+
return { ...result2, mirrored };
|
|
161734
|
+
}
|
|
161735
|
+
var PLAN_DOCUMENT_KEY;
|
|
161736
|
+
var init_plan_artifact_writeback = __esm({
|
|
161737
|
+
"../engine/src/plan-artifact-writeback.ts"() {
|
|
161738
|
+
"use strict";
|
|
161739
|
+
PLAN_DOCUMENT_KEY = "plan";
|
|
161740
|
+
}
|
|
161741
|
+
});
|
|
161742
|
+
|
|
161630
161743
|
// ../engine/src/auto-recovery-handlers/message-delivery.ts
|
|
161631
161744
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
161632
161745
|
var baseLog, MessageDeliveryAutoRecoveryHandler;
|
|
@@ -163636,7 +163749,7 @@ var init_worktree_prune = __esm({
|
|
|
163636
163749
|
|
|
163637
163750
|
// ../engine/src/worktree-stale-lock.ts
|
|
163638
163751
|
import { exec as exec8 } from "node:child_process";
|
|
163639
|
-
import { readFile as
|
|
163752
|
+
import { readFile as readFile31, stat as stat8, unlink as unlink9 } from "node:fs/promises";
|
|
163640
163753
|
import { dirname as dirname23, resolve as resolve26 } from "node:path";
|
|
163641
163754
|
import { promisify as promisify12 } from "node:util";
|
|
163642
163755
|
function parseIndexLockPath(stderr) {
|
|
@@ -163661,7 +163774,7 @@ async function resolveOwningWorktreePath(input) {
|
|
|
163661
163774
|
if (!worktreeName) return void 0;
|
|
163662
163775
|
const gitdirFile = resolve26(dirname23(input.lockPath), "gitdir");
|
|
163663
163776
|
try {
|
|
163664
|
-
const gitdirRef = (await
|
|
163777
|
+
const gitdirRef = (await readFile31(gitdirFile, "utf-8")).trim();
|
|
163665
163778
|
if (gitdirRef) {
|
|
163666
163779
|
const resolvedGitdirRef = resolve26(dirname23(gitdirFile), gitdirRef);
|
|
163667
163780
|
if (resolvedGitdirRef.endsWith("/.git") || resolvedGitdirRef.endsWith("\\.git")) {
|
|
@@ -165040,7 +165153,7 @@ import { exec as exec11, execFile as execFile9 } from "node:child_process";
|
|
|
165040
165153
|
import { promisify as promisify15 } from "node:util";
|
|
165041
165154
|
import { existsSync as existsSync47, lstatSync as lstatSync2, readdirSync as readdirSync7, readFileSync as readFileSync16, rmSync as rmSync5, realpathSync as realpathSync6 } from "node:fs";
|
|
165042
165155
|
import { mkdir as mkdir24 } from "node:fs/promises";
|
|
165043
|
-
import { basename as basename15, dirname as dirname24, join as
|
|
165156
|
+
import { basename as basename15, dirname as dirname24, join as join62, relative as relative8, resolve as resolve29, isAbsolute as isAbsolute9 } from "node:path";
|
|
165044
165157
|
async function getWorktrunkBinary(settings) {
|
|
165045
165158
|
const cacheKey = `${process.env.HOME ?? ""}::${settings.binaryPath ?? ""}`;
|
|
165046
165159
|
const cached2 = _worktrunkBinaryCache.get(cacheKey);
|
|
@@ -165191,7 +165304,7 @@ async function isRegisteredGitWorktree2(rootDir, worktreePath) {
|
|
|
165191
165304
|
return (await getRegisteredWorktreePaths(rootDir)).has(canonicalizePath(worktreePath));
|
|
165192
165305
|
}
|
|
165193
165306
|
function hasRequiredWorktreeFiles(worktreePath) {
|
|
165194
|
-
return existsSync47(
|
|
165307
|
+
return existsSync47(join62(worktreePath, ".git"));
|
|
165195
165308
|
}
|
|
165196
165309
|
async function isInsideGitWorkTree2(worktreePath) {
|
|
165197
165310
|
try {
|
|
@@ -165324,7 +165437,7 @@ async function scanIdleWorktrees(rootDir, store, settings) {
|
|
|
165324
165437
|
let dirs;
|
|
165325
165438
|
try {
|
|
165326
165439
|
const entries = readdirSync7(worktreesDir, { withFileTypes: true });
|
|
165327
|
-
dirs = entries.filter((e) => e.isDirectory() && !isAiMergeContainerDir(e.name)).map((e) =>
|
|
165440
|
+
dirs = entries.filter((e) => e.isDirectory() && !isAiMergeContainerDir(e.name)).map((e) => join62(worktreesDir, e.name));
|
|
165328
165441
|
} catch (err) {
|
|
165329
165442
|
const errorMessage2 = err instanceof Error ? err.message : String(err);
|
|
165330
165443
|
worktreePoolLog.warn(`Failed to read .worktrees/ directory: ${errorMessage2}`);
|
|
@@ -165356,7 +165469,7 @@ async function cleanupOrphanedWorktrees(rootDir, store, settings) {
|
|
|
165356
165469
|
let dirs = [];
|
|
165357
165470
|
if (existsSync47(worktreesDir)) {
|
|
165358
165471
|
try {
|
|
165359
|
-
dirs = readdirSync7(worktreesDir, { withFileTypes: true }).filter((e) => e.isDirectory() && !isAiMergeContainerDir(e.name)).map((e) =>
|
|
165472
|
+
dirs = readdirSync7(worktreesDir, { withFileTypes: true }).filter((e) => e.isDirectory() && !isAiMergeContainerDir(e.name)).map((e) => join62(worktreesDir, e.name));
|
|
165360
165473
|
} catch (err) {
|
|
165361
165474
|
const errorMessage2 = err instanceof Error ? err.message : String(err);
|
|
165362
165475
|
worktreePoolLog.warn(`Failed to read .worktrees/ directory for cleanup: ${errorMessage2}`);
|
|
@@ -165434,11 +165547,11 @@ async function reapOrphanWorktrees(projectRoot, settings) {
|
|
|
165434
165547
|
entries = readdirSync7(worktreesDir, { withFileTypes: true }).filter((e) => {
|
|
165435
165548
|
if (!e.isDirectory() || isAiMergeContainerDir(e.name)) return false;
|
|
165436
165549
|
try {
|
|
165437
|
-
return lstatSync2(
|
|
165550
|
+
return lstatSync2(join62(worktreesDir, e.name)).isDirectory() && !lstatSync2(join62(worktreesDir, e.name)).isSymbolicLink();
|
|
165438
165551
|
} catch {
|
|
165439
165552
|
return false;
|
|
165440
165553
|
}
|
|
165441
|
-
}).map((e) => ({ name: e.name, fullPath:
|
|
165554
|
+
}).map((e) => ({ name: e.name, fullPath: join62(worktreesDir, e.name) }));
|
|
165442
165555
|
} catch (err) {
|
|
165443
165556
|
const msg = err instanceof Error ? err.message : String(err);
|
|
165444
165557
|
worktreePoolLog.warn(`reapOrphanWorktrees: failed to read .worktrees/ \u2014 ${msg}`);
|
|
@@ -165457,7 +165570,7 @@ async function reapOrphanWorktrees(projectRoot, settings) {
|
|
|
165457
165570
|
if (registered2.has(resolvedFull)) {
|
|
165458
165571
|
continue;
|
|
165459
165572
|
}
|
|
165460
|
-
const dotGit =
|
|
165573
|
+
const dotGit = join62(resolvedFull, ".git");
|
|
165461
165574
|
if (existsSync47(dotGit)) {
|
|
165462
165575
|
if (!dotGitPointerIsDangling(dotGit)) {
|
|
165463
165576
|
worktreePoolLog.log(`reapOrphanWorktrees: skipping ${name2} (has .git entry but not in registered list \u2014 may be partially registered)`);
|
|
@@ -165823,27 +165936,27 @@ var init_worktree_pool = __esm({
|
|
|
165823
165936
|
|
|
165824
165937
|
// ../engine/src/worktree-paths.ts
|
|
165825
165938
|
import { homedir as homedir10 } from "node:os";
|
|
165826
|
-
import { basename as basename16, isAbsolute as isAbsolute10, join as
|
|
165939
|
+
import { basename as basename16, isAbsolute as isAbsolute10, join as join63, relative as relative9, resolve as resolve30 } from "node:path";
|
|
165827
165940
|
function isAiMergeContainerDir(name2) {
|
|
165828
165941
|
return name2 === AI_MERGE_DIRNAME;
|
|
165829
165942
|
}
|
|
165830
165943
|
function resolveAiMergeRootPath(rootDir, settings) {
|
|
165831
|
-
return
|
|
165944
|
+
return join63(resolveWorktreesDir(rootDir, settings), AI_MERGE_DIRNAME);
|
|
165832
165945
|
}
|
|
165833
165946
|
function resolveLegacyAiMergeRootPath(rootDir) {
|
|
165834
|
-
return
|
|
165947
|
+
return join63(rootDir, ".fusion", "ai-merge");
|
|
165835
165948
|
}
|
|
165836
165949
|
function resolveWorktreesDir(rootDir, settings) {
|
|
165837
165950
|
const configured = settings?.worktreesDir;
|
|
165838
165951
|
if (!configured) {
|
|
165839
|
-
return
|
|
165952
|
+
return join63(rootDir, ".worktrees");
|
|
165840
165953
|
}
|
|
165841
165954
|
const expandedHome = configured.replace(/^~(?=$|[\\/])/, homedir10());
|
|
165842
165955
|
const expandedRepo = expandedHome.replaceAll("{repo}", basename16(rootDir));
|
|
165843
165956
|
return resolve30(rootDir, expandedRepo);
|
|
165844
165957
|
}
|
|
165845
165958
|
function resolveTaskWorktreePath(rootDir, settings, worktreeName) {
|
|
165846
|
-
return
|
|
165959
|
+
return join63(resolveWorktreesDir(rootDir, settings), worktreeName);
|
|
165847
165960
|
}
|
|
165848
165961
|
async function resolveTaskWorktreePathForBackend(rootDir, worktreeName, settings, backend, branch) {
|
|
165849
165962
|
if (backend.kind === "worktrunk" && backend.resolveWorktreePath) {
|
|
@@ -166957,9 +167070,9 @@ function assertInRootRepoRelPath(repoRelPath, sep17, isAbsolute27, normalize8) {
|
|
|
166957
167070
|
async function acquireWorkspaceRepoWorktree(opts) {
|
|
166958
167071
|
const { repoRelPath, workspaceRootDir, task, store, settings, logger: logger3, secretsStore, audit, runContext, runConfiguredCommand: runConfiguredCommand2, taskEnv } = opts;
|
|
166959
167072
|
const registry3 = opts.registry ?? activeSessionRegistry;
|
|
166960
|
-
const { join:
|
|
167073
|
+
const { join: join109, isAbsolute: isAbsolute27, normalize: normalize8, sep: sep17 } = await import("node:path");
|
|
166961
167074
|
assertInRootRepoRelPath(repoRelPath, sep17, isAbsolute27, normalize8);
|
|
166962
|
-
const repoAbsPath =
|
|
167075
|
+
const repoAbsPath = join109(workspaceRootDir, repoRelPath);
|
|
166963
167076
|
const existing = task.workspaceWorktrees?.[repoRelPath];
|
|
166964
167077
|
if (existing) {
|
|
166965
167078
|
let live = existsSync49(existing.worktreePath);
|
|
@@ -168683,7 +168796,7 @@ import { execFile as execFile11 } from "node:child_process";
|
|
|
168683
168796
|
import { createRequire as createRequire6 } from "node:module";
|
|
168684
168797
|
import { mkdtemp, rm as rm7, writeFile as writeFile24 } from "node:fs/promises";
|
|
168685
168798
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
168686
|
-
import { join as
|
|
168799
|
+
import { join as join64 } from "node:path";
|
|
168687
168800
|
function getTransformSync() {
|
|
168688
168801
|
if (!cachedTransformSync) {
|
|
168689
168802
|
const req = createRequire6(import.meta.url);
|
|
@@ -168770,9 +168883,9 @@ function readStdin() {
|
|
|
168770
168883
|
async function runCodeNode(opts) {
|
|
168771
168884
|
const timeoutMs = resolveCodeNodeTimeout(opts.timeoutMs);
|
|
168772
168885
|
const compiled = await compileCodeNodeSource(opts.source);
|
|
168773
|
-
const dir = await mkdtemp(
|
|
168774
|
-
const userModuleFile =
|
|
168775
|
-
const harnessFile =
|
|
168886
|
+
const dir = await mkdtemp(join64(tmpdir4(), "fusion-code-node-"));
|
|
168887
|
+
const userModuleFile = join64(dir, "user.mjs");
|
|
168888
|
+
const harnessFile = join64(dir, "harness.mjs");
|
|
168776
168889
|
try {
|
|
168777
168890
|
await writeFile24(userModuleFile, compiled, "utf8");
|
|
168778
168891
|
await writeFile24(harnessFile, buildChildHarness(userModuleFile), "utf8");
|
|
@@ -169000,11 +169113,11 @@ var init_code_node_runner = __esm({
|
|
|
169000
169113
|
});
|
|
169001
169114
|
|
|
169002
169115
|
// ../engine/src/agent-tools.ts
|
|
169003
|
-
import { appendFile as appendFile3, mkdir as mkdir26, readFile as
|
|
169116
|
+
import { appendFile as appendFile3, mkdir as mkdir26, readFile as readFile32, readdir as readdir9, realpath, stat as stat9, writeFile as writeFile25 } from "node:fs/promises";
|
|
169004
169117
|
import { existsSync as existsSync50 } from "node:fs";
|
|
169005
169118
|
import { createHash as createHash16, randomUUID as randomUUID45 } from "node:crypto";
|
|
169006
169119
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
169007
|
-
import { extname as extname3, isAbsolute as isAbsolute12, join as
|
|
169120
|
+
import { extname as extname3, isAbsolute as isAbsolute12, join as join65, relative as relative11, resolve as resolve32, sep as sep9 } from "node:path";
|
|
169008
169121
|
import { Type as Type2 } from "@earendil-works/pi-ai";
|
|
169009
169122
|
function sanitizeAgentMemoryId(agentId) {
|
|
169010
169123
|
return agentId.trim().replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "agent";
|
|
@@ -169016,16 +169129,16 @@ function agentDreamsDisplayPath(agentId) {
|
|
|
169016
169129
|
return `${AGENT_MEMORY_ROOT3}/${sanitizeAgentMemoryId(agentId)}/${AGENT_DREAMS_FILENAME2}`;
|
|
169017
169130
|
}
|
|
169018
169131
|
function agentMemoryDirectory(rootDir, agentId) {
|
|
169019
|
-
return
|
|
169132
|
+
return join65(rootDir, AGENT_MEMORY_ROOT3, sanitizeAgentMemoryId(agentId));
|
|
169020
169133
|
}
|
|
169021
169134
|
function agentMemoryFilePath(rootDir, agentId) {
|
|
169022
|
-
return
|
|
169135
|
+
return join65(agentMemoryDirectory(rootDir, agentId), AGENT_MEMORY_FILENAME2);
|
|
169023
169136
|
}
|
|
169024
169137
|
function agentDreamsFilePath(rootDir, agentId) {
|
|
169025
|
-
return
|
|
169138
|
+
return join65(agentMemoryDirectory(rootDir, agentId), AGENT_DREAMS_FILENAME2);
|
|
169026
169139
|
}
|
|
169027
169140
|
function agentDailyFilePath(rootDir, agentId, date5 = /* @__PURE__ */ new Date()) {
|
|
169028
|
-
return
|
|
169141
|
+
return join65(agentMemoryDirectory(rootDir, agentId), `${date5.toISOString().slice(0, 10)}.md`);
|
|
169029
169142
|
}
|
|
169030
169143
|
async function readAgentMemoryWorkspaceLongTerm(rootDir, agentId) {
|
|
169031
169144
|
const safeRoot = typeof rootDir === "string" ? rootDir.trim() : "";
|
|
@@ -169039,7 +169152,7 @@ async function readAgentMemoryWorkspaceLongTerm(rootDir, agentId) {
|
|
|
169039
169152
|
if (!fileStat.isFile()) {
|
|
169040
169153
|
return "";
|
|
169041
169154
|
}
|
|
169042
|
-
const content = await
|
|
169155
|
+
const content = await readFile32(filePath, "utf-8");
|
|
169043
169156
|
return typeof content === "string" ? content.trim() : "";
|
|
169044
169157
|
} catch {
|
|
169045
169158
|
return "";
|
|
@@ -169118,7 +169231,7 @@ async function listAgentMemoryFiles2(rootDir, agentMemory) {
|
|
|
169118
169231
|
}
|
|
169119
169232
|
for (const entry of entries) {
|
|
169120
169233
|
if (!DAILY_AGENT_MEMORY_RE2.test(entry)) continue;
|
|
169121
|
-
const absPath =
|
|
169234
|
+
const absPath = join65(dir, entry);
|
|
169122
169235
|
const fileStat = await stat9(absPath);
|
|
169123
169236
|
if (fileStat.isFile()) {
|
|
169124
169237
|
files.push({
|
|
@@ -169141,7 +169254,7 @@ async function searchAgentMemoryFile(rootDir, agentMemory, query, limit) {
|
|
|
169141
169254
|
}
|
|
169142
169255
|
const results = [];
|
|
169143
169256
|
for (const file of await listAgentMemoryFiles2(rootDir, agentMemory)) {
|
|
169144
|
-
const content = await
|
|
169257
|
+
const content = await readFile32(file.absPath, "utf-8");
|
|
169145
169258
|
const lines = content.split("\n");
|
|
169146
169259
|
for (let index2 = 0; index2 < lines.length; index2 += 8) {
|
|
169147
169260
|
const chunk = lines.slice(index2, index2 + 12).join("\n").trim();
|
|
@@ -169287,7 +169400,7 @@ function resolveAgentMemoryPath(rootDir, agentId, path10) {
|
|
|
169287
169400
|
return null;
|
|
169288
169401
|
}
|
|
169289
169402
|
return {
|
|
169290
|
-
absPath:
|
|
169403
|
+
absPath: join65(agentMemoryDirectory(rootDir, agentId), filename),
|
|
169291
169404
|
displayPath: `${prefix}${filename}`
|
|
169292
169405
|
};
|
|
169293
169406
|
}
|
|
@@ -169297,7 +169410,7 @@ async function getAgentMemoryWindow(rootDir, agentMemory, path10, startLine = 1,
|
|
|
169297
169410
|
return null;
|
|
169298
169411
|
}
|
|
169299
169412
|
await syncAgentMemoryFile(rootDir, agentMemory);
|
|
169300
|
-
const content = await
|
|
169413
|
+
const content = await readFile32(resolved.absPath, "utf-8");
|
|
169301
169414
|
const lines = content.split("\n");
|
|
169302
169415
|
const start = Math.max(1, Math.floor(startLine));
|
|
169303
169416
|
const count2 = Math.max(1, Math.min(Math.floor(lineCount), 200));
|
|
@@ -169956,6 +170069,9 @@ function createTaskPromptWriteTool(store, taskId, runContext) {
|
|
|
169956
170069
|
if (persisted?.prompt !== params.content) {
|
|
169957
170070
|
throw new Error("authoritative PROMPT.md read-back did not match the requested content; persistence could not be verified");
|
|
169958
170071
|
}
|
|
170072
|
+
await mirrorPlanToProjectDb(store, taskId, params.content, {
|
|
170073
|
+
author: runContext?.agentId ?? "agent"
|
|
170074
|
+
});
|
|
169959
170075
|
return {
|
|
169960
170076
|
content: [{ type: "text", text: `Updated PROMPT.md for ${taskId}.` }],
|
|
169961
170077
|
details: {}
|
|
@@ -170244,7 +170360,7 @@ async function readArtifactFileFromPath(params, baseDir) {
|
|
|
170244
170360
|
if (!mimeType) {
|
|
170245
170361
|
throw new Error(`Could not infer a MIME type from ${resolvedPath}; pass mimeType explicitly.`);
|
|
170246
170362
|
}
|
|
170247
|
-
const data = await
|
|
170363
|
+
const data = await readFile32(canonicalPath);
|
|
170248
170364
|
if (params.type === "image") {
|
|
170249
170365
|
if (!mimeType.startsWith("image/")) {
|
|
170250
170366
|
throw new Error(`image artifacts require an image/* mimeType, got ${mimeType}.`);
|
|
@@ -170587,25 +170703,33 @@ function createTaskPromoteTool(store, currentTaskId) {
|
|
|
170587
170703
|
return {
|
|
170588
170704
|
name: "fn_task_promote",
|
|
170589
170705
|
label: "Promote Held Task",
|
|
170590
|
-
description: "Manually promote a held task out of its hold column, releasing it regardless of the hold's release kind (the explicit operator action a 'manual' hold waits for). Defaults to the current task. Returns the destination column, or a rejection reason when the task is not held or the destination is full.",
|
|
170706
|
+
description: "Manually promote a held task out of its hold column, releasing it regardless of the hold's release kind (the explicit operator action a 'manual' hold waits for). Defaults to the current task. Returns the destination column, or a rejection reason when the task is not held or the destination is full. Pass force:true to start execution even when planning or plan review is still outstanding (that waives the plan gate and cancels the pending replan; capacity still applies).",
|
|
170591
170707
|
parameters: taskPromoteParams,
|
|
170592
170708
|
execute: async (_id, params) => {
|
|
170593
170709
|
const taskId = params.task_id?.trim() || currentTaskId;
|
|
170710
|
+
const force = params.force === true;
|
|
170594
170711
|
try {
|
|
170595
|
-
const outcome = await promoteHeldTask(store, taskId);
|
|
170712
|
+
const outcome = await promoteHeldTask(store, taskId, {}, { force });
|
|
170596
170713
|
if (outcome.released) {
|
|
170714
|
+
const forcedNote = outcome.forcedUnplanned ? " Forced past the outstanding planning/plan review \u2014 the pending replan was cancelled." : "";
|
|
170597
170715
|
return {
|
|
170598
170716
|
content: [{
|
|
170599
170717
|
type: "text",
|
|
170600
|
-
text: `Promoted ${taskId} to column '${outcome.toColumn}'
|
|
170718
|
+
text: `Promoted ${taskId} to column '${outcome.toColumn}'.${forcedNote}`
|
|
170601
170719
|
}],
|
|
170602
|
-
details: {
|
|
170720
|
+
details: {
|
|
170721
|
+
taskId,
|
|
170722
|
+
released: true,
|
|
170723
|
+
toColumn: outcome.toColumn,
|
|
170724
|
+
forcedUnplanned: outcome.forcedUnplanned === true
|
|
170725
|
+
}
|
|
170603
170726
|
};
|
|
170604
170727
|
}
|
|
170728
|
+
const forceHint = outcome.rejection === "unplanned-for-execution" ? " Pass force:true to start execution anyway." : "";
|
|
170605
170729
|
return {
|
|
170606
170730
|
content: [{
|
|
170607
170731
|
type: "text",
|
|
170608
|
-
text: `ERROR: Could not promote ${taskId}: ${outcome.rejection ?? "unknown"}
|
|
170732
|
+
text: `ERROR: Could not promote ${taskId}: ${outcome.rejection ?? "unknown"}.${forceHint}`
|
|
170609
170733
|
}],
|
|
170610
170734
|
details: { taskId, released: false, rejection: outcome.rejection },
|
|
170611
170735
|
isError: true
|
|
@@ -172829,6 +172953,7 @@ var init_agent_tools = __esm({
|
|
|
172829
172953
|
init_provider_registry();
|
|
172830
172954
|
init_research_step_runner();
|
|
172831
172955
|
init_logger3();
|
|
172956
|
+
init_plan_artifact_writeback();
|
|
172832
172957
|
init_web_fetch();
|
|
172833
172958
|
init_agent_action_gate();
|
|
172834
172959
|
init_message_delivery();
|
|
@@ -173008,6 +173133,19 @@ var init_agent_tools = __esm({
|
|
|
173008
173133
|
taskPromoteParams = Type2.Object({
|
|
173009
173134
|
task_id: Type2.Optional(
|
|
173010
173135
|
Type2.String({ description: "Held task to promote. Defaults to the current task." })
|
|
173136
|
+
),
|
|
173137
|
+
/*
|
|
173138
|
+
FNXC:WorkflowScheduling 2026-07-25-05:40:
|
|
173139
|
+
Agent-native parity with the dashboard's force-promote override: an agent that
|
|
173140
|
+
has read the card and judged the pending replan / Plan Review not worth waiting
|
|
173141
|
+
for can start execution anyway. Opt-in per call and never defaulted on — the
|
|
173142
|
+
automatic surfaces (hold-release sweep, webhook release) still cannot force, so
|
|
173143
|
+
FN-7648 holds for everything that is not an explicit promote request.
|
|
173144
|
+
*/
|
|
173145
|
+
force: Type2.Optional(
|
|
173146
|
+
Type2.Boolean({
|
|
173147
|
+
description: "Start execution even when the task is still waiting on planning or plan review (rejection 'unplanned-for-execution'). Waives ONLY that gate \u2014 hold membership and downstream capacity still apply \u2014 and cancels the pending replan. Default false."
|
|
173148
|
+
})
|
|
173011
173149
|
)
|
|
173012
173150
|
});
|
|
173013
173151
|
workflowCreateParams = Type2.Object({
|
|
@@ -177316,7 +177454,7 @@ Follow instructions precisely and avoid unrelated changes.`,
|
|
|
177316
177454
|
|
|
177317
177455
|
// ../engine/src/spec-validation/task-document-references.ts
|
|
177318
177456
|
import { access as access7 } from "node:fs/promises";
|
|
177319
|
-
import { join as
|
|
177457
|
+
import { join as join66 } from "node:path";
|
|
177320
177458
|
function normalizePathToken(token) {
|
|
177321
177459
|
return token.replace(/^[`([{"']+/, "").replace(/[`),.;:!?\]}'"]+$/, "");
|
|
177322
177460
|
}
|
|
@@ -177404,7 +177542,7 @@ async function detectDanglingTaskDocReferences(promptContent, opts) {
|
|
|
177404
177542
|
}
|
|
177405
177543
|
const dangling = [];
|
|
177406
177544
|
for (const [path10, sections] of references.entries()) {
|
|
177407
|
-
const absPath =
|
|
177545
|
+
const absPath = join66(opts.rootDir, path10);
|
|
177408
177546
|
if (await existsImpl(absPath)) continue;
|
|
177409
177547
|
dangling.push({ path: path10, sections: Array.from(sections).sort() });
|
|
177410
177548
|
}
|
|
@@ -177665,8 +177803,8 @@ var init_session_skill_context = __esm({
|
|
|
177665
177803
|
});
|
|
177666
177804
|
|
|
177667
177805
|
// ../engine/src/agent-memory-index.ts
|
|
177668
|
-
import { readFile as
|
|
177669
|
-
import { join as
|
|
177806
|
+
import { readFile as readFile33 } from "node:fs/promises";
|
|
177807
|
+
import { join as join67 } from "node:path";
|
|
177670
177808
|
function clampUtf8(input, maxBytes) {
|
|
177671
177809
|
if (Buffer.byteLength(input, "utf8") <= maxBytes) return input;
|
|
177672
177810
|
let out = "";
|
|
@@ -177698,7 +177836,7 @@ function parseHeadings(content) {
|
|
|
177698
177836
|
}
|
|
177699
177837
|
async function buildFileSection(sectionHeader, displayPath, fsPath) {
|
|
177700
177838
|
try {
|
|
177701
|
-
const content = await
|
|
177839
|
+
const content = await readFile33(fsPath, "utf-8");
|
|
177702
177840
|
const headings = parseHeadings(content);
|
|
177703
177841
|
const lines = [sectionHeader, `- ${displayPath}`];
|
|
177704
177842
|
for (const entry of headings) {
|
|
@@ -177714,9 +177852,9 @@ async function buildFileSection(sectionHeader, displayPath, fsPath) {
|
|
|
177714
177852
|
async function buildMemoryIndex({ rootDir, agentId }) {
|
|
177715
177853
|
const safeAgentId = agentId.trim().replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "agent";
|
|
177716
177854
|
const agentDisplayPath = `.fusion/agent-memory/${safeAgentId}/MEMORY.md`;
|
|
177717
|
-
const agentFsPath =
|
|
177855
|
+
const agentFsPath = join67(rootDir, ".fusion", "agent-memory", safeAgentId, "MEMORY.md");
|
|
177718
177856
|
const projectDisplayPath = ".fusion/memory/MEMORY.md";
|
|
177719
|
-
const projectFsPath =
|
|
177857
|
+
const projectFsPath = join67(rootDir, ".fusion", "memory", "MEMORY.md");
|
|
177720
177858
|
const [agentSection, projectSection] = await Promise.all([
|
|
177721
177859
|
buildFileSection("## Agent Memory Index (use fn_memory_search / fn_memory_get to read)", agentDisplayPath, agentFsPath),
|
|
177722
177860
|
buildFileSection("## Project Memory Index", projectDisplayPath, projectFsPath)
|
|
@@ -177735,7 +177873,7 @@ var init_agent_memory_index = __esm({
|
|
|
177735
177873
|
});
|
|
177736
177874
|
|
|
177737
177875
|
// ../engine/src/agent-instructions.ts
|
|
177738
|
-
import { readFile as
|
|
177876
|
+
import { readFile as readFile34, writeFile as writeFile26, mkdir as mkdir27, access as access8 } from "node:fs/promises";
|
|
177739
177877
|
import { constants as fsConstants3 } from "node:fs";
|
|
177740
177878
|
import { isAbsolute as isAbsolute13, resolve as resolve33, relative as relative12, normalize as normalize7, sep as sep10, dirname as dirname28 } from "node:path";
|
|
177741
177879
|
function trimAndClamp(value, maxLength, label, agentId) {
|
|
@@ -177797,7 +177935,7 @@ async function resolveAgentHeartbeatProcedure(agent, rootDir) {
|
|
|
177797
177935
|
return null;
|
|
177798
177936
|
}
|
|
177799
177937
|
try {
|
|
177800
|
-
const content = await
|
|
177938
|
+
const content = await readFile34(filePath, "utf-8");
|
|
177801
177939
|
const normalized = trimAndClamp(
|
|
177802
177940
|
content,
|
|
177803
177941
|
MAX_INSTRUCTIONS_TEXT_LENGTH2,
|
|
@@ -177943,7 +178081,7 @@ async function resolveAgentInstructions(agent, rootDir, ratingSummary, inclusion
|
|
|
177943
178081
|
const filePath = resolveValidatedInstructionsPath(agent.instructionsPath, rootDir, agent.id);
|
|
177944
178082
|
if (filePath) {
|
|
177945
178083
|
try {
|
|
177946
|
-
const content = await
|
|
178084
|
+
const content = await readFile34(filePath, "utf-8");
|
|
177947
178085
|
const normalizedContent = trimAndClamp(
|
|
177948
178086
|
content,
|
|
177949
178087
|
MAX_INSTRUCTIONS_TEXT_LENGTH2,
|
|
@@ -185950,8 +186088,8 @@ var init_mission_symbol_admission = __esm({
|
|
|
185950
186088
|
|
|
185951
186089
|
// ../engine/src/scheduler.ts
|
|
185952
186090
|
import { existsSync as existsSync54 } from "node:fs";
|
|
185953
|
-
import { readFile as
|
|
185954
|
-
import { join as
|
|
186091
|
+
import { readFile as readFile35 } from "node:fs/promises";
|
|
186092
|
+
import { join as join68 } from "node:path";
|
|
185955
186093
|
function logTaskRouting(taskId, node) {
|
|
185956
186094
|
const message = `Task ${taskId} routed to node=${node.nodeId ?? "local"} (source=${node.source})`;
|
|
185957
186095
|
if (node.nodeId === void 0) {
|
|
@@ -186584,16 +186722,16 @@ var init_scheduler = __esm({
|
|
|
186584
186722
|
if (typeof this.store.getTasksDir !== "function") {
|
|
186585
186723
|
return { valid: true };
|
|
186586
186724
|
}
|
|
186587
|
-
const taskDir =
|
|
186725
|
+
const taskDir = join68(this.store.getTasksDir(), id);
|
|
186588
186726
|
if (!existsSync54(taskDir)) {
|
|
186589
186727
|
return { valid: false, reason: "missing directory" };
|
|
186590
186728
|
}
|
|
186591
|
-
const promptPath =
|
|
186729
|
+
const promptPath = join68(taskDir, "PROMPT.md");
|
|
186592
186730
|
if (!existsSync54(promptPath)) {
|
|
186593
186731
|
return { valid: false, reason: "missing or empty PROMPT.md" };
|
|
186594
186732
|
}
|
|
186595
186733
|
try {
|
|
186596
|
-
const content = await
|
|
186734
|
+
const content = await readFile35(promptPath, "utf-8");
|
|
186597
186735
|
if (!content || content.trim().length === 0) {
|
|
186598
186736
|
return { valid: false, reason: "missing or empty PROMPT.md" };
|
|
186599
186737
|
}
|
|
@@ -186963,7 +187101,7 @@ var init_scheduler = __esm({
|
|
|
186963
187101
|
todo = (await Promise.all(
|
|
186964
187102
|
todo.map(async (t) => {
|
|
186965
187103
|
try {
|
|
186966
|
-
const content = await
|
|
187104
|
+
const content = await readFile35(getPromptPath(this.store.getTasksDir(), t.id), "utf-8");
|
|
186967
187105
|
if (isUnplannedSeedPrompt(content, t.id, t.title, t.description)) return null;
|
|
186968
187106
|
} catch {
|
|
186969
187107
|
}
|
|
@@ -190530,10 +190668,10 @@ var init_verification_utils = __esm({
|
|
|
190530
190668
|
import { exec as exec23 } from "node:child_process";
|
|
190531
190669
|
import { createHash as createHash18 } from "node:crypto";
|
|
190532
190670
|
import { existsSync as existsSync55, readFileSync as readFileSync18, writeFileSync as writeFileSync7 } from "node:fs";
|
|
190533
|
-
import { join as
|
|
190671
|
+
import { join as join69 } from "node:path";
|
|
190534
190672
|
import { promisify as promisify32 } from "node:util";
|
|
190535
190673
|
function hasInstallState(rootDir) {
|
|
190536
|
-
return existsSync55(
|
|
190674
|
+
return existsSync55(join69(rootDir, "node_modules")) || existsSync55(join69(rootDir, ".pnp.cjs"));
|
|
190537
190675
|
}
|
|
190538
190676
|
function getConfiguredWorktreeInitCommand(settings) {
|
|
190539
190677
|
const trimmed = settings?.worktreeInitCommand?.trim();
|
|
@@ -190542,17 +190680,17 @@ function getConfiguredWorktreeInitCommand(settings) {
|
|
|
190542
190680
|
function getDependencySyncCommand(rootDir, settings) {
|
|
190543
190681
|
const configuredCommand = getConfiguredWorktreeInitCommand(settings);
|
|
190544
190682
|
if (configuredCommand) return configuredCommand;
|
|
190545
|
-
if (existsSync55(
|
|
190546
|
-
if (existsSync55(
|
|
190547
|
-
if (existsSync55(
|
|
190548
|
-
if (existsSync55(
|
|
190683
|
+
if (existsSync55(join69(rootDir, "pnpm-lock.yaml"))) return "pnpm install --frozen-lockfile";
|
|
190684
|
+
if (existsSync55(join69(rootDir, "package-lock.json"))) return "npm install";
|
|
190685
|
+
if (existsSync55(join69(rootDir, "yarn.lock"))) return "yarn install --frozen-lockfile";
|
|
190686
|
+
if (existsSync55(join69(rootDir, "bun.lock")) || existsSync55(join69(rootDir, "bun.lockb"))) {
|
|
190549
190687
|
return "bun install --frozen-lockfile";
|
|
190550
190688
|
}
|
|
190551
190689
|
return null;
|
|
190552
190690
|
}
|
|
190553
190691
|
function computeLockfileHash(rootDir) {
|
|
190554
190692
|
for (const name2 of LOCKFILE_CANDIDATES) {
|
|
190555
|
-
const p2 =
|
|
190693
|
+
const p2 = join69(rootDir, name2);
|
|
190556
190694
|
if (existsSync55(p2)) {
|
|
190557
190695
|
try {
|
|
190558
190696
|
return createHash18("sha256").update(readFileSync18(p2)).digest("hex");
|
|
@@ -190565,7 +190703,7 @@ function computeLockfileHash(rootDir) {
|
|
|
190565
190703
|
}
|
|
190566
190704
|
function readInstallMarker(rootDir) {
|
|
190567
190705
|
try {
|
|
190568
|
-
const value = readFileSync18(
|
|
190706
|
+
const value = readFileSync18(join69(rootDir, INSTALL_MARKER_RELPATH), "utf-8").trim();
|
|
190569
190707
|
return value || null;
|
|
190570
190708
|
} catch {
|
|
190571
190709
|
return null;
|
|
@@ -190573,7 +190711,7 @@ function readInstallMarker(rootDir) {
|
|
|
190573
190711
|
}
|
|
190574
190712
|
function writeInstallMarker(rootDir, hash) {
|
|
190575
190713
|
try {
|
|
190576
|
-
writeFileSync7(
|
|
190714
|
+
writeFileSync7(join69(rootDir, INSTALL_MARKER_RELPATH), hash);
|
|
190577
190715
|
} catch {
|
|
190578
190716
|
}
|
|
190579
190717
|
}
|
|
@@ -190664,7 +190802,7 @@ var init_merge_dependency_sync = __esm({
|
|
|
190664
190802
|
"../engine/src/merge-dependency-sync.ts"() {
|
|
190665
190803
|
"use strict";
|
|
190666
190804
|
execAsync21 = promisify32(exec23);
|
|
190667
|
-
INSTALL_MARKER_RELPATH =
|
|
190805
|
+
INSTALL_MARKER_RELPATH = join69("node_modules", ".fusion-install-marker");
|
|
190668
190806
|
LOCKFILE_CANDIDATES = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lockb", "bun.lock"];
|
|
190669
190807
|
INSTALL_TIMEOUT_MS = 3e5;
|
|
190670
190808
|
}
|
|
@@ -191041,7 +191179,7 @@ var init_merger_glob = __esm({
|
|
|
191041
191179
|
|
|
191042
191180
|
// ../engine/src/merger-workspace-test-commands.ts
|
|
191043
191181
|
import { existsSync as existsSync56, readdirSync as readdirSync9, readFileSync as readFileSync19 } from "node:fs";
|
|
191044
|
-
import { basename as basename18, dirname as dirname31, join as
|
|
191182
|
+
import { basename as basename18, dirname as dirname31, join as join70 } from "node:path";
|
|
191045
191183
|
import { execSync as execSync4 } from "node:child_process";
|
|
191046
191184
|
function quoteArg2(value) {
|
|
191047
191185
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
@@ -191072,14 +191210,14 @@ function resolveWorkspacePackageRoots(rootDir, globs) {
|
|
|
191072
191210
|
for (const glob of globs) {
|
|
191073
191211
|
const starIdx = glob.indexOf("*");
|
|
191074
191212
|
if (starIdx === -1) {
|
|
191075
|
-
const candidate =
|
|
191076
|
-
if (existsSync56(
|
|
191213
|
+
const candidate = join70(rootDir, glob);
|
|
191214
|
+
if (existsSync56(join70(candidate, "package.json"))) {
|
|
191077
191215
|
roots.push(glob);
|
|
191078
191216
|
}
|
|
191079
191217
|
continue;
|
|
191080
191218
|
}
|
|
191081
191219
|
const prefix = glob.slice(0, starIdx);
|
|
191082
|
-
const parentDir =
|
|
191220
|
+
const parentDir = join70(rootDir, prefix.replace(/\/$/, ""));
|
|
191083
191221
|
let entries;
|
|
191084
191222
|
try {
|
|
191085
191223
|
entries = readdirSync9(parentDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
@@ -191088,8 +191226,8 @@ function resolveWorkspacePackageRoots(rootDir, globs) {
|
|
|
191088
191226
|
}
|
|
191089
191227
|
for (const entry of entries) {
|
|
191090
191228
|
const relPath = `${prefix.replace(/\/$/, "")}/${entry}`;
|
|
191091
|
-
const absPath =
|
|
191092
|
-
if (existsSync56(
|
|
191229
|
+
const absPath = join70(rootDir, relPath);
|
|
191230
|
+
if (existsSync56(join70(absPath, "package.json"))) {
|
|
191093
191231
|
roots.push(relPath);
|
|
191094
191232
|
}
|
|
191095
191233
|
}
|
|
@@ -191112,7 +191250,7 @@ function mapChangedFilesToPackageNames(changedFiles, packageRoots, rootDir) {
|
|
|
191112
191250
|
}
|
|
191113
191251
|
if (bestRoot !== null) {
|
|
191114
191252
|
try {
|
|
191115
|
-
const pkgJsonPath =
|
|
191253
|
+
const pkgJsonPath = join70(rootDir, bestRoot, "package.json");
|
|
191116
191254
|
const raw = readFileSync19(pkgJsonPath, "utf-8");
|
|
191117
191255
|
const parsed = JSON.parse(raw);
|
|
191118
191256
|
if (parsed.name) {
|
|
@@ -191129,7 +191267,7 @@ function packageNamesForFiles(rootDir, files) {
|
|
|
191129
191267
|
if (files.length === 0) return [];
|
|
191130
191268
|
let workspaceContent;
|
|
191131
191269
|
try {
|
|
191132
|
-
workspaceContent = readFileSync19(
|
|
191270
|
+
workspaceContent = readFileSync19(join70(rootDir, "pnpm-workspace.yaml"), "utf-8");
|
|
191133
191271
|
} catch {
|
|
191134
191272
|
return [];
|
|
191135
191273
|
}
|
|
@@ -191140,7 +191278,7 @@ function packageNamesForFiles(rootDir, files) {
|
|
|
191140
191278
|
return mapChangedFilesToPackageNames(files, packageRoots, rootDir);
|
|
191141
191279
|
}
|
|
191142
191280
|
function deriveScopedPnpmTestCommand(rootDir, baseBranch, branch) {
|
|
191143
|
-
const workspacePath =
|
|
191281
|
+
const workspacePath = join70(rootDir, "pnpm-workspace.yaml");
|
|
191144
191282
|
let workspaceContent;
|
|
191145
191283
|
try {
|
|
191146
191284
|
workspaceContent = readFileSync19(workspacePath, "utf-8");
|
|
@@ -191178,7 +191316,7 @@ function deriveScopedPnpmTestCommand(rootDir, baseBranch, branch) {
|
|
|
191178
191316
|
function deriveFileScopedPnpmTestCommand(rootDir, baseBranch, branch) {
|
|
191179
191317
|
let workspaceContent;
|
|
191180
191318
|
try {
|
|
191181
|
-
workspaceContent = readFileSync19(
|
|
191319
|
+
workspaceContent = readFileSync19(join70(rootDir, "pnpm-workspace.yaml"), "utf-8");
|
|
191182
191320
|
} catch {
|
|
191183
191321
|
return null;
|
|
191184
191322
|
}
|
|
@@ -191220,7 +191358,7 @@ function deriveFileScopedPnpmTestCommand(rootDir, baseBranch, branch) {
|
|
|
191220
191358
|
];
|
|
191221
191359
|
for (const candidate of candidates) {
|
|
191222
191360
|
const normalized = candidate.startsWith("./") ? candidate.slice(2) : candidate;
|
|
191223
|
-
if (existsSync56(
|
|
191361
|
+
if (existsSync56(join70(rootDir, normalized))) {
|
|
191224
191362
|
resolvedTests.add(normalized);
|
|
191225
191363
|
}
|
|
191226
191364
|
}
|
|
@@ -191248,7 +191386,7 @@ function deriveFileScopedPnpmTestCommand(rootDir, baseBranch, branch) {
|
|
|
191248
191386
|
let name2 = bestRoot;
|
|
191249
191387
|
try {
|
|
191250
191388
|
const parsed = JSON.parse(
|
|
191251
|
-
readFileSync19(
|
|
191389
|
+
readFileSync19(join70(rootDir, bestRoot, "package.json"), "utf-8")
|
|
191252
191390
|
);
|
|
191253
191391
|
if (parsed.name) name2 = parsed.name;
|
|
191254
191392
|
} catch {
|
|
@@ -191292,8 +191430,8 @@ function inferDefaultTestCommand(rootDir, explicitTestCommand, explicitBuildComm
|
|
|
191292
191430
|
};
|
|
191293
191431
|
}
|
|
191294
191432
|
const buildSource = explicitBuildCommand?.trim() ? "explicit" : void 0;
|
|
191295
|
-
if (existsSync56(
|
|
191296
|
-
if (existsSync56(
|
|
191433
|
+
if (existsSync56(join70(rootDir, "pnpm-lock.yaml"))) {
|
|
191434
|
+
if (existsSync56(join70(rootDir, "pnpm-workspace.yaml"))) {
|
|
191297
191435
|
if (baseBranch?.trim() && branch?.trim()) {
|
|
191298
191436
|
try {
|
|
191299
191437
|
const scoped = deriveScopedPnpmTestCommand(rootDir, baseBranch.trim(), branch.trim());
|
|
@@ -191312,13 +191450,13 @@ function inferDefaultTestCommand(rootDir, explicitTestCommand, explicitBuildComm
|
|
|
191312
191450
|
}
|
|
191313
191451
|
return { command: "pnpm test", testSource: "inferred", buildSource };
|
|
191314
191452
|
}
|
|
191315
|
-
if (existsSync56(
|
|
191453
|
+
if (existsSync56(join70(rootDir, "yarn.lock"))) {
|
|
191316
191454
|
return { command: "yarn test", testSource: "inferred", buildSource };
|
|
191317
191455
|
}
|
|
191318
|
-
if (existsSync56(
|
|
191456
|
+
if (existsSync56(join70(rootDir, "bun.lock")) || existsSync56(join70(rootDir, "bun.lockb"))) {
|
|
191319
191457
|
return { command: "bun test", testSource: "inferred", buildSource };
|
|
191320
191458
|
}
|
|
191321
|
-
if (existsSync56(
|
|
191459
|
+
if (existsSync56(join70(rootDir, "package-lock.json"))) {
|
|
191322
191460
|
return { command: "npm test", testSource: "inferred", buildSource };
|
|
191323
191461
|
}
|
|
191324
191462
|
return null;
|
|
@@ -193595,7 +193733,7 @@ var init_merger_integration_worktree = __esm({
|
|
|
193595
193733
|
import { execFile as execFile23, spawn as spawn7 } from "node:child_process";
|
|
193596
193734
|
import { promisify as promisify43 } from "node:util";
|
|
193597
193735
|
import { copyFileSync, existsSync as existsSync57, mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync2, readFileSync as readFileSync20, rmSync as rmSync7, writeFileSync as writeFileSync8 } from "node:fs";
|
|
193598
|
-
import { dirname as dirname32, join as
|
|
193736
|
+
import { dirname as dirname32, join as join71 } from "node:path";
|
|
193599
193737
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
193600
193738
|
async function runGit4(args, cwd, timeoutMs) {
|
|
193601
193739
|
const result2 = await execFileAsync16("git", ["-c", "core.quotePath=false", ...args], {
|
|
@@ -193681,9 +193819,9 @@ async function syncWorktreeToHead(input) {
|
|
|
193681
193819
|
if (mode === "ff-only") {
|
|
193682
193820
|
return { kind: "skipped-dirty", fromSha: previousSha, reason: "ff-only-mode-requires-clean-tree", dirtyFiles, untrackedFiles };
|
|
193683
193821
|
}
|
|
193684
|
-
const stageDir = mkdtempSync2(
|
|
193685
|
-
const patchPath =
|
|
193686
|
-
const untrackedDir =
|
|
193822
|
+
const stageDir = mkdtempSync2(join71(tmpdir6(), "fusion-worktree-sync-"));
|
|
193823
|
+
const patchPath = join71(stageDir, "edits.patch");
|
|
193824
|
+
const untrackedDir = join71(stageDir, "untracked");
|
|
193687
193825
|
let preserveStageDir = false;
|
|
193688
193826
|
try {
|
|
193689
193827
|
mkdirSync9(untrackedDir, { recursive: true });
|
|
@@ -193703,8 +193841,8 @@ async function syncWorktreeToHead(input) {
|
|
|
193703
193841
|
}
|
|
193704
193842
|
}
|
|
193705
193843
|
for (const rel of untrackedFiles) {
|
|
193706
|
-
const src =
|
|
193707
|
-
const dst =
|
|
193844
|
+
const src = join71(worktreePath, rel);
|
|
193845
|
+
const dst = join71(untrackedDir, rel);
|
|
193708
193846
|
try {
|
|
193709
193847
|
mkdirSync9(dirname32(dst), { recursive: true });
|
|
193710
193848
|
copyFileSync(src, dst);
|
|
@@ -193767,13 +193905,13 @@ async function syncWorktreeToHead(input) {
|
|
|
193767
193905
|
const restored = [];
|
|
193768
193906
|
const untrackedSkippedAsTracked = [];
|
|
193769
193907
|
for (const rel of untrackedFiles) {
|
|
193770
|
-
const src =
|
|
193908
|
+
const src = join71(untrackedDir, rel);
|
|
193771
193909
|
if (!existsSync57(src)) continue;
|
|
193772
193910
|
if (trackedAtHead.has(rel)) {
|
|
193773
193911
|
untrackedSkippedAsTracked.push(rel);
|
|
193774
193912
|
continue;
|
|
193775
193913
|
}
|
|
193776
|
-
const dst =
|
|
193914
|
+
const dst = join71(worktreePath, rel);
|
|
193777
193915
|
try {
|
|
193778
193916
|
mkdirSync9(dirname32(dst), { recursive: true });
|
|
193779
193917
|
const data = readFileSync20(src);
|
|
@@ -193842,8 +193980,8 @@ var init_worktree_ref_sync = __esm({
|
|
|
193842
193980
|
|
|
193843
193981
|
// ../engine/src/merger-scope-auto-widen.ts
|
|
193844
193982
|
import { exec as exec30 } from "node:child_process";
|
|
193845
|
-
import { readFile as
|
|
193846
|
-
import { join as
|
|
193983
|
+
import { readFile as readFile36, writeFile as writeFile27 } from "node:fs/promises";
|
|
193984
|
+
import { join as join72 } from "node:path";
|
|
193847
193985
|
import { promisify as promisify44 } from "node:util";
|
|
193848
193986
|
function quoteArg4(value) {
|
|
193849
193987
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
@@ -193982,8 +194120,8 @@ function parseScopeEntries(section) {
|
|
|
193982
194120
|
async function appendAutoWidenedScopeToPrompt(params) {
|
|
193983
194121
|
const { store, taskId, files } = params;
|
|
193984
194122
|
if (files.length === 0) return [];
|
|
193985
|
-
const promptPath =
|
|
193986
|
-
const prompt = await
|
|
194123
|
+
const promptPath = join72(store.getTaskDir(taskId), "PROMPT.md");
|
|
194124
|
+
const prompt = await readFile36(promptPath, "utf-8");
|
|
193987
194125
|
const { before, section, after } = splitPromptSections(prompt);
|
|
193988
194126
|
const existing = parseScopeEntries(section);
|
|
193989
194127
|
const toAdd = files.filter((file) => !existing.has(file));
|
|
@@ -194139,7 +194277,7 @@ import * as childProcess4 from "node:child_process";
|
|
|
194139
194277
|
import { promisify as promisify45 } from "node:util";
|
|
194140
194278
|
import { existsSync as existsSync58, readFileSync as readFileSync21, writeFileSync as writeFileSync9, unlinkSync as unlinkSync3, renameSync as renameSync5 } from "node:fs";
|
|
194141
194279
|
import { createHash as createHash20 } from "node:crypto";
|
|
194142
|
-
import { join as
|
|
194280
|
+
import { join as join73, resolve as resolve36 } from "node:path";
|
|
194143
194281
|
import { hostname as hostname2 } from "node:os";
|
|
194144
194282
|
import { Type as Type4 } from "typebox";
|
|
194145
194283
|
function mergerCommitEnv() {
|
|
@@ -194452,7 +194590,7 @@ async function runDeterministicVerification(store, rootDir, taskId, testCommand,
|
|
|
194452
194590
|
const deterministicVerificationMessage = "Running deterministic merge verification" + (hasTestCommand ? ` (test${testSourceDisplayLabel}: ${normalizedTestCommand})` : "") + (hasBuildCommand ? ` (build${buildSource === "inferred" ? " [inferred]" : ""}: ${normalizedBuildCommand})` : "");
|
|
194453
194591
|
await store.logEntry(taskId, deterministicVerificationMessage);
|
|
194454
194592
|
await store.appendAgentLog(taskId, deterministicVerificationMessage, "status", void 0, "merger");
|
|
194455
|
-
const bootstrapScriptPath =
|
|
194593
|
+
const bootstrapScriptPath = join73(rootDir, "scripts/ensure-test-artifacts.mjs");
|
|
194456
194594
|
if (hasTestCommand || hasBuildCommand) {
|
|
194457
194595
|
if (!existsSync58(bootstrapScriptPath)) {
|
|
194458
194596
|
const bootstrapMissingMessage = `${taskId}: [verification:bootstrap] script missing at scripts/ensure-test-artifacts.mjs \u2014 skipping preamble`;
|
|
@@ -194951,7 +195089,7 @@ async function stashTreesEqual(rootDir, aSha, bSha) {
|
|
|
194951
195089
|
}
|
|
194952
195090
|
function writeActiveMergerStatus(rootDir, taskId) {
|
|
194953
195091
|
try {
|
|
194954
|
-
const statusPath =
|
|
195092
|
+
const statusPath = join73(rootDir, ".git", ACTIVE_MERGER_STATUS_FILENAME);
|
|
194955
195093
|
const payload = {
|
|
194956
195094
|
taskId,
|
|
194957
195095
|
pid: process.pid,
|
|
@@ -194980,7 +195118,7 @@ function clearActiveMergerStatus(statusPath, taskId) {
|
|
|
194980
195118
|
}
|
|
194981
195119
|
function readActiveMergerStatus(rootDir) {
|
|
194982
195120
|
try {
|
|
194983
|
-
const statusPath =
|
|
195121
|
+
const statusPath = join73(rootDir, ".git", ACTIVE_MERGER_STATUS_FILENAME);
|
|
194984
195122
|
if (!existsSync58(statusPath)) return null;
|
|
194985
195123
|
const raw = readFileSync21(statusPath, "utf-8");
|
|
194986
195124
|
const parsed = JSON.parse(raw);
|
|
@@ -195553,7 +195691,7 @@ async function findFilesWithConflictMarkers(rootDir, files) {
|
|
|
195553
195691
|
const stillConflicted = [];
|
|
195554
195692
|
for (const file of files) {
|
|
195555
195693
|
try {
|
|
195556
|
-
const fullPath =
|
|
195694
|
+
const fullPath = join73(rootDir, file);
|
|
195557
195695
|
if (!existsSync58(fullPath)) continue;
|
|
195558
195696
|
const { stdout } = await execAsync29(
|
|
195559
195697
|
`git grep -l -e "^<<<<<<< " -e "^=======$" -e "^>>>>>>> " --no-index -- ${quoteArg3(fullPath)}`,
|
|
@@ -195580,7 +195718,7 @@ async function tryRecoverHardFailApply(params) {
|
|
|
195580
195718
|
if (!patchText.trim()) {
|
|
195581
195719
|
mergerLog.warn(`${taskId}: autostash ${sha.slice(0, 7)} produced empty patch; cannot 3-way recover`);
|
|
195582
195720
|
} else {
|
|
195583
|
-
const patchPath =
|
|
195721
|
+
const patchPath = join73(rootDir, ".git", `fusion-autostash-${sha.slice(0, 7)}.patch`);
|
|
195584
195722
|
writeFileSync9(patchPath, patchText, "utf-8");
|
|
195585
195723
|
try {
|
|
195586
195724
|
await execAsync29(`git apply --3way --whitespace=nowarn ${quoteArg3(patchPath)}`, { cwd: rootDir });
|
|
@@ -197068,13 +197206,13 @@ async function isCherryPickInProgress(rootDir) {
|
|
|
197068
197206
|
cwd: rootDir,
|
|
197069
197207
|
encoding: "utf-8"
|
|
197070
197208
|
});
|
|
197071
|
-
const cherryPickHeadPath =
|
|
197209
|
+
const cherryPickHeadPath = join73(rootDir, cherryPickHeadPathOut.trim());
|
|
197072
197210
|
if (existsSync58(cherryPickHeadPath)) return true;
|
|
197073
197211
|
const { stdout: sequencerPathOut } = await execAsync29("git rev-parse --git-path sequencer", {
|
|
197074
197212
|
cwd: rootDir,
|
|
197075
197213
|
encoding: "utf-8"
|
|
197076
197214
|
});
|
|
197077
|
-
const sequencerPath =
|
|
197215
|
+
const sequencerPath = join73(rootDir, sequencerPathOut.trim());
|
|
197078
197216
|
return existsSync58(sequencerPath);
|
|
197079
197217
|
} catch {
|
|
197080
197218
|
return false;
|
|
@@ -202117,7 +202255,7 @@ import { promisify as promisify46 } from "node:util";
|
|
|
202117
202255
|
import { setImmediate as setImmediateCb2 } from "node:timers";
|
|
202118
202256
|
import { existsSync as existsSync59, mkdirSync as mkdirSync10, readdirSync as readdirSync10, readFileSync as readFileSync22, realpathSync as realpathSync7, rmSync as rmSync8, statSync as statSync10, writeFileSync as writeFileSync10 } from "node:fs";
|
|
202119
202257
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
202120
|
-
import { isAbsolute as isAbsolute14, join as
|
|
202258
|
+
import { isAbsolute as isAbsolute14, join as join74, relative as relative13, resolve as resolve37 } from "node:path";
|
|
202121
202259
|
function resolveRepoLocalAiMergeRoot(rootDir, settings) {
|
|
202122
202260
|
return resolveAiMergeRootPath(rootDir, settings);
|
|
202123
202261
|
}
|
|
@@ -202150,9 +202288,9 @@ async function preserveWorktreeChanges(repoDir, worktreePath, taskId) {
|
|
|
202150
202288
|
return null;
|
|
202151
202289
|
}
|
|
202152
202290
|
const diff = (await execAsync30("git diff HEAD --binary", { cwd: worktreePath, encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 })).stdout;
|
|
202153
|
-
const recoveryDir =
|
|
202291
|
+
const recoveryDir = join74(repoDir, ".fusion", "recovery");
|
|
202154
202292
|
mkdirSync10(recoveryDir, { recursive: true });
|
|
202155
|
-
const patchPath =
|
|
202293
|
+
const patchPath = join74(recoveryDir, `${taskId.toLowerCase()}-${formatRecoveryTimestamp()}.patch`);
|
|
202156
202294
|
writeFileSync10(patchPath, diff, "utf-8");
|
|
202157
202295
|
return patchPath;
|
|
202158
202296
|
} catch (error3) {
|
|
@@ -203585,6 +203723,35 @@ var init_self_healing = __esm({
|
|
|
203585
203723
|
}
|
|
203586
203724
|
return false;
|
|
203587
203725
|
}
|
|
203726
|
+
/**
|
|
203727
|
+
* FNXC:WorkflowRecovery 2026-07-25-09:40:
|
|
203728
|
+
* Single shared decision for "is this branch tip's foreign `Fusion-Task-Id`/`Fusion-Task-Lineage` trailer real
|
|
203729
|
+
* evidence of cross-task contamination, or just an inherited start point?"
|
|
203730
|
+
*
|
|
203731
|
+
* A task branch cut from the integration branch points at whatever landed last. When the task has not committed
|
|
203732
|
+
* anything of its own (planning aborted, spec revise, operator move back to `todo`), the branch tip IS that
|
|
203733
|
+
* previous task's commit — a foreign trailer with zero foreign intent. FN-1406 hit exactly this: `fusion/fn-1406`
|
|
203734
|
+
* was cut from `main` at FN-1401's landed commit, planning ended without a commit, and the reclaim sweep logged
|
|
203735
|
+
* `already-merged rejected ... owner=FN-1401 reason=foreign-task-tip` every pass instead of clearing the stale
|
|
203736
|
+
* worktree/branch metadata.
|
|
203737
|
+
*
|
|
203738
|
+
* Merge-base-to-tip diff proof separates the two: no unique diff means the branch carries no task content, so the
|
|
203739
|
+
* foreign trailer is inherited and the caller may treat the row as stale metadata. The one exception is when the
|
|
203740
|
+
* base ALREADY has an explicit commit for this task — then the branch should have been sitting on the task's own
|
|
203741
|
+
* landed commit, and a foreign tip is genuine misbinding worth rejecting.
|
|
203742
|
+
*
|
|
203743
|
+
* Callers: already-merged recovery (`branchTipForeignOwnership`), branch-misbound recovery
|
|
203744
|
+
* (`isBranchTipMisboundToTask`), and the self-owned-branch reclaim sweep's `tip-already-merged` arm. Keeping the
|
|
203745
|
+
* three on one helper is the point — the reclaim arm drifted without the diff proof and that was the bug.
|
|
203746
|
+
*/
|
|
203747
|
+
async foreignTipRejection(input) {
|
|
203748
|
+
const { taskId, lineageId, branchTip, baseBranch, ownership } = input;
|
|
203749
|
+
if (ownership.rejectionReason !== "foreign-task" && ownership.rejectionReason !== "foreign-lineage") return null;
|
|
203750
|
+
const hasNoUniqueDiff = await this.branchHasNoUniqueDiff(branchTip, baseBranch).catch(() => false);
|
|
203751
|
+
const baseAlreadyHasCurrentTask = hasNoUniqueDiff ? await this.baseHasExplicitTaskOwnership(taskId, lineageId, baseBranch).catch(() => false) : false;
|
|
203752
|
+
if (hasNoUniqueDiff && !baseAlreadyHasCurrentTask) return null;
|
|
203753
|
+
return ownership.rejectionReason === "foreign-task" ? { reason: "foreign-task-tip", owner: ownership.ownerTaskId } : { reason: "foreign-lineage-tip", owner: ownership.ownerLineageId };
|
|
203754
|
+
}
|
|
203588
203755
|
async rejectForeignAlreadyMergedCandidate(input) {
|
|
203589
203756
|
const { task, candidateSha, candidateOwner, taskBranch, baseBranch, reason, phase } = input;
|
|
203590
203757
|
await this.store.logEntry(
|
|
@@ -203626,20 +203793,14 @@ var init_self_healing = __esm({
|
|
|
203626
203793
|
}
|
|
203627
203794
|
const sha = stdout.trim();
|
|
203628
203795
|
if (!sha) return null;
|
|
203629
|
-
const hasNoUniqueDiff = await this.branchHasNoUniqueDiff(sha, baseBranch).catch(() => false);
|
|
203630
203796
|
let ownership;
|
|
203631
203797
|
try {
|
|
203632
203798
|
ownership = await this.readCommitTaskOwnership(sha, taskId, lineageId);
|
|
203633
203799
|
} catch {
|
|
203634
203800
|
return { sha, reason: "ownership-unverifiable" };
|
|
203635
203801
|
}
|
|
203636
|
-
const
|
|
203637
|
-
if (
|
|
203638
|
-
return { sha, owner: ownership.ownerTaskId, reason: "foreign-task-tip" };
|
|
203639
|
-
}
|
|
203640
|
-
if ((!hasNoUniqueDiff || baseAlreadyHasCurrentTask) && ownership.rejectionReason === "foreign-lineage") {
|
|
203641
|
-
return { sha, owner: ownership.ownerLineageId, reason: "foreign-lineage-tip" };
|
|
203642
|
-
}
|
|
203802
|
+
const rejection = await this.foreignTipRejection({ taskId, lineageId, branchTip: sha, baseBranch, ownership });
|
|
203803
|
+
if (rejection) return { sha, owner: rejection.owner, reason: rejection.reason };
|
|
203643
203804
|
return null;
|
|
203644
203805
|
}
|
|
203645
203806
|
async resolveSelfHealingMergeTarget(task, settings, phase) {
|
|
@@ -204855,14 +205016,21 @@ var init_self_healing = __esm({
|
|
|
204855
205016
|
if (!ownership) {
|
|
204856
205017
|
continue;
|
|
204857
205018
|
}
|
|
204858
|
-
|
|
205019
|
+
const foreignRejection = await this.foreignTipRejection({
|
|
205020
|
+
taskId: task.id,
|
|
205021
|
+
lineageId: task.lineageId,
|
|
205022
|
+
branchTip: inspection.tipSha,
|
|
205023
|
+
baseBranch: inspection.integrationRef,
|
|
205024
|
+
ownership
|
|
205025
|
+
});
|
|
205026
|
+
if (foreignRejection) {
|
|
204859
205027
|
await this.rejectForeignAlreadyMergedCandidate({
|
|
204860
205028
|
task,
|
|
204861
205029
|
candidateSha: inspection.tipSha,
|
|
204862
|
-
candidateOwner:
|
|
205030
|
+
candidateOwner: foreignRejection.owner,
|
|
204863
205031
|
taskBranch: branchName,
|
|
204864
205032
|
baseBranch: inspection.integrationRef,
|
|
204865
|
-
reason:
|
|
205033
|
+
reason: foreignRejection.reason,
|
|
204866
205034
|
phase: "tip-already-merged"
|
|
204867
205035
|
});
|
|
204868
205036
|
continue;
|
|
@@ -208802,7 +208970,7 @@ var init_self_healing = __esm({
|
|
|
208802
208970
|
const unrecoverableRepos = [];
|
|
208803
208971
|
for (const repoRel of repoKeys) {
|
|
208804
208972
|
const entry = workspaceWorktrees[repoRel];
|
|
208805
|
-
const repoRootDir =
|
|
208973
|
+
const repoRootDir = join74(this.options.rootDir, repoRel);
|
|
208806
208974
|
let integrationBranch;
|
|
208807
208975
|
try {
|
|
208808
208976
|
integrationBranch = await resolveIntegrationBranch(
|
|
@@ -209096,7 +209264,7 @@ var init_self_healing = __esm({
|
|
|
209096
209264
|
if ((this.orphanWorktreeRemovalFailures.get(worktreePath) ?? 0) >= MAX_STARVATION_DROPS) {
|
|
209097
209265
|
continue;
|
|
209098
209266
|
}
|
|
209099
|
-
const repoRootDir =
|
|
209267
|
+
const repoRootDir = join74(this.options.rootDir, repoRel);
|
|
209100
209268
|
let success = false;
|
|
209101
209269
|
let reason = "removed";
|
|
209102
209270
|
try {
|
|
@@ -210017,7 +210185,7 @@ var init_self_healing = __esm({
|
|
|
210017
210185
|
if (testWorkerRoot) {
|
|
210018
210186
|
try {
|
|
210019
210187
|
for (const entry of readdirSync10(testWorkerRoot)) {
|
|
210020
|
-
if (entry.startsWith("redir-")) roots.push(
|
|
210188
|
+
if (entry.startsWith("redir-")) roots.push(join74(testWorkerRoot, entry));
|
|
210021
210189
|
}
|
|
210022
210190
|
} catch {
|
|
210023
210191
|
}
|
|
@@ -210031,7 +210199,7 @@ var init_self_healing = __esm({
|
|
|
210031
210199
|
} catch {
|
|
210032
210200
|
continue;
|
|
210033
210201
|
}
|
|
210034
|
-
for (const entry of entries) paths2.push(
|
|
210202
|
+
for (const entry of entries) paths2.push(join74(root, entry));
|
|
210035
210203
|
}
|
|
210036
210204
|
return paths2;
|
|
210037
210205
|
}
|
|
@@ -210267,14 +210435,10 @@ var init_self_healing = __esm({
|
|
|
210267
210435
|
maxBuffer: 1024 * 1024
|
|
210268
210436
|
});
|
|
210269
210437
|
const branchTip = tipOut.trim();
|
|
210270
|
-
const hasNoUniqueDiff = await this.branchHasNoUniqueDiff(branchTip, baseBranch).catch(() => false);
|
|
210271
210438
|
const ownership = await this.readCommitTaskOwnership(branchTip, taskId, lineageId);
|
|
210272
|
-
const
|
|
210273
|
-
if (
|
|
210274
|
-
return { misbound: false, branchTip, landed: null, rejection
|
|
210275
|
-
}
|
|
210276
|
-
if ((!hasNoUniqueDiff || baseAlreadyHasCurrentTask) && ownership.rejectionReason === "foreign-lineage") {
|
|
210277
|
-
return { misbound: false, branchTip, landed: null, rejection: { reason: "foreign-lineage-tip", owner: ownership.ownerLineageId } };
|
|
210439
|
+
const rejection = await this.foreignTipRejection({ taskId, lineageId, branchTip, baseBranch, ownership });
|
|
210440
|
+
if (rejection) {
|
|
210441
|
+
return { misbound: false, branchTip, landed: null, rejection };
|
|
210278
210442
|
}
|
|
210279
210443
|
const hasTaskId = ownership.ownerTaskId === taskId;
|
|
210280
210444
|
const hasLineage = lineageId ? ownership.ownerLineageId === lineageId : false;
|
|
@@ -211936,7 +212100,7 @@ var init_self_healing = __esm({
|
|
|
211936
212100
|
let processedMarkers = 0;
|
|
211937
212101
|
for (const task of candidates) {
|
|
211938
212102
|
try {
|
|
211939
|
-
const promptPath =
|
|
212103
|
+
const promptPath = join74(this.options.rootDir, ".fusion", "tasks", task.id, "PROMPT.md");
|
|
211940
212104
|
if (!existsSync59(promptPath)) {
|
|
211941
212105
|
continue;
|
|
211942
212106
|
}
|
|
@@ -212323,7 +212487,7 @@ var init_self_healing = __esm({
|
|
|
212323
212487
|
if (!existsSync59(worktreesDir)) return 0;
|
|
212324
212488
|
let dirs;
|
|
212325
212489
|
try {
|
|
212326
|
-
dirs = readdirSync10(worktreesDir, { withFileTypes: true }).filter((e) => e.isDirectory() && !isAiMergeContainerDir(e.name)).map((e) =>
|
|
212490
|
+
dirs = readdirSync10(worktreesDir, { withFileTypes: true }).filter((e) => e.isDirectory() && !isAiMergeContainerDir(e.name)).map((e) => join74(worktreesDir, e.name));
|
|
212327
212491
|
} catch (err) {
|
|
212328
212492
|
log28.warn(`Failed to read .worktrees/ for unregistered orphan reap: ${err instanceof Error ? err.message : String(err)}`);
|
|
212329
212493
|
return 0;
|
|
@@ -212393,7 +212557,7 @@ var init_self_healing = __esm({
|
|
|
212393
212557
|
}
|
|
212394
212558
|
if (entries.length === 0) continue;
|
|
212395
212559
|
for (const entry of entries) {
|
|
212396
|
-
const path10 =
|
|
212560
|
+
const path10 = join74(tempRoot, entry);
|
|
212397
212561
|
let canonicalPath = path10;
|
|
212398
212562
|
let cleanupReason = "stale";
|
|
212399
212563
|
try {
|
|
@@ -212631,8 +212795,8 @@ var init_self_healing = __esm({
|
|
|
212631
212795
|
// ../engine/src/triage.ts
|
|
212632
212796
|
import { Type as Type5 } from "@earendil-works/pi-ai";
|
|
212633
212797
|
import { exec as exec33 } from "node:child_process";
|
|
212634
|
-
import { readFile as
|
|
212635
|
-
import { join as
|
|
212798
|
+
import { readFile as readFile37, writeFile as writeFile28, rm as rm9 } from "node:fs/promises";
|
|
212799
|
+
import { join as join75 } from "node:path";
|
|
212636
212800
|
import { promisify as promisify47 } from "node:util";
|
|
212637
212801
|
function inlineTaskListFallback(lines, opts = {}) {
|
|
212638
212802
|
const maxChars = Math.max(1, Math.floor(opts.maxChars ?? MAX_TASK_LIST_TEXT_CHARS));
|
|
@@ -212683,10 +212847,10 @@ async function readAttachmentContents(rootDir, taskId, attachments) {
|
|
|
212683
212847
|
if (!attachments || attachments.length === 0) {
|
|
212684
212848
|
return { attachmentContents, imageContents };
|
|
212685
212849
|
}
|
|
212686
|
-
const { readFile:
|
|
212687
|
-
const { join:
|
|
212850
|
+
const { readFile: readFile47 } = await import("node:fs/promises");
|
|
212851
|
+
const { join: join109 } = await import("node:path");
|
|
212688
212852
|
for (const att of attachments) {
|
|
212689
|
-
const filePath =
|
|
212853
|
+
const filePath = join109(
|
|
212690
212854
|
rootDir,
|
|
212691
212855
|
".fusion",
|
|
212692
212856
|
"tasks",
|
|
@@ -212696,7 +212860,7 @@ async function readAttachmentContents(rootDir, taskId, attachments) {
|
|
|
212696
212860
|
);
|
|
212697
212861
|
try {
|
|
212698
212862
|
if (IMAGE_MIME_TYPES.has(att.mimeType)) {
|
|
212699
|
-
const data = await
|
|
212863
|
+
const data = await readFile47(filePath);
|
|
212700
212864
|
const detectedMimeType = detectImageMimeFromBytes(data);
|
|
212701
212865
|
const imageMimeType = detectedMimeType ?? att.mimeType;
|
|
212702
212866
|
if (detectedMimeType && detectedMimeType !== att.mimeType) {
|
|
@@ -212713,7 +212877,7 @@ async function readAttachmentContents(rootDir, taskId, attachments) {
|
|
|
212713
212877
|
text: null
|
|
212714
212878
|
});
|
|
212715
212879
|
} else {
|
|
212716
|
-
const data = await
|
|
212880
|
+
const data = await readFile47(filePath, "utf-8");
|
|
212717
212881
|
const text2 = data.length > TEXT_INLINE_LIMIT ? data.slice(0, TEXT_INLINE_LIMIT) + "\n... (truncated at 50KB)" : data;
|
|
212718
212882
|
attachmentContents.push({
|
|
212719
212883
|
originalName: att.originalName,
|
|
@@ -212954,6 +213118,7 @@ var init_triage = __esm({
|
|
|
212954
213118
|
init_prompt_layers();
|
|
212955
213119
|
init_fallback_model_observer();
|
|
212956
213120
|
init_logger3();
|
|
213121
|
+
init_plan_artifact_writeback();
|
|
212957
213122
|
init_mcp_resolution();
|
|
212958
213123
|
init_usage_limit_detector();
|
|
212959
213124
|
init_transient_error_detector();
|
|
@@ -213510,8 +213675,8 @@ var init_triage = __esm({
|
|
|
213510
213675
|
}
|
|
213511
213676
|
const settings = await mergeEffectiveSettings(this.store, task, await this.store.getSettings());
|
|
213512
213677
|
const approvalRequired = resolvePlanApprovalRequired(settings);
|
|
213513
|
-
const promptPath =
|
|
213514
|
-
const written = await
|
|
213678
|
+
const promptPath = join75(this.rootDir, ".fusion", "tasks", task.id, "PROMPT.md");
|
|
213679
|
+
const written = await readFile37(promptPath, "utf-8").catch((err) => {
|
|
213515
213680
|
const msg = err instanceof Error ? err.message : String(err);
|
|
213516
213681
|
planLog.warn(`${task.id}: failed to read PROMPT.md during planning recovery (${promptPath}): ${msg}`);
|
|
213517
213682
|
return "";
|
|
@@ -213549,8 +213714,8 @@ var init_triage = __esm({
|
|
|
213549
213714
|
return true;
|
|
213550
213715
|
}
|
|
213551
213716
|
async readNonEmptyPromptDraft(taskId, context) {
|
|
213552
|
-
const promptPath =
|
|
213553
|
-
const written = await
|
|
213717
|
+
const promptPath = join75(this.rootDir, ".fusion", "tasks", taskId, "PROMPT.md");
|
|
213718
|
+
const written = await readFile37(promptPath, "utf-8").catch((err) => {
|
|
213554
213719
|
const msg = err instanceof Error ? err.message : String(err);
|
|
213555
213720
|
planLog.warn(`${taskId}: failed to read PROMPT.md during ${context} (${promptPath}): ${msg}`);
|
|
213556
213721
|
return "";
|
|
@@ -213714,8 +213879,8 @@ var init_triage = __esm({
|
|
|
213714
213879
|
continue;
|
|
213715
213880
|
}
|
|
213716
213881
|
try {
|
|
213717
|
-
const promptPath =
|
|
213718
|
-
const content = await
|
|
213882
|
+
const promptPath = join75(this.rootDir, ".fusion", "tasks", todoTask.id, "PROMPT.md");
|
|
213883
|
+
const content = await readFile37(promptPath, "utf-8");
|
|
213719
213884
|
if (isUnplannedSeedPrompt(content, todoTask.id, todoTask.title, todoTask.description)) {
|
|
213720
213885
|
eligibleTodoTasks.push(todoTask);
|
|
213721
213886
|
}
|
|
@@ -213926,7 +214091,7 @@ var init_triage = __esm({
|
|
|
213926
214091
|
const detail = await this.store.getTask(task.id);
|
|
213927
214092
|
const currentTask = detail ?? task;
|
|
213928
214093
|
const settings = await mergeEffectiveSettings(this.store, currentTask, await this.store.getSettings());
|
|
213929
|
-
const promptPath =
|
|
214094
|
+
const promptPath = relativePromptPath(task.id);
|
|
213930
214095
|
const isFast = task.executionMode === "fast";
|
|
213931
214096
|
const leanPlanning = settings.leanPlanning === true || isFast;
|
|
213932
214097
|
const agentWork = async () => {
|
|
@@ -214262,8 +214427,22 @@ You are ${assignedAgent.name}${assignedAgent.title?.trim() ? `, ${assignedAgent.
|
|
|
214262
214427
|
}
|
|
214263
214428
|
return;
|
|
214264
214429
|
}
|
|
214265
|
-
const
|
|
214266
|
-
|
|
214430
|
+
const planPersistence = await persistPlanArtifact({
|
|
214431
|
+
store: this.store,
|
|
214432
|
+
taskId: task.id,
|
|
214433
|
+
rootDir: this.rootDir,
|
|
214434
|
+
planningCwd,
|
|
214435
|
+
author: "triage",
|
|
214436
|
+
logger: { log: (m2) => planLog.log(m2), warn: (m2) => planLog.warn(m2) }
|
|
214437
|
+
});
|
|
214438
|
+
if (planPersistence.outcome === "recovered") {
|
|
214439
|
+
await this.store.logEntry(
|
|
214440
|
+
task.id,
|
|
214441
|
+
"Recovered the plan written inside the task worktree into the project .fusion folder"
|
|
214442
|
+
).catch(() => void 0);
|
|
214443
|
+
}
|
|
214444
|
+
const written = await readFile37(
|
|
214445
|
+
join75(this.rootDir, promptPath),
|
|
214267
214446
|
"utf-8"
|
|
214268
214447
|
).catch((err) => {
|
|
214269
214448
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -214880,7 +215059,7 @@ Remove or replace these ids and call fn_task_create again.`
|
|
|
214880
215059
|
if (isNearDuplicateCanonicalInactive(canonicalTask ?? void 0)) {
|
|
214881
215060
|
if (canClearInactiveMarker) {
|
|
214882
215061
|
if (!await this.runIfStillPlanningUnderTaskLock(task, async () => {
|
|
214883
|
-
await rm9(
|
|
215062
|
+
await rm9(join75(this.rootDir, ".fusion", "tasks", task.id, "PROMPT.md"), { force: true });
|
|
214884
215063
|
})) return;
|
|
214885
215064
|
await this.updatePlanningStateIfStillCurrent(task, { paused: false, pausedReason: null, status: null });
|
|
214886
215065
|
}
|
|
@@ -214891,7 +215070,7 @@ Remove or replace these ids and call fn_task_create again.`
|
|
|
214891
215070
|
if (resolution === "prompt" && keepAcknowledged) {
|
|
214892
215071
|
if (canClearInactiveMarker) {
|
|
214893
215072
|
if (!await this.runIfStillPlanningUnderTaskLock(task, async () => {
|
|
214894
|
-
await rm9(
|
|
215073
|
+
await rm9(join75(this.rootDir, ".fusion", "tasks", task.id, "PROMPT.md"), { force: true });
|
|
214895
215074
|
})) return;
|
|
214896
215075
|
await this.updatePlanningStateIfStillCurrent(task, {
|
|
214897
215076
|
paused: false,
|
|
@@ -214932,7 +215111,7 @@ Remove or replace these ids and call fn_task_create again.`
|
|
|
214932
215111
|
return;
|
|
214933
215112
|
}
|
|
214934
215113
|
if (!await this.runIfStillPlanningUnderTaskLock(task, async () => {
|
|
214935
|
-
await rm9(
|
|
215114
|
+
await rm9(join75(this.rootDir, ".fusion", "tasks", task.id, "PROMPT.md"), { force: true });
|
|
214936
215115
|
})) return;
|
|
214937
215116
|
if (!await this.updatePlanningStateIfStillCurrent(task, {
|
|
214938
215117
|
paused: false,
|
|
@@ -214997,7 +215176,7 @@ Remove or replace these ids and call fn_task_create again.`
|
|
|
214997
215176
|
let nextPrompt = applyOriginalDescription(written, originalDescription);
|
|
214998
215177
|
nextPrompt = applyFrontendUxCriteria(nextPrompt, parsedFileScope);
|
|
214999
215178
|
if (nextPrompt !== written) {
|
|
215000
|
-
const promptPath =
|
|
215179
|
+
const promptPath = join75(this.rootDir, ".fusion", "tasks", task.id, "PROMPT.md");
|
|
215001
215180
|
try {
|
|
215002
215181
|
if (!await this.runIfStillPlanningUnderTaskLock(task, async () => {
|
|
215003
215182
|
await writeFile28(promptPath, nextPrompt, "utf-8");
|
|
@@ -215009,6 +215188,10 @@ Remove or replace these ids and call fn_task_create again.`
|
|
|
215009
215188
|
}
|
|
215010
215189
|
}
|
|
215011
215190
|
}
|
|
215191
|
+
await mirrorPlanToProjectDb(this.store, task.id, written, {
|
|
215192
|
+
author: "triage",
|
|
215193
|
+
logger: { warn: (m2) => planLog.warn(m2) }
|
|
215194
|
+
});
|
|
215012
215195
|
let taskIntentSignature = {
|
|
215013
215196
|
routePaths: [],
|
|
215014
215197
|
filePaths: [],
|
|
@@ -215255,10 +215438,10 @@ Remove or replace these ids and call fn_task_create again.`
|
|
|
215255
215438
|
});
|
|
215256
215439
|
|
|
215257
215440
|
// ../engine/src/review-artifacts/feature-video.ts
|
|
215258
|
-
import { access as access9, mkdtemp as mkdtemp2, readFile as
|
|
215441
|
+
import { access as access9, mkdtemp as mkdtemp2, readFile as readFile38, rm as rm10 } from "node:fs/promises";
|
|
215259
215442
|
import { constants as constants2 } from "node:fs";
|
|
215260
215443
|
import { tmpdir as tmpdir8 } from "node:os";
|
|
215261
|
-
import { join as
|
|
215444
|
+
import { join as join76 } from "node:path";
|
|
215262
215445
|
function shouldGenerateReviewArtifacts(task, settings) {
|
|
215263
215446
|
return isReviewArtifactGenerationEligible(settings, task.prompt);
|
|
215264
215447
|
}
|
|
@@ -215284,7 +215467,7 @@ async function generateFeatureVideo(options) {
|
|
|
215284
215467
|
let browser;
|
|
215285
215468
|
let context;
|
|
215286
215469
|
try {
|
|
215287
|
-
recordingDir = await mkdtemp2(
|
|
215470
|
+
recordingDir = await mkdtemp2(join76(tmpdir8(), "fusion-feature-video-"));
|
|
215288
215471
|
try {
|
|
215289
215472
|
browser = await client.launch({ executablePath, headless: true });
|
|
215290
215473
|
} catch {
|
|
@@ -215302,7 +215485,7 @@ async function generateFeatureVideo(options) {
|
|
|
215302
215485
|
await (options.sleep ?? defaultSleep)(Math.min(Math.max(options.durationMs ?? DEFAULT_DURATION_MS, 0), MAX_DURATION_MS));
|
|
215303
215486
|
await context.close();
|
|
215304
215487
|
context = void 0;
|
|
215305
|
-
const data = await
|
|
215488
|
+
const data = await readFile38(await video.path());
|
|
215306
215489
|
if (data.byteLength > (options.maxBytes ?? DEFAULT_MAX_BYTES2)) {
|
|
215307
215490
|
return { status: "failed", reason: "size-cap-exceeded" };
|
|
215308
215491
|
}
|
|
@@ -215451,16 +215634,16 @@ async function persistBranchState(persistence, state) {
|
|
|
215451
215634
|
);
|
|
215452
215635
|
}
|
|
215453
215636
|
}
|
|
215454
|
-
function resolveJoinConfig(
|
|
215455
|
-
const rawMode =
|
|
215637
|
+
function resolveJoinConfig(join109) {
|
|
215638
|
+
const rawMode = join109.config?.mode;
|
|
215456
215639
|
let mode = "all";
|
|
215457
215640
|
if (rawMode === "all" || rawMode === "any") mode = rawMode;
|
|
215458
215641
|
else if (rawMode && typeof rawMode === "object" && "quorum" in rawMode) {
|
|
215459
215642
|
const n = rawMode.quorum;
|
|
215460
215643
|
if (typeof n === "number" && Number.isInteger(n) && n > 0) mode = { quorum: n };
|
|
215461
|
-
else throw new WorkflowIrError(`join '${
|
|
215644
|
+
else throw new WorkflowIrError(`join '${join109.id}' quorum must be a positive integer`);
|
|
215462
215645
|
}
|
|
215463
|
-
const rawFail =
|
|
215646
|
+
const rawFail = join109.config?.onBranchFailure;
|
|
215464
215647
|
const onBranchFailure = rawFail === "collect" ? "collect" : "fail-fast";
|
|
215465
215648
|
return { mode, onBranchFailure };
|
|
215466
215649
|
}
|
|
@@ -215476,9 +215659,9 @@ async function runSplitJoin(split, env) {
|
|
|
215476
215659
|
if (branchEdges.length === 0) {
|
|
215477
215660
|
throw new WorkflowIrError(`split '${split.id}' has no traversable branches`);
|
|
215478
215661
|
}
|
|
215479
|
-
const
|
|
215480
|
-
if (!
|
|
215481
|
-
const joinConfig = resolveJoinConfig(env.nodeMap.get(
|
|
215662
|
+
const join109 = findMatchingJoin(branchEdges[0].to, env);
|
|
215663
|
+
if (!join109) throw new WorkflowIrError(`split '${split.id}' has no reachable matching join`);
|
|
215664
|
+
const joinConfig = resolveJoinConfig(env.nodeMap.get(join109));
|
|
215482
215665
|
const controller = new AbortController();
|
|
215483
215666
|
const branchCount = branchEdges.length;
|
|
215484
215667
|
const required2 = requiredCompletions(joinConfig.mode, branchCount);
|
|
@@ -215514,7 +215697,7 @@ async function runSplitJoin(split, env) {
|
|
|
215514
215697
|
};
|
|
215515
215698
|
const branchPromises = branchEdges.map((edge) => {
|
|
215516
215699
|
const branchId = edge.to;
|
|
215517
|
-
return walkBranch(branchId,
|
|
215700
|
+
return walkBranch(branchId, join109, env, controller.signal, visitedNodeIds).then((result2) => {
|
|
215518
215701
|
branchOutcomes.push({ branchId, outcome: result2.outcome, nodeId: result2.lastNodeId });
|
|
215519
215702
|
if (result2.outcome === "success") succeeded += 1;
|
|
215520
215703
|
else failed += 1;
|
|
@@ -215532,7 +215715,7 @@ async function runSplitJoin(split, env) {
|
|
|
215532
215715
|
});
|
|
215533
215716
|
const outcome = await joinReached;
|
|
215534
215717
|
await Promise.allSettled(branchPromises);
|
|
215535
|
-
return { joinNodeId:
|
|
215718
|
+
return { joinNodeId: join109, outcome, branchOutcomes, visitedNodeIds };
|
|
215536
215719
|
}
|
|
215537
215720
|
async function walkBranch(startNodeId, joinId, env, signal, visitedNodeIds) {
|
|
215538
215721
|
let currentId = startNodeId;
|
|
@@ -218948,7 +219131,7 @@ var init_workspace_paths = __esm({
|
|
|
218948
219131
|
|
|
218949
219132
|
// ../engine/src/cli-agent/hook-scripts.ts
|
|
218950
219133
|
import { mkdir as mkdir28, rm as rm11, writeFile as writeFile29 } from "node:fs/promises";
|
|
218951
|
-
import { join as
|
|
219134
|
+
import { join as join77 } from "node:path";
|
|
218952
219135
|
function shellSingleQuote(value) {
|
|
218953
219136
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
218954
219137
|
}
|
|
@@ -219020,8 +219203,8 @@ exit 0
|
|
|
219020
219203
|
async function writeSessionHookScripts(opts) {
|
|
219021
219204
|
const { sessionId, token, endpointUrl, dir } = opts;
|
|
219022
219205
|
await mkdir28(dir, { recursive: true, mode: 448 });
|
|
219023
|
-
const hookScriptPath =
|
|
219024
|
-
const notifyScriptPath =
|
|
219206
|
+
const hookScriptPath = join77(dir, HOOK_SCRIPT_NAMES.hook);
|
|
219207
|
+
const notifyScriptPath = join77(dir, HOOK_SCRIPT_NAMES.notify);
|
|
219025
219208
|
await writeFile29(hookScriptPath, buildHookScriptContent({ sessionId, token, endpointUrl }), {
|
|
219026
219209
|
mode: 448
|
|
219027
219210
|
});
|
|
@@ -219180,7 +219363,7 @@ var init_autonomy = __esm({
|
|
|
219180
219363
|
// ../engine/src/cli-agent/task-session.ts
|
|
219181
219364
|
import { mkdtemp as mkdtemp3, rm as rm12 } from "node:fs/promises";
|
|
219182
219365
|
import { tmpdir as tmpdir9 } from "node:os";
|
|
219183
|
-
import { join as
|
|
219366
|
+
import { join as join78 } from "node:path";
|
|
219184
219367
|
function launchCliTaskSession(opts) {
|
|
219185
219368
|
return CliTaskSession.launch(opts);
|
|
219186
219369
|
}
|
|
@@ -219246,9 +219429,9 @@ var init_task_session = __esm({
|
|
|
219246
219429
|
isApproved: opts.isAutonomyApproved ?? (() => false)
|
|
219247
219430
|
});
|
|
219248
219431
|
const root = opts.hookDirRoot ?? tmpdir9();
|
|
219249
|
-
const hookDir = await mkdtemp3(
|
|
219250
|
-
const hookScriptPath =
|
|
219251
|
-
const settingsPath =
|
|
219432
|
+
const hookDir = await mkdtemp3(join78(root, "fusion-cli-hooks-"));
|
|
219433
|
+
const hookScriptPath = join78(hookDir, HOOK_SCRIPT_NAMES.hook);
|
|
219434
|
+
const settingsPath = join78(hookDir, "settings.json");
|
|
219252
219435
|
const cliAgentSettings = opts.config.cliAgentSettings ?? null;
|
|
219253
219436
|
const operatorEnvAdditions = (cliAgentSettings?.envAdditions ?? []).filter(
|
|
219254
219437
|
(k2) => !/^FUSION_/i.test(k2)
|
|
@@ -219490,7 +219673,7 @@ var init_task_session = __esm({
|
|
|
219490
219673
|
// ../engine/src/pty-native.ts
|
|
219491
219674
|
import * as fs7 from "node:fs";
|
|
219492
219675
|
import { createRequire as createRequire7 } from "node:module";
|
|
219493
|
-
import { join as
|
|
219676
|
+
import { join as join79, dirname as dirname33 } from "node:path";
|
|
219494
219677
|
function getNativePrebuildName() {
|
|
219495
219678
|
const platform4 = process.platform === "darwin" ? "darwin" : process.platform === "linux" ? "linux" : process.platform === "win32" ? "win32" : "unknown";
|
|
219496
219679
|
const arch = process.arch === "arm64" ? "arm64" : process.arch === "x64" ? "x64" : "unknown";
|
|
@@ -219500,12 +219683,12 @@ function findInstalledNodePtyNativeDir() {
|
|
|
219500
219683
|
try {
|
|
219501
219684
|
const packageJsonPath = require4.resolve("node-pty/package.json");
|
|
219502
219685
|
const pkgRoot = dirname33(packageJsonPath);
|
|
219503
|
-
const releaseDir =
|
|
219504
|
-
if (fs7.existsSync(
|
|
219686
|
+
const releaseDir = join79(pkgRoot, "build", "Release");
|
|
219687
|
+
if (fs7.existsSync(join79(releaseDir, "pty.node"))) {
|
|
219505
219688
|
return releaseDir;
|
|
219506
219689
|
}
|
|
219507
|
-
const prebuildDir =
|
|
219508
|
-
if (fs7.existsSync(
|
|
219690
|
+
const prebuildDir = join79(pkgRoot, "prebuilds", getNativePrebuildName());
|
|
219691
|
+
if (fs7.existsSync(join79(prebuildDir, "pty.node"))) {
|
|
219509
219692
|
return prebuildDir;
|
|
219510
219693
|
}
|
|
219511
219694
|
return null;
|
|
@@ -219516,14 +219699,14 @@ function findInstalledNodePtyNativeDir() {
|
|
|
219516
219699
|
function findStagedNativeDir() {
|
|
219517
219700
|
const prebuildName = getNativePrebuildName();
|
|
219518
219701
|
if (process.env.FUSION_RUNTIME_DIR) {
|
|
219519
|
-
const envPath =
|
|
219520
|
-
if (fs7.existsSync(
|
|
219702
|
+
const envPath = join79(process.env.FUSION_RUNTIME_DIR, prebuildName);
|
|
219703
|
+
if (fs7.existsSync(join79(envPath, "pty.node"))) {
|
|
219521
219704
|
return envPath;
|
|
219522
219705
|
}
|
|
219523
219706
|
}
|
|
219524
219707
|
const execDir = dirname33(process.execPath);
|
|
219525
|
-
const nextToBinary =
|
|
219526
|
-
if (fs7.existsSync(
|
|
219708
|
+
const nextToBinary = join79(execDir, "runtime", prebuildName);
|
|
219709
|
+
if (fs7.existsSync(join79(nextToBinary, "pty.node"))) {
|
|
219527
219710
|
return nextToBinary;
|
|
219528
219711
|
}
|
|
219529
219712
|
return null;
|
|
@@ -219546,8 +219729,8 @@ function ensureNodePtyNativePermissions() {
|
|
|
219546
219729
|
candidateDirs.add(installedNativeDir);
|
|
219547
219730
|
}
|
|
219548
219731
|
for (const nativeDir of candidateDirs) {
|
|
219549
|
-
const helperPath =
|
|
219550
|
-
const nativeModulePath =
|
|
219732
|
+
const helperPath = join79(nativeDir, "spawn-helper");
|
|
219733
|
+
const nativeModulePath = join79(nativeDir, "pty.node");
|
|
219551
219734
|
try {
|
|
219552
219735
|
fs7.chmodSync(helperPath, 493);
|
|
219553
219736
|
} catch {
|
|
@@ -219577,7 +219760,7 @@ async function loadPtyModule() {
|
|
|
219577
219760
|
process.env.NODE_PTY_SPAWN_HELPER_DIR = nativeDir;
|
|
219578
219761
|
}
|
|
219579
219762
|
process.env.FUSION_NATIVE_ASSETS_PATH = nativeDir;
|
|
219580
|
-
const nativePath =
|
|
219763
|
+
const nativePath = join79(nativeDir, "pty.node");
|
|
219581
219764
|
if (fs7.existsSync(nativePath)) {
|
|
219582
219765
|
try {
|
|
219583
219766
|
const nativeModule = { exports: {} };
|
|
@@ -221116,7 +221299,7 @@ var init_file_scope2 = __esm({
|
|
|
221116
221299
|
|
|
221117
221300
|
// ../engine/src/run-verification-tool.ts
|
|
221118
221301
|
import { existsSync as existsSync64, readdirSync as readdirSync11, readFileSync as readFileSync23 } from "node:fs";
|
|
221119
|
-
import { isAbsolute as isAbsolute16, join as
|
|
221302
|
+
import { isAbsolute as isAbsolute16, join as join80, relative as relative14 } from "node:path";
|
|
221120
221303
|
import { Type as Type6 } from "@earendil-works/pi-ai";
|
|
221121
221304
|
function shellSplit(input) {
|
|
221122
221305
|
const tokens = [];
|
|
@@ -221231,7 +221414,7 @@ function findWorkspacePackageDir(rootDir, packageName) {
|
|
|
221231
221414
|
for (const candidate of candidates) {
|
|
221232
221415
|
if (!candidate) continue;
|
|
221233
221416
|
try {
|
|
221234
|
-
const pkg = JSON.parse(readFileSync23(
|
|
221417
|
+
const pkg = JSON.parse(readFileSync23(join80(rootDir, candidate, "package.json"), "utf8"));
|
|
221235
221418
|
if (pkg.name === packageName) {
|
|
221236
221419
|
packageDirCache.set(cacheKey, candidate);
|
|
221237
221420
|
return candidate;
|
|
@@ -221246,7 +221429,7 @@ function findWorkspacePackageDir(rootDir, packageName) {
|
|
|
221246
221429
|
while (queue.length > 0) {
|
|
221247
221430
|
const current = queue.shift();
|
|
221248
221431
|
if (!current) break;
|
|
221249
|
-
const abs =
|
|
221432
|
+
const abs = join80(rootDir, current.dir);
|
|
221250
221433
|
let entries;
|
|
221251
221434
|
try {
|
|
221252
221435
|
entries = readdirSync11(abs, { withFileTypes: true });
|
|
@@ -221256,9 +221439,9 @@ function findWorkspacePackageDir(rootDir, packageName) {
|
|
|
221256
221439
|
for (const entry of entries) {
|
|
221257
221440
|
if (!entry.isDirectory()) continue;
|
|
221258
221441
|
if (entry.name === "node_modules" || entry.name === "dist") continue;
|
|
221259
|
-
const child =
|
|
221442
|
+
const child = join80(current.dir, entry.name);
|
|
221260
221443
|
try {
|
|
221261
|
-
const pkg = JSON.parse(readFileSync23(
|
|
221444
|
+
const pkg = JSON.parse(readFileSync23(join80(rootDir, child, "package.json"), "utf8"));
|
|
221262
221445
|
if (pkg.name === packageName) {
|
|
221263
221446
|
packageDirCache.set(cacheKey, child);
|
|
221264
221447
|
return child;
|
|
@@ -221278,7 +221461,7 @@ function toPackageRelativeFilter(token, rootDir, packageDir) {
|
|
|
221278
221461
|
return normalized.slice(normalizedPackageDir.length + 1);
|
|
221279
221462
|
}
|
|
221280
221463
|
if (isAbsolute16(token)) {
|
|
221281
|
-
const rel = relative14(
|
|
221464
|
+
const rel = relative14(join80(rootDir, packageDir), token).replace(/\\/g, "/");
|
|
221282
221465
|
if (!rel.startsWith("../") && rel !== "..") return rel;
|
|
221283
221466
|
}
|
|
221284
221467
|
return token;
|
|
@@ -221535,7 +221718,7 @@ function createRunVerificationTool(opts) {
|
|
|
221535
221718
|
if (params.cwd && isAbsolute16(params.cwd)) {
|
|
221536
221719
|
resolvedCwd = params.cwd;
|
|
221537
221720
|
} else if (params.cwd) {
|
|
221538
|
-
resolvedCwd =
|
|
221721
|
+
resolvedCwd = join80(worktreePath, params.cwd);
|
|
221539
221722
|
} else {
|
|
221540
221723
|
resolvedCwd = worktreePath;
|
|
221541
221724
|
}
|
|
@@ -221568,7 +221751,7 @@ function createRunVerificationTool(opts) {
|
|
|
221568
221751
|
warnings.push(...normalized.warnings);
|
|
221569
221752
|
}
|
|
221570
221753
|
if (effectiveCommand.trimStart().startsWith("pnpm --filter")) {
|
|
221571
|
-
const modulesYaml =
|
|
221754
|
+
const modulesYaml = join80(rootDir, "node_modules", ".modules.yaml");
|
|
221572
221755
|
if (!existsSync64(modulesYaml)) {
|
|
221573
221756
|
const installCmd = "pnpm install --prefer-offline";
|
|
221574
221757
|
const msg = `node_modules/.modules.yaml not found in workspace root \u2014 auto-prepending \`${installCmd}\` before running the command.`;
|
|
@@ -221913,9 +222096,9 @@ var init_pseudo_pause = __esm({
|
|
|
221913
222096
|
import { exec as exec38, execFile as execFile26, execSync as execSync7 } from "node:child_process";
|
|
221914
222097
|
import { promisify as promisify53 } from "node:util";
|
|
221915
222098
|
import { setImmediate as setImmediateCb3 } from "node:timers";
|
|
221916
|
-
import { basename as basename19, delimiter as delimiter2, isAbsolute as isAbsolute18, join as
|
|
222099
|
+
import { basename as basename19, delimiter as delimiter2, isAbsolute as isAbsolute18, join as join81, relative as relative16, resolve as resolvePath3 } from "node:path";
|
|
221917
222100
|
import { existsSync as existsSync65, lstatSync as lstatSync3, realpathSync as realpathSync9 } from "node:fs";
|
|
221918
|
-
import { readFile as
|
|
222101
|
+
import { readFile as readFile39, rm as rm13, writeFile as writeFile30 } from "node:fs/promises";
|
|
221919
222102
|
import { Type as Type7 } from "@earendil-works/pi-ai";
|
|
221920
222103
|
import { SessionManager as SessionManager2 } from "@earendil-works/pi-coding-agent";
|
|
221921
222104
|
function mergeAdditionalSkillPaths2(...pathGroups) {
|
|
@@ -221929,7 +222112,7 @@ function isWorkflowStepSkillDiscoverable(skillName, additionalSkillPaths, ceSkil
|
|
|
221929
222112
|
return false;
|
|
221930
222113
|
}
|
|
221931
222114
|
return (additionalSkillPaths ?? []).some(
|
|
221932
|
-
(skillPath) => basename19(skillPath) === bareSkillName && existsSync65(
|
|
222115
|
+
(skillPath) => basename19(skillPath) === bareSkillName && existsSync65(join81(skillPath, "SKILL.md")) || existsSync65(join81(skillPath, bareSkillName, "SKILL.md"))
|
|
221933
222116
|
);
|
|
221934
222117
|
}
|
|
221935
222118
|
function getPromptSection(prompt, heading) {
|
|
@@ -222238,7 +222421,7 @@ function normalizeWorktreePath(pathValue) {
|
|
|
222238
222421
|
}
|
|
222239
222422
|
async function extractPersistedSessionWorktreePath(sessionFile, rootDir, settings) {
|
|
222240
222423
|
try {
|
|
222241
|
-
const content = await
|
|
222424
|
+
const content = await readFile39(sessionFile, "utf-8");
|
|
222242
222425
|
const matches = content.match(buildSessionWorktreePathRegex(rootDir, settings)) ?? [];
|
|
222243
222426
|
if (matches.length === 0) return null;
|
|
222244
222427
|
const normalizedCounts = /* @__PURE__ */ new Map();
|
|
@@ -225686,7 +225869,7 @@ ${info.feedback}`, revisionKey),
|
|
|
225686
225869
|
const authoritativeAgentLayer = this.store.getAsyncLayer();
|
|
225687
225870
|
if (!this.authoritativeAssignedAgentStore || authoritativeAgentLayer && !this.authoritativeAssignedAgentStore.backendMode) {
|
|
225688
225871
|
this.authoritativeAssignedAgentStore = new AgentStore({
|
|
225689
|
-
rootDir:
|
|
225872
|
+
rootDir: join81(this.rootDir, ".fusion"),
|
|
225690
225873
|
taskStore: this.store,
|
|
225691
225874
|
...authoritativeAgentLayer ? { asyncLayer: authoritativeAgentLayer } : {}
|
|
225692
225875
|
});
|
|
@@ -230146,7 +230329,7 @@ Graph value: ${failureValue}` : ""}`, budget.key),
|
|
|
230146
230329
|
const activeMergeStatuses = /* @__PURE__ */ new Set(["merging", "merging-pr", "merging-fix"]);
|
|
230147
230330
|
const isActiveTask = activeColumns.has(task.column) || activeMergeStatuses.has(task.status ?? "");
|
|
230148
230331
|
if (!isActiveTask) {
|
|
230149
|
-
const tasksDir =
|
|
230332
|
+
const tasksDir = join81(this.store.getFusionDir(), "tasks");
|
|
230150
230333
|
const promptPath = getPromptPath(tasksDir, task.id);
|
|
230151
230334
|
const staleness = await evaluateSpecStaleness({ settings, promptPath, task });
|
|
230152
230335
|
if (staleness.isStale) {
|
|
@@ -234007,10 +234190,10 @@ Please fix the issues so the verification can pass on the next attempt.`,
|
|
|
234007
234190
|
* The section is replaced entirely to avoid accumulation of old feedback.
|
|
234008
234191
|
*/
|
|
234009
234192
|
async injectWorkflowStepFailureInstructions(task, failureFeedback, stepName, retry) {
|
|
234010
|
-
const promptPath =
|
|
234193
|
+
const promptPath = join81(this.store.getFusionDir(), "tasks", task.id, "PROMPT.md");
|
|
234011
234194
|
let content;
|
|
234012
234195
|
try {
|
|
234013
|
-
content = await
|
|
234196
|
+
content = await readFile39(promptPath, "utf-8");
|
|
234014
234197
|
} catch {
|
|
234015
234198
|
executorLog.warn(`${task.id}: PROMPT.md not found at ${promptPath}, skipping workflow failure injection`);
|
|
234016
234199
|
return;
|
|
@@ -240549,7 +240732,7 @@ import { execFile as execFile27 } from "node:child_process";
|
|
|
240549
240732
|
import { appendFileSync as appendFileSync2, existsSync as existsSync66, mkdirSync as mkdirSync11, readdirSync as readdirSync12, readFileSync as readFileSync24, realpathSync as realpathSync10, rmSync as rmSync9, statSync as statSync13 } from "node:fs";
|
|
240550
240733
|
import { rm as rm14 } from "node:fs/promises";
|
|
240551
240734
|
import { tmpdir as tmpdir10 } from "node:os";
|
|
240552
|
-
import { isAbsolute as isAbsolute19, join as
|
|
240735
|
+
import { isAbsolute as isAbsolute19, join as join82, relative as relative17 } from "node:path";
|
|
240553
240736
|
import { promisify as promisify56 } from "node:util";
|
|
240554
240737
|
async function git4(args, cwd, opts = {}) {
|
|
240555
240738
|
const { stdout } = await execFileAsync20("git", args, {
|
|
@@ -240580,7 +240763,7 @@ function isBenignAbsentWorktreeError(err) {
|
|
|
240580
240763
|
return /is not a working tree|No such file or directory|spawn\s+.*\bENOENT\b/i.test(description);
|
|
240581
240764
|
}
|
|
240582
240765
|
function ensureAiMergeRootIgnored(projectRootDir, settings) {
|
|
240583
|
-
const excludePath =
|
|
240766
|
+
const excludePath = join82(projectRootDir, ".git", "info", "exclude");
|
|
240584
240767
|
if (!existsSync66(excludePath)) return;
|
|
240585
240768
|
try {
|
|
240586
240769
|
const current = readFileSync24(excludePath, "utf-8");
|
|
@@ -240612,7 +240795,7 @@ function getAiMergeTempSearchRoots(projectRootDir, settings) {
|
|
|
240612
240795
|
if (testWorkerRoot) {
|
|
240613
240796
|
try {
|
|
240614
240797
|
for (const entry of readdirSync12(testWorkerRoot)) {
|
|
240615
|
-
if (entry.startsWith("redir-")) roots.push(
|
|
240798
|
+
if (entry.startsWith("redir-")) roots.push(join82(testWorkerRoot, entry));
|
|
240616
240799
|
}
|
|
240617
240800
|
} catch {
|
|
240618
240801
|
}
|
|
@@ -240635,7 +240818,7 @@ async function pruneExistingAiMergeWorktrees(taskId, projectRootDir, audit, log3
|
|
|
240635
240818
|
continue;
|
|
240636
240819
|
}
|
|
240637
240820
|
for (const entry of entries) {
|
|
240638
|
-
const candidatePath =
|
|
240821
|
+
const candidatePath = join82(tempRoot, entry);
|
|
240639
240822
|
let canonicalPath = candidatePath;
|
|
240640
240823
|
try {
|
|
240641
240824
|
canonicalPath = realpathSync10(candidatePath);
|
|
@@ -241058,7 +241241,7 @@ import { promisify as promisify57 } from "node:util";
|
|
|
241058
241241
|
import { realpathSync as realpathSync11, readdirSync as readdirSync13 } from "node:fs";
|
|
241059
241242
|
import { mkdtemp as mkdtemp4 } from "node:fs/promises";
|
|
241060
241243
|
import { tmpdir as tmpdir11 } from "node:os";
|
|
241061
|
-
import { join as
|
|
241244
|
+
import { join as join83 } from "node:path";
|
|
241062
241245
|
async function git5(args, cwd, opts = {}) {
|
|
241063
241246
|
const { stdout } = await execFileAsync21("git", args, {
|
|
241064
241247
|
cwd,
|
|
@@ -241130,7 +241313,7 @@ function listAiMergeWorktreeCandidates(taskId, projectRootDir, settings) {
|
|
|
241130
241313
|
if (testWorkerRoot) {
|
|
241131
241314
|
try {
|
|
241132
241315
|
for (const entry of readdirSync13(testWorkerRoot)) {
|
|
241133
|
-
if (entry.startsWith("redir-")) roots.push(
|
|
241316
|
+
if (entry.startsWith("redir-")) roots.push(join83(testWorkerRoot, entry));
|
|
241134
241317
|
}
|
|
241135
241318
|
} catch {
|
|
241136
241319
|
}
|
|
@@ -241143,7 +241326,7 @@ function listAiMergeWorktreeCandidates(taskId, projectRootDir, settings) {
|
|
|
241143
241326
|
} catch {
|
|
241144
241327
|
continue;
|
|
241145
241328
|
}
|
|
241146
|
-
for (const entry of entries) candidates.push(
|
|
241329
|
+
for (const entry of entries) candidates.push(join83(root, entry));
|
|
241147
241330
|
}
|
|
241148
241331
|
return candidates;
|
|
241149
241332
|
}
|
|
@@ -241477,7 +241660,7 @@ async function landOneRepo(repoRootDir, branch, integrationBranch, ctx) {
|
|
|
241477
241660
|
registeredMergePaths.add(pathToRegister);
|
|
241478
241661
|
};
|
|
241479
241662
|
try {
|
|
241480
|
-
mergeRoot = await mkdtemp4(
|
|
241663
|
+
mergeRoot = await mkdtemp4(join83(resolveAiMergeRoot(repoRootDir, settings), `fusion-ai-merge-${taskId.toLowerCase()}-`));
|
|
241481
241664
|
registerMergeRoot(mergeRoot);
|
|
241482
241665
|
await git5(["worktree", "add", "--detach", mergeRoot, tipSha], repoRootDir);
|
|
241483
241666
|
worktreeAdded = true;
|
|
@@ -241973,7 +242156,7 @@ async function landWorkspaceTask(store, task, workspaceRootDir, options = {}, de
|
|
|
241973
242156
|
for (const repoRel of repoKeys) {
|
|
241974
242157
|
throwIfAborted2(options.signal, taskId);
|
|
241975
242158
|
const entry = workspaceWorktrees[repoRel];
|
|
241976
|
-
const repoRootDir =
|
|
242159
|
+
const repoRootDir = join83(workspaceRootDir, repoRel);
|
|
241977
242160
|
let integrationBranch;
|
|
241978
242161
|
try {
|
|
241979
242162
|
integrationBranch = await resolveIntegrationBranch(
|
|
@@ -242290,7 +242473,7 @@ async function pushAfterMergeToRemote(input) {
|
|
|
242290
242473
|
let worktreeAdded = false;
|
|
242291
242474
|
const registeredPaths = /* @__PURE__ */ new Set();
|
|
242292
242475
|
try {
|
|
242293
|
-
pushRoot = await mkdtemp4(
|
|
242476
|
+
pushRoot = await mkdtemp4(join83(resolveAiMergeRoot(projectRootDir, settings), `fusion-ai-merge-push-${taskId.toLowerCase()}-`));
|
|
242294
242477
|
for (const p2 of [pushRoot]) {
|
|
242295
242478
|
activeSessionRegistry.registerPath(p2, { taskId, kind: "ai-merge", ownerKey: `ai-merge-push:${taskId}` });
|
|
242296
242479
|
registeredPaths.add(p2);
|
|
@@ -242597,7 +242780,7 @@ var init_merger_ai = __esm({
|
|
|
242597
242780
|
|
|
242598
242781
|
// ../engine/src/task-revert.ts
|
|
242599
242782
|
import { exec as exec41 } from "node:child_process";
|
|
242600
|
-
import { join as
|
|
242783
|
+
import { join as join84 } from "node:path";
|
|
242601
242784
|
import { promisify as promisify58 } from "node:util";
|
|
242602
242785
|
function quoteShellArg7(value) {
|
|
242603
242786
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
@@ -243047,7 +243230,7 @@ async function resolveWorkspaceTaskRevertCommits(task, opts) {
|
|
|
243047
243230
|
const result2 = {};
|
|
243048
243231
|
for (const repoRel of repoKeys) {
|
|
243049
243232
|
const entry = workspaceWorktrees[repoRel];
|
|
243050
|
-
const repoRootDir =
|
|
243233
|
+
const repoRootDir = join84(opts.workspaceRootDir, repoRel);
|
|
243051
243234
|
const landedSha = workspaceLandedShas[repoRel] ?? entry?.landedSha;
|
|
243052
243235
|
if (landedSha && !entry?.baseCommitSha) {
|
|
243053
243236
|
result2[repoRel] = { commits: [landedSha], source: "squash" };
|
|
@@ -243114,7 +243297,7 @@ async function revertWorkspaceTask(opts) {
|
|
|
243114
243297
|
});
|
|
243115
243298
|
const contexts = [];
|
|
243116
243299
|
for (const repoRel of repoKeys) {
|
|
243117
|
-
const repoRootDir =
|
|
243300
|
+
const repoRootDir = join84(workspaceRootDir, repoRel);
|
|
243118
243301
|
let integrationBranch;
|
|
243119
243302
|
try {
|
|
243120
243303
|
integrationBranch = await resolveIntegrationBranch(repoRootDir, { ...opts.settings, integrationBranch: void 0, baseBranch: void 0 });
|
|
@@ -243239,7 +243422,7 @@ async function prepareWorkspaceRevertPrBranches(opts) {
|
|
|
243239
243422
|
});
|
|
243240
243423
|
const contexts = [];
|
|
243241
243424
|
for (const repoRel of repoKeys) {
|
|
243242
|
-
const repoRootDir =
|
|
243425
|
+
const repoRootDir = join84(workspaceRootDir, repoRel);
|
|
243243
243426
|
let integrationBranch;
|
|
243244
243427
|
try {
|
|
243245
243428
|
integrationBranch = await resolveIntegrationBranch(repoRootDir, { ...opts.settings, integrationBranch: void 0, baseBranch: void 0 });
|
|
@@ -243580,7 +243763,7 @@ async function readOptionalTextFile(filePath) {
|
|
|
243580
243763
|
}
|
|
243581
243764
|
async function discoverMcpServers(opts) {
|
|
243582
243765
|
const homeDir = opts.homeDir ?? process.env.HOME ?? process.env.USERPROFILE ?? osHomedir();
|
|
243583
|
-
const
|
|
243766
|
+
const readFile47 = opts.readFile ?? readOptionalTextFile;
|
|
243584
243767
|
const sources = getMcpDiscoverySources({
|
|
243585
243768
|
homeDir,
|
|
243586
243769
|
platform: osPlatform(),
|
|
@@ -243591,7 +243774,7 @@ async function discoverMcpServers(opts) {
|
|
|
243591
243774
|
for (const source of sources) {
|
|
243592
243775
|
let contents;
|
|
243593
243776
|
try {
|
|
243594
|
-
contents = await
|
|
243777
|
+
contents = await readFile47(source.path);
|
|
243595
243778
|
} catch (error3) {
|
|
243596
243779
|
errors.push(`${source.label}: ${error3 instanceof Error ? error3.message : String(error3)}`);
|
|
243597
243780
|
continue;
|
|
@@ -244141,7 +244324,7 @@ var agent_reflection_exports = {};
|
|
|
244141
244324
|
__export(agent_reflection_exports, {
|
|
244142
244325
|
AgentReflectionService: () => AgentReflectionService
|
|
244143
244326
|
});
|
|
244144
|
-
import { readFile as
|
|
244327
|
+
import { readFile as readFile40 } from "node:fs/promises";
|
|
244145
244328
|
import { isAbsolute as isAbsolute20, resolve as resolve38 } from "node:path";
|
|
244146
244329
|
var reflectionLog, REFLECTION_SYSTEM_PROMPT, DEFAULT_OUTCOME_LIMIT, AgentReflectionService;
|
|
244147
244330
|
var init_agent_reflection = __esm({
|
|
@@ -244700,7 +244883,7 @@ Rules:
|
|
|
244700
244883
|
if (agent.instructionsPath?.trim()) {
|
|
244701
244884
|
const resolvedPath = isAbsolute20(agent.instructionsPath) ? agent.instructionsPath : resolve38(this.rootDir, agent.instructionsPath);
|
|
244702
244885
|
try {
|
|
244703
|
-
const content = await
|
|
244886
|
+
const content = await readFile40(resolvedPath, "utf-8");
|
|
244704
244887
|
if (content.trim()) {
|
|
244705
244888
|
pieces.push(content.trim());
|
|
244706
244889
|
}
|
|
@@ -246808,7 +246991,7 @@ The note must be specific (what/where/why). Prefer citing File Scope, PROMPT, a
|
|
|
246808
246991
|
|
|
246809
246992
|
// ../engine/src/overseer-watchdog.ts
|
|
246810
246993
|
import { existsSync as existsSync67, readFileSync as readFileSync25 } from "node:fs";
|
|
246811
|
-
import { dirname as dirname34, join as
|
|
246994
|
+
import { dirname as dirname34, join as join85, relative as relative18, resolve as resolve39, sep as sep11 } from "node:path";
|
|
246812
246995
|
import { homedir as homedir11 } from "node:os";
|
|
246813
246996
|
function defaultReadText(path10) {
|
|
246814
246997
|
try {
|
|
@@ -246837,7 +247020,7 @@ function discoverOverseerWatchdogFiles(options) {
|
|
|
246837
247020
|
};
|
|
246838
247021
|
if (agentDir) {
|
|
246839
247022
|
for (const name2 of WATCHDOG_FILENAMES) {
|
|
246840
|
-
tryAdd(
|
|
247023
|
+
tryAdd(join85(agentDir, name2), "user", 999);
|
|
246841
247024
|
}
|
|
246842
247025
|
}
|
|
246843
247026
|
let current = cwd;
|
|
@@ -246845,9 +247028,9 @@ function discoverOverseerWatchdogFiles(options) {
|
|
|
246845
247028
|
for (let hop = 0; hop < 64; hop++) {
|
|
246846
247029
|
const depth = relative18(cwd, current) === "" ? 0 : relative18(cwd, current).split(sep11).filter(Boolean).length;
|
|
246847
247030
|
for (const name2 of WATCHDOG_FILENAMES) {
|
|
246848
|
-
tryAdd(
|
|
246849
|
-
tryAdd(
|
|
246850
|
-
tryAdd(
|
|
247031
|
+
tryAdd(join85(current, name2), "project", depth);
|
|
247032
|
+
tryAdd(join85(current, ".fusion", name2), "project", depth);
|
|
247033
|
+
tryAdd(join85(current, ".omp", name2), "project", depth);
|
|
246851
247034
|
}
|
|
246852
247035
|
if (current === stopAt) break;
|
|
246853
247036
|
const parent = dirname34(current);
|
|
@@ -255150,7 +255333,7 @@ __export(child_process_runtime_exports, {
|
|
|
255150
255333
|
import { EventEmitter as EventEmitter28 } from "node:events";
|
|
255151
255334
|
import { fork } from "node:child_process";
|
|
255152
255335
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
255153
|
-
import { dirname as dirname35, join as
|
|
255336
|
+
import { dirname as dirname35, join as join86 } from "node:path";
|
|
255154
255337
|
var HealthMonitor, ChildProcessRuntime;
|
|
255155
255338
|
var init_child_process_runtime = __esm({
|
|
255156
255339
|
"../engine/src/runtimes/child-process-runtime.ts"() {
|
|
@@ -255312,7 +255495,7 @@ var init_child_process_runtime = __esm({
|
|
|
255312
255495
|
const isCompiled = !import.meta.url.endsWith(".ts");
|
|
255313
255496
|
const currentDir = dirname35(fileURLToPath4(import.meta.url));
|
|
255314
255497
|
const workerFile = isCompiled ? "child-process-worker.js" : "child-process-worker.ts";
|
|
255315
|
-
return
|
|
255498
|
+
return join86(currentDir, workerFile);
|
|
255316
255499
|
}
|
|
255317
255500
|
/**
|
|
255318
255501
|
* Set up event forwarding from IPC host to runtime listeners.
|
|
@@ -261579,7 +261762,7 @@ import { mkdirSync as mkdirSync12 } from "node:fs";
|
|
|
261579
261762
|
import { access as access10, unlink as unlink10, writeFile as writeFile32 } from "node:fs/promises";
|
|
261580
261763
|
import net2 from "node:net";
|
|
261581
261764
|
import { platform as platform3, tmpdir as tmpdir12 } from "node:os";
|
|
261582
|
-
import { join as
|
|
261765
|
+
import { join as join87 } from "node:path";
|
|
261583
261766
|
import { createHash as createHash24 } from "node:crypto";
|
|
261584
261767
|
function projectHash(projectId) {
|
|
261585
261768
|
return createHash24("sha1").update(projectId).digest("hex").slice(0, 16);
|
|
@@ -261589,10 +261772,10 @@ function computeEngineSocketPath(projectId) {
|
|
|
261589
261772
|
if (platform3() === "win32") {
|
|
261590
261773
|
return `\\\\.\\pipe\\fusion-engine-${hash}`;
|
|
261591
261774
|
}
|
|
261592
|
-
return
|
|
261775
|
+
return join87(tmpdir12(), `fusion-engine-${hash}.sock`);
|
|
261593
261776
|
}
|
|
261594
261777
|
function computeEngineLockFilePath(workingDir) {
|
|
261595
|
-
return
|
|
261778
|
+
return join87(workingDir, ".fusion", "engine.lock");
|
|
261596
261779
|
}
|
|
261597
261780
|
async function ensureLockTargetExists(lockPath) {
|
|
261598
261781
|
try {
|
|
@@ -261602,7 +261785,7 @@ async function ensureLockTargetExists(lockPath) {
|
|
|
261602
261785
|
}
|
|
261603
261786
|
}
|
|
261604
261787
|
async function acquireLockfile(workingDir, onCompromised) {
|
|
261605
|
-
const dir =
|
|
261788
|
+
const dir = join87(workingDir, ".fusion");
|
|
261606
261789
|
mkdirSync12(dir, { recursive: true });
|
|
261607
261790
|
const path10 = computeEngineLockFilePath(workingDir);
|
|
261608
261791
|
await ensureLockTargetExists(path10);
|
|
@@ -267278,7 +267461,7 @@ var init_issue_image_attachments = __esm({
|
|
|
267278
267461
|
import { exec as exec45 } from "node:child_process";
|
|
267279
267462
|
import { mkdtemp as mkdtemp6, rm as rm15 } from "node:fs/promises";
|
|
267280
267463
|
import { tmpdir as tmpdir13 } from "node:os";
|
|
267281
|
-
import { join as
|
|
267464
|
+
import { join as join88 } from "node:path";
|
|
267282
267465
|
import { promisify as promisify65 } from "node:util";
|
|
267283
267466
|
function resolveCommentAuthor(input) {
|
|
267284
267467
|
const login = input.login || "unknown";
|
|
@@ -268447,8 +268630,8 @@ var init_github = __esm({
|
|
|
268447
268630
|
{ timeout: 3e4, maxBuffer: 10 * 1024 * 1024 }
|
|
268448
268631
|
);
|
|
268449
268632
|
const mergeBase = mergeBaseStdout.trim();
|
|
268450
|
-
const indexDir = await mkdtemp6(
|
|
268451
|
-
const indexPath =
|
|
268633
|
+
const indexDir = await mkdtemp6(join88(tmpdir13(), "fn-pr-conflict-"));
|
|
268634
|
+
const indexPath = join88(indexDir, "index");
|
|
268452
268635
|
const gitEnv = { ...process.env, GIT_INDEX_FILE: indexPath };
|
|
268453
268636
|
try {
|
|
268454
268637
|
await execAsync40(`git -C ${quoteGitArg(opts.repoRoot)} read-tree -m ${quoteGitArg(mergeBase)} ${quoteGitArg(baseRef)} ${quoteGitArg(headRef)}`, {
|
|
@@ -272035,8 +272218,8 @@ var init_knowledge_index_refresh = __esm({
|
|
|
272035
272218
|
// ../dashboard/src/pr-metadata-generator.ts
|
|
272036
272219
|
import { promisify as promisify66 } from "node:util";
|
|
272037
272220
|
import { exec as execCb } from "node:child_process";
|
|
272038
|
-
import { access as access11, readFile as
|
|
272039
|
-
import { join as
|
|
272221
|
+
import { access as access11, readFile as readFile41 } from "node:fs/promises";
|
|
272222
|
+
import { join as join89 } from "node:path";
|
|
272040
272223
|
function buildFallbackPrMetadata(task) {
|
|
272041
272224
|
return {
|
|
272042
272225
|
title: task.title ?? task.id,
|
|
@@ -272236,14 +272419,14 @@ async function generatePrMetadata(input) {
|
|
|
272236
272419
|
]), combinedSignal);
|
|
272237
272420
|
let promptContent = "";
|
|
272238
272421
|
try {
|
|
272239
|
-
const promptPath =
|
|
272240
|
-
promptContent = (await raceWithAbort(
|
|
272422
|
+
const promptPath = join89(repoRoot, ".fusion", "tasks", task.id, "PROMPT.md");
|
|
272423
|
+
promptContent = (await raceWithAbort(readFile41(promptPath, "utf8"), combinedSignal)).trim();
|
|
272241
272424
|
} catch {
|
|
272242
272425
|
promptContent = "";
|
|
272243
272426
|
}
|
|
272244
|
-
const templatePath =
|
|
272427
|
+
const templatePath = join89(repoRoot, ".github", "pull_request_template.md");
|
|
272245
272428
|
const templateExists = await raceWithAbort(access11(templatePath).then(() => true).catch(() => false), combinedSignal);
|
|
272246
|
-
const template = templateExists ? await raceWithAbort(
|
|
272429
|
+
const template = templateExists ? await raceWithAbort(readFile41(templatePath, "utf8"), combinedSignal) : "";
|
|
272247
272430
|
const model = resolveTitleSummarizerSettingsModel(settings);
|
|
272248
272431
|
const systemPrompt = [PR_METADATA_SYSTEM_PROMPT];
|
|
272249
272432
|
const titleGuidance = settings.prTitlePromptInstructions?.trim();
|
|
@@ -279896,12 +280079,12 @@ import {
|
|
|
279896
280079
|
unlinkSync as unlinkSync4
|
|
279897
280080
|
} from "node:fs";
|
|
279898
280081
|
import { homedir as homedir12 } from "node:os";
|
|
279899
|
-
import { basename as basename21, dirname as dirname36, join as
|
|
280082
|
+
import { basename as basename21, dirname as dirname36, join as join90, resolve as resolve40 } from "node:path";
|
|
279900
280083
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
279901
280084
|
function resolveHermesHome(profile) {
|
|
279902
|
-
const base = process.env.HERMES_HOME ??
|
|
280085
|
+
const base = process.env.HERMES_HOME ?? join90(homedir12(), ".hermes");
|
|
279903
280086
|
if (!profile || profile === "default") return base;
|
|
279904
|
-
return
|
|
280087
|
+
return join90(base, "profiles", profile);
|
|
279905
280088
|
}
|
|
279906
280089
|
function getFusionSkillSourceCandidates(moduleUrl = import.meta.url) {
|
|
279907
280090
|
const here = fileURLToPath5(moduleUrl);
|
|
@@ -279916,13 +280099,13 @@ function getFusionSkillSourceCandidates(moduleUrl = import.meta.url) {
|
|
|
279916
280099
|
function resolveBundledFusionSkillSource() {
|
|
279917
280100
|
const candidates = getFusionSkillSourceCandidates();
|
|
279918
280101
|
for (const candidate of candidates) {
|
|
279919
|
-
if (existsSync69(
|
|
280102
|
+
if (existsSync69(join90(candidate, "SKILL.md"))) return candidate;
|
|
279920
280103
|
}
|
|
279921
280104
|
return null;
|
|
279922
280105
|
}
|
|
279923
280106
|
function installFusionSkillIntoHermesHome(options = {}) {
|
|
279924
280107
|
const sourceDir = options.sourceDir ?? resolveBundledFusionSkillSource();
|
|
279925
|
-
const targetDir =
|
|
280108
|
+
const targetDir = join90(resolveHermesHome(options.profile), "skills", FUSION_SKILL_NAME);
|
|
279926
280109
|
if (!sourceDir) {
|
|
279927
280110
|
return {
|
|
279928
280111
|
outcome: "warning",
|
|
@@ -280011,7 +280194,7 @@ function isBrokenSymlink(path10) {
|
|
|
280011
280194
|
}
|
|
280012
280195
|
}
|
|
280013
280196
|
function looksLikePriorFusionInstall(path10) {
|
|
280014
|
-
const skillMd =
|
|
280197
|
+
const skillMd = join90(path10, "SKILL.md");
|
|
280015
280198
|
if (!existsSync69(skillMd)) return false;
|
|
280016
280199
|
try {
|
|
280017
280200
|
const body = readFileSync26(skillMd, "utf-8");
|
|
@@ -280023,7 +280206,7 @@ function looksLikePriorFusionInstall(path10) {
|
|
|
280023
280206
|
function looksLikeFusionSkillTarget(path10) {
|
|
280024
280207
|
if (!path10) return false;
|
|
280025
280208
|
if (basename21(path10).toLowerCase() === FUSION_SKILL_NAME) return true;
|
|
280026
|
-
return existsSync69(
|
|
280209
|
+
return existsSync69(join90(path10, "SKILL.md"));
|
|
280027
280210
|
}
|
|
280028
280211
|
var FUSION_SKILL_NAME;
|
|
280029
280212
|
var init_fusion_skill_install = __esm({
|
|
@@ -280204,7 +280387,7 @@ var init_src8 = __esm({
|
|
|
280204
280387
|
// ../../plugins/fusion-plugin-openclaw-runtime/src/pi-module.ts
|
|
280205
280388
|
import { spawn as spawn13 } from "node:child_process";
|
|
280206
280389
|
import { randomUUID as randomUUID50 } from "node:crypto";
|
|
280207
|
-
import { readFile as
|
|
280390
|
+
import { readFile as readFile43 } from "node:fs/promises";
|
|
280208
280391
|
function asString2(v2) {
|
|
280209
280392
|
return typeof v2 === "string" && v2.trim() !== "" ? v2.trim() : void 0;
|
|
280210
280393
|
}
|
|
@@ -280275,7 +280458,7 @@ function createCliSession(opts) {
|
|
|
280275
280458
|
};
|
|
280276
280459
|
}
|
|
280277
280460
|
async function configureOpenClawMcpServer(opts) {
|
|
280278
|
-
const serverValue = await
|
|
280461
|
+
const serverValue = await readFile43(opts.serverConfigPath, "utf-8");
|
|
280279
280462
|
await new Promise((resolve53, reject) => {
|
|
280280
280463
|
const child = spawn13(opts.binaryPath, ["--no-color", "--profile", opts.profile, "mcp", "set", opts.serverName, serverValue], {
|
|
280281
280464
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -280419,7 +280602,7 @@ var init_pi_module = __esm({
|
|
|
280419
280602
|
// ../../plugins/fusion-plugin-openclaw-runtime/src/mcp-config.ts
|
|
280420
280603
|
import { writeFileSync as writeFileSync13 } from "node:fs";
|
|
280421
280604
|
import { tmpdir as tmpdir14 } from "node:os";
|
|
280422
|
-
import { join as
|
|
280605
|
+
import { join as join91 } from "node:path";
|
|
280423
280606
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
280424
280607
|
import { dirname as dirname37 } from "node:path";
|
|
280425
280608
|
function toolsToMcpToolDefs(tools) {
|
|
@@ -280432,16 +280615,16 @@ function toolsToMcpToolDefs(tools) {
|
|
|
280432
280615
|
}
|
|
280433
280616
|
function writeOpenClawMcpBridgeFiles(toolDefs, cacheKey) {
|
|
280434
280617
|
const suffix = cacheKey ? `${process.pid}-${cacheKey}` : `${process.pid}`;
|
|
280435
|
-
const schemaPath =
|
|
280618
|
+
const schemaPath = join91(tmpdir14(), `openclaw-runtime-mcp-schemas-${suffix}.json`);
|
|
280436
280619
|
writeFileSync13(schemaPath, JSON.stringify(toolDefs));
|
|
280437
280620
|
const __filename = fileURLToPath6(import.meta.url);
|
|
280438
280621
|
const __dirname3 = dirname37(__filename);
|
|
280439
|
-
const serverPath =
|
|
280622
|
+
const serverPath = join91(__dirname3, "mcp-schema-server.cjs");
|
|
280440
280623
|
const serverConfig = {
|
|
280441
280624
|
command: "node",
|
|
280442
280625
|
args: [serverPath, schemaPath]
|
|
280443
280626
|
};
|
|
280444
|
-
const serverConfigPath =
|
|
280627
|
+
const serverConfigPath = join91(tmpdir14(), `openclaw-runtime-mcp-server-${suffix}.json`);
|
|
280445
280628
|
writeFileSync13(serverConfigPath, JSON.stringify(serverConfig));
|
|
280446
280629
|
return {
|
|
280447
280630
|
schemaPath,
|
|
@@ -281209,9 +281392,9 @@ var init_cli_spawn3 = __esm({
|
|
|
281209
281392
|
});
|
|
281210
281393
|
|
|
281211
281394
|
// ../../plugins/fusion-plugin-grok-runtime/src/probe.ts
|
|
281212
|
-
import { readFile as
|
|
281395
|
+
import { readFile as readFile44 } from "node:fs/promises";
|
|
281213
281396
|
import { homedir as homedir13 } from "node:os";
|
|
281214
|
-
import { join as
|
|
281397
|
+
import { join as join92 } from "node:path";
|
|
281215
281398
|
function buildCandidates2(binaryPath) {
|
|
281216
281399
|
const configuredBinaryPath = binaryPath?.trim() || void 0;
|
|
281217
281400
|
const ordered = configuredBinaryPath ? [configuredBinaryPath, ...CANDIDATES3] : [...CANDIDATES3];
|
|
@@ -281228,10 +281411,10 @@ async function probeGrokApiKeyPresence() {
|
|
|
281228
281411
|
if (typeof envKey === "string" && envKey.trim().length > 0) {
|
|
281229
281412
|
return { detected: true };
|
|
281230
281413
|
}
|
|
281231
|
-
const settingsPath =
|
|
281414
|
+
const settingsPath = join92(homedir13(), ".grok", "user-settings.json");
|
|
281232
281415
|
let raw;
|
|
281233
281416
|
try {
|
|
281234
|
-
raw = await
|
|
281417
|
+
raw = await readFile44(settingsPath, "utf-8");
|
|
281235
281418
|
} catch {
|
|
281236
281419
|
return { detected: false, reason: "No Grok API key detected by Fusion (GROK_API_KEY unset, ~/.grok/user-settings.json not found); the CLI will use its own credentials." };
|
|
281237
281420
|
}
|
|
@@ -281380,7 +281563,7 @@ var init_provider2 = __esm({
|
|
|
281380
281563
|
|
|
281381
281564
|
// ../../plugins/fusion-plugin-grok-runtime/src/acp/cli-spawn.ts
|
|
281382
281565
|
import { existsSync as existsSync70 } from "node:fs";
|
|
281383
|
-
import { dirname as dirname38, isAbsolute as isAbsolute22, join as
|
|
281566
|
+
import { dirname as dirname38, isAbsolute as isAbsolute22, join as join93, resolve as resolve41 } from "node:path";
|
|
281384
281567
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
281385
281568
|
function asTrimmedString(value) {
|
|
281386
281569
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
@@ -281398,7 +281581,7 @@ function pluginRootDir() {
|
|
|
281398
281581
|
}
|
|
281399
281582
|
function bundledClaudeBridgeBinPath(pluginRoot = pluginRootDir()) {
|
|
281400
281583
|
const extension = process.platform === "win32" ? ".cmd" : "";
|
|
281401
|
-
return
|
|
281584
|
+
return join93(pluginRoot, "node_modules", ".bin", `${CLAUDE_CODE_CLI_ACP_BINARY}${extension}`);
|
|
281402
281585
|
}
|
|
281403
281586
|
function resolveBundledClaudeBridgeBinary(options = {}) {
|
|
281404
281587
|
const root = options.pluginRoot ?? pluginRootDir();
|
|
@@ -282761,10 +282944,10 @@ import {
|
|
|
282761
282944
|
} from "node:fs";
|
|
282762
282945
|
import { createRequire as createRequire8 } from "node:module";
|
|
282763
282946
|
import { tmpdir as tmpdir15 } from "node:os";
|
|
282764
|
-
import { basename as basename23, dirname as dirname40, join as
|
|
282947
|
+
import { basename as basename23, dirname as dirname40, join as join95, resolve as resolve43 } from "node:path";
|
|
282765
282948
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
282766
282949
|
function isSkillDir(dir) {
|
|
282767
|
-
return existsSync71(
|
|
282950
|
+
return existsSync71(join95(dir, "SKILL.md"));
|
|
282768
282951
|
}
|
|
282769
282952
|
function pushUnique(out, candidate) {
|
|
282770
282953
|
if (!candidate) return;
|
|
@@ -282772,8 +282955,8 @@ function pushUnique(out, candidate) {
|
|
|
282772
282955
|
if (!out.includes(resolved)) out.push(resolved);
|
|
282773
282956
|
}
|
|
282774
282957
|
function pushSkillLayoutsAtRoot(out, root) {
|
|
282775
|
-
pushUnique(out,
|
|
282776
|
-
pushUnique(out,
|
|
282958
|
+
pushUnique(out, join95(root, "skill", FUSION_SKILL_NAME2));
|
|
282959
|
+
pushUnique(out, join95(root, "packages", "cli", "skill", FUSION_SKILL_NAME2));
|
|
282777
282960
|
}
|
|
282778
282961
|
function walkAncestorSkillCandidates(out, startDir, maxParents = 8) {
|
|
282779
282962
|
let dir = startDir;
|
|
@@ -282788,7 +282971,7 @@ function pushPackageRequireCandidates(out, from) {
|
|
|
282788
282971
|
try {
|
|
282789
282972
|
const require5 = createRequire8(from);
|
|
282790
282973
|
const pkgJson = require5.resolve("@runfusion/fusion/package.json");
|
|
282791
|
-
pushUnique(out,
|
|
282974
|
+
pushUnique(out, join95(dirname40(pkgJson), "skill", FUSION_SKILL_NAME2));
|
|
282792
282975
|
} catch {
|
|
282793
282976
|
}
|
|
282794
282977
|
}
|
|
@@ -282856,21 +283039,21 @@ function collectSkillsFromRoot(root, out) {
|
|
|
282856
283039
|
return;
|
|
282857
283040
|
}
|
|
282858
283041
|
for (const entry of entries) {
|
|
282859
|
-
const child =
|
|
283042
|
+
const child = join95(root, entry);
|
|
282860
283043
|
if (isSkillDir(child)) {
|
|
282861
283044
|
out.set(entry, child);
|
|
282862
283045
|
}
|
|
282863
283046
|
}
|
|
282864
283047
|
}
|
|
282865
283048
|
function stageGrokSessionSkills(options = {}) {
|
|
282866
|
-
const pluginDir = mkdtempSync3(
|
|
282867
|
-
const skillsDir =
|
|
283049
|
+
const pluginDir = mkdtempSync3(join95(tmpdir15(), "fusion-grok-plugin-"));
|
|
283050
|
+
const skillsDir = join95(pluginDir, "skills");
|
|
282868
283051
|
mkdirSync14(skillsDir, { recursive: true });
|
|
282869
283052
|
const installed = /* @__PURE__ */ new Map();
|
|
282870
283053
|
const includeFusion = options.includeFusionSkill !== false;
|
|
282871
283054
|
if (includeFusion) {
|
|
282872
283055
|
const fusionSource = resolveBundledFusionSkillSource2();
|
|
282873
|
-
if (fusionSource && installSkillDir(fusionSource,
|
|
283056
|
+
if (fusionSource && installSkillDir(fusionSource, join95(skillsDir, FUSION_SKILL_NAME2))) {
|
|
282874
283057
|
installed.set(FUSION_SKILL_NAME2, fusionSource);
|
|
282875
283058
|
}
|
|
282876
283059
|
}
|
|
@@ -282880,15 +283063,15 @@ function stageGrokSessionSkills(options = {}) {
|
|
|
282880
283063
|
}
|
|
282881
283064
|
for (const [name2, source] of installed) {
|
|
282882
283065
|
if (name2 === FUSION_SKILL_NAME2 && includeFusion) continue;
|
|
282883
|
-
installSkillDir(source,
|
|
283066
|
+
installSkillDir(source, join95(skillsDir, name2));
|
|
282884
283067
|
}
|
|
282885
283068
|
for (const [name2, source] of installed) {
|
|
282886
|
-
if (!existsSync71(
|
|
282887
|
-
installSkillDir(source,
|
|
283069
|
+
if (!existsSync71(join95(skillsDir, name2))) {
|
|
283070
|
+
installSkillDir(source, join95(skillsDir, name2));
|
|
282888
283071
|
}
|
|
282889
283072
|
}
|
|
282890
283073
|
writeFileSync14(
|
|
282891
|
-
|
|
283074
|
+
join95(pluginDir, "plugin.json"),
|
|
282892
283075
|
JSON.stringify(
|
|
282893
283076
|
{
|
|
282894
283077
|
name: "fusion-session-skills",
|
|
@@ -282954,7 +283137,7 @@ var init_skill_loader = __esm({
|
|
|
282954
283137
|
import { createServer as createServer2 } from "node:http";
|
|
282955
283138
|
import { existsSync as existsSync72, writeFileSync as writeFileSync15 } from "node:fs";
|
|
282956
283139
|
import { tmpdir as tmpdir16 } from "node:os";
|
|
282957
|
-
import { dirname as dirname41, join as
|
|
283140
|
+
import { dirname as dirname41, join as join96 } from "node:path";
|
|
282958
283141
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
282959
283142
|
import { randomUUID as randomUUID52 } from "node:crypto";
|
|
282960
283143
|
function toolsToMcpToolDefs2(tools) {
|
|
@@ -282966,7 +283149,7 @@ function toolsToMcpToolDefs2(tools) {
|
|
|
282966
283149
|
}));
|
|
282967
283150
|
}
|
|
282968
283151
|
function fusionToolsMcpServerPath() {
|
|
282969
|
-
return
|
|
283152
|
+
return join96(dirname41(fileURLToPath9(import.meta.url)), "mcp-schema-server.cjs");
|
|
282970
283153
|
}
|
|
282971
283154
|
function missingMcpSchemaServerError(serverPath) {
|
|
282972
283155
|
const error3 = new Error(`Fusion MCP schema server is missing: ${serverPath}`);
|
|
@@ -283007,7 +283190,7 @@ async function startFusionToolBridge(tools) {
|
|
|
283007
283190
|
byName.set(tool.name, tool);
|
|
283008
283191
|
}
|
|
283009
283192
|
}
|
|
283010
|
-
const schemaPath =
|
|
283193
|
+
const schemaPath = join96(tmpdir16(), `fusion-grok-mcp-schemas-${process.pid}-${randomUUID52()}.json`);
|
|
283011
283194
|
writeFileSync15(schemaPath, JSON.stringify(defs));
|
|
283012
283195
|
const server = createServer2(async (req, res) => {
|
|
283013
283196
|
if (req.method !== "POST" || req.url !== "/tool-call") {
|
|
@@ -283440,7 +283623,7 @@ var init_src11 = __esm({
|
|
|
283440
283623
|
|
|
283441
283624
|
// ../../plugins/fusion-plugin-claude-runtime/src/acp/cli-spawn.ts
|
|
283442
283625
|
import { existsSync as existsSync73 } from "node:fs";
|
|
283443
|
-
import { dirname as dirname42, isAbsolute as isAbsolute23, join as
|
|
283626
|
+
import { dirname as dirname42, isAbsolute as isAbsolute23, join as join97, resolve as resolve44 } from "node:path";
|
|
283444
283627
|
import { fileURLToPath as fileURLToPath10 } from "node:url";
|
|
283445
283628
|
function asTrimmedString2(value) {
|
|
283446
283629
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
@@ -283458,7 +283641,7 @@ function pluginRootDir2() {
|
|
|
283458
283641
|
}
|
|
283459
283642
|
function bundledClaudeBridgeBinPath2(pluginRoot = pluginRootDir2()) {
|
|
283460
283643
|
const extension = process.platform === "win32" ? ".cmd" : "";
|
|
283461
|
-
return
|
|
283644
|
+
return join97(pluginRoot, "node_modules", ".bin", `${CLAUDE_CODE_CLI_ACP_BINARY2}${extension}`);
|
|
283462
283645
|
}
|
|
283463
283646
|
function resolveBundledClaudeBridgeBinary2(options = {}) {
|
|
283464
283647
|
const root = options.pluginRoot ?? pluginRootDir2();
|
|
@@ -284698,14 +284881,14 @@ var init_acp2 = __esm({
|
|
|
284698
284881
|
// ../../plugins/fusion-plugin-claude-runtime/src/cli-spawn.ts
|
|
284699
284882
|
import { spawn as spawn19 } from "node:child_process";
|
|
284700
284883
|
import { existsSync as existsSync74 } from "node:fs";
|
|
284701
|
-
import { basename as basename25, dirname as dirname44, isAbsolute as isAbsolute24, join as
|
|
284884
|
+
import { basename as basename25, dirname as dirname44, isAbsolute as isAbsolute24, join as join99, resolve as resolve46 } from "node:path";
|
|
284702
284885
|
import { fileURLToPath as fileURLToPath11 } from "node:url";
|
|
284703
284886
|
function pluginRootDir3() {
|
|
284704
284887
|
const moduleDir = dirname44(fileURLToPath11(import.meta.url));
|
|
284705
284888
|
return ["src", "dist"].includes(basename25(moduleDir)) ? resolve46(moduleDir, "..") : moduleDir;
|
|
284706
284889
|
}
|
|
284707
284890
|
function bundledClaudeBridgeBinPath3(pluginRoot = pluginRootDir3()) {
|
|
284708
|
-
return
|
|
284891
|
+
return join99(pluginRoot, "bridge", `${CLAUDE_CODE_CLI_ACP_BINARY3}${process.platform === "win32" ? ".cmd" : ""}`);
|
|
284709
284892
|
}
|
|
284710
284893
|
function resolveBundledClaudeBridgeBinary3(options = {}) {
|
|
284711
284894
|
const candidate = bundledClaudeBridgeBinPath3(options.pluginRoot ?? pluginRootDir3());
|
|
@@ -284882,10 +285065,10 @@ import {
|
|
|
284882
285065
|
} from "node:fs";
|
|
284883
285066
|
import { createRequire as createRequire9 } from "node:module";
|
|
284884
285067
|
import { tmpdir as tmpdir17 } from "node:os";
|
|
284885
|
-
import { basename as basename26, dirname as dirname45, join as
|
|
285068
|
+
import { basename as basename26, dirname as dirname45, join as join100, resolve as resolve47 } from "node:path";
|
|
284886
285069
|
import { fileURLToPath as fileURLToPath12 } from "node:url";
|
|
284887
285070
|
function isSkillDir2(dir) {
|
|
284888
|
-
return existsSync75(
|
|
285071
|
+
return existsSync75(join100(dir, "SKILL.md"));
|
|
284889
285072
|
}
|
|
284890
285073
|
function pushUnique2(out, candidate) {
|
|
284891
285074
|
if (!candidate) return;
|
|
@@ -284893,8 +285076,8 @@ function pushUnique2(out, candidate) {
|
|
|
284893
285076
|
if (!out.includes(resolved)) out.push(resolved);
|
|
284894
285077
|
}
|
|
284895
285078
|
function pushSkillLayoutsAtRoot2(out, root) {
|
|
284896
|
-
pushUnique2(out,
|
|
284897
|
-
pushUnique2(out,
|
|
285079
|
+
pushUnique2(out, join100(root, "skill", FUSION_SKILL_NAME3));
|
|
285080
|
+
pushUnique2(out, join100(root, "packages", "cli", "skill", FUSION_SKILL_NAME3));
|
|
284898
285081
|
}
|
|
284899
285082
|
function walkAncestorSkillCandidates2(out, startDir, maxParents = 8) {
|
|
284900
285083
|
let dir = startDir;
|
|
@@ -284909,7 +285092,7 @@ function pushPackageRequireCandidates2(out, from) {
|
|
|
284909
285092
|
try {
|
|
284910
285093
|
const require5 = createRequire9(from);
|
|
284911
285094
|
const pkgJson = require5.resolve("@runfusion/fusion/package.json");
|
|
284912
|
-
pushUnique2(out,
|
|
285095
|
+
pushUnique2(out, join100(dirname45(pkgJson), "skill", FUSION_SKILL_NAME3));
|
|
284913
285096
|
} catch {
|
|
284914
285097
|
}
|
|
284915
285098
|
}
|
|
@@ -284977,21 +285160,21 @@ function collectSkillsFromRoot2(root, out) {
|
|
|
284977
285160
|
return;
|
|
284978
285161
|
}
|
|
284979
285162
|
for (const entry of entries) {
|
|
284980
|
-
const child =
|
|
285163
|
+
const child = join100(root, entry);
|
|
284981
285164
|
if (isSkillDir2(child)) {
|
|
284982
285165
|
out.set(entry, child);
|
|
284983
285166
|
}
|
|
284984
285167
|
}
|
|
284985
285168
|
}
|
|
284986
285169
|
function stageClaudeSessionSkills(options = {}) {
|
|
284987
|
-
const pluginDir = mkdtempSync4(
|
|
284988
|
-
const skillsDir =
|
|
285170
|
+
const pluginDir = mkdtempSync4(join100(tmpdir17(), "fusion-claude-plugin-"));
|
|
285171
|
+
const skillsDir = join100(pluginDir, "skills");
|
|
284989
285172
|
mkdirSync15(skillsDir, { recursive: true });
|
|
284990
285173
|
const installed = /* @__PURE__ */ new Map();
|
|
284991
285174
|
const includeFusion = options.includeFusionSkill !== false;
|
|
284992
285175
|
if (includeFusion) {
|
|
284993
285176
|
const fusionSource = resolveBundledFusionSkillSource3();
|
|
284994
|
-
if (fusionSource && installSkillDir2(fusionSource,
|
|
285177
|
+
if (fusionSource && installSkillDir2(fusionSource, join100(skillsDir, FUSION_SKILL_NAME3))) {
|
|
284995
285178
|
installed.set(FUSION_SKILL_NAME3, fusionSource);
|
|
284996
285179
|
}
|
|
284997
285180
|
}
|
|
@@ -285001,15 +285184,15 @@ function stageClaudeSessionSkills(options = {}) {
|
|
|
285001
285184
|
}
|
|
285002
285185
|
for (const [name2, source] of installed) {
|
|
285003
285186
|
if (name2 === FUSION_SKILL_NAME3 && includeFusion) continue;
|
|
285004
|
-
installSkillDir2(source,
|
|
285187
|
+
installSkillDir2(source, join100(skillsDir, name2));
|
|
285005
285188
|
}
|
|
285006
285189
|
for (const [name2, source] of installed) {
|
|
285007
|
-
if (!existsSync75(
|
|
285008
|
-
installSkillDir2(source,
|
|
285190
|
+
if (!existsSync75(join100(skillsDir, name2))) {
|
|
285191
|
+
installSkillDir2(source, join100(skillsDir, name2));
|
|
285009
285192
|
}
|
|
285010
285193
|
}
|
|
285011
285194
|
writeFileSync16(
|
|
285012
|
-
|
|
285195
|
+
join100(pluginDir, "plugin.json"),
|
|
285013
285196
|
JSON.stringify(
|
|
285014
285197
|
{
|
|
285015
285198
|
name: "fusion-session-skills",
|
|
@@ -285075,7 +285258,7 @@ var init_skill_loader2 = __esm({
|
|
|
285075
285258
|
import { createServer as createServer3 } from "node:http";
|
|
285076
285259
|
import { existsSync as existsSync76, rmSync as rmSync13, writeFileSync as writeFileSync17 } from "node:fs";
|
|
285077
285260
|
import { tmpdir as tmpdir18 } from "node:os";
|
|
285078
|
-
import { dirname as dirname46, join as
|
|
285261
|
+
import { dirname as dirname46, join as join101 } from "node:path";
|
|
285079
285262
|
import { fileURLToPath as fileURLToPath13 } from "node:url";
|
|
285080
285263
|
import { randomBytes as randomBytes7, randomUUID as randomUUID53 } from "node:crypto";
|
|
285081
285264
|
function toolsToMcpToolDefs3(tools) {
|
|
@@ -285087,7 +285270,7 @@ function toolsToMcpToolDefs3(tools) {
|
|
|
285087
285270
|
}));
|
|
285088
285271
|
}
|
|
285089
285272
|
function fusionToolsMcpServerPath2() {
|
|
285090
|
-
return
|
|
285273
|
+
return join101(dirname46(fileURLToPath13(import.meta.url)), "mcp-schema-server.cjs");
|
|
285091
285274
|
}
|
|
285092
285275
|
function missingMcpSchemaServerError2(serverPath) {
|
|
285093
285276
|
const error3 = new Error(`Fusion MCP schema server is missing: ${serverPath}`);
|
|
@@ -285128,7 +285311,7 @@ async function startFusionToolBridge2(tools, options = {}) {
|
|
|
285128
285311
|
byName.set(tool.name, tool);
|
|
285129
285312
|
}
|
|
285130
285313
|
}
|
|
285131
|
-
const schemaPath =
|
|
285314
|
+
const schemaPath = join101(tmpdir18(), `fusion-claude-mcp-schemas-${process.pid}-${randomUUID53()}.json`);
|
|
285132
285315
|
writeFileSync17(schemaPath, JSON.stringify(defs));
|
|
285133
285316
|
const capabilityToken = randomBytes7(32).toString("base64url");
|
|
285134
285317
|
const server = createServer3(async (req, res) => {
|
|
@@ -285932,7 +286115,7 @@ var init_provider6 = __esm({
|
|
|
285932
286115
|
|
|
285933
286116
|
// ../../plugins/fusion-plugin-omp-runtime/src/acp/cli-spawn.ts
|
|
285934
286117
|
import { existsSync as existsSync77 } from "node:fs";
|
|
285935
|
-
import { dirname as dirname47, isAbsolute as isAbsolute25, join as
|
|
286118
|
+
import { dirname as dirname47, isAbsolute as isAbsolute25, join as join102, resolve as resolve48 } from "node:path";
|
|
285936
286119
|
import { fileURLToPath as fileURLToPath14 } from "node:url";
|
|
285937
286120
|
function asTrimmedString3(value) {
|
|
285938
286121
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
@@ -285950,7 +286133,7 @@ function pluginRootDir4() {
|
|
|
285950
286133
|
}
|
|
285951
286134
|
function bundledClaudeBridgeBinPath4(pluginRoot = pluginRootDir4()) {
|
|
285952
286135
|
const extension = process.platform === "win32" ? ".cmd" : "";
|
|
285953
|
-
return
|
|
286136
|
+
return join102(pluginRoot, "node_modules", ".bin", `${CLAUDE_CODE_CLI_ACP_BINARY4}${extension}`);
|
|
285954
286137
|
}
|
|
285955
286138
|
function resolveBundledClaudeBridgeBinary4(options = {}) {
|
|
285956
286139
|
const root = options.pluginRoot ?? pluginRootDir4();
|
|
@@ -287268,7 +287451,7 @@ var init_mcp_forwarding3 = __esm({
|
|
|
287268
287451
|
import { createServer as createServer4 } from "node:http";
|
|
287269
287452
|
import { existsSync as existsSync78, unlinkSync as unlinkSync5, writeFileSync as writeFileSync18 } from "node:fs";
|
|
287270
287453
|
import { tmpdir as tmpdir19 } from "node:os";
|
|
287271
|
-
import { dirname as dirname49, join as
|
|
287454
|
+
import { dirname as dirname49, join as join104 } from "node:path";
|
|
287272
287455
|
import { fileURLToPath as fileURLToPath15 } from "node:url";
|
|
287273
287456
|
import { randomUUID as randomUUID54 } from "node:crypto";
|
|
287274
287457
|
function toolsToMcpToolDefs4(tools) {
|
|
@@ -287285,12 +287468,12 @@ function fusionToolsMcpServerPath3() {
|
|
|
287285
287468
|
const here = dirname49(fileURLToPath15(import.meta.url));
|
|
287286
287469
|
const candidates = [
|
|
287287
287470
|
// Packaged CLI / same-dir as bundled.js or tool-bridge source.
|
|
287288
|
-
|
|
287471
|
+
join104(here, "mcp-schema-server.cjs"),
|
|
287289
287472
|
// Source layout when running from dist/ that still has ../src assets.
|
|
287290
|
-
|
|
287291
|
-
|
|
287473
|
+
join104(here, "src", "mcp-schema-server.cjs"),
|
|
287474
|
+
join104(here, "..", "src", "mcp-schema-server.cjs"),
|
|
287292
287475
|
// Monorepo plugin root relative to src/ or dist/plugins/.../bundled.js.
|
|
287293
|
-
|
|
287476
|
+
join104(here, "..", "mcp-schema-server.cjs")
|
|
287294
287477
|
];
|
|
287295
287478
|
for (const candidate of candidates) {
|
|
287296
287479
|
if (existsSync78(candidate)) return candidate;
|
|
@@ -287327,7 +287510,7 @@ async function startFusionToolBridge3(tools) {
|
|
|
287327
287510
|
byName.set(tool.name, tool);
|
|
287328
287511
|
}
|
|
287329
287512
|
}
|
|
287330
|
-
const schemaPath =
|
|
287513
|
+
const schemaPath = join104(tmpdir19(), `fusion-omp-mcp-schemas-${process.pid}-${randomUUID54()}.json`);
|
|
287331
287514
|
writeFileSync18(schemaPath, JSON.stringify(defs));
|
|
287332
287515
|
const server = createServer4(async (req, res) => {
|
|
287333
287516
|
if (req.method !== "POST" || req.url !== "/tool-call") {
|
|
@@ -289049,8 +289232,8 @@ var init_types5 = __esm({
|
|
|
289049
289232
|
|
|
289050
289233
|
// ../dashboard/src/stt/model-manager.ts
|
|
289051
289234
|
import { createHash as createHash25, randomUUID as randomUUID56 } from "node:crypto";
|
|
289052
|
-
import { mkdir as mkdir31, open as open4, readFile as
|
|
289053
|
-
import { join as
|
|
289235
|
+
import { mkdir as mkdir31, open as open4, readFile as readFile45, readdir as readdir11, rename as rename10, rm as rm18, stat as stat12, writeFile as writeFile34 } from "node:fs/promises";
|
|
289236
|
+
import { join as join105, relative as relative19, resolve as resolve50, sep as sep15 } from "node:path";
|
|
289054
289237
|
function parseSafeTarListing(listing) {
|
|
289055
289238
|
for (const line2 of listing.split("\n").filter(Boolean)) {
|
|
289056
289239
|
const type = line2[0];
|
|
@@ -289065,8 +289248,8 @@ function parseSafeTarListing(listing) {
|
|
|
289065
289248
|
function createVoiceModelManager(options = {}) {
|
|
289066
289249
|
const asset = options.asset ?? PARAKEET_V3_ASSET;
|
|
289067
289250
|
let configuredCacheDir = options.cacheDir;
|
|
289068
|
-
const cacheDir = () => configuredCacheDir ??=
|
|
289069
|
-
const finalDir = () =>
|
|
289251
|
+
const cacheDir = () => configuredCacheDir ??= join105(resolveGlobalDir(), "models", "parakeet-v3");
|
|
289252
|
+
const finalDir = () => join105(cacheDir(), "model");
|
|
289070
289253
|
let state = { status: "not-installed" };
|
|
289071
289254
|
let generation = 0;
|
|
289072
289255
|
let cleanupBarrier = Promise.resolve();
|
|
@@ -289129,8 +289312,8 @@ function createVoiceModelManager(options = {}) {
|
|
|
289129
289312
|
if (!current(g2, signal)) return state;
|
|
289130
289313
|
await mkdir31(cacheDir(), { recursive: true });
|
|
289131
289314
|
if (!current(g2, signal)) return state;
|
|
289132
|
-
partial2 =
|
|
289133
|
-
staging =
|
|
289315
|
+
partial2 = join105(cacheDir(), `.partial-${g2}-${randomUUID56()}`);
|
|
289316
|
+
staging = join105(cacheDir(), `.staging-${g2}-${randomUUID56()}`);
|
|
289134
289317
|
const file = await open4(partial2, "wx");
|
|
289135
289318
|
try {
|
|
289136
289319
|
const response = await (options.fetch ?? globalThis.fetch)(asset.url, { signal });
|
|
@@ -289175,10 +289358,10 @@ function createVoiceModelManager(options = {}) {
|
|
|
289175
289358
|
}
|
|
289176
289359
|
}
|
|
289177
289360
|
if (!current(g2, signal)) return state;
|
|
289178
|
-
await writeFile34(
|
|
289361
|
+
await writeFile34(join105(staging, "manifest.json"), JSON.stringify({ filename: asset.filename, sha256: asset.sha256, installedAt: (/* @__PURE__ */ new Date()).toISOString(), expectedFiles: asset.expectedFiles }));
|
|
289179
289362
|
await options.beforePromote?.(signal);
|
|
289180
289363
|
if (!current(g2, signal)) return state;
|
|
289181
|
-
const backup =
|
|
289364
|
+
const backup = join105(cacheDir(), `.backup-${g2}-${randomUUID56()}`);
|
|
289182
289365
|
let movedPrevious = false;
|
|
289183
289366
|
try {
|
|
289184
289367
|
try {
|
|
@@ -289258,9 +289441,9 @@ function createVoiceModelManager(options = {}) {
|
|
|
289258
289441
|
publish(absent);
|
|
289259
289442
|
return absent;
|
|
289260
289443
|
}
|
|
289261
|
-
const manifest = JSON.parse(await
|
|
289444
|
+
const manifest = JSON.parse(await readFile45(join105(finalDir(), "manifest.json"), "utf8"));
|
|
289262
289445
|
if (manifest.sha256 !== asset.sha256) throw new Error("stale manifest digest");
|
|
289263
|
-
for (const expected of asset.expectedFiles) if (!await existsFile(
|
|
289446
|
+
for (const expected of asset.expectedFiles) if (!await existsFile(join105(finalDir(), expected))) throw new Error("missing expected model file");
|
|
289264
289447
|
const installed = { status: "installed", checksumVerified: true, installedPath: finalDir() };
|
|
289265
289448
|
publish(installed);
|
|
289266
289449
|
return installed;
|
|
@@ -289272,7 +289455,7 @@ function createVoiceModelManager(options = {}) {
|
|
|
289272
289455
|
try {
|
|
289273
289456
|
for (const entry of await readdir11(cacheDir())) {
|
|
289274
289457
|
const own = /^\.(partial|staging|backup)-(\d+)-/.exec(entry);
|
|
289275
|
-
if (own && Number(own[2]) !== active?.generation) await rm18(
|
|
289458
|
+
if (own && Number(own[2]) !== active?.generation) await rm18(join105(cacheDir(), entry), { recursive: true, force: true });
|
|
289276
289459
|
}
|
|
289277
289460
|
} catch {
|
|
289278
289461
|
}
|
|
@@ -289294,7 +289477,7 @@ function createVoiceModelManager(options = {}) {
|
|
|
289294
289477
|
try {
|
|
289295
289478
|
for (const entry of await readdir11(cacheDir())) {
|
|
289296
289479
|
const match = /^\.(partial|staging|backup)-(\d+)-/.exec(entry);
|
|
289297
|
-
if (match && Number(match[2]) <= g2) await rm18(
|
|
289480
|
+
if (match && Number(match[2]) <= g2) await rm18(join105(cacheDir(), entry), { recursive: true, force: true });
|
|
289298
289481
|
}
|
|
289299
289482
|
} catch {
|
|
289300
289483
|
}
|
|
@@ -290080,7 +290263,7 @@ var init_provider_health_monitor = __esm({
|
|
|
290080
290263
|
|
|
290081
290264
|
// ../dashboard/src/server.ts
|
|
290082
290265
|
import express3 from "express";
|
|
290083
|
-
import { join as
|
|
290266
|
+
import { join as join106, dirname as dirname50 } from "node:path";
|
|
290084
290267
|
import { fileURLToPath as fileURLToPath16 } from "node:url";
|
|
290085
290268
|
import { WebSocketServer as WebSocketServer2 } from "ws";
|
|
290086
290269
|
function clearAiSessionCleanupInterval() {
|
|
@@ -290784,7 +290967,7 @@ __export(task_exports, {
|
|
|
290784
290967
|
});
|
|
290785
290968
|
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
290786
290969
|
import { watchFile, unwatchFile, statSync as statSync14, existsSync as existsSync80, readFileSync as readFileSync27 } from "node:fs";
|
|
290787
|
-
import { basename as basename29, join as
|
|
290970
|
+
import { basename as basename29, join as join107 } from "node:path";
|
|
290788
290971
|
function columnLabel(column) {
|
|
290789
290972
|
return COLUMN_LABELS[column] ?? column;
|
|
290790
290973
|
}
|
|
@@ -291142,7 +291325,7 @@ async function runTaskCreate(descriptionArg, attachFiles, depends, projectName,
|
|
|
291142
291325
|
}
|
|
291143
291326
|
console.log(` Path: .fusion/tasks/${resolvedTask.id}/`);
|
|
291144
291327
|
if (attachFiles && attachFiles.length > 0) {
|
|
291145
|
-
const { readFile:
|
|
291328
|
+
const { readFile: readFile47 } = await import("node:fs/promises");
|
|
291146
291329
|
const { basename: basename31, extname: extname5, resolve: resolve53 } = await import("node:path");
|
|
291147
291330
|
for (const filePath of attachFiles) {
|
|
291148
291331
|
const resolvedPath = resolve53(filePath);
|
|
@@ -291155,7 +291338,7 @@ async function runTaskCreate(descriptionArg, attachFiles, depends, projectName,
|
|
|
291155
291338
|
}
|
|
291156
291339
|
let content;
|
|
291157
291340
|
try {
|
|
291158
|
-
content = await
|
|
291341
|
+
content = await readFile47(resolvedPath);
|
|
291159
291342
|
} catch {
|
|
291160
291343
|
console.error(` \u2717 Cannot read file: ${filePath}`);
|
|
291161
291344
|
continue;
|
|
@@ -291326,7 +291509,7 @@ async function runTaskLogs(id, options = {}, projectName) {
|
|
|
291326
291509
|
printEntries(filteredEntries);
|
|
291327
291510
|
if (options.follow) {
|
|
291328
291511
|
const projectPath = context.projectPath ?? process.cwd();
|
|
291329
|
-
const logPath =
|
|
291512
|
+
const logPath = join107(projectPath, ".fusion", "tasks", id, "agent.log");
|
|
291330
291513
|
if (!existsSync80(logPath)) {
|
|
291331
291514
|
console.log(`
|
|
291332
291515
|
Waiting for log file to be created...`);
|
|
@@ -291531,7 +291714,7 @@ async function runTaskMerge(id, projectName) {
|
|
|
291531
291714
|
}
|
|
291532
291715
|
}
|
|
291533
291716
|
async function runTaskAttach(id, filePath, projectName) {
|
|
291534
|
-
const { readFile:
|
|
291717
|
+
const { readFile: readFile47 } = await import("node:fs/promises");
|
|
291535
291718
|
const { basename: basename31, extname: extname5 } = await import("node:path");
|
|
291536
291719
|
const { resolve: resolve53 } = await import("node:path");
|
|
291537
291720
|
const resolvedPath = resolve53(filePath);
|
|
@@ -291545,7 +291728,7 @@ async function runTaskAttach(id, filePath, projectName) {
|
|
|
291545
291728
|
}
|
|
291546
291729
|
let content;
|
|
291547
291730
|
try {
|
|
291548
|
-
content = await
|
|
291731
|
+
content = await readFile47(resolvedPath);
|
|
291549
291732
|
} catch {
|
|
291550
291733
|
console.error(`Cannot read file: ${filePath}`);
|
|
291551
291734
|
process.exit(1);
|
|
@@ -292710,8 +292893,8 @@ init_src15();
|
|
|
292710
292893
|
import { randomUUID as randomUUID58 } from "node:crypto";
|
|
292711
292894
|
import { Type as Type9 } from "typebox";
|
|
292712
292895
|
import { StringEnum } from "@earendil-works/pi-ai";
|
|
292713
|
-
import { resolve as resolve52, relative as relative20, isAbsolute as isAbsolute26, sep as sep16, basename as basename30, extname as extname4, join as
|
|
292714
|
-
import { readFile as
|
|
292896
|
+
import { resolve as resolve52, relative as relative20, isAbsolute as isAbsolute26, sep as sep16, basename as basename30, extname as extname4, join as join108 } from "node:path";
|
|
292897
|
+
import { readFile as readFile46 } from "node:fs/promises";
|
|
292715
292898
|
import { existsSync as existsSync81 } from "node:fs";
|
|
292716
292899
|
import { spawn as spawn23 } from "node:child_process";
|
|
292717
292900
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -292792,12 +292975,12 @@ function resolveProjectRoot2(cwd) {
|
|
|
292792
292975
|
warnedMissingProjectRootResolver = true;
|
|
292793
292976
|
console.warn("[fusion-extension] @fusion/core.getProjectRootFromWorktree is unavailable; using filesystem fallback resolution.");
|
|
292794
292977
|
}
|
|
292795
|
-
if (worktreeProjectRoot && existsSync81(
|
|
292978
|
+
if (worktreeProjectRoot && existsSync81(join108(worktreeProjectRoot, ".fusion"))) {
|
|
292796
292979
|
return worktreeProjectRoot;
|
|
292797
292980
|
}
|
|
292798
292981
|
let current = resolve52(cwd);
|
|
292799
292982
|
while (true) {
|
|
292800
|
-
if (existsSync81(
|
|
292983
|
+
if (existsSync81(join108(current, ".fusion"))) {
|
|
292801
292984
|
return current;
|
|
292802
292985
|
}
|
|
292803
292986
|
const parent = resolve52(current, "..");
|
|
@@ -293059,7 +293242,7 @@ async function closeCachedStores() {
|
|
|
293059
293242
|
}
|
|
293060
293243
|
}
|
|
293061
293244
|
function getFusionDir(cwd) {
|
|
293062
|
-
return
|
|
293245
|
+
return join108(resolveProjectRoot2(cwd), ".fusion");
|
|
293063
293246
|
}
|
|
293064
293247
|
function requireProjectLayer(store, consumer) {
|
|
293065
293248
|
const layer = store.getAsyncLayer();
|
|
@@ -293841,7 +294024,7 @@ ${renderAgentLogEntries(entries)}` : `${header}
|
|
|
293841
294024
|
}
|
|
293842
294025
|
let content;
|
|
293843
294026
|
try {
|
|
293844
|
-
content = await
|
|
294027
|
+
content = await readFile46(filePath);
|
|
293845
294028
|
} catch {
|
|
293846
294029
|
throw new Error(`Cannot read file: ${params.path}`);
|
|
293847
294030
|
}
|