@runfusion/fusion 0.77.0-beta.1 → 0.77.0-beta.2

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 (137) hide show
  1. package/dist/bin.js +298 -62
  2. package/dist/child-process-worker.js +287 -57
  3. package/dist/client/.vite/manifest.json +262 -262
  4. package/dist/client/assets/{AgentDetailView-Crk9OdF-.js → AgentDetailView-Dew3af1O.js} +1 -1
  5. package/dist/client/assets/{AgentPermissionPolicyEditor-BHQ9RPKE.js → AgentPermissionPolicyEditor-CxPQffiY.js} +1 -1
  6. package/dist/client/assets/{AgentsView-BWOl5J6F.js → AgentsView-Cr4LDGdt.js} +3 -3
  7. package/dist/client/assets/{ChatView-BP8-Are_.js → ChatView-cNYtYx05.js} +1 -1
  8. package/dist/client/assets/{CommandCenter-C1adapJC.js → CommandCenter-DCC90LOP.js} +1 -1
  9. package/dist/client/assets/{DevServerView-B2wexHCU.js → DevServerView-B5b520w6.js} +1 -1
  10. package/dist/client/assets/{DirectoryPicker-C7rzLVyD.js → DirectoryPicker-1JvRd5mC.js} +1 -1
  11. package/dist/client/assets/{DocumentsView-hOjlyCfz.js → DocumentsView-ksK9f7xt.js} +1 -1
  12. package/dist/client/assets/{EvalsView-CdAB_4D_.js → EvalsView-a3LhgRSo.js} +1 -1
  13. package/dist/client/assets/{ExperimentalAgentOnboardingModal-GEypAOXx.js → ExperimentalAgentOnboardingModal-vdVa8h7F.js} +1 -1
  14. package/dist/client/assets/{GoalsView-DW1qRxeP.js → GoalsView-Dz2o91fd.js} +1 -1
  15. package/dist/client/assets/{InsightsView-B5roc0nI.js → InsightsView-De3R_46d.js} +1 -1
  16. package/dist/client/assets/{MemoryView-B0mSfU8f.js → MemoryView-Cagk2wZG.js} +1 -1
  17. package/dist/client/assets/{PiExtensionsManager-ps7tZzok.js → PiExtensionsManager-C9JABO_4.js} +1 -1
  18. package/dist/client/assets/{PluginManager-BrsdP_Zs.js → PluginManager-D2csmdQa.js} +1 -1
  19. package/dist/client/assets/{PullRequestView-CkLoEm3J.js → PullRequestView-DT8vTeVi.js} +1 -1
  20. package/dist/client/assets/{ReportModal-BKdSSVii.js → ReportModal-YMP6V4vu.js} +1 -1
  21. package/dist/client/assets/{ResearchView-OZW77xd4.js → ResearchView-cNsjYu8F.js} +1 -1
  22. package/dist/client/assets/{SecretsView-CawXNPvr.js → SecretsView-BAmf7KyS.js} +1 -1
  23. package/dist/client/assets/{SessionTerminal-C26iOW6f.js → SessionTerminal-BjGcxq22.js} +1 -1
  24. package/dist/client/assets/{SettingsModal-BNWlULmc.js → SettingsModal-C_9RiEI7.js} +1 -1
  25. package/dist/client/assets/{SettingsModal-CfXTMT99.js → SettingsModal-DLfy2e_5.js} +4 -4
  26. package/dist/client/assets/{SettingsTextareaRow-DrXj-rTG.js → SettingsTextareaRow-D8RHSj8b.js} +1 -1
  27. package/dist/client/assets/{SetupWizardModal-Dk4cldse.js → SetupWizardModal-DRJ96pHQ.js} +2 -2
  28. package/dist/client/assets/{SkillsView-NBEe0Qjt.js → SkillsView-DyeCwYit.js} +1 -1
  29. package/dist/client/assets/{WorkflowNodeEditor-CZX7Mlum.js → WorkflowNodeEditor-C5Jc9w_A.js} +3 -3
  30. package/dist/client/assets/{agent-import-generation-TK-wCZBK.js → agent-import-generation-SCPNeF25.js} +1 -1
  31. package/dist/client/assets/{agentsOrgChartLayout-BFC39-tw.js → agentsOrgChartLayout-CqKtNCjy.js} +1 -1
  32. package/dist/client/assets/{architectureDiagram-3BPJPVTR-CYHuEL_5.js → architectureDiagram-3BPJPVTR-Cz2HYn0b.js} +1 -1
  33. package/dist/client/assets/{blockDiagram-GPEHLZMM-BhFoNt44.js → blockDiagram-GPEHLZMM-IimJVscG.js} +1 -1
  34. package/dist/client/assets/{c4Diagram-AAUBKEIU-CQorfIRn.js → c4Diagram-AAUBKEIU-C-xii7zn.js} +1 -1
  35. package/dist/client/assets/channel-D-UHgx8G.js +1 -0
  36. package/dist/client/assets/{chunk-2J33WTMH-DLyODy_m.js → chunk-2J33WTMH-DQ-9Xccu.js} +1 -1
  37. package/dist/client/assets/{chunk-4BX2VUAB-C4ZfqjSh.js → chunk-4BX2VUAB-DmdAX9Bx.js} +1 -1
  38. package/dist/client/assets/{chunk-55IACEB6-CvGg-ubc.js → chunk-55IACEB6-IF2bk5IL.js} +1 -1
  39. package/dist/client/assets/{chunk-727SXJPM-jCzUYl5C.js → chunk-727SXJPM-AeYpIzVu.js} +1 -1
  40. package/dist/client/assets/{chunk-AQP2D5EJ-DYLT-tu8.js → chunk-AQP2D5EJ-DV942DD9.js} +1 -1
  41. package/dist/client/assets/{chunk-FMBD7UC4-CCgBBj1Z.js → chunk-FMBD7UC4-Bt_riVlZ.js} +1 -1
  42. package/dist/client/assets/{chunk-ND2GUHAM-BFdFrIja.js → chunk-ND2GUHAM-CbyjNbXR.js} +1 -1
  43. package/dist/client/assets/{chunk-QZHKN3VN-BUTaQ50G.js → chunk-QZHKN3VN-DqiRniYQ.js} +1 -1
  44. package/dist/client/assets/classDiagram-4FO5ZUOK-Do-8MdAc.js +1 -0
  45. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-Do-8MdAc.js +1 -0
  46. package/dist/client/assets/{cose-bilkent-S5V4N54A-DUbNlc_8.js → cose-bilkent-S5V4N54A-UCvthviL.js} +1 -1
  47. package/dist/client/assets/{dagre-BM42HDAG-Db_33UO6.js → dagre-BM42HDAG-DnMlT1Oi.js} +1 -1
  48. package/dist/client/assets/{dashboard-view-C3PU63FX.js → dashboard-view-C9D0aoRW.js} +1 -1
  49. package/dist/client/assets/dashboard-view-Cz0sp2Wl.js +1 -0
  50. package/dist/client/assets/{dashboard-view-CblIAx4p.js → dashboard-view-JysoyDRX.js} +1 -1
  51. package/dist/client/assets/{dashboard-view-ZGZ80pF3.js → dashboard-view-myjM9tr8.js} +1 -1
  52. package/dist/client/assets/{diagram-2AECGRRQ-BCTLM-Gj.js → diagram-2AECGRRQ-BYFiqXGw.js} +1 -1
  53. package/dist/client/assets/{diagram-5GNKFQAL-CkYPWqJ0.js → diagram-5GNKFQAL-DZU3pSYq.js} +1 -1
  54. package/dist/client/assets/{diagram-KO2AKTUF-7_DJ9TOL.js → diagram-KO2AKTUF-0ybdKuMm.js} +1 -1
  55. package/dist/client/assets/{diagram-LMA3HP47-BAkMEapl.js → diagram-LMA3HP47-Rxbgnbsp.js} +1 -1
  56. package/dist/client/assets/{diagram-OG6HWLK6-DbsQHZ0F.js → diagram-OG6HWLK6-BAU_hTeV.js} +1 -1
  57. package/dist/client/assets/{erDiagram-TEJ5UH35-Bz1kISgV.js → erDiagram-TEJ5UH35-zr8HrwTt.js} +1 -1
  58. package/dist/client/assets/{flowDiagram-I6XJVG4X-fkBLx_JW.js → flowDiagram-I6XJVG4X-CrTw0iFw.js} +1 -1
  59. package/dist/client/assets/{folder-open-l8Z1o786.js → folder-open-DnAlsXXn.js} +1 -1
  60. package/dist/client/assets/{ganttDiagram-6RSMTGT7-BEDb0Uyw.js → ganttDiagram-6RSMTGT7-CCORsxxz.js} +1 -1
  61. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-Cen5lgL7.js → gitGraphDiagram-PVQCEYII-C07wWSjj.js} +1 -1
  62. package/dist/client/assets/index-B_z7OKl4.js +2818 -0
  63. package/dist/client/assets/index-DPo-IAb2.css +1 -0
  64. package/dist/client/assets/{infoDiagram-5YYISTIA-BHqjYX5-.js → infoDiagram-5YYISTIA-hAeccD_4.js} +1 -1
  65. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-6JaCT-0H.js → ishikawaDiagram-YF4QCWOH-WLCzv-NH.js} +1 -1
  66. package/dist/client/assets/{journeyDiagram-JHISSGLW-C_sUwyWW.js → journeyDiagram-JHISSGLW-ClnasNhy.js} +1 -1
  67. package/dist/client/assets/{kanban-definition-UN3LZRKU-__o8oDEP.js → kanban-definition-UN3LZRKU-CAuARhUz.js} +1 -1
  68. package/dist/client/assets/{mermaid.core-BwF2BF3U.js → mermaid.core-Bh02RvfX.js} +4 -4
  69. package/dist/client/assets/{mindmap-definition-RKZ34NQL-DMhvCrGK.js → mindmap-definition-RKZ34NQL-KNTlbW4V.js} +1 -1
  70. package/dist/client/assets/{pieDiagram-4H26LBE5-Dk0KKcwv.js → pieDiagram-4H26LBE5-BouAfBEw.js} +1 -1
  71. package/dist/client/assets/{puzzle-DcLi6jmv.js → puzzle-CC8Ur3Cy.js} +1 -1
  72. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-DXcBYGil.js → quadrantDiagram-W4KKPZXB-wTdkCUJU.js} +1 -1
  73. package/dist/client/assets/{requirementDiagram-4Y6WPE33--GXgKHm2.js → requirementDiagram-4Y6WPE33-BnjY4Tc_.js} +1 -1
  74. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-fX5WAFdr.js → sankeyDiagram-5OEKKPKP-C-QsS08u.js} +1 -1
  75. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-VQOx2wc2.js → sequenceDiagram-3UESZ5HK-DD36MILE.js} +1 -1
  76. package/dist/client/assets/{shield-alert-DLW2jAvI.js → shield-alert-DcXc56Fy.js} +1 -1
  77. package/dist/client/assets/{standing-instructions-template-RbXYE69q.js → standing-instructions-template-BF5y1BLz.js} +1 -1
  78. package/dist/client/assets/{stateDiagram-AJRCARHV-COZ_NGxp.js → stateDiagram-AJRCARHV-WTq1wQr1.js} +1 -1
  79. package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-CmgPEZwe.js → stateDiagram-v2-BHNVJYJU-eILJdjII.js} +1 -1
  80. package/dist/client/assets/{timeline-definition-PNZ67QCA-eJYKjHOn.js → timeline-definition-PNZ67QCA-PRNwI0NR.js} +1 -1
  81. package/dist/client/assets/{upload-DwRVPojw.js → upload-qH_64O-B.js} +1 -1
  82. package/dist/client/assets/{useDiscoveredSkillsCache-DhScYUmX.js → useDiscoveredSkillsCache-C-GPCNaO.js} +1 -1
  83. package/dist/client/assets/{users-BrTlKeXP.js → users-D2UesRE4.js} +1 -1
  84. package/dist/client/assets/{vennDiagram-CIIHVFJN-Ddt59BdZ.js → vennDiagram-CIIHVFJN-CG2Z4T4O.js} +1 -1
  85. package/dist/client/assets/{wardley-L42UT6IY-C4R0wOO2.js → wardley-L42UT6IY-gO_fGvF9.js} +1 -1
  86. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-BJDm4S7I.js → wardleyDiagram-YWT4CUSO-BkyNpjUb.js} +1 -1
  87. package/dist/client/assets/{xychartDiagram-2RQKCTM6-DlypQnRH.js → xychartDiagram-2RQKCTM6-CMlZsiPq.js} +1 -1
  88. package/dist/client/index.html +2 -2
  89. package/dist/client/version.json +1 -1
  90. package/dist/droid-cli/package.json +1 -1
  91. package/dist/extension.js +290 -59
  92. package/dist/pi-claude-cli/package.json +1 -1
  93. package/dist/plugin-sdk/index.js +29 -2
  94. package/dist/plugins/fusion-plugin-acp-runtime/bundled.js +269 -16
  95. package/dist/plugins/fusion-plugin-acp-runtime/mcp-schema-server.cjs +171 -0
  96. package/dist/plugins/fusion-plugin-acp-runtime/package.json +1 -1
  97. package/dist/plugins/fusion-plugin-claude-runtime/bundled.js +29 -2
  98. package/dist/plugins/fusion-plugin-claude-runtime/package.json +1 -1
  99. package/dist/plugins/fusion-plugin-cli-printing-press/bundled.js +29 -2
  100. package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
  101. package/dist/plugins/fusion-plugin-compound-engineering/bundled.js +29 -2
  102. package/dist/plugins/fusion-plugin-compound-engineering/package.json +1 -1
  103. package/dist/plugins/fusion-plugin-cursor-runtime/bundled.js +29 -2
  104. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
  105. package/dist/plugins/fusion-plugin-dependency-graph/bundled.js +29 -2
  106. package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
  107. package/dist/plugins/fusion-plugin-droid-runtime/bundled.js +29 -2
  108. package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
  109. package/dist/plugins/fusion-plugin-grok-runtime/bundled.js +29 -2
  110. package/dist/plugins/fusion-plugin-grok-runtime/package.json +1 -1
  111. package/dist/plugins/fusion-plugin-hermes-runtime/bundled.js +29 -2
  112. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  113. package/dist/plugins/fusion-plugin-linear-import/bundled.js +29 -2
  114. package/dist/plugins/fusion-plugin-linear-import/package.json +1 -1
  115. package/dist/plugins/fusion-plugin-omp-runtime/bundled.js +29 -2
  116. package/dist/plugins/fusion-plugin-omp-runtime/package.json +1 -1
  117. package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +29 -2
  118. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  119. package/dist/plugins/fusion-plugin-paperclip-runtime/bundled.js +29 -2
  120. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  121. package/dist/plugins/fusion-plugin-quality/bundled.js +29 -2
  122. package/dist/plugins/fusion-plugin-quality/package.json +1 -1
  123. package/dist/plugins/fusion-plugin-reports/bundled.js +29 -2
  124. package/dist/plugins/fusion-plugin-reports/package.json +1 -1
  125. package/dist/plugins/fusion-plugin-roadmap/bundled.js +29 -2
  126. package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
  127. package/dist/plugins/fusion-plugin-todos/bundled.js +29 -2
  128. package/dist/plugins/fusion-plugin-todos/package.json +1 -1
  129. package/dist/plugins/fusion-plugin-whatsapp-chat/bundled.js +29 -2
  130. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
  131. package/package.json +1 -1
  132. package/dist/client/assets/channel-DgImfyB5.js +0 -1
  133. package/dist/client/assets/classDiagram-4FO5ZUOK-C3pUNxZS.js +0 -1
  134. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-C3pUNxZS.js +0 -1
  135. package/dist/client/assets/dashboard-view-c3FuWBJb.js +0 -1
  136. package/dist/client/assets/index-BnZB0GkD.js +0 -2818
  137. package/dist/client/assets/index-CPGSlKrd.css +0 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion/pi-claude-cli",
3
- "version": "0.77.0-beta.1",
3
+ "version": "0.77.0-beta.2",
4
4
  "type": "module",
5
5
  "private": true,
6
6
  "main": "index.ts",
@@ -16105,6 +16105,7 @@ function applyPromptOverridesToIr(ir, overrides) {
16105
16105
  function defaultCodingWorkflowIr() {
16106
16106
  return resolveDefaultWorkflowIr();
16107
16107
  }
16108
+ var inflightSelectionReads = /* @__PURE__ */ new WeakMap();
16108
16109
  async function resolveWorkflowIrById(store, workflowId, irCache) {
16109
16110
  let projectId;
16110
16111
  try {
@@ -16148,8 +16149,34 @@ function didFallBackToDefault(ir) {
16148
16149
  async function resolveWorkflowIrForTaskWithProvenance(store, taskId, irCache, selectionCache) {
16149
16150
  let workflowId;
16150
16151
  try {
16151
- const selection = selectionCache?.has(taskId) ? selectionCache.get(taskId) : store.getTaskWorkflowSelectionAsync ? await store.getTaskWorkflowSelectionAsync(taskId) : store.getTaskWorkflowSelection(taskId);
16152
- if (!selectionCache?.has(taskId)) selectionCache?.set(taskId, selection);
16152
+ const isSelectionCached = selectionCache?.has(taskId) ?? false;
16153
+ let selection = isSelectionCached && selectionCache ? selectionCache.get(taskId) : void 0;
16154
+ if (!isSelectionCached) {
16155
+ let inflight;
16156
+ let coalesced = false;
16157
+ if (selectionCache) {
16158
+ inflight = inflightSelectionReads.get(selectionCache);
16159
+ if (!inflight) {
16160
+ inflight = /* @__PURE__ */ new Map();
16161
+ inflightSelectionReads.set(selectionCache, inflight);
16162
+ }
16163
+ const pending = inflight.get(taskId);
16164
+ if (pending) {
16165
+ selection = await pending;
16166
+ coalesced = true;
16167
+ }
16168
+ }
16169
+ if (!coalesced) {
16170
+ const readPromise = store.getTaskWorkflowSelectionAsync ? store.getTaskWorkflowSelectionAsync(taskId) : Promise.resolve(store.getTaskWorkflowSelection(taskId));
16171
+ if (inflight) inflight.set(taskId, readPromise);
16172
+ try {
16173
+ selection = await readPromise;
16174
+ } finally {
16175
+ inflight?.delete(taskId);
16176
+ }
16177
+ }
16178
+ selectionCache?.set(taskId, selection);
16179
+ }
16153
16180
  workflowId = selection?.workflowId;
16154
16181
  } catch {
16155
16182
  return { ir: defaultCodingWorkflowIr(), source: "default" };
@@ -1074,7 +1074,7 @@ function sql(strings, ...params) {
1074
1074
  return new SQL([new StringChunk(str)]);
1075
1075
  }
1076
1076
  sql2.raw = raw;
1077
- function join4(chunks, separator) {
1077
+ function join5(chunks, separator) {
1078
1078
  const result = [];
1079
1079
  for (const [i, chunk] of chunks.entries()) {
1080
1080
  if (i > 0 && separator !== void 0) {
@@ -1084,7 +1084,7 @@ function sql(strings, ...params) {
1084
1084
  }
1085
1085
  return new SQL(result);
1086
1086
  }
1087
- sql2.join = join4;
1087
+ sql2.join = join5;
1088
1088
  function identifier(value) {
1089
1089
  return new Name(value);
1090
1090
  }
@@ -4535,7 +4535,7 @@ var PgSelectQueryBuilderBase = class extends TypedQueryBuilder {
4535
4535
  const baseTableName = this.tableName;
4536
4536
  const tableName = getTableLikeName(table);
4537
4537
  for (const item of extractUsedTable(table)) this.usedTables.add(item);
4538
- if (typeof tableName === "string" && this.config.joins?.some((join4) => join4.alias === tableName)) {
4538
+ if (typeof tableName === "string" && this.config.joins?.some((join5) => join5.alias === tableName)) {
4539
4539
  throw new Error(`Alias "${tableName}" is already used in this query`);
4540
4540
  }
4541
4541
  if (!this.isPartialSelect) {
@@ -10713,26 +10713,26 @@ function validateParallelism(nodes2, outgoing, nodesById) {
10713
10713
  }
10714
10714
  const joinsReached = /* @__PURE__ */ new Set();
10715
10715
  for (const edge of branchEdges) {
10716
- const join5 = walkBranchToJoin(edge.to, split.id, outgoing, nodesById);
10717
- if (!join5) {
10716
+ const join6 = walkBranchToJoin(edge.to, split.id, outgoing, nodesById);
10717
+ if (!join6) {
10718
10718
  throw new WorkflowIrError(`split '${split.id}' has a branch with no reachable matching join`);
10719
10719
  }
10720
- joinsReached.add(join5);
10720
+ joinsReached.add(join6);
10721
10721
  }
10722
10722
  if (joinsReached.size !== 1) {
10723
10723
  throw new WorkflowIrError(`split '${split.id}' branches converge on more than one join`);
10724
10724
  }
10725
10725
  const joinId = [...joinsReached][0];
10726
- const join4 = nodesById.get(joinId);
10727
- const mode = join4.config?.mode;
10726
+ const join5 = nodesById.get(joinId);
10727
+ const mode = join5.config?.mode;
10728
10728
  if (mode && typeof mode === "object" && "quorum" in mode) {
10729
10729
  const n = mode.quorum;
10730
10730
  if (typeof n !== "number" || !Number.isInteger(n) || n < 1) {
10731
- throw new WorkflowIrError(`join '${join4.id}' quorum must be a positive integer`);
10731
+ throw new WorkflowIrError(`join '${join5.id}' quorum must be a positive integer`);
10732
10732
  }
10733
10733
  if (n > branchEdges.length) {
10734
10734
  throw new WorkflowIrError(
10735
- `join '${join4.id}' quorum(${n}) exceeds the split's ${branchEdges.length} branches`
10735
+ `join '${join5.id}' quorum(${n}) exceeds the split's ${branchEdges.length} branches`
10736
10736
  );
10737
10737
  }
10738
10738
  }
@@ -16113,6 +16113,7 @@ function applyPromptOverridesToIr(ir, overrides) {
16113
16113
  function defaultCodingWorkflowIr() {
16114
16114
  return resolveDefaultWorkflowIr();
16115
16115
  }
16116
+ var inflightSelectionReads = /* @__PURE__ */ new WeakMap();
16116
16117
  async function resolveWorkflowIrById(store, workflowId, irCache) {
16117
16118
  let projectId;
16118
16119
  try {
@@ -16156,8 +16157,34 @@ function didFallBackToDefault(ir) {
16156
16157
  async function resolveWorkflowIrForTaskWithProvenance(store, taskId, irCache, selectionCache) {
16157
16158
  let workflowId;
16158
16159
  try {
16159
- const selection = selectionCache?.has(taskId) ? selectionCache.get(taskId) : store.getTaskWorkflowSelectionAsync ? await store.getTaskWorkflowSelectionAsync(taskId) : store.getTaskWorkflowSelection(taskId);
16160
- if (!selectionCache?.has(taskId)) selectionCache?.set(taskId, selection);
16160
+ const isSelectionCached = selectionCache?.has(taskId) ?? false;
16161
+ let selection = isSelectionCached && selectionCache ? selectionCache.get(taskId) : void 0;
16162
+ if (!isSelectionCached) {
16163
+ let inflight;
16164
+ let coalesced = false;
16165
+ if (selectionCache) {
16166
+ inflight = inflightSelectionReads.get(selectionCache);
16167
+ if (!inflight) {
16168
+ inflight = /* @__PURE__ */ new Map();
16169
+ inflightSelectionReads.set(selectionCache, inflight);
16170
+ }
16171
+ const pending = inflight.get(taskId);
16172
+ if (pending) {
16173
+ selection = await pending;
16174
+ coalesced = true;
16175
+ }
16176
+ }
16177
+ if (!coalesced) {
16178
+ const readPromise = store.getTaskWorkflowSelectionAsync ? store.getTaskWorkflowSelectionAsync(taskId) : Promise.resolve(store.getTaskWorkflowSelection(taskId));
16179
+ if (inflight) inflight.set(taskId, readPromise);
16180
+ try {
16181
+ selection = await readPromise;
16182
+ } finally {
16183
+ inflight?.delete(taskId);
16184
+ }
16185
+ }
16186
+ selectionCache?.set(taskId, selection);
16187
+ }
16161
16188
  workflowId = selection?.workflowId;
16162
16189
  } catch {
16163
16190
  return { ir: defaultCodingWorkflowIr(), source: "default" };
@@ -37619,6 +37646,207 @@ function buildPromptBlocks(prompt, opts) {
37619
37646
  return blocks;
37620
37647
  }
37621
37648
 
37649
+ // ../../plugins/fusion-plugin-acp-runtime/src/tool-bridge.ts
37650
+ import { createServer } from "node:http";
37651
+ import { existsSync as existsSync2, unlinkSync, writeFileSync } from "node:fs";
37652
+ import { tmpdir } from "node:os";
37653
+ import { dirname as dirname4, join as join4 } from "node:path";
37654
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
37655
+ import { randomBytes as randomBytes2, randomUUID as randomUUID2 } from "node:crypto";
37656
+ var BUILT_IN_TOOL_NAMES = /* @__PURE__ */ new Set(["read", "write", "edit", "bash", "grep", "find"]);
37657
+ var TOOL_DRAIN_TIMEOUT_MS = 5e3;
37658
+ function toolsToMcpToolDefs(tools) {
37659
+ if (!Array.isArray(tools)) return [];
37660
+ return tools.filter((tool) => tool && typeof tool.name === "string" && tool.name.trim().length > 0 && !BUILT_IN_TOOL_NAMES.has(tool.name) && typeof tool.execute === "function").map((tool) => ({
37661
+ name: tool.name,
37662
+ description: typeof tool.description === "string" ? tool.description : "",
37663
+ inputSchema: tool.parameters ?? { type: "object", properties: {} }
37664
+ }));
37665
+ }
37666
+ function fusionToolsMcpServerPath() {
37667
+ return join4(dirname4(fileURLToPath2(import.meta.url)), "mcp-schema-server.cjs");
37668
+ }
37669
+ function missingMcpSchemaServerError(serverPath) {
37670
+ const error51 = new Error(`Fusion MCP schema server is missing: ${serverPath}`);
37671
+ error51.code = "mcp-schema-server-missing";
37672
+ return error51;
37673
+ }
37674
+ function resultToText(result) {
37675
+ if (result == null) return "";
37676
+ if (typeof result === "string") return result;
37677
+ if (typeof result === "object") {
37678
+ const obj = result;
37679
+ if (typeof obj.text === "string") return obj.text;
37680
+ if (Array.isArray(obj.content)) {
37681
+ return obj.content.map((block) => {
37682
+ if (block && typeof block === "object" && "text" in block && typeof block.text === "string") {
37683
+ return block.text;
37684
+ }
37685
+ return JSON.stringify(block);
37686
+ }).join("\n");
37687
+ }
37688
+ }
37689
+ try {
37690
+ return JSON.stringify(result);
37691
+ } catch {
37692
+ return String(result);
37693
+ }
37694
+ }
37695
+ async function startFusionToolBridge(tools) {
37696
+ const defs = toolsToMcpToolDefs(tools);
37697
+ if (defs.length === 0) return null;
37698
+ const serverPath = fusionToolsMcpServerPath();
37699
+ if (!existsSync2(serverPath)) {
37700
+ throw missingMcpSchemaServerError(serverPath);
37701
+ }
37702
+ const byName = /* @__PURE__ */ new Map();
37703
+ for (const tool of tools ?? []) {
37704
+ if (tool && typeof tool.name === "string" && !BUILT_IN_TOOL_NAMES.has(tool.name) && typeof tool.execute === "function") {
37705
+ byName.set(tool.name, tool);
37706
+ }
37707
+ }
37708
+ const token = randomBytes2(24).toString("hex");
37709
+ const schemaPath = join4(tmpdir(), `fusion-acp-mcp-schemas-${process.pid}-${randomUUID2()}.json`);
37710
+ writeFileSync(schemaPath, JSON.stringify(defs));
37711
+ const activeExecutions = /* @__PURE__ */ new Set();
37712
+ const activeControllers = /* @__PURE__ */ new Set();
37713
+ const server = createServer((req, res) => {
37714
+ void (async () => {
37715
+ if (req.method !== "POST" || req.url !== "/tool-call") {
37716
+ res.statusCode = 404;
37717
+ res.end(JSON.stringify({ isError: true, text: "not found" }));
37718
+ return;
37719
+ }
37720
+ const auth = req.headers.authorization;
37721
+ if (auth !== `Bearer ${token}`) {
37722
+ res.statusCode = 401;
37723
+ res.end(JSON.stringify({ isError: true, text: "unauthorized" }));
37724
+ return;
37725
+ }
37726
+ let body = "";
37727
+ for await (const chunk of req) body += chunk;
37728
+ if (disposed) {
37729
+ res.statusCode = 503;
37730
+ res.end(JSON.stringify({ isError: true, text: "tool bridge disposed" }));
37731
+ return;
37732
+ }
37733
+ let parsed;
37734
+ try {
37735
+ parsed = JSON.parse(body || "{}");
37736
+ } catch {
37737
+ res.statusCode = 400;
37738
+ res.end(JSON.stringify({ isError: true, text: "invalid JSON body" }));
37739
+ return;
37740
+ }
37741
+ const name = typeof parsed.name === "string" ? parsed.name : "";
37742
+ const tool = byName.get(name);
37743
+ if (!tool?.execute) {
37744
+ res.statusCode = 404;
37745
+ res.end(JSON.stringify({ isError: true, text: `Unknown Fusion tool: ${name}` }));
37746
+ return;
37747
+ }
37748
+ const execute = tool.execute;
37749
+ const controller = new AbortController();
37750
+ activeControllers.add(controller);
37751
+ const execution = (async () => {
37752
+ try {
37753
+ const result = await execute(
37754
+ (typeof parsed.toolCallId === "string" || typeof parsed.toolCallId === "number") && String(parsed.toolCallId) ? String(parsed.toolCallId) : `acp-mcp-${randomUUID2()}`,
37755
+ parsed.arguments ?? {},
37756
+ controller.signal,
37757
+ void 0,
37758
+ void 0
37759
+ );
37760
+ res.statusCode = 200;
37761
+ res.setHeader("content-type", "application/json");
37762
+ res.end(
37763
+ JSON.stringify({
37764
+ isError: typeof result === "object" && result !== null && "isError" in result && result.isError === true,
37765
+ content: [{ type: "text", text: resultToText(result) }]
37766
+ })
37767
+ );
37768
+ } catch (err) {
37769
+ res.statusCode = 200;
37770
+ res.setHeader("content-type", "application/json");
37771
+ res.end(
37772
+ JSON.stringify({
37773
+ isError: true,
37774
+ content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }]
37775
+ })
37776
+ );
37777
+ }
37778
+ })();
37779
+ activeExecutions.add(execution);
37780
+ try {
37781
+ await execution;
37782
+ } finally {
37783
+ activeExecutions.delete(execution);
37784
+ activeControllers.delete(controller);
37785
+ }
37786
+ })().catch(() => {
37787
+ });
37788
+ });
37789
+ let address;
37790
+ try {
37791
+ address = await new Promise((resolve5, reject) => {
37792
+ server.once("error", reject);
37793
+ server.listen(0, "127.0.0.1", () => {
37794
+ const addr = server.address();
37795
+ if (!addr || typeof addr === "string") {
37796
+ reject(new Error("tool bridge failed to bind"));
37797
+ return;
37798
+ }
37799
+ resolve5({ port: addr.port });
37800
+ });
37801
+ });
37802
+ } catch (error51) {
37803
+ server.close();
37804
+ try {
37805
+ unlinkSync(schemaPath);
37806
+ } catch {
37807
+ }
37808
+ throw error51;
37809
+ }
37810
+ const bridgeUrl = `http://127.0.0.1:${address.port}`;
37811
+ let disposed = false;
37812
+ return {
37813
+ toolCount: defs.length,
37814
+ mcpServer: {
37815
+ name: "fusion-custom-tools",
37816
+ command: process.execPath,
37817
+ args: [serverPath, schemaPath],
37818
+ env: [
37819
+ { name: "FUSION_ACP_TOOL_BRIDGE_URL", value: bridgeUrl },
37820
+ { name: "FUSION_ACP_TOOL_BRIDGE_TOKEN", value: token }
37821
+ ]
37822
+ },
37823
+ dispose: async () => {
37824
+ if (disposed) return;
37825
+ disposed = true;
37826
+ for (const controller of activeControllers) controller.abort();
37827
+ server.close(() => void 0);
37828
+ if (typeof server.closeAllConnections === "function") {
37829
+ server.closeAllConnections();
37830
+ }
37831
+ await Promise.allSettled(
37832
+ [...activeExecutions].map(
37833
+ (execution) => Promise.race([
37834
+ execution,
37835
+ new Promise((resolve5) => {
37836
+ const timer = setTimeout(resolve5, TOOL_DRAIN_TIMEOUT_MS);
37837
+ timer.unref?.();
37838
+ })
37839
+ ])
37840
+ )
37841
+ );
37842
+ try {
37843
+ unlinkSync(schemaPath);
37844
+ } catch {
37845
+ }
37846
+ }
37847
+ };
37848
+ }
37849
+
37622
37850
  // ../../plugins/fusion-plugin-acp-runtime/src/runtime-adapter.ts
37623
37851
  var AcpRuntimeAdapter = class {
37624
37852
  id = "acp";
@@ -37658,20 +37886,38 @@ var AcpRuntimeAdapter = class {
37658
37886
  clientHandler,
37659
37887
  ...this.settings.authenticate ? { authenticate: this.settings.authenticate } : {}
37660
37888
  });
37889
+ let toolBridge = null;
37890
+ let toolBridgeFailure;
37661
37891
  let sessionId;
37892
+ const customTools = Array.isArray(options.customTools) ? options.customTools : [];
37662
37893
  try {
37894
+ if (customTools.length > 0) {
37895
+ try {
37896
+ toolBridge = await startFusionToolBridge(customTools);
37897
+ } catch (error51) {
37898
+ toolBridgeFailure = error51.code === "mcp-schema-server-missing" ? "mcp-schema-server-missing" : "bridge-start-failed";
37899
+ options.onText?.(`FUSION_TOOL_BRIDGE_FAILED: ${toolBridgeFailure}`);
37900
+ }
37901
+ }
37663
37902
  const sessionMeta = options && typeof options === "object" && "sessionMeta" in options ? options.sessionMeta : void 0;
37664
37903
  const opened = await newAcpSession(connection, {
37665
37904
  cwd: options.cwd,
37666
- mcpServers: options.mcpServers,
37905
+ mcpServers: [...options.mcpServers ?? [], ...toolBridge ? [toolBridge.mcpServer] : []],
37667
37906
  meta: sessionMeta
37668
37907
  });
37669
37908
  sessionId = opened.sessionId;
37670
37909
  } catch (err) {
37910
+ await toolBridge?.dispose();
37671
37911
  connection.dispose();
37672
37912
  throw err;
37673
37913
  }
37674
37914
  let disposed = false;
37915
+ let bridgeDisposePromise;
37916
+ let disposePromise = Promise.resolve();
37917
+ const disposeBridge = () => {
37918
+ bridgeDisposePromise ??= toolBridge?.dispose() ?? Promise.resolve();
37919
+ return bridgeDisposePromise;
37920
+ };
37675
37921
  const session = {
37676
37922
  model,
37677
37923
  systemPrompt: options.systemPrompt,
@@ -37679,6 +37925,7 @@ var AcpRuntimeAdapter = class {
37679
37925
  cwd: options.cwd,
37680
37926
  lastModelDescription: `acp/${model}`,
37681
37927
  callbacks,
37928
+ fusionToolBridgeError: toolBridgeFailure ? { reasonCode: toolBridgeFailure } : void 0,
37682
37929
  // Persist the per-run gate (KTD3) so U5/U7 can reach the live action gate.
37683
37930
  gate: options.actionGateContext,
37684
37931
  connection,
@@ -37686,10 +37933,15 @@ var AcpRuntimeAdapter = class {
37686
37933
  // turn that trips the per-turn output cap can't latch and suppress every
37687
37934
  // subsequent turn (FIX 1).
37688
37935
  resetTurn,
37936
+ disposeBridge,
37937
+ get disposePromise() {
37938
+ return disposePromise;
37939
+ },
37689
37940
  dispose: () => {
37690
37941
  if (disposed) return;
37691
37942
  disposed = true;
37692
37943
  cancelPending();
37944
+ disposePromise = disposeBridge();
37693
37945
  connection.dispose();
37694
37946
  }
37695
37947
  };
@@ -37714,13 +37966,14 @@ var AcpRuntimeAdapter = class {
37714
37966
  if (acp.connection && acp.sessionId) {
37715
37967
  await cancelAcpSession(acp.connection, acp.sessionId);
37716
37968
  }
37969
+ await acp.disposeBridge?.();
37717
37970
  session.dispose();
37718
37971
  }
37719
37972
  };
37720
37973
 
37721
37974
  // ../../plugins/fusion-plugin-acp-runtime/src/setup.ts
37722
- import { dirname as dirname4, relative, resolve as resolve4, sep as sep2 } from "node:path";
37723
- import { fileURLToPath as fileURLToPath2 } from "node:url";
37975
+ import { dirname as dirname5, relative, resolve as resolve4, sep as sep2 } from "node:path";
37976
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
37724
37977
 
37725
37978
  // ../../plugins/fusion-plugin-acp-runtime/src/probe.ts
37726
37979
  function isMissingBinary(err) {
@@ -37789,7 +38042,7 @@ function isInside(parent, child) {
37789
38042
  return rel === "" || !rel.startsWith("..") && !rel.includes(`..${sep2}`);
37790
38043
  }
37791
38044
  function defaultPluginRoot() {
37792
- return resolve4(dirname4(fileURLToPath2(import.meta.url)), "..");
38045
+ return resolve4(dirname5(fileURLToPath3(import.meta.url)), "..");
37793
38046
  }
37794
38047
  function validateBundledBridgeIdentity(binaryPath, pluginRoot = defaultPluginRoot()) {
37795
38048
  const expectedBin = resolve4(bundledClaudeBridgeBinPath(pluginRoot));
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ FNXC:AcpCustomTools 2026-08-16-00:30:
4
+ Executable MCP bridge for Fusion custom tools (fn_*) on generic ACP paths
5
+ (Hermes ACP, Prime, ...). tools/list is served from a schema file; tools/call
6
+ POSTs to a localhost bridge owned by AcpRuntimeAdapter so ToolDefinition.execute
7
+ runs in-process with the engine's closures. The bridge authenticates the POST
8
+ with a per-session bearer token passed via FUSION_ACP_TOOL_BRIDGE_TOKEN.
9
+ */
10
+ "use strict";
11
+
12
+ const fs = require("fs");
13
+ const http = require("http");
14
+ const readline = require("readline");
15
+ // FNXC:AcpCustomTools 2026-08-16-00:30: CJS has no global URL under eslint no-undef; use node:url.
16
+ const { URL } = require("node:url");
17
+
18
+ const schemaPath = process.argv[2];
19
+ const bridgeUrl = process.env.FUSION_ACP_TOOL_BRIDGE_URL;
20
+ const bridgeToken = process.env.FUSION_ACP_TOOL_BRIDGE_TOKEN;
21
+ if (!schemaPath || !bridgeUrl) {
22
+ process.stderr.write("fusion-custom-tools-mcp: missing schema path or FUSION_ACP_TOOL_BRIDGE_URL\n");
23
+ process.exit(1);
24
+ }
25
+
26
+ let tools = [];
27
+ try {
28
+ tools = JSON.parse(fs.readFileSync(schemaPath, "utf-8"));
29
+ if (!Array.isArray(tools)) tools = [];
30
+ } catch {
31
+ process.exit(1);
32
+ }
33
+
34
+ function write(msg) {
35
+ process.stdout.write(JSON.stringify(msg) + "\n");
36
+ }
37
+
38
+ function callBridge(toolName, toolCallId, args) {
39
+ return new Promise((resolve, reject) => {
40
+ const body = JSON.stringify({ name: toolName, toolCallId, arguments: args ?? {} });
41
+ const url = new URL("/tool-call", bridgeUrl);
42
+ const req = http.request(
43
+ {
44
+ hostname: url.hostname,
45
+ port: url.port,
46
+ path: url.pathname,
47
+ method: "POST",
48
+ headers: {
49
+ "content-type": "application/json",
50
+ "content-length": Buffer.byteLength(body),
51
+ ...(bridgeToken ? { authorization: `Bearer ${bridgeToken}` } : {}),
52
+ },
53
+ timeout: 120_000,
54
+ },
55
+ (res) => {
56
+ let data = "";
57
+ res.on("data", (chunk) => {
58
+ data += chunk;
59
+ });
60
+ res.on("end", () => {
61
+ // A non-2xx bridge response is a transport failure, not a tool result:
62
+ // surface it as an error instead of fabricating an empty "success".
63
+ if (res.statusCode < 200 || res.statusCode >= 300) {
64
+ reject(new Error(`tool bridge responded ${res.statusCode}: ${data.slice(0, 200)}`));
65
+ return;
66
+ }
67
+ try {
68
+ resolve(JSON.parse(data || "{}"));
69
+ } catch (err) {
70
+ reject(err);
71
+ }
72
+ });
73
+ },
74
+ );
75
+ req.on("error", reject);
76
+ req.on("timeout", () => {
77
+ req.destroy(new Error("tool bridge timeout"));
78
+ });
79
+ req.write(body);
80
+ req.end();
81
+ });
82
+ }
83
+
84
+ const rl = readline.createInterface({ input: process.stdin });
85
+ rl.on("line", (line) => {
86
+ let msg;
87
+ try {
88
+ msg = JSON.parse(line);
89
+ } catch {
90
+ return;
91
+ }
92
+
93
+ if (msg.method === "initialize") {
94
+ write({
95
+ jsonrpc: "2.0",
96
+ id: msg.id,
97
+ result: {
98
+ protocolVersion: "2024-11-05",
99
+ capabilities: { tools: {} },
100
+ serverInfo: { name: "fusion-custom-tools", version: "1.0.0" },
101
+ },
102
+ });
103
+ return;
104
+ }
105
+
106
+ // Ping must answer: some clients (Hermes ACP) treat a missing handler as a
107
+ // method-not-found and back off.
108
+ if (msg.method === "ping") {
109
+ write({ jsonrpc: "2.0", id: msg.id, result: {} });
110
+ return;
111
+ }
112
+
113
+ if (msg.method === "notifications/initialized" || msg.method === "initialized") {
114
+ return;
115
+ }
116
+
117
+ if (msg.method === "tools/list") {
118
+ write({
119
+ jsonrpc: "2.0",
120
+ id: msg.id,
121
+ result: {
122
+ tools: tools.map((tool) => ({
123
+ name: tool.name,
124
+ description: tool.description ?? "",
125
+ inputSchema: tool.inputSchema ?? { type: "object", properties: {} },
126
+ })),
127
+ },
128
+ });
129
+ return;
130
+ }
131
+
132
+ if (msg.method === "tools/call") {
133
+ const toolName = msg.params?.name;
134
+ const args = msg.params?.arguments ?? {};
135
+ // JSON-RPC ids are commonly numbers; coerce so the bridge threads the real
136
+ // request id as the toolCallId instead of falling back to a fabricated id.
137
+ const toolCallId = typeof msg.id === "string" ? msg.id : String(msg.id);
138
+ callBridge(toolName, toolCallId, args)
139
+ .then((result) => {
140
+ write({
141
+ jsonrpc: "2.0",
142
+ id: msg.id,
143
+ result: {
144
+ content: Array.isArray(result.content)
145
+ ? result.content
146
+ : [{ type: "text", text: typeof result.text === "string" ? result.text : JSON.stringify(result) }],
147
+ isError: result.isError === true,
148
+ },
149
+ });
150
+ })
151
+ .catch((err) => {
152
+ write({
153
+ jsonrpc: "2.0",
154
+ id: msg.id,
155
+ result: {
156
+ content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }],
157
+ isError: true,
158
+ },
159
+ });
160
+ });
161
+ return;
162
+ }
163
+
164
+ if (msg.id !== undefined) {
165
+ write({
166
+ jsonrpc: "2.0",
167
+ id: msg.id,
168
+ error: { code: -32601, message: `Method not found: ${msg.method}` },
169
+ });
170
+ }
171
+ });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/acp-runtime",
3
- "version": "0.1.36-beta.1",
3
+ "version": "0.1.36-beta.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -16113,6 +16113,7 @@ function applyPromptOverridesToIr(ir, overrides) {
16113
16113
  function defaultCodingWorkflowIr() {
16114
16114
  return resolveDefaultWorkflowIr();
16115
16115
  }
16116
+ var inflightSelectionReads = /* @__PURE__ */ new WeakMap();
16116
16117
  async function resolveWorkflowIrById(store, workflowId, irCache) {
16117
16118
  let projectId;
16118
16119
  try {
@@ -16156,8 +16157,34 @@ function didFallBackToDefault(ir) {
16156
16157
  async function resolveWorkflowIrForTaskWithProvenance(store, taskId, irCache, selectionCache) {
16157
16158
  let workflowId;
16158
16159
  try {
16159
- const selection = selectionCache?.has(taskId) ? selectionCache.get(taskId) : store.getTaskWorkflowSelectionAsync ? await store.getTaskWorkflowSelectionAsync(taskId) : store.getTaskWorkflowSelection(taskId);
16160
- if (!selectionCache?.has(taskId)) selectionCache?.set(taskId, selection);
16160
+ const isSelectionCached = selectionCache?.has(taskId) ?? false;
16161
+ let selection = isSelectionCached && selectionCache ? selectionCache.get(taskId) : void 0;
16162
+ if (!isSelectionCached) {
16163
+ let inflight;
16164
+ let coalesced = false;
16165
+ if (selectionCache) {
16166
+ inflight = inflightSelectionReads.get(selectionCache);
16167
+ if (!inflight) {
16168
+ inflight = /* @__PURE__ */ new Map();
16169
+ inflightSelectionReads.set(selectionCache, inflight);
16170
+ }
16171
+ const pending = inflight.get(taskId);
16172
+ if (pending) {
16173
+ selection = await pending;
16174
+ coalesced = true;
16175
+ }
16176
+ }
16177
+ if (!coalesced) {
16178
+ const readPromise = store.getTaskWorkflowSelectionAsync ? store.getTaskWorkflowSelectionAsync(taskId) : Promise.resolve(store.getTaskWorkflowSelection(taskId));
16179
+ if (inflight) inflight.set(taskId, readPromise);
16180
+ try {
16181
+ selection = await readPromise;
16182
+ } finally {
16183
+ inflight?.delete(taskId);
16184
+ }
16185
+ }
16186
+ selectionCache?.set(taskId, selection);
16187
+ }
16161
16188
  workflowId = selection?.workflowId;
16162
16189
  } catch {
16163
16190
  return { ir: defaultCodingWorkflowIr(), source: "default" };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/claude-runtime",
3
- "version": "0.1.11-beta.1",
3
+ "version": "0.1.11-beta.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {