@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.
Files changed (112) hide show
  1. package/dist/bin.js +847 -655
  2. package/dist/child-process-worker.js +414 -231
  3. package/dist/client/.vite/manifest.json +268 -268
  4. package/dist/client/assets/{AgentDetailView-DH4Cn5iG.js → AgentDetailView-D0J_GDct.js} +1 -1
  5. package/dist/client/assets/{AgentPermissionPolicyEditor-BycC7HhP.js → AgentPermissionPolicyEditor-BBAwprvO.js} +1 -1
  6. package/dist/client/assets/{AgentsView-Dkij8Sm8.js → AgentsView-DTY5DIav.js} +3 -3
  7. package/dist/client/assets/{ChatView-DAsZY1We.js → ChatView-CRoW2tRJ.js} +1 -1
  8. package/dist/client/assets/{CommandCenter-jTzBo-pg.js → CommandCenter-BieyKvKb.js} +1 -1
  9. package/dist/client/assets/{DevServerView-CxlacYJp.js → DevServerView-CLR1LmhK.js} +1 -1
  10. package/dist/client/assets/{DirectoryPicker-DsCk3Nsw.js → DirectoryPicker-B-olNAvT.js} +1 -1
  11. package/dist/client/assets/{DocumentsView-8EI6KNBY.js → DocumentsView-CG_-pnXU.js} +1 -1
  12. package/dist/client/assets/{EvalsView-kYnaIk11.js → EvalsView-Xp0zCUlr.js} +1 -1
  13. package/dist/client/assets/{ExperimentalAgentOnboardingModal-ce6DROKD.js → ExperimentalAgentOnboardingModal-z8m5V5yv.js} +1 -1
  14. package/dist/client/assets/{GoalsView-BVlTtw-u.js → GoalsView-Bd-4g949.js} +1 -1
  15. package/dist/client/assets/{InsightsView-BKQeROkb.js → InsightsView-tCgg66wJ.js} +1 -1
  16. package/dist/client/assets/{MemoryView-DCzTnxsV.js → MemoryView-Dqgsd_0E.js} +1 -1
  17. package/dist/client/assets/{PiExtensionsManager-C94HwDz5.js → PiExtensionsManager-GzGoWgb5.js} +1 -1
  18. package/dist/client/assets/{PluginManager-C3DegklW.js → PluginManager-BWdqEqr9.js} +1 -1
  19. package/dist/client/assets/{PullRequestView-CrE89UL7.js → PullRequestView-CQq1G1kY.js} +1 -1
  20. package/dist/client/assets/{ReportModal-BD1ZUDdV.js → ReportModal-C-3rBFhw.js} +1 -1
  21. package/dist/client/assets/{ResearchView-eMiRw1EM.js → ResearchView-CS1HwDg_.js} +1 -1
  22. package/dist/client/assets/{SecretsView-6qK8Idb7.js → SecretsView-C6RP9Rkw.js} +1 -1
  23. package/dist/client/assets/{SessionTerminal-DtFLyUaK.js → SessionTerminal-C9nCSefk.js} +1 -1
  24. package/dist/client/assets/SettingsModal-C1oEklYy.css +1 -0
  25. package/dist/client/assets/{SettingsModal-BkOSlfyr.js → SettingsModal-D3DCvCfP.js} +1 -1
  26. package/dist/client/assets/{SettingsModal-DSq-_qwo.js → SettingsModal-D4mjT8hw.js} +3 -3
  27. package/dist/client/assets/{SettingsTextareaRow-Btyx5kaR.js → SettingsTextareaRow-zBVXQbcC.js} +1 -1
  28. package/dist/client/assets/{SetupWizardModal-Blhx-dRt.js → SetupWizardModal-C9r1dd-h.js} +2 -2
  29. package/dist/client/assets/{SkillsView-DGE5kYc3.js → SkillsView-DFyUBWd8.js} +1 -1
  30. package/dist/client/assets/{TodoView-YSGI7ATd.js → TodoView-BC8f952m.js} +1 -1
  31. package/dist/client/assets/{WorkflowNodeEditor-CZiEThu2.js → WorkflowNodeEditor-UTX757WH.js} +1 -1
  32. package/dist/client/assets/{agent-import-generation-DQeNZMAm.js → agent-import-generation-DN0q1xEo.js} +1 -1
  33. package/dist/client/assets/{app-DJIiVHdA.js → app-BP57l_5h.js} +1 -1
  34. package/dist/client/assets/{app-hQw_x2KJ.js → app-D4frL0Ka.js} +1 -1
  35. package/dist/client/assets/{app-DaikOPcV.js → app-niWDkeV8.js} +3 -3
  36. package/dist/client/assets/{app-Dn1u7zJ9.js → app-sLOwmHAE.js} +1 -1
  37. package/dist/client/assets/{app-DMZ_RusZ.js → app-vRWwM-aD.js} +1 -1
  38. package/dist/client/assets/{app-DxTbBEMH.js → app-zPyey_fg.js} +1 -1
  39. package/dist/client/assets/{architectureDiagram-3BPJPVTR-DhaJNKa4.js → architectureDiagram-3BPJPVTR-D-nqJ95-.js} +1 -1
  40. package/dist/client/assets/{blockDiagram-GPEHLZMM-pKpg7gJU.js → blockDiagram-GPEHLZMM--OlkXlyS.js} +1 -1
  41. package/dist/client/assets/{c4Diagram-AAUBKEIU-DVPXKJnr.js → c4Diagram-AAUBKEIU-CH7PaWgs.js} +1 -1
  42. package/dist/client/assets/channel-FJNMzlkv.js +1 -0
  43. package/dist/client/assets/{chunk-2J33WTMH-CHt90T5z.js → chunk-2J33WTMH-CpHDwqg2.js} +1 -1
  44. package/dist/client/assets/{chunk-4BX2VUAB-DsWFYy0a.js → chunk-4BX2VUAB-BdW4tdnc.js} +1 -1
  45. package/dist/client/assets/{chunk-55IACEB6-D8XiXEo8.js → chunk-55IACEB6-b3tBFiuH.js} +1 -1
  46. package/dist/client/assets/{chunk-727SXJPM-DlUYBn_Y.js → chunk-727SXJPM-DifknEtv.js} +1 -1
  47. package/dist/client/assets/{chunk-AQP2D5EJ-BSdPOr9q.js → chunk-AQP2D5EJ-DHIZNZ4Z.js} +1 -1
  48. package/dist/client/assets/{chunk-FMBD7UC4-B9IAeBld.js → chunk-FMBD7UC4-BLRLYW2y.js} +1 -1
  49. package/dist/client/assets/{chunk-ND2GUHAM-CmxnYQrR.js → chunk-ND2GUHAM-Dh8f06Ld.js} +1 -1
  50. package/dist/client/assets/{chunk-QZHKN3VN-Dxp6Po_j.js → chunk-QZHKN3VN-CpzUiemt.js} +1 -1
  51. package/dist/client/assets/classDiagram-4FO5ZUOK-BOenhjVP.js +1 -0
  52. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BOenhjVP.js +1 -0
  53. package/dist/client/assets/common-13IRj_PO.js +1 -0
  54. package/dist/client/assets/common-BBynATth.js +1 -0
  55. package/dist/client/assets/common-BG-vw0tL.js +1 -0
  56. package/dist/client/assets/common-DSo46rnH.js +1 -0
  57. package/dist/client/assets/common-DbOCE-0i.js +1 -0
  58. package/dist/client/assets/common-DnXF4Jmj.js +1 -0
  59. package/dist/client/assets/{cose-bilkent-S5V4N54A-BNl3bhpS.js → cose-bilkent-S5V4N54A-CE2RJ_k0.js} +1 -1
  60. package/dist/client/assets/{dagre-BM42HDAG-DFs7WCcz.js → dagre-BM42HDAG-CCs_xlYw.js} +1 -1
  61. package/dist/client/assets/{dashboard-view-vc8kgLMs.js → dashboard-view-D5qv61fP.js} +1 -1
  62. package/dist/client/assets/{dashboard-view-ZGxLEL9r.js → dashboard-view-Eg7Jyvnm.js} +1 -1
  63. package/dist/client/assets/{dashboard-view-DnoTcnIo.js → dashboard-view-Z6H-k0uR.js} +1 -1
  64. package/dist/client/assets/{diagram-2AECGRRQ-C2PVozvu.js → diagram-2AECGRRQ-CF60Q-de.js} +1 -1
  65. package/dist/client/assets/{diagram-5GNKFQAL-DFJ5b9H8.js → diagram-5GNKFQAL-DDcGMlua.js} +1 -1
  66. package/dist/client/assets/{diagram-KO2AKTUF-D335CW-c.js → diagram-KO2AKTUF-YgvJ4DQf.js} +1 -1
  67. package/dist/client/assets/{diagram-LMA3HP47-DSfhroAW.js → diagram-LMA3HP47-Bi-j9nGw.js} +1 -1
  68. package/dist/client/assets/{diagram-OG6HWLK6-8iGveM-Z.js → diagram-OG6HWLK6-DEmMqnwc.js} +1 -1
  69. package/dist/client/assets/{erDiagram-TEJ5UH35-Xc56MEEi.js → erDiagram-TEJ5UH35-DwmZwhiW.js} +1 -1
  70. package/dist/client/assets/{flowDiagram-I6XJVG4X-DjCU9WbD.js → flowDiagram-I6XJVG4X-B5ITa_HJ.js} +1 -1
  71. package/dist/client/assets/{folder-open-BRrB44UX.js → folder-open-BVxA7YtM.js} +1 -1
  72. package/dist/client/assets/{ganttDiagram-6RSMTGT7-CXQE1bea.js → ganttDiagram-6RSMTGT7-BgAPwh9w.js} +1 -1
  73. package/dist/client/assets/{gitGraphDiagram-PVQCEYII--mrSABLC.js → gitGraphDiagram-PVQCEYII-DTtGzZFj.js} +1 -1
  74. package/dist/client/assets/{index-C2xsZoNG.js → index-idkERMsE.js} +289 -289
  75. package/dist/client/assets/{infoDiagram-5YYISTIA-CTS_nljP.js → infoDiagram-5YYISTIA-CkSnTje1.js} +1 -1
  76. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CpV5x3gk.js → ishikawaDiagram-YF4QCWOH-jn5VNpMh.js} +1 -1
  77. package/dist/client/assets/{journeyDiagram-JHISSGLW-BK2QCMnt.js → journeyDiagram-JHISSGLW-BpaqoXaI.js} +1 -1
  78. package/dist/client/assets/{kanban-definition-UN3LZRKU-B4srpspY.js → kanban-definition-UN3LZRKU-CpfjJoBN.js} +1 -1
  79. package/dist/client/assets/{mermaid.core-B8DVAt21.js → mermaid.core-DZNGPQzF.js} +4 -4
  80. package/dist/client/assets/{mindmap-definition-RKZ34NQL-CsmmiPpA.js → mindmap-definition-RKZ34NQL-BdbX1EJa.js} +1 -1
  81. package/dist/client/assets/{pieDiagram-4H26LBE5-BahLDqf4.js → pieDiagram-4H26LBE5-Xn0322tJ.js} +1 -1
  82. package/dist/client/assets/{puzzle-BFPQsuIa.js → puzzle-CPx1RP2g.js} +1 -1
  83. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-Bo3u0wTU.js → quadrantDiagram-W4KKPZXB-OOHqqw5y.js} +1 -1
  84. package/dist/client/assets/{requirementDiagram-4Y6WPE33-DYkYsz7d.js → requirementDiagram-4Y6WPE33-Dvj6zvaB.js} +1 -1
  85. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-BCbh0BSY.js → sankeyDiagram-5OEKKPKP-DEkEqthK.js} +1 -1
  86. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-C2AP9GlE.js → sequenceDiagram-3UESZ5HK-BPc9ncPj.js} +1 -1
  87. package/dist/client/assets/{shield-alert-tlZOi02c.js → shield-alert-baoKRyU6.js} +1 -1
  88. package/dist/client/assets/{standing-instructions-template-C0Rzv9Mr.js → standing-instructions-template-CkqsGC1L.js} +1 -1
  89. package/dist/client/assets/{stateDiagram-AJRCARHV-CARkH0ug.js → stateDiagram-AJRCARHV-DywhjHIx.js} +1 -1
  90. package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-C2He043y.js → stateDiagram-v2-BHNVJYJU-D7t7x4uT.js} +1 -1
  91. package/dist/client/assets/{timeline-definition-PNZ67QCA-MvbYneEM.js → timeline-definition-PNZ67QCA-BH3CKgrg.js} +1 -1
  92. package/dist/client/assets/{upload-DWK0F17Z.js → upload-DtIvOGwM.js} +1 -1
  93. package/dist/client/assets/{users-1AkDfM14.js → users-DcxsxPlj.js} +1 -1
  94. package/dist/client/assets/{vennDiagram-CIIHVFJN-DOjzzLqc.js → vennDiagram-CIIHVFJN-CCDllBgJ.js} +1 -1
  95. package/dist/client/assets/{wardley-L42UT6IY-Di70vhu2.js → wardley-L42UT6IY-C43hFLXh.js} +1 -1
  96. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-nK6ARhDv.js → wardleyDiagram-YWT4CUSO-__f9rI8w.js} +1 -1
  97. package/dist/client/assets/{xychartDiagram-2RQKCTM6-C7_y76B7.js → xychartDiagram-2RQKCTM6-DY-fpQ_x.js} +1 -1
  98. package/dist/client/index.html +1 -1
  99. package/dist/client/version.json +1 -1
  100. package/dist/extension.js +551 -368
  101. package/package.json +1 -1
  102. package/skill/fusion/references/engine-tools.md +1 -1
  103. package/dist/client/assets/SettingsModal-BTfZlghk.css +0 -1
  104. package/dist/client/assets/channel-xFBfK0sX.js +0 -1
  105. package/dist/client/assets/classDiagram-4FO5ZUOK-BFBVD968.js +0 -1
  106. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BFBVD968.js +0 -1
  107. package/dist/client/assets/common-BDp2y6CF.js +0 -1
  108. package/dist/client/assets/common-BnEo5fLN.js +0 -1
  109. package/dist/client/assets/common-Bzr_Y8h4.js +0 -1
  110. package/dist/client/assets/common-CvwyFzfv.js +0 -1
  111. package/dist/client/assets/common-CztCXRkz.js +0 -1
  112. 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 join108(chunks, separator) {
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 = join108;
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((join108) => join108.alias === tableName)) {
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((join108) => join108.alias === tableName)) {
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 join108 of this.config.joins) {
11818
- const tableName2 = getTableLikeName(join108.table);
11819
- if (typeof tableName2 === "string" && !is(join108.table, SQL)) {
11820
- const fromFields = this.getTableLikeFields(join108.table);
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 join109 = walkBranchToJoin(edge.to, split.id, outgoing, nodesById);
20425
- if (!join109) {
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(join109);
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 join108 = nodesById.get(joinId);
20435
- const mode = join108.config?.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 '${join108.id}' quorum must be a positive integer`);
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 '${join108.id}' quorum(${n}) exceeds the split's ${branchEdges.length} branches`
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: join108 } = await import("node:path");
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 = join108(dir, entry);
24004
+ const childDir = join109(dir, entry);
24005
24005
  try {
24006
- const s3 = await stat13(join108(childDir, ".git"));
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: readFile46 } = await import("node:fs/promises");
24020
- const { join: join108 } = await import("node:path");
24021
- const raw = await readFile46(join108(projectPath, ".fusion", "config.json"), "utf-8");
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: readFile46, writeFile: writeFile35, mkdir: mkdir32 } = await import("node:fs/promises");
24030
- const { join: join108 } = await import("node:path");
24031
- const configPath = join108(projectPath, ".fusion", "config.json");
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 readFile46(configPath, "utf-8"));
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(join108(projectPath, ".fusion"), { recursive: true });
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: readFile46 } = await import("node:fs/promises");
24056
+ const { readFile: readFile47 } = await import("node:fs/promises");
24057
24057
  const pathMod = await import("node:path");
24058
- const { join: join108 } = pathMod;
24059
- const configPath = join108(rootDir, ".fusion", WORKSPACE_CONFIG_FILENAME);
24058
+ const { join: join109 } = pathMod;
24059
+ const configPath = join109(rootDir, ".fusion", WORKSPACE_CONFIG_FILENAME);
24060
24060
  try {
24061
- const raw = await readFile46(configPath, "utf-8");
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: join108 } = await import("node:path");
24076
- const fusionDir = join108(rootDir, ".fusion");
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
- join108(fusionDir, WORKSPACE_CONFIG_FILENAME),
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 join108 = fk.childColumns.map((column, index2) => `child.${quoteIdentifier(column)} IS NOT DISTINCT FROM parent.${quoteIdentifier(fk.parentColumns[index2])}`).join(" AND ");
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 ${join108}
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: readFile46 } = await Promise.resolve().then(() => __importStar(__require("fs/promises")));
49750
- const data = await readFile46(filePath, "utf8");
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 = readFile46;
132675
- function readFile46(path10, options, cb) {
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
- if (targetIsProcessing && await isUnplannedForExecution(store, task, ir2)) {
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
- task,
135482
+ promoted,
135454
135483
  target,
135455
- ir2
135484
+ ir2,
135485
+ { allowUnplanned: unplanned }
135456
135486
  );
135457
- return released ? { released: true, toColumn: target } : { released: false, rejection: "capacity-exhausted-or-no-slot" };
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 readFile30, stat as stat8, unlink as unlink9 } from "node:fs/promises";
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 readFile30(gitdirFile, "utf-8")).trim();
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 join61, relative as relative8, resolve as resolve29, isAbsolute as isAbsolute9 } from "node:path";
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(join61(worktreePath, ".git"));
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) => join61(worktreesDir, e.name));
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) => join61(worktreesDir, e.name));
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(join61(worktreesDir, e.name)).isDirectory() && !lstatSync2(join61(worktreesDir, e.name)).isSymbolicLink();
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: join61(worktreesDir, e.name) }));
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 = join61(resolvedFull, ".git");
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 join62, relative as relative9, resolve as resolve30 } from "node:path";
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 join62(resolveWorktreesDir(rootDir, settings), AI_MERGE_DIRNAME);
165944
+ return join63(resolveWorktreesDir(rootDir, settings), AI_MERGE_DIRNAME);
165832
165945
  }
165833
165946
  function resolveLegacyAiMergeRootPath(rootDir) {
165834
- return join62(rootDir, ".fusion", "ai-merge");
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 join62(rootDir, ".worktrees");
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 join62(resolveWorktreesDir(rootDir, settings), worktreeName);
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: join108, isAbsolute: isAbsolute27, normalize: normalize8, sep: sep17 } = await import("node:path");
167073
+ const { join: join109, isAbsolute: isAbsolute27, normalize: normalize8, sep: sep17 } = await import("node:path");
166961
167074
  assertInRootRepoRelPath(repoRelPath, sep17, isAbsolute27, normalize8);
166962
- const repoAbsPath = join108(workspaceRootDir, repoRelPath);
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 join63 } from "node:path";
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(join63(tmpdir4(), "fusion-code-node-"));
168774
- const userModuleFile = join63(dir, "user.mjs");
168775
- const harnessFile = join63(dir, "harness.mjs");
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 readFile31, readdir as readdir9, realpath, stat as stat9, writeFile as writeFile25 } from "node:fs/promises";
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 join64, relative as relative11, resolve as resolve32, sep as sep9 } from "node:path";
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 join64(rootDir, AGENT_MEMORY_ROOT3, sanitizeAgentMemoryId(agentId));
169132
+ return join65(rootDir, AGENT_MEMORY_ROOT3, sanitizeAgentMemoryId(agentId));
169020
169133
  }
169021
169134
  function agentMemoryFilePath(rootDir, agentId) {
169022
- return join64(agentMemoryDirectory(rootDir, agentId), AGENT_MEMORY_FILENAME2);
169135
+ return join65(agentMemoryDirectory(rootDir, agentId), AGENT_MEMORY_FILENAME2);
169023
169136
  }
169024
169137
  function agentDreamsFilePath(rootDir, agentId) {
169025
- return join64(agentMemoryDirectory(rootDir, agentId), AGENT_DREAMS_FILENAME2);
169138
+ return join65(agentMemoryDirectory(rootDir, agentId), AGENT_DREAMS_FILENAME2);
169026
169139
  }
169027
169140
  function agentDailyFilePath(rootDir, agentId, date5 = /* @__PURE__ */ new Date()) {
169028
- return join64(agentMemoryDirectory(rootDir, agentId), `${date5.toISOString().slice(0, 10)}.md`);
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 readFile31(filePath, "utf-8");
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 = join64(dir, entry);
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 readFile31(file.absPath, "utf-8");
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: join64(agentMemoryDirectory(rootDir, agentId), filename),
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 readFile31(resolved.absPath, "utf-8");
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 readFile31(canonicalPath);
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: { taskId, released: true, toColumn: outcome.toColumn }
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 join65 } from "node:path";
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 = join65(opts.rootDir, path10);
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 readFile32 } from "node:fs/promises";
177669
- import { join as join66 } from "node:path";
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 readFile32(fsPath, "utf-8");
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 = join66(rootDir, ".fusion", "agent-memory", safeAgentId, "MEMORY.md");
177855
+ const agentFsPath = join67(rootDir, ".fusion", "agent-memory", safeAgentId, "MEMORY.md");
177718
177856
  const projectDisplayPath = ".fusion/memory/MEMORY.md";
177719
- const projectFsPath = join66(rootDir, ".fusion", "memory", "MEMORY.md");
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 readFile33, writeFile as writeFile26, mkdir as mkdir27, access as access8 } from "node:fs/promises";
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 readFile33(filePath, "utf-8");
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 readFile33(filePath, "utf-8");
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 readFile34 } from "node:fs/promises";
185954
- import { join as join67 } from "node:path";
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 = join67(this.store.getTasksDir(), id);
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 = join67(taskDir, "PROMPT.md");
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 readFile34(promptPath, "utf-8");
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 readFile34(getPromptPath(this.store.getTasksDir(), t.id), "utf-8");
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 join68 } from "node:path";
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(join68(rootDir, "node_modules")) || existsSync55(join68(rootDir, ".pnp.cjs"));
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(join68(rootDir, "pnpm-lock.yaml"))) return "pnpm install --frozen-lockfile";
190546
- if (existsSync55(join68(rootDir, "package-lock.json"))) return "npm install";
190547
- if (existsSync55(join68(rootDir, "yarn.lock"))) return "yarn install --frozen-lockfile";
190548
- if (existsSync55(join68(rootDir, "bun.lock")) || existsSync55(join68(rootDir, "bun.lockb"))) {
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 = join68(rootDir, name2);
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(join68(rootDir, INSTALL_MARKER_RELPATH), "utf-8").trim();
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(join68(rootDir, INSTALL_MARKER_RELPATH), hash);
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 = join68("node_modules", ".fusion-install-marker");
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 join69 } from "node:path";
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 = join69(rootDir, glob);
191076
- if (existsSync56(join69(candidate, "package.json"))) {
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 = join69(rootDir, prefix.replace(/\/$/, ""));
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 = join69(rootDir, relPath);
191092
- if (existsSync56(join69(absPath, "package.json"))) {
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 = join69(rootDir, bestRoot, "package.json");
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(join69(rootDir, "pnpm-workspace.yaml"), "utf-8");
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 = join69(rootDir, "pnpm-workspace.yaml");
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(join69(rootDir, "pnpm-workspace.yaml"), "utf-8");
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(join69(rootDir, normalized))) {
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(join69(rootDir, bestRoot, "package.json"), "utf-8")
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(join69(rootDir, "pnpm-lock.yaml"))) {
191296
- if (existsSync56(join69(rootDir, "pnpm-workspace.yaml"))) {
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(join69(rootDir, "yarn.lock"))) {
191453
+ if (existsSync56(join70(rootDir, "yarn.lock"))) {
191316
191454
  return { command: "yarn test", testSource: "inferred", buildSource };
191317
191455
  }
191318
- if (existsSync56(join69(rootDir, "bun.lock")) || existsSync56(join69(rootDir, "bun.lockb"))) {
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(join69(rootDir, "package-lock.json"))) {
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 join70 } from "node:path";
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(join70(tmpdir6(), "fusion-worktree-sync-"));
193685
- const patchPath = join70(stageDir, "edits.patch");
193686
- const untrackedDir = join70(stageDir, "untracked");
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 = join70(worktreePath, rel);
193707
- const dst = join70(untrackedDir, rel);
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 = join70(untrackedDir, rel);
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 = join70(worktreePath, rel);
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 readFile35, writeFile as writeFile27 } from "node:fs/promises";
193846
- import { join as join71 } from "node:path";
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 = join71(store.getTaskDir(taskId), "PROMPT.md");
193986
- const prompt = await readFile35(promptPath, "utf-8");
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 join72, resolve as resolve36 } from "node:path";
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 = join72(rootDir, "scripts/ensure-test-artifacts.mjs");
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 = join72(rootDir, ".git", ACTIVE_MERGER_STATUS_FILENAME);
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 = join72(rootDir, ".git", ACTIVE_MERGER_STATUS_FILENAME);
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 = join72(rootDir, file);
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 = join72(rootDir, ".git", `fusion-autostash-${sha.slice(0, 7)}.patch`);
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 = join72(rootDir, cherryPickHeadPathOut.trim());
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 = join72(rootDir, sequencerPathOut.trim());
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 join73, relative as relative13, resolve as resolve37 } from "node:path";
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 = join73(repoDir, ".fusion", "recovery");
202291
+ const recoveryDir = join74(repoDir, ".fusion", "recovery");
202154
202292
  mkdirSync10(recoveryDir, { recursive: true });
202155
- const patchPath = join73(recoveryDir, `${taskId.toLowerCase()}-${formatRecoveryTimestamp()}.patch`);
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 baseAlreadyHasCurrentTask = hasNoUniqueDiff ? await this.baseHasExplicitTaskOwnership(taskId, lineageId, baseBranch).catch(() => false) : false;
203637
- if ((!hasNoUniqueDiff || baseAlreadyHasCurrentTask) && ownership.rejectionReason === "foreign-task") {
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
- if (ownership?.rejectionReason === "foreign-task" || ownership?.rejectionReason === "foreign-lineage") {
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: ownership.rejectionReason === "foreign-task" ? ownership.ownerTaskId : ownership.ownerLineageId,
205030
+ candidateOwner: foreignRejection.owner,
204863
205031
  taskBranch: branchName,
204864
205032
  baseBranch: inspection.integrationRef,
204865
- reason: ownership.rejectionReason === "foreign-task" ? "foreign-task-tip" : "foreign-lineage-tip",
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 = join73(this.options.rootDir, repoRel);
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 = join73(this.options.rootDir, repoRel);
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(join73(testWorkerRoot, entry));
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(join73(root, entry));
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 baseAlreadyHasCurrentTask = hasNoUniqueDiff ? await this.baseHasExplicitTaskOwnership(taskId, lineageId, baseBranch).catch(() => false) : false;
210273
- if ((!hasNoUniqueDiff || baseAlreadyHasCurrentTask) && ownership.rejectionReason === "foreign-task") {
210274
- return { misbound: false, branchTip, landed: null, rejection: { reason: "foreign-task-tip", owner: ownership.ownerTaskId } };
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 = join73(this.options.rootDir, ".fusion", "tasks", task.id, "PROMPT.md");
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) => join73(worktreesDir, e.name));
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 = join73(tempRoot, entry);
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 readFile36, writeFile as writeFile28, rm as rm9 } from "node:fs/promises";
212635
- import { join as join74 } from "node:path";
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: readFile46 } = await import("node:fs/promises");
212687
- const { join: join108 } = await import("node:path");
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 = join108(
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 readFile46(filePath);
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 readFile46(filePath, "utf-8");
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 = join74(this.rootDir, ".fusion", "tasks", task.id, "PROMPT.md");
213514
- const written = await readFile36(promptPath, "utf-8").catch((err) => {
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 = join74(this.rootDir, ".fusion", "tasks", taskId, "PROMPT.md");
213553
- const written = await readFile36(promptPath, "utf-8").catch((err) => {
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 = join74(this.rootDir, ".fusion", "tasks", todoTask.id, "PROMPT.md");
213718
- const content = await readFile36(promptPath, "utf-8");
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 = `.fusion/tasks/${task.id}/PROMPT.md`;
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 written = await readFile36(
214266
- join74(this.rootDir, promptPath),
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(join74(this.rootDir, ".fusion", "tasks", task.id, "PROMPT.md"), { force: true });
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(join74(this.rootDir, ".fusion", "tasks", task.id, "PROMPT.md"), { force: true });
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(join74(this.rootDir, ".fusion", "tasks", task.id, "PROMPT.md"), { force: true });
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 = join74(this.rootDir, ".fusion", "tasks", task.id, "PROMPT.md");
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 readFile37, rm as rm10 } from "node:fs/promises";
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 join75 } from "node:path";
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(join75(tmpdir8(), "fusion-feature-video-"));
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 readFile37(await video.path());
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(join108) {
215455
- const rawMode = join108.config?.mode;
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 '${join108.id}' quorum must be a positive integer`);
215644
+ else throw new WorkflowIrError(`join '${join109.id}' quorum must be a positive integer`);
215462
215645
  }
215463
- const rawFail = join108.config?.onBranchFailure;
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 join108 = findMatchingJoin(branchEdges[0].to, env);
215480
- if (!join108) throw new WorkflowIrError(`split '${split.id}' has no reachable matching join`);
215481
- const joinConfig = resolveJoinConfig(env.nodeMap.get(join108));
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, join108, env, controller.signal, visitedNodeIds).then((result2) => {
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: join108, outcome, branchOutcomes, visitedNodeIds };
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 join76 } from "node:path";
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 = join76(dir, HOOK_SCRIPT_NAMES.hook);
219024
- const notifyScriptPath = join76(dir, HOOK_SCRIPT_NAMES.notify);
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 join77 } from "node:path";
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(join77(root, "fusion-cli-hooks-"));
219250
- const hookScriptPath = join77(hookDir, HOOK_SCRIPT_NAMES.hook);
219251
- const settingsPath = join77(hookDir, "settings.json");
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 join78, dirname as dirname33 } from "node:path";
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 = join78(pkgRoot, "build", "Release");
219504
- if (fs7.existsSync(join78(releaseDir, "pty.node"))) {
219686
+ const releaseDir = join79(pkgRoot, "build", "Release");
219687
+ if (fs7.existsSync(join79(releaseDir, "pty.node"))) {
219505
219688
  return releaseDir;
219506
219689
  }
219507
- const prebuildDir = join78(pkgRoot, "prebuilds", getNativePrebuildName());
219508
- if (fs7.existsSync(join78(prebuildDir, "pty.node"))) {
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 = join78(process.env.FUSION_RUNTIME_DIR, prebuildName);
219520
- if (fs7.existsSync(join78(envPath, "pty.node"))) {
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 = join78(execDir, "runtime", prebuildName);
219526
- if (fs7.existsSync(join78(nextToBinary, "pty.node"))) {
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 = join78(nativeDir, "spawn-helper");
219550
- const nativeModulePath = join78(nativeDir, "pty.node");
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 = join78(nativeDir, "pty.node");
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 join79, relative as relative14 } from "node:path";
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(join79(rootDir, candidate, "package.json"), "utf8"));
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 = join79(rootDir, current.dir);
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 = join79(current.dir, entry.name);
221442
+ const child = join80(current.dir, entry.name);
221260
221443
  try {
221261
- const pkg = JSON.parse(readFileSync23(join79(rootDir, child, "package.json"), "utf8"));
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(join79(rootDir, packageDir), token).replace(/\\/g, "/");
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 = join79(worktreePath, params.cwd);
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 = join79(rootDir, "node_modules", ".modules.yaml");
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 join80, relative as relative16, resolve as resolvePath3 } from "node:path";
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 readFile38, rm as rm13, writeFile as writeFile30 } from "node:fs/promises";
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(join80(skillPath, "SKILL.md")) || existsSync65(join80(skillPath, bareSkillName, "SKILL.md"))
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 readFile38(sessionFile, "utf-8");
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: join80(this.rootDir, ".fusion"),
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 = join80(this.store.getFusionDir(), "tasks");
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 = join80(this.store.getFusionDir(), "tasks", task.id, "PROMPT.md");
234193
+ const promptPath = join81(this.store.getFusionDir(), "tasks", task.id, "PROMPT.md");
234011
234194
  let content;
234012
234195
  try {
234013
- content = await readFile38(promptPath, "utf-8");
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 join81, relative as relative17 } from "node:path";
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 = join81(projectRootDir, ".git", "info", "exclude");
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(join81(testWorkerRoot, entry));
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 = join81(tempRoot, entry);
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 join82 } from "node:path";
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(join82(testWorkerRoot, entry));
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(join82(root, entry));
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(join82(resolveAiMergeRoot(repoRootDir, settings), `fusion-ai-merge-${taskId.toLowerCase()}-`));
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 = join82(workspaceRootDir, repoRel);
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(join82(resolveAiMergeRoot(projectRootDir, settings), `fusion-ai-merge-push-${taskId.toLowerCase()}-`));
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 join83 } from "node:path";
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 = join83(opts.workspaceRootDir, repoRel);
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 = join83(workspaceRootDir, repoRel);
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 = join83(workspaceRootDir, repoRel);
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 readFile46 = opts.readFile ?? readOptionalTextFile;
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 readFile46(source.path);
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 readFile39 } from "node:fs/promises";
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 readFile39(resolvedPath, "utf-8");
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 join84, relative as relative18, resolve as resolve39, sep as sep11 } from "node:path";
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(join84(agentDir, name2), "user", 999);
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(join84(current, name2), "project", depth);
246849
- tryAdd(join84(current, ".fusion", name2), "project", depth);
246850
- tryAdd(join84(current, ".omp", name2), "project", depth);
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 join85 } from "node:path";
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 join85(currentDir, workerFile);
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 join86 } from "node:path";
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 join86(tmpdir12(), `fusion-engine-${hash}.sock`);
261775
+ return join87(tmpdir12(), `fusion-engine-${hash}.sock`);
261593
261776
  }
261594
261777
  function computeEngineLockFilePath(workingDir) {
261595
- return join86(workingDir, ".fusion", "engine.lock");
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 = join86(workingDir, ".fusion");
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 join87 } from "node:path";
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(join87(tmpdir13(), "fn-pr-conflict-"));
268451
- const indexPath = join87(indexDir, "index");
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 readFile40 } from "node:fs/promises";
272039
- import { join as join88 } from "node:path";
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 = join88(repoRoot, ".fusion", "tasks", task.id, "PROMPT.md");
272240
- promptContent = (await raceWithAbort(readFile40(promptPath, "utf8"), combinedSignal)).trim();
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 = join88(repoRoot, ".github", "pull_request_template.md");
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(readFile40(templatePath, "utf8"), combinedSignal) : "";
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 join89, resolve as resolve40 } from "node:path";
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 ?? join89(homedir12(), ".hermes");
280085
+ const base = process.env.HERMES_HOME ?? join90(homedir12(), ".hermes");
279903
280086
  if (!profile || profile === "default") return base;
279904
- return join89(base, "profiles", profile);
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(join89(candidate, "SKILL.md"))) return candidate;
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 = join89(resolveHermesHome(options.profile), "skills", FUSION_SKILL_NAME);
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 = join89(path10, "SKILL.md");
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(join89(path10, "SKILL.md"));
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 readFile42 } from "node:fs/promises";
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 readFile42(opts.serverConfigPath, "utf-8");
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 join90 } from "node:path";
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 = join90(tmpdir14(), `openclaw-runtime-mcp-schemas-${suffix}.json`);
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 = join90(__dirname3, "mcp-schema-server.cjs");
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 = join90(tmpdir14(), `openclaw-runtime-mcp-server-${suffix}.json`);
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 readFile43 } from "node:fs/promises";
281395
+ import { readFile as readFile44 } from "node:fs/promises";
281213
281396
  import { homedir as homedir13 } from "node:os";
281214
- import { join as join91 } from "node:path";
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 = join91(homedir13(), ".grok", "user-settings.json");
281414
+ const settingsPath = join92(homedir13(), ".grok", "user-settings.json");
281232
281415
  let raw;
281233
281416
  try {
281234
- raw = await readFile43(settingsPath, "utf-8");
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 join92, resolve as resolve41 } from "node:path";
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 join92(pluginRoot, "node_modules", ".bin", `${CLAUDE_CODE_CLI_ACP_BINARY}${extension}`);
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 join94, resolve as resolve43 } from "node:path";
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(join94(dir, "SKILL.md"));
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, join94(root, "skill", FUSION_SKILL_NAME2));
282776
- pushUnique(out, join94(root, "packages", "cli", "skill", FUSION_SKILL_NAME2));
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, join94(dirname40(pkgJson), "skill", FUSION_SKILL_NAME2));
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 = join94(root, entry);
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(join94(tmpdir15(), "fusion-grok-plugin-"));
282867
- const skillsDir = join94(pluginDir, "skills");
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, join94(skillsDir, FUSION_SKILL_NAME2))) {
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, join94(skillsDir, name2));
283066
+ installSkillDir(source, join95(skillsDir, name2));
282884
283067
  }
282885
283068
  for (const [name2, source] of installed) {
282886
- if (!existsSync71(join94(skillsDir, name2))) {
282887
- installSkillDir(source, join94(skillsDir, name2));
283069
+ if (!existsSync71(join95(skillsDir, name2))) {
283070
+ installSkillDir(source, join95(skillsDir, name2));
282888
283071
  }
282889
283072
  }
282890
283073
  writeFileSync14(
282891
- join94(pluginDir, "plugin.json"),
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 join95 } from "node:path";
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 join95(dirname41(fileURLToPath9(import.meta.url)), "mcp-schema-server.cjs");
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 = join95(tmpdir16(), `fusion-grok-mcp-schemas-${process.pid}-${randomUUID52()}.json`);
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 join96, resolve as resolve44 } from "node:path";
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 join96(pluginRoot, "node_modules", ".bin", `${CLAUDE_CODE_CLI_ACP_BINARY2}${extension}`);
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 join98, resolve as resolve46 } from "node:path";
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 join98(pluginRoot, "bridge", `${CLAUDE_CODE_CLI_ACP_BINARY3}${process.platform === "win32" ? ".cmd" : ""}`);
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 join99, resolve as resolve47 } from "node:path";
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(join99(dir, "SKILL.md"));
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, join99(root, "skill", FUSION_SKILL_NAME3));
284897
- pushUnique2(out, join99(root, "packages", "cli", "skill", FUSION_SKILL_NAME3));
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, join99(dirname45(pkgJson), "skill", FUSION_SKILL_NAME3));
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 = join99(root, entry);
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(join99(tmpdir17(), "fusion-claude-plugin-"));
284988
- const skillsDir = join99(pluginDir, "skills");
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, join99(skillsDir, FUSION_SKILL_NAME3))) {
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, join99(skillsDir, name2));
285187
+ installSkillDir2(source, join100(skillsDir, name2));
285005
285188
  }
285006
285189
  for (const [name2, source] of installed) {
285007
- if (!existsSync75(join99(skillsDir, name2))) {
285008
- installSkillDir2(source, join99(skillsDir, name2));
285190
+ if (!existsSync75(join100(skillsDir, name2))) {
285191
+ installSkillDir2(source, join100(skillsDir, name2));
285009
285192
  }
285010
285193
  }
285011
285194
  writeFileSync16(
285012
- join99(pluginDir, "plugin.json"),
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 join100 } from "node:path";
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 join100(dirname46(fileURLToPath13(import.meta.url)), "mcp-schema-server.cjs");
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 = join100(tmpdir18(), `fusion-claude-mcp-schemas-${process.pid}-${randomUUID53()}.json`);
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 join101, resolve as resolve48 } from "node:path";
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 join101(pluginRoot, "node_modules", ".bin", `${CLAUDE_CODE_CLI_ACP_BINARY4}${extension}`);
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 join103 } from "node:path";
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
- join103(here, "mcp-schema-server.cjs"),
287471
+ join104(here, "mcp-schema-server.cjs"),
287289
287472
  // Source layout when running from dist/ that still has ../src assets.
287290
- join103(here, "src", "mcp-schema-server.cjs"),
287291
- join103(here, "..", "src", "mcp-schema-server.cjs"),
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
- join103(here, "..", "mcp-schema-server.cjs")
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 = join103(tmpdir19(), `fusion-omp-mcp-schemas-${process.pid}-${randomUUID54()}.json`);
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 readFile44, readdir as readdir11, rename as rename10, rm as rm18, stat as stat12, writeFile as writeFile34 } from "node:fs/promises";
289053
- import { join as join104, relative as relative19, resolve as resolve50, sep as sep15 } from "node:path";
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 ??= join104(resolveGlobalDir(), "models", "parakeet-v3");
289069
- const finalDir = () => join104(cacheDir(), "model");
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 = join104(cacheDir(), `.partial-${g2}-${randomUUID56()}`);
289133
- staging = join104(cacheDir(), `.staging-${g2}-${randomUUID56()}`);
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(join104(staging, "manifest.json"), JSON.stringify({ filename: asset.filename, sha256: asset.sha256, installedAt: (/* @__PURE__ */ new Date()).toISOString(), expectedFiles: asset.expectedFiles }));
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 = join104(cacheDir(), `.backup-${g2}-${randomUUID56()}`);
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 readFile44(join104(finalDir(), "manifest.json"), "utf8"));
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(join104(finalDir(), expected))) throw new Error("missing expected model file");
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(join104(cacheDir(), entry), { recursive: true, force: true });
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(join104(cacheDir(), entry), { recursive: true, force: true });
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 join105, dirname as dirname50 } from "node:path";
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 join106 } from "node:path";
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: readFile46 } = await import("node:fs/promises");
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 readFile46(resolvedPath);
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 = join106(projectPath, ".fusion", "tasks", id, "agent.log");
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: readFile46 } = await import("node:fs/promises");
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 readFile46(resolvedPath);
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 join107 } from "node:path";
292714
- import { readFile as readFile45 } from "node:fs/promises";
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(join107(worktreeProjectRoot, ".fusion"))) {
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(join107(current, ".fusion"))) {
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 join107(resolveProjectRoot2(cwd), ".fusion");
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 readFile45(filePath);
294027
+ content = await readFile46(filePath);
293845
294028
  } catch {
293846
294029
  throw new Error(`Cannot read file: ${params.path}`);
293847
294030
  }