@runfusion/fusion 0.75.1-beta.0 → 0.75.1-beta.1

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 (132) hide show
  1. package/dist/bin.js +259 -76
  2. package/dist/child-process-worker.js +185 -61
  3. package/dist/client/.vite/manifest.json +248 -248
  4. package/dist/client/assets/{AgentDetailView-swTdiyeE.js → AgentDetailView-CE_7nvDT.js} +1 -1
  5. package/dist/client/assets/{AgentPermissionPolicyEditor-Dq-KuDaA.js → AgentPermissionPolicyEditor-DYr3dk5X.js} +1 -1
  6. package/dist/client/assets/{AgentsView-D1GEHyH0.js → AgentsView-DZoYoiaD.js} +3 -3
  7. package/dist/client/assets/{ChatView-D1czGvvT.js → ChatView-BE9zMzYZ.js} +1 -1
  8. package/dist/client/assets/{CommandCenter-DWZ7OTOB.js → CommandCenter-DnLsp4_S.js} +1 -1
  9. package/dist/client/assets/{DevServerView-CAcUKOXd.js → DevServerView-CI-3j-lH.js} +1 -1
  10. package/dist/client/assets/{DirectoryPicker-DVUl5jOk.js → DirectoryPicker-D1ADu0Av.js} +1 -1
  11. package/dist/client/assets/{DocumentsView-CnexOxtr.js → DocumentsView-CF8y1gob.js} +1 -1
  12. package/dist/client/assets/{EvalsView-rTupzcDf.js → EvalsView-C9vLiM2_.js} +1 -1
  13. package/dist/client/assets/{ExperimentalAgentOnboardingModal-CXE6Bj3V.js → ExperimentalAgentOnboardingModal-CX_2Hjh0.js} +1 -1
  14. package/dist/client/assets/{GoalsView-CjHwnnIi.js → GoalsView-DJIA3k8q.js} +1 -1
  15. package/dist/client/assets/{InsightsView-C3XocYP-.js → InsightsView--TCeutLO.js} +1 -1
  16. package/dist/client/assets/{MemoryView-CsNHcx_d.js → MemoryView-Btp4m7pK.js} +1 -1
  17. package/dist/client/assets/{PiExtensionsManager-BPTPoZBI.js → PiExtensionsManager-DXdfh-Uf.js} +1 -1
  18. package/dist/client/assets/{PluginManager-CXadn8JE.js → PluginManager-BDFelFY6.js} +1 -1
  19. package/dist/client/assets/{PullRequestView-CC03CtZJ.js → PullRequestView-TSNKGSAg.js} +1 -1
  20. package/dist/client/assets/{ReportModal-Ci0na1eI.js → ReportModal-DhXMNHDL.js} +1 -1
  21. package/dist/client/assets/{ResearchView-DGWyAo8p.js → ResearchView-0w30HikQ.js} +1 -1
  22. package/dist/client/assets/{SecretsView-Cv2IuqFO.js → SecretsView-DgMu7279.js} +1 -1
  23. package/dist/client/assets/{SessionTerminal-B22RlQeo.js → SessionTerminal-CF6_uy2u.js} +1 -1
  24. package/dist/client/assets/{SettingsModal-BkgBQZ19.js → SettingsModal-BMAPX_7v.js} +1 -1
  25. package/dist/client/assets/{SettingsModal-CPRpRK71.js → SettingsModal-Dckls6LL.js} +3 -3
  26. package/dist/client/assets/{SettingsTextareaRow-0LXwMUQR.js → SettingsTextareaRow-LqXxpJl5.js} +1 -1
  27. package/dist/client/assets/{SetupWizardModal-CyW3AlRO.js → SetupWizardModal-D1ZvGOcK.js} +2 -2
  28. package/dist/client/assets/{SkillsView-3oqB1ubq.js → SkillsView-CfO5B7SO.js} +1 -1
  29. package/dist/client/assets/{WorkflowNodeEditor-CfUK_xs1.js → WorkflowNodeEditor-CjdK9fFS.js} +3 -3
  30. package/dist/client/assets/{agent-import-generation-C7-Cmo3M.js → agent-import-generation-DqTzyLOZ.js} +1 -1
  31. package/dist/client/assets/{architectureDiagram-3BPJPVTR-BQ7ZN1r_.js → architectureDiagram-3BPJPVTR-CHkolL_b.js} +1 -1
  32. package/dist/client/assets/{blockDiagram-GPEHLZMM-Debw1Xka.js → blockDiagram-GPEHLZMM-BFRYQi8H.js} +1 -1
  33. package/dist/client/assets/{c4Diagram-AAUBKEIU-CiU212s3.js → c4Diagram-AAUBKEIU-D9mMEYbR.js} +1 -1
  34. package/dist/client/assets/channel-CLdamWm5.js +1 -0
  35. package/dist/client/assets/{chunk-2J33WTMH-BUJQ86zb.js → chunk-2J33WTMH-CCv6QaQn.js} +1 -1
  36. package/dist/client/assets/{chunk-4BX2VUAB-C6GdEm1z.js → chunk-4BX2VUAB-Bfe22y5T.js} +1 -1
  37. package/dist/client/assets/{chunk-55IACEB6-CImvrxQL.js → chunk-55IACEB6-CwicrA9V.js} +1 -1
  38. package/dist/client/assets/{chunk-727SXJPM-Dt-A3pkM.js → chunk-727SXJPM-DlIpTC03.js} +1 -1
  39. package/dist/client/assets/{chunk-AQP2D5EJ-DDj4oXTx.js → chunk-AQP2D5EJ-CRX4mFVq.js} +1 -1
  40. package/dist/client/assets/{chunk-FMBD7UC4-BD4r1ukC.js → chunk-FMBD7UC4-DzG-bovU.js} +1 -1
  41. package/dist/client/assets/{chunk-ND2GUHAM-DFSteefi.js → chunk-ND2GUHAM-D5F2jtpM.js} +1 -1
  42. package/dist/client/assets/{chunk-QZHKN3VN-t2zF8tjB.js → chunk-QZHKN3VN-BmSaCwG6.js} +1 -1
  43. package/dist/client/assets/classDiagram-4FO5ZUOK-BYWknNX0.js +1 -0
  44. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BYWknNX0.js +1 -0
  45. package/dist/client/assets/{cose-bilkent-S5V4N54A-tkvDkXQA.js → cose-bilkent-S5V4N54A-BbKTljui.js} +1 -1
  46. package/dist/client/assets/{dagre-BM42HDAG-DD2rW7wo.js → dagre-BM42HDAG-u0hwXb_T.js} +1 -1
  47. package/dist/client/assets/{dashboard-view-B1vduc8x.js → dashboard-view-BfYZZ9Ms.js} +1 -1
  48. package/dist/client/assets/{dashboard-view-DruCruAc.js → dashboard-view-BjPZG2Fv.js} +1 -1
  49. package/dist/client/assets/{dashboard-view-CciuDS5A.js → dashboard-view-faKSXA4_.js} +1 -1
  50. package/dist/client/assets/{dashboard-view-C7jJ1lA4.js → dashboard-view-oCjWDGbW.js} +1 -1
  51. package/dist/client/assets/{diagram-2AECGRRQ-DASuxGNc.js → diagram-2AECGRRQ-Q7towbBl.js} +1 -1
  52. package/dist/client/assets/{diagram-5GNKFQAL-f9WtiIUk.js → diagram-5GNKFQAL-UAwBmAxb.js} +1 -1
  53. package/dist/client/assets/{diagram-KO2AKTUF-QivICYCd.js → diagram-KO2AKTUF-BL1n0pkf.js} +1 -1
  54. package/dist/client/assets/{diagram-LMA3HP47-CMwcDFHR.js → diagram-LMA3HP47-O-v_IZUJ.js} +1 -1
  55. package/dist/client/assets/{diagram-OG6HWLK6-C-vPMeHZ.js → diagram-OG6HWLK6-CAYSE2Mz.js} +1 -1
  56. package/dist/client/assets/{erDiagram-TEJ5UH35-CxGtk9vj.js → erDiagram-TEJ5UH35-Cr_DgCyp.js} +1 -1
  57. package/dist/client/assets/{flowDiagram-I6XJVG4X-qBZRZoV1.js → flowDiagram-I6XJVG4X-TdLzHKPW.js} +1 -1
  58. package/dist/client/assets/{folder-open-Dysi9Zzg.js → folder-open-BoddkTkv.js} +1 -1
  59. package/dist/client/assets/{ganttDiagram-6RSMTGT7-DAaXroiu.js → ganttDiagram-6RSMTGT7-CO1ErtJY.js} +1 -1
  60. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-DNUNQot_.js → gitGraphDiagram-PVQCEYII-C8_Kx0Yh.js} +1 -1
  61. package/dist/client/assets/index-C7KY0q8Q.js +2767 -0
  62. package/dist/client/assets/{infoDiagram-5YYISTIA-BSJmWLwh.js → infoDiagram-5YYISTIA-Dd6Zo7Dh.js} +1 -1
  63. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-AyVKvoDq.js → ishikawaDiagram-YF4QCWOH-BE9JCLb5.js} +1 -1
  64. package/dist/client/assets/{journeyDiagram-JHISSGLW-972txzzd.js → journeyDiagram-JHISSGLW-B6RIZGDq.js} +1 -1
  65. package/dist/client/assets/{kanban-definition-UN3LZRKU-1xiNvIqK.js → kanban-definition-UN3LZRKU-CPXff-h-.js} +1 -1
  66. package/dist/client/assets/{mermaid.core-oeDA8jOm.js → mermaid.core-CbGj7iEw.js} +4 -4
  67. package/dist/client/assets/{mindmap-definition-RKZ34NQL-DcktmI8s.js → mindmap-definition-RKZ34NQL-DF5LZmsH.js} +1 -1
  68. package/dist/client/assets/{pieDiagram-4H26LBE5-ekBwLt-O.js → pieDiagram-4H26LBE5-Dpy0Xm9T.js} +1 -1
  69. package/dist/client/assets/{puzzle-I6pr6ZrW.js → puzzle-BZa4U8-N.js} +1 -1
  70. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-D_wjTsvn.js → quadrantDiagram-W4KKPZXB-BTLAQFpz.js} +1 -1
  71. package/dist/client/assets/{requirementDiagram-4Y6WPE33-CKGHyiJ1.js → requirementDiagram-4Y6WPE33-DSUV9ySs.js} +1 -1
  72. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-CtiZFNk5.js → sankeyDiagram-5OEKKPKP-Fmfn0XDL.js} +1 -1
  73. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-B6OMrfGk.js → sequenceDiagram-3UESZ5HK-_343I_b4.js} +1 -1
  74. package/dist/client/assets/{shield-alert-CVMmviMG.js → shield-alert-CdJ55UvI.js} +1 -1
  75. package/dist/client/assets/{standing-instructions-template-Cg1a3tjW.js → standing-instructions-template-r03dZ5Z0.js} +1 -1
  76. package/dist/client/assets/{stateDiagram-AJRCARHV-CyTY2M_7.js → stateDiagram-AJRCARHV-C9EbWegm.js} +1 -1
  77. package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-NWPCCiqC.js → stateDiagram-v2-BHNVJYJU-Bmh2GRh6.js} +1 -1
  78. package/dist/client/assets/{timeline-definition-PNZ67QCA-DU4TVYpw.js → timeline-definition-PNZ67QCA-q86S9wyl.js} +1 -1
  79. package/dist/client/assets/{upload-VCzeCiFH.js → upload-DS9-qtCF.js} +1 -1
  80. package/dist/client/assets/{users-DB3knZtm.js → users-DP5Sngeg.js} +1 -1
  81. package/dist/client/assets/{vennDiagram-CIIHVFJN-DX0Ppll6.js → vennDiagram-CIIHVFJN-BFq8uIt3.js} +1 -1
  82. package/dist/client/assets/{wardley-L42UT6IY-CBoWxpDv.js → wardley-L42UT6IY-BL_sLGYI.js} +1 -1
  83. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-B_eVqdhC.js → wardleyDiagram-YWT4CUSO-BEKJJ9Vi.js} +1 -1
  84. package/dist/client/assets/{xychartDiagram-2RQKCTM6-DeZzEX0f.js → xychartDiagram-2RQKCTM6-DsvFnlxK.js} +1 -1
  85. package/dist/client/index.html +1 -1
  86. package/dist/client/version.json +1 -1
  87. package/dist/droid-cli/package.json +1 -1
  88. package/dist/extension.js +186 -62
  89. package/dist/pi-claude-cli/package.json +1 -1
  90. package/dist/plugin-sdk/index.d.ts +157 -140
  91. package/dist/plugin-sdk/index.js +19 -0
  92. package/dist/plugins/fusion-plugin-acp-runtime/bundled.js +19 -0
  93. package/dist/plugins/fusion-plugin-acp-runtime/package.json +1 -1
  94. package/dist/plugins/fusion-plugin-claude-runtime/bundled.js +19 -0
  95. package/dist/plugins/fusion-plugin-claude-runtime/package.json +1 -1
  96. package/dist/plugins/fusion-plugin-cli-printing-press/bundled.js +19 -0
  97. package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
  98. package/dist/plugins/fusion-plugin-compound-engineering/bundled.js +19 -0
  99. package/dist/plugins/fusion-plugin-compound-engineering/package.json +1 -1
  100. package/dist/plugins/fusion-plugin-cursor-runtime/bundled.js +19 -0
  101. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
  102. package/dist/plugins/fusion-plugin-dependency-graph/bundled.js +19 -0
  103. package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
  104. package/dist/plugins/fusion-plugin-droid-runtime/bundled.js +19 -0
  105. package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
  106. package/dist/plugins/fusion-plugin-grok-runtime/bundled.js +19 -0
  107. package/dist/plugins/fusion-plugin-grok-runtime/package.json +1 -1
  108. package/dist/plugins/fusion-plugin-hermes-runtime/bundled.js +19 -0
  109. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  110. package/dist/plugins/fusion-plugin-linear-import/bundled.js +19 -0
  111. package/dist/plugins/fusion-plugin-linear-import/package.json +1 -1
  112. package/dist/plugins/fusion-plugin-omp-runtime/bundled.js +19 -0
  113. package/dist/plugins/fusion-plugin-omp-runtime/package.json +1 -1
  114. package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +19 -0
  115. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  116. package/dist/plugins/fusion-plugin-paperclip-runtime/bundled.js +19 -0
  117. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  118. package/dist/plugins/fusion-plugin-quality/bundled.js +19 -0
  119. package/dist/plugins/fusion-plugin-quality/package.json +1 -1
  120. package/dist/plugins/fusion-plugin-reports/bundled.js +19 -0
  121. package/dist/plugins/fusion-plugin-reports/package.json +1 -1
  122. package/dist/plugins/fusion-plugin-roadmap/bundled.js +19 -0
  123. package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
  124. package/dist/plugins/fusion-plugin-todos/bundled.js +19 -0
  125. package/dist/plugins/fusion-plugin-todos/package.json +1 -1
  126. package/dist/plugins/fusion-plugin-whatsapp-chat/bundled.js +19 -0
  127. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
  128. package/package.json +1 -1
  129. package/dist/client/assets/channel-D-O4mRXx.js +0 -1
  130. package/dist/client/assets/classDiagram-4FO5ZUOK-BhHdSetA.js +0 -1
  131. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BhHdSetA.js +0 -1
  132. package/dist/client/assets/index-D0QgE5F5.js +0 -2767
package/dist/extension.js CHANGED
@@ -9968,6 +9968,7 @@ function validateForeach(node, topLevelNodeIds, columnIds) {
9968
9968
  );
9969
9969
  }
9970
9970
  for (const inner of templateNodes) {
9971
+ validateReviewKind(inner, "nested");
9971
9972
  if (inner.kind === "foreach" || inner.kind === "loop") {
9972
9973
  throw new WorkflowIrError(
9973
9974
  `foreach node '${node.id}' template may not contain nested loop/foreach ('${inner.id}')`
@@ -10086,6 +10087,7 @@ function validateLoop(node, topLevelNodeIds, columnIds) {
10086
10087
  );
10087
10088
  }
10088
10089
  for (const inner of templateNodes) {
10090
+ validateReviewKind(inner, "nested");
10089
10091
  if (inner.kind === "loop" || inner.kind === "foreach") {
10090
10092
  throw new WorkflowIrError(
10091
10093
  `loop node '${node.id}' template may not contain nested loop/foreach ('${inner.id}')`
@@ -10179,6 +10181,7 @@ function validateOptionalGroup(node, topLevelNodeIds, columnIds) {
10179
10181
  throw new WorkflowIrError(`optional-group node '${node.id}' template has duplicate node ids`);
10180
10182
  }
10181
10183
  for (const inner of templateNodes) {
10184
+ validateReviewKind(inner, "nested");
10182
10185
  if (inner.kind === "loop" || inner.kind === "foreach" || inner.kind === "optional-group") {
10183
10186
  throw new WorkflowIrError(
10184
10187
  `optional-group node '${node.id}' template may not contain nested loop/foreach/optional-group ('${inner.id}')`
@@ -10850,6 +10853,19 @@ function validateColumnRecovery(column) {
10850
10853
  );
10851
10854
  }
10852
10855
  }
10856
+ function validateReviewKind(node, placement) {
10857
+ const value = node.config?.reviewKind;
10858
+ if (value === void 0) return;
10859
+ if (value !== "plan" && value !== "code") {
10860
+ throw new WorkflowIrError(`Workflow node '${node.id}' has invalid reviewKind '${String(value)}'; expected 'plan' or 'code'`);
10861
+ }
10862
+ if (placement === "nested") {
10863
+ throw new WorkflowIrError(`Workflow node '${node.id}' has reviewKind in an unsupported nested template placement`);
10864
+ }
10865
+ if (node.kind !== "prompt" && node.kind !== "gate" && node.kind !== "script" && node.kind !== "optional-group") {
10866
+ throw new WorkflowIrError(`Workflow node '${node.id}' has reviewKind on unsupported node kind '${node.kind}'`);
10867
+ }
10868
+ }
10853
10869
  function validateV2(ir2) {
10854
10870
  validateColumns(ir2);
10855
10871
  for (const [index2, column] of ir2.columns.entries()) {
@@ -10872,6 +10888,7 @@ function validateV2(ir2) {
10872
10888
  }
10873
10889
  const nodesById = new Map(ir2.nodes.map((n) => [n.id, n]));
10874
10890
  for (const node of ir2.nodes) {
10891
+ validateReviewKind(node, "top-level");
10875
10892
  validateExtensionMetadata(`Workflow node '${node.id}'`, node.extensions);
10876
10893
  if (node.column !== void 0 && !columnIds.has(node.column)) {
10877
10894
  throw new WorkflowIrError(
@@ -13335,6 +13352,7 @@ function codeReviewOptionalGroupNode(column, options = {}) {
13335
13352
  column,
13336
13353
  config: {
13337
13354
  name: CODE_REVIEW_NAME,
13355
+ reviewKind: "code",
13338
13356
  // Default-ON: runs for every coding task by default, but operators can toggle it
13339
13357
  // off per task (remove `code-review` from enabledWorkflowSteps).
13340
13358
  defaultOn: options.defaultOn ?? true,
@@ -13480,6 +13498,7 @@ function planReviewOptionalGroupNode(column, options = {}) {
13480
13498
  ...column ? { column } : {},
13481
13499
  config: {
13482
13500
  name: PLAN_REVIEW_NAME,
13501
+ reviewKind: "plan",
13483
13502
  defaultOn: options.defaultOn ?? true,
13484
13503
  /*
13485
13504
  * FNXC:WorkflowRemediation 2026-06-29-12:14:
@@ -127080,6 +127099,36 @@ var init_async_knowledge = __esm({
127080
127099
  });
127081
127100
 
127082
127101
  // ../core/src/workflows/workflow-step-results.ts
127102
+ function normalizeWorkflowReviewFindings(raw) {
127103
+ if (!Array.isArray(raw)) return void 0;
127104
+ const normalized = [];
127105
+ const usedIds = /* @__PURE__ */ new Set();
127106
+ for (const candidate of raw) {
127107
+ if (normalized.length >= MAX_WORKFLOW_REVIEW_FINDINGS || !candidate || typeof candidate !== "object") continue;
127108
+ const value = candidate;
127109
+ const title = boundedTrimmedString(value.title, MAX_FINDING_TITLE_LENGTH);
127110
+ const body = boundedTrimmedString(value.body, MAX_FINDING_BODY_LENGTH);
127111
+ if (!title || !body) continue;
127112
+ const baseId = boundedTrimmedString(value.id, MAX_FINDING_ID_LENGTH) || `finding-${normalized.length + 1}`;
127113
+ let id = baseId;
127114
+ let suffix = 2;
127115
+ while (usedIds.has(id)) id = `${baseId.slice(0, Math.max(1, MAX_FINDING_ID_LENGTH - String(suffix).length - 1))}-${suffix++}`;
127116
+ usedIds.add(id);
127117
+ const filePath = boundedTrimmedString(value.filePath, MAX_FINDING_PATH_LENGTH);
127118
+ const line2 = typeof value.line === "number" && Number.isFinite(value.line) && value.line > 0 ? Math.floor(value.line) : void 0;
127119
+ const severity = isWorkflowReviewFindingSeverity(value.severity) ? value.severity : void 0;
127120
+ normalized.push({ id, title, body, ...filePath ? { filePath } : {}, ...line2 ? { line: line2 } : {}, ...severity ? { severity } : {} });
127121
+ }
127122
+ return normalized.length > 0 ? normalized : void 0;
127123
+ }
127124
+ function boundedTrimmedString(value, maxLength) {
127125
+ if (typeof value !== "string") return void 0;
127126
+ const trimmed = value.trim();
127127
+ return trimmed && trimmed.length <= maxLength ? trimmed : void 0;
127128
+ }
127129
+ function isWorkflowReviewFindingSeverity(value) {
127130
+ return typeof value === "string" && WORKFLOW_REVIEW_FINDING_SEVERITIES.includes(value);
127131
+ }
127083
127132
  function isTerminalFailure(result2) {
127084
127133
  return TERMINAL_FAILURE_STATUSES.has(result2.status);
127085
127134
  }
@@ -127145,10 +127194,16 @@ function makeReviewLeaseRecord(args) {
127145
127194
  leaseOwner: args.owner
127146
127195
  };
127147
127196
  }
127148
- var MAX_WORKFLOW_STEP_PRIOR_ATTEMPTS, TERMINAL_FAILURE_STATUSES, PLAN_REVIEW_LEASE_STALENESS_MS, TERMINAL_STEP_STATUSES;
127197
+ var WORKFLOW_REVIEW_FINDING_SEVERITIES, MAX_WORKFLOW_REVIEW_FINDINGS, MAX_FINDING_ID_LENGTH, MAX_FINDING_TITLE_LENGTH, MAX_FINDING_BODY_LENGTH, MAX_FINDING_PATH_LENGTH, MAX_WORKFLOW_STEP_PRIOR_ATTEMPTS, TERMINAL_FAILURE_STATUSES, PLAN_REVIEW_LEASE_STALENESS_MS, TERMINAL_STEP_STATUSES;
127149
127198
  var init_workflow_step_results = __esm({
127150
127199
  "../core/src/workflows/workflow-step-results.ts"() {
127151
127200
  "use strict";
127201
+ WORKFLOW_REVIEW_FINDING_SEVERITIES = ["low", "medium", "high", "critical"];
127202
+ MAX_WORKFLOW_REVIEW_FINDINGS = 20;
127203
+ MAX_FINDING_ID_LENGTH = 128;
127204
+ MAX_FINDING_TITLE_LENGTH = 240;
127205
+ MAX_FINDING_BODY_LENGTH = 4e3;
127206
+ MAX_FINDING_PATH_LENGTH = 1e3;
127152
127207
  MAX_WORKFLOW_STEP_PRIOR_ATTEMPTS = 5;
127153
127208
  TERMINAL_FAILURE_STATUSES = /* @__PURE__ */ new Set([
127154
127209
  "failed",
@@ -127635,6 +127690,7 @@ __export(src_exports, {
127635
127690
  MAX_TITLE_LENGTH: () => MAX_TITLE_LENGTH,
127636
127691
  MAX_TITLE_SUMMARIZE_INPUT_LENGTH: () => MAX_TITLE_SUMMARIZE_INPUT_LENGTH,
127637
127692
  MAX_WORKFLOW_ICON_LENGTH: () => MAX_WORKFLOW_ICON_LENGTH,
127693
+ MAX_WORKFLOW_REVIEW_FINDINGS: () => MAX_WORKFLOW_REVIEW_FINDINGS,
127638
127694
  MAX_WORKFLOW_STEP_PRIOR_ATTEMPTS: () => MAX_WORKFLOW_STEP_PRIOR_ATTEMPTS,
127639
127695
  MEMORY_AUDIT_PATH: () => MEMORY_AUDIT_PATH,
127640
127696
  MEMORY_BACKEND_SETTINGS_KEYS: () => MEMORY_BACKEND_SETTINGS_KEYS,
@@ -127836,6 +127892,7 @@ __export(src_exports, {
127836
127892
  WAKE_DELTA_ASSIGNED_TASKS_CAP: () => WAKE_DELTA_ASSIGNED_TASKS_CAP,
127837
127893
  WEDGE_RENOTIFY_COOLDOWN_MS: () => WEDGE_RENOTIFY_COOLDOWN_MS,
127838
127894
  WORKFLOW_EXTENSION_SCHEMA_VERSION: () => WORKFLOW_EXTENSION_SCHEMA_VERSION,
127895
+ WORKFLOW_REVIEW_FINDING_SEVERITIES: () => WORKFLOW_REVIEW_FINDING_SEVERITIES,
127839
127896
  WORKFLOW_SETTING_REJECTION_CODES: () => WORKFLOW_SETTING_REJECTION_CODES,
127840
127897
  WORKFLOW_SETTING_TYPES: () => WORKFLOW_SETTING_TYPES,
127841
127898
  WORKFLOW_WORK_ITEM_KINDS: () => WORKFLOW_WORK_ITEM_KINDS,
@@ -128363,6 +128420,7 @@ __export(src_exports, {
128363
128420
  isWipColumn: () => isWipColumn,
128364
128421
  isWipColumnRole: () => isWipColumnRole,
128365
128422
  isWorkflowOptionalGroupEnabled: () => isWorkflowOptionalGroupEnabled,
128423
+ isWorkflowReviewFindingSeverity: () => isWorkflowReviewFindingSeverity,
128366
128424
  isWorkspaceTask: () => isWorkspaceTask,
128367
128425
  layoutForIr: () => layoutForIr,
128368
128426
  listActiveAiSessions: () => listActiveAiSessions,
@@ -128436,6 +128494,7 @@ __export(src_exports, {
128436
128494
  normalizeValidationDiagnostics: () => normalizeValidationDiagnostics,
128437
128495
  normalizeWorkflowIcon: () => normalizeWorkflowIcon,
128438
128496
  normalizeWorkflowPromptOverrides: () => normalizeWorkflowPromptOverrides,
128497
+ normalizeWorkflowReviewFindings: () => normalizeWorkflowReviewFindings,
128439
128498
  notifyOperatorOfNonOperatorDelete: () => notifyOperatorOfNonOperatorDelete,
128440
128499
  overseerAdviceSeverityRank: () => overseerAdviceSeverityRank,
128441
128500
  parseAgentManifest: () => parseAgentManifest,
@@ -173094,37 +173153,6 @@ var init_effective_settings = __esm({
173094
173153
  }
173095
173154
  });
173096
173155
 
173097
- // ../engine/src/errors/transient-merge-error-classifier.ts
173098
- function classifyTransientMergeError(error3) {
173099
- if (!error3) return null;
173100
- if (/lease-handoff-failed[^a-z]+target-not-queued/i.test(error3)) {
173101
- return "lease-handoff-target-not-queued";
173102
- }
173103
- if (/\bACP turn failed\b/i.test(error3) || /\bacp rpc code -32(?:603|00[0-3])\b/i.test(error3)) {
173104
- return "ai-provider-turn-failure";
173105
- }
173106
- if (/\bspawn(?:\s+\S+)?\s+ENO(?:TDIR|ENT)\b/i.test(error3)) {
173107
- return "process-spawn-failure";
173108
- }
173109
- if (/\bis not a working tree\b/i.test(error3)) {
173110
- return "process-spawn-failure";
173111
- }
173112
- const sameSha = error3.match(/advanced concurrently \(expected ([0-9a-f]{7,40}),\s+observed ([0-9a-f]{7,40})\)/i);
173113
- if (sameSha && sameSha[1].toLowerCase() === sameSha[2].toLowerCase()) {
173114
- return "spurious-concurrent-advance-same-sha";
173115
- }
173116
- if (isTransientError(error3)) {
173117
- return "network-transport-failure";
173118
- }
173119
- return null;
173120
- }
173121
- var init_transient_merge_error_classifier = __esm({
173122
- "../engine/src/errors/transient-merge-error-classifier.ts"() {
173123
- "use strict";
173124
- init_transient_error_patterns();
173125
- }
173126
- });
173127
-
173128
173156
  // ../engine/src/notification/ntfy-provider.ts
173129
173157
  function resolveParticipantLabel(metadata, kind) {
173130
173158
  const nameKey = kind === "from" ? "fromName" : "toName";
@@ -173598,7 +173626,50 @@ var init_webhook_provider = __esm({
173598
173626
  }
173599
173627
  });
173600
173628
 
173629
+ // ../engine/src/errors/transient-merge-error-classifier.ts
173630
+ function classifyTransientMergeError(error3) {
173631
+ if (!error3) return null;
173632
+ if (/lease-handoff-failed[^a-z]+target-not-queued/i.test(error3)) {
173633
+ return "lease-handoff-target-not-queued";
173634
+ }
173635
+ if (/\bACP turn failed\b/i.test(error3) || /\bacp rpc code -32(?:603|00[0-3])\b/i.test(error3)) {
173636
+ return "ai-provider-turn-failure";
173637
+ }
173638
+ if (/\bspawn(?:\s+\S+)?\s+ENO(?:TDIR|ENT)\b/i.test(error3)) {
173639
+ return "process-spawn-failure";
173640
+ }
173641
+ if (/\bis not a working tree\b/i.test(error3)) {
173642
+ return "process-spawn-failure";
173643
+ }
173644
+ const sameSha = error3.match(/advanced concurrently \(expected ([0-9a-f]{7,40}),\s+observed ([0-9a-f]{7,40})\)/i);
173645
+ if (sameSha && sameSha[1].toLowerCase() === sameSha[2].toLowerCase()) {
173646
+ return "spurious-concurrent-advance-same-sha";
173647
+ }
173648
+ if (isTransientError(error3)) {
173649
+ return "network-transport-failure";
173650
+ }
173651
+ return null;
173652
+ }
173653
+ function hasTransientMergeRecoveryOwner(task) {
173654
+ return classifyTransientMergeError(task.error) !== null && typeof task.mergeTransientRetryCount === "number" && Number.isInteger(task.mergeTransientRetryCount) && task.mergeTransientRetryCount >= 0 && task.mergeTransientRetryCount < MAX_AUTO_MERGE_TRANSIENT_RETRIES;
173655
+ }
173656
+ var MAX_AUTO_MERGE_TRANSIENT_RETRIES;
173657
+ var init_transient_merge_error_classifier = __esm({
173658
+ "../engine/src/errors/transient-merge-error-classifier.ts"() {
173659
+ "use strict";
173660
+ init_transient_error_patterns();
173661
+ MAX_AUTO_MERGE_TRANSIENT_RETRIES = 5;
173662
+ }
173663
+ });
173664
+
173601
173665
  // ../engine/src/notification/task-wedge-notification.ts
173666
+ function describeTaskRecoveryOwner(task) {
173667
+ if (hasTransientMergeRecoveryOwner(task)) return { kind: "transient-merge-retry" };
173668
+ if (typeof task.recoveryRetryCount === "number" && Number.isInteger(task.recoveryRetryCount) && task.recoveryRetryCount >= 0 && typeof task.nextRecoveryAt === "string" && Number.isFinite(Date.parse(task.nextRecoveryAt))) {
173669
+ return { kind: "scheduled-recovery" };
173670
+ }
173671
+ return null;
173672
+ }
173602
173673
  function describeSelfHealingNoActionWedge(task, stage, metadata) {
173603
173674
  const description = SELF_HEALING_NO_ACTIONS[stage];
173604
173675
  if (!description || task.userPaused || task.paused || task.autoMerge === false) return null;
@@ -173656,6 +173727,7 @@ function describeTaskWedge(task) {
173656
173727
  if (/merge.*(?:blocked|verification|gate)|(?:verification|gate).*(?:failed|exhaust)/i.test(error3)) {
173657
173728
  return { reasonKey: "merge-blocked", reason: "Merge verification cannot progress without operator action.", action: "Fix the failing verification, then retry the task." };
173658
173729
  }
173730
+ if (describeTaskRecoveryOwner(task)) return null;
173659
173731
  if (!error3 && (task.mergeRetries ?? 0) < 3) return null;
173660
173732
  return {
173661
173733
  reasonKey: "terminal-failed",
@@ -173667,6 +173739,7 @@ var SELF_HEALING_NO_ACTIONS;
173667
173739
  var init_task_wedge_notification = __esm({
173668
173740
  "../engine/src/notification/task-wedge-notification.ts"() {
173669
173741
  "use strict";
173742
+ init_transient_merge_error_classifier();
173670
173743
  SELF_HEALING_NO_ACTIONS = {
173671
173744
  "reclaim-pr-conflict": {
173672
173745
  reason: "Self-healing could not reclaim a stalled pull-request conflict.",
@@ -173732,7 +173805,6 @@ var init_notification_service = __esm({
173732
173805
  init_src2();
173733
173806
  init_notifier();
173734
173807
  init_logger3();
173735
- init_transient_merge_error_classifier();
173736
173808
  init_ntfy_provider();
173737
173809
  init_webhook_provider();
173738
173810
  init_task_wedge_notification();
@@ -173958,10 +174030,10 @@ var init_notification_service = __esm({
173958
174030
  }
173959
174031
  }
173960
174032
  handleTaskUpdated = (task, meta2) => {
173961
- const transientFailure = task.status === "failed" ? classifyTransientMergeError(task.error) : null;
173962
- const wedge = transientFailure ? null : describeTaskWedge(task);
174033
+ const recoveryOwner = task.status === "failed" ? describeTaskRecoveryOwner(task) : null;
174034
+ const wedge = describeTaskWedge(task);
173963
174035
  if (wedge) this.cancelPendingFailureNotification(task.id, "classified-terminal-wedge");
173964
- if (!transientFailure) void this.enqueueWedgeHandling(task.id, () => this.maybeNotifyTaskWedge(task, wedge));
174036
+ void this.enqueueWedgeHandling(task.id, () => this.maybeNotifyTaskWedge(task, wedge));
173965
174037
  void this.maybeSuppressTransientFailedNotification(task, `status=${task.status ?? "undefined"}`);
173966
174038
  if (task.status === "awaiting-approval") {
173967
174039
  void this.writeAwaitingApprovalMailboxMessage(task);
@@ -173972,17 +174044,12 @@ var init_notification_service = __esm({
173972
174044
  if (!this.notificationsEnabled) {
173973
174045
  return;
173974
174046
  }
173975
- if (task.status === "failed" && !wedge) {
173976
- const transientClass = classifyTransientMergeError(task.error);
173977
- if (transientClass) {
173978
- this.failureNotificationSuppressedCount += 1;
173979
- schedulerLog.debug(
173980
- `[notify] ${task.id} transient merge failure (${transientClass}) \u2014 suppressed notification (self-heal in flight)`
173981
- );
173982
- return;
173983
- }
174047
+ if (task.status === "failed" && recoveryOwner) {
174048
+ this.failureNotificationSuppressedCount += 1;
174049
+ schedulerLog.debug(`[notify] ${task.id} recovery-owned failure \u2014 suppressed notification`);
174050
+ } else if (task.status === "failed" && !wedge) {
173984
174051
  if (this.failureNotificationMode === "all") {
173985
- this.maybeNotify(task.id, "failed", this.createTaskPayload(task, "failed"));
174052
+ void this.maybeNotifyImmediateFailure(task);
173986
174053
  } else {
173987
174054
  this.scheduleFailureNotification(task);
173988
174055
  }
@@ -174069,7 +174136,17 @@ var init_notification_service = __esm({
174069
174136
  await this.enqueueWedgeHandling(task.id, () => this.maybeNotifyTaskWedge(task, descriptor));
174070
174137
  }
174071
174138
  async maybeNotifyTaskWedge(task, suppliedDescriptor) {
174072
- const descriptor = suppliedDescriptor ?? describeTaskWedge(task);
174139
+ const liveTask = this.store.getTask ? await this.store.getTask(task.id) ?? task : task;
174140
+ const recoveryOwner = describeTaskRecoveryOwner(liveTask);
174141
+ if (recoveryOwner) {
174142
+ if (this.activeWedgeReasons.has(task.id) || liveTask.wedgeNotification?.status === "active") {
174143
+ this.activeWedgeReasons.delete(task.id);
174144
+ await this.store.claimTaskWedgeNotificationEpisode?.(task.id, null);
174145
+ }
174146
+ return;
174147
+ }
174148
+ const descriptor = suppliedDescriptor ?? describeTaskWedge(liveTask);
174149
+ task = liveTask;
174073
174150
  let episode;
174074
174151
  if (!descriptor) {
174075
174152
  const isActiveSelfHealingNoAction = task.wedgeNotification?.status === "active" && task.wedgeNotification.reasonKey.startsWith("self-healing-no-action:");
@@ -174436,6 +174513,14 @@ var init_notification_service = __esm({
174436
174513
  this.failureNotificationDelayMs = typeof settings.failureNotificationDelayMs === "number" && settings.failureNotificationDelayMs >= 0 ? settings.failureNotificationDelayMs : this.failedNotificationGraceMs;
174437
174514
  this.failureNotificationMode = settings.failureNotificationMode ?? "sticky-only";
174438
174515
  }
174516
+ async maybeNotifyImmediateFailure(task) {
174517
+ const liveTask = this.store.getTask ? await this.store.getTask(task.id) ?? task : task;
174518
+ if (liveTask.status !== "failed" || describeTaskRecoveryOwner(liveTask) || describeTaskWedge(liveTask)) {
174519
+ this.failureNotificationSuppressedCount += 1;
174520
+ return;
174521
+ }
174522
+ this.maybeNotify(liveTask.id, "failed", this.createTaskPayload(liveTask, "failed"));
174523
+ }
174439
174524
  scheduleFailureNotification(task) {
174440
174525
  if (this.pendingFailureNotifications.has(task.id)) {
174441
174526
  return;
@@ -174492,12 +174577,9 @@ var init_notification_service = __esm({
174492
174577
  schedulerLog.debug(`[notify] ${taskId} no longer failed at dispatch time \u2014 suppressed notification`);
174493
174578
  return;
174494
174579
  }
174495
- const transientClassAtDispatch = classifyTransientMergeError(task.error);
174496
- if (transientClassAtDispatch) {
174580
+ if (describeTaskRecoveryOwner(task)) {
174497
174581
  this.failureNotificationSuppressedCount += 1;
174498
- schedulerLog.debug(
174499
- `[notify] ${taskId} transient merge failure (${transientClassAtDispatch}) at dispatch time \u2014 suppressed notification (self-heal in flight)`
174500
- );
174582
+ schedulerLog.debug(`[notify] ${taskId} recovery-owned failure at dispatch time \u2014 suppressed notification`);
174501
174583
  return;
174502
174584
  }
174503
174585
  if (describeTaskWedge(task)) {
@@ -186152,10 +186234,21 @@ var init_scheduler = __esm({
186152
186234
  const unmetDeps = getUnmetSchedulingDependencies(task, tasks2, schedulingDependencyOptions);
186153
186235
  if (unmetDeps.length > 0) {
186154
186236
  const normalizedUnmetDeps = [...new Set(unmetDeps)].sort();
186237
+ let activeOverlapBlockedBy = null;
186238
+ if (activeScopes.size > 0) {
186239
+ try {
186240
+ const taskScope = await getFilteredFileScope(task.id);
186241
+ if (taskScope.length > 0 && !isCoordinationOnlyTask(task, taskScope)) {
186242
+ activeOverlapBlockedBy = Array.from(activeScopes.entries()).sort(([aId], [bId]) => aId.localeCompare(bId)).find(([, activeScope]) => this.pathsOverlap(taskScope, activeScope))?.[0] ?? null;
186243
+ }
186244
+ } catch (error3) {
186245
+ schedulerLog.warn(`Failed to refresh file-scope overlap blocker for dependency-blocked task ${task.id}`, error3);
186246
+ }
186247
+ }
186155
186248
  await this.transitionQueuedEpisode(task, {
186156
186249
  signature: `dependency:${normalizedUnmetDeps.join(",")}`,
186157
186250
  blockedBy: unmetDeps[0] ?? null,
186158
- overlapBlockedBy: task.overlapBlockedBy ?? null,
186251
+ overlapBlockedBy: activeOverlapBlockedBy,
186159
186252
  action: `queued \u2014 unmet dependencies: ${unmetDeps.join(", ")}`
186160
186253
  });
186161
186254
  this.options.onBlocked?.(task, unmetDeps);
@@ -217957,7 +218050,7 @@ function recoverPassedPlanReviewFromLatestLog(task) {
217957
218050
  completedAt: latest.timestamp
217958
218051
  };
217959
218052
  }
217960
- var PLAN_REVIEW_PROVIDER_FAILURE_HOLD_VALUE, PLAN_REVIEW_LEASE_HELD_VALUE, SESSION_CONTENTION_HOLD_VALUE, WORKFLOW_INTERRUPTED_NODE_ID_CONTEXT_KEY, WORKFLOW_INTERRUPTED_NODE_ABORT_KIND_CONTEXT_KEY, WORKFLOW_OPTIONAL_GROUP_CONTEXT_KEY, WORKFLOW_NODE_ENGINE_PAUSE_ABORT_KIND, WORKFLOW_DRIFT_PARK_CONTEXT_KEY, WorkflowGraphSuspended, MERGE_REGION_KINDS, WorkflowGraphExecutor;
218053
+ var PLAN_REVIEW_PROVIDER_FAILURE_HOLD_VALUE, PLAN_REVIEW_LEASE_HELD_VALUE, SESSION_CONTENTION_HOLD_VALUE, WORKFLOW_INTERRUPTED_NODE_ID_CONTEXT_KEY, WORKFLOW_INTERRUPTED_NODE_ABORT_KIND_CONTEXT_KEY, WORKFLOW_OPTIONAL_GROUP_CONTEXT_KEY, WORKFLOW_REVIEW_KIND_CONTEXT_KEY, WORKFLOW_NODE_ENGINE_PAUSE_ABORT_KIND, WORKFLOW_DRIFT_PARK_CONTEXT_KEY, WorkflowGraphSuspended, MERGE_REGION_KINDS, WorkflowGraphExecutor;
217961
218054
  var init_workflow_graph_executor = __esm({
217962
218055
  "../engine/src/workflows/workflow-graph-executor.ts"() {
217963
218056
  "use strict";
@@ -217977,6 +218070,7 @@ var init_workflow_graph_executor = __esm({
217977
218070
  WORKFLOW_INTERRUPTED_NODE_ID_CONTEXT_KEY = "workflow:interruptedNodeId";
217978
218071
  WORKFLOW_INTERRUPTED_NODE_ABORT_KIND_CONTEXT_KEY = "workflow:interruptedNodeAbortKind";
217979
218072
  WORKFLOW_OPTIONAL_GROUP_CONTEXT_KEY = "workflow:optionalGroupActive";
218073
+ WORKFLOW_REVIEW_KIND_CONTEXT_KEY = "workflow:reviewKind";
217980
218074
  WORKFLOW_NODE_ENGINE_PAUSE_ABORT_KIND = "engine-pause";
217981
218075
  WORKFLOW_DRIFT_PARK_CONTEXT_KEY = "workflow:driftPark";
217982
218076
  WorkflowGraphSuspended = class extends Error {
@@ -218225,6 +218319,7 @@ var init_workflow_graph_executor = __esm({
218225
218319
  phase: stepPhase,
218226
218320
  status: "pending",
218227
218321
  source: "optional-group",
218322
+ ...this.workflowReviewKind(node) ? { reviewKind: this.workflowReviewKind(node) } : {},
218228
218323
  startedAt: stepStartedAt,
218229
218324
  // U3/KTD-4: stamp the lease owner so a concurrent/crashed re-entry
218230
218325
  // adopts this pending gate instead of dispatching a second reviewer.
@@ -218244,7 +218339,8 @@ var init_workflow_graph_executor = __esm({
218244
218339
  runTemplateNode: (tNode, sig, contextOverride) => {
218245
218340
  const optionalGroupContext = {
218246
218341
  ...contextOverride ?? context,
218247
- [WORKFLOW_OPTIONAL_GROUP_CONTEXT_KEY]: node.id
218342
+ [WORKFLOW_OPTIONAL_GROUP_CONTEXT_KEY]: node.id,
218343
+ ...this.workflowReviewKind(node) ? { [WORKFLOW_REVIEW_KIND_CONTEXT_KEY]: this.workflowReviewKind(node) } : {}
218248
218344
  };
218249
218345
  return this.executeNodeWithRetries(tNode, task, settings, optionalGroupContext, ir2, sig, false);
218250
218346
  },
@@ -218262,6 +218358,7 @@ var init_workflow_graph_executor = __esm({
218262
218358
  const exitContextPatch = exitResult?.contextPatch;
218263
218359
  let stepOutput = typeof exitContextPatch?.output === "string" ? exitContextPatch.output : void 0;
218264
218360
  const stepNotes = typeof exitContextPatch?.notes === "string" ? exitContextPatch.notes : void 0;
218361
+ const stepFindings = this.workflowReviewKind(node) && Array.isArray(exitContextPatch?.findings) ? exitContextPatch.findings : void 0;
218265
218362
  if (stepStatus === "failed" && !verdict && stepOutput === void 0 && stepNotes === void 0) {
218266
218363
  const lastVisited = groupResult.visitedNodeIds[groupResult.visitedNodeIds.length - 1];
218267
218364
  const templateNodeId = lastVisited?.includes("::") ? lastVisited.slice(lastVisited.indexOf("::") + 2) : void 0;
@@ -218279,9 +218376,11 @@ var init_workflow_graph_executor = __esm({
218279
218376
  phase: stepPhase,
218280
218377
  source: "optional-group",
218281
218378
  status: stepStatus,
218379
+ ...this.workflowReviewKind(node) ? { reviewKind: this.workflowReviewKind(node) } : {},
218282
218380
  ...verdict ? { verdict } : {},
218283
218381
  ...stepOutput !== void 0 ? { output: stepOutput } : {},
218284
218382
  ...stepNotes !== void 0 ? { notes: stepNotes } : {},
218383
+ ...stepFindings?.length ? { findings: stepFindings } : {},
218285
218384
  startedAt: stepStartedAt,
218286
218385
  completedAt: (/* @__PURE__ */ new Date()).toISOString()
218287
218386
  });
@@ -218741,9 +218840,15 @@ var init_workflow_graph_executor = __esm({
218741
218840
  }
218742
218841
  return failureResult;
218743
218842
  }
218843
+ /** FNXC:WorkflowReviewKind 2026-08-05-02:31: Persist only the declared closed
218844
+ * marker; execution never derives review semantics from a label, verdict, or gate mode. */
218845
+ workflowReviewKind(node) {
218846
+ return node.config?.reviewKind === "plan" || node.config?.reviewKind === "code" ? node.config.reviewKind : void 0;
218847
+ }
218744
218848
  shouldRecordNodeProgress(node) {
218745
218849
  const skillName = typeof node.config?.skillName === "string" ? node.config.skillName.trim() : "";
218746
- return skillName.length > 0 && (node.kind === "prompt" || node.kind === "gate");
218850
+ const markedReview = this.workflowReviewKind(node) !== void 0;
218851
+ return markedReview && (node.kind === "prompt" || node.kind === "gate" || node.kind === "script") || skillName.length > 0 && (node.kind === "prompt" || node.kind === "gate");
218747
218852
  }
218748
218853
  workflowNodeProgressName(node) {
218749
218854
  const configuredName = typeof node.config?.name === "string" ? node.config.name.trim() : "";
@@ -218757,6 +218862,7 @@ var init_workflow_graph_executor = __esm({
218757
218862
  phase: node.config?.phase === "post-merge" ? "post-merge" : "pre-merge",
218758
218863
  source: "node",
218759
218864
  status: "pending",
218865
+ ...this.workflowReviewKind(node) ? { reviewKind: this.workflowReviewKind(node) } : {},
218760
218866
  startedAt
218761
218867
  };
218762
218868
  await this.recordOptionalGroupStepResult(taskId, result2);
@@ -218767,6 +218873,7 @@ var init_workflow_graph_executor = __esm({
218767
218873
  const contextPatch = nodeResult.contextPatch ?? {};
218768
218874
  let output = typeof contextPatch.output === "string" ? contextPatch.output : void 0;
218769
218875
  const notes = typeof contextPatch.notes === "string" ? contextPatch.notes : void 0;
218876
+ const findings = this.workflowReviewKind(node) && Array.isArray(contextPatch.findings) ? contextPatch.findings : void 0;
218770
218877
  if (status === "failed" && output === void 0 && notes === void 0) {
218771
218878
  output = this.synthesizeNonVerdictFailureOutput({
218772
218879
  stepLabel: this.workflowNodeProgressName(node),
@@ -218781,8 +218888,10 @@ var init_workflow_graph_executor = __esm({
218781
218888
  phase: started?.phase ?? (node.config?.phase === "post-merge" ? "post-merge" : "pre-merge"),
218782
218889
  source: "node",
218783
218890
  status,
218891
+ ...this.workflowReviewKind(node) ? { reviewKind: this.workflowReviewKind(node) } : {},
218784
218892
  ...output !== void 0 ? { output } : {},
218785
218893
  ...notes !== void 0 ? { notes } : {},
218894
+ ...findings?.length ? { findings } : {},
218786
218895
  startedAt: started?.startedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
218787
218896
  completedAt: (/* @__PURE__ */ new Date()).toISOString()
218788
218897
  });
@@ -224063,9 +224172,11 @@ function parseWorkflowStepVerdict(rawOutput) {
224063
224172
  verdict = "REVISE";
224064
224173
  }
224065
224174
  if (!verdict) continue;
224175
+ const findings = normalizeWorkflowReviewFindings(parsed.findings);
224066
224176
  return {
224067
224177
  verdict,
224068
- notes: typeof parsed.notes === "string" ? parsed.notes : ""
224178
+ notes: typeof parsed.notes === "string" ? parsed.notes : "",
224179
+ ...findings ? { findings } : {}
224069
224180
  };
224070
224181
  } catch {
224071
224182
  }
@@ -224097,7 +224208,8 @@ function parseWorkflowStepOutput(rawOutput, options = {}) {
224097
224208
  return {
224098
224209
  output: parsed.notes || "",
224099
224210
  verdict: parsed.verdict,
224100
- notes: parsed.notes
224211
+ notes: parsed.notes,
224212
+ ...parsed.findings ? { findings: parsed.findings } : {}
224101
224213
  };
224102
224214
  }
224103
224215
  const inferred = inferWorkflowStepVerdictFromProse(trimmed);
@@ -230358,6 +230470,7 @@ ${info.feedback}`, revisionKey),
230358
230470
  return this.runCliAgentNode(node, await this.store.getTask(live.id), cfg);
230359
230471
  }
230360
230472
  const optionalGroupId = typeof graphContext?.[WORKFLOW_OPTIONAL_GROUP_CONTEXT_KEY] === "string" ? graphContext[WORKFLOW_OPTIONAL_GROUP_CONTEXT_KEY] : void 0;
230473
+ const declaredReviewKind = cfg.reviewKind === "plan" || cfg.reviewKind === "code" ? cfg.reviewKind : graphContext?.[WORKFLOW_REVIEW_KIND_CONTEXT_KEY] === "plan" || graphContext?.[WORKFLOW_REVIEW_KIND_CONTEXT_KEY] === "code" ? graphContext[WORKFLOW_REVIEW_KIND_CONTEXT_KEY] : void 0;
230361
230474
  const isCompletionSummaryNode2 = cfg.summaryTarget === "task" || node.id === "completion-summary";
230362
230475
  if (live.executionMode === "fast" && !isCompletionSummaryNode2 && !optionalGroupId && !cfg.seam && (node.kind === "prompt" || node.kind === "script" || node.kind === "gate")) {
230363
230476
  executorLog.debug(`${live.id}: fast mode \u2014 skipping custom graph node '${node.id}'`);
@@ -230506,6 +230619,9 @@ ${prompt}`;
230506
230619
  if (optionalGroupId) {
230507
230620
  step.optionalGroupId = optionalGroupId;
230508
230621
  }
230622
+ if (declaredReviewKind) {
230623
+ step.reviewKind = declaredReviewKind;
230624
+ }
230509
230625
  if (cfg.reviewCanFixInline === true) {
230510
230626
  step.reviewCanFixInline = true;
230511
230627
  }
@@ -230518,7 +230634,11 @@ ${prompt}`;
230518
230634
  executorLog.debug(`${live.id}: graph node '${node.id}' runtime env injected (${injected.pathEntryCount} PATH entries, ${injected.injectedKeyCount} env keys)`);
230519
230635
  }
230520
230636
  const unattended = this.graphUnattendedRuns.has(live.id);
230521
- const outcome = mode === "script" ? await this.executeScriptWorkflowStep(live, step, worktreePath, settings, nodeEnv) : await this.executeWorkflowStep(live, step, worktreePath, settings, nodeEnv, { unattended });
230637
+ let outcome = mode === "script" ? await this.executeScriptWorkflowStep(live, step, worktreePath, settings, nodeEnv) : await this.executeWorkflowStep(live, step, worktreePath, settings, nodeEnv, { unattended });
230638
+ if (declaredReviewKind && typeof outcome.output === "string") {
230639
+ const parsedReviewOutput = parseWorkflowStepOutput(outcome.output, { requireVerdict: false });
230640
+ if (parsedReviewOutput.findings?.length) outcome = { ...outcome, findings: parsedReviewOutput.findings };
230641
+ }
230522
230642
  const awaitQuestion = parseAwaitInputSentinel(outcome.output);
230523
230643
  if (awaitQuestion) {
230524
230644
  await this.store.logEntry(
@@ -230541,6 +230661,8 @@ ${prompt}`;
230541
230661
  const contextPatch = {};
230542
230662
  if (typeof stepOutput === "string") contextPatch.output = stepOutput;
230543
230663
  if (typeof stepNotes === "string" && stepNotes) contextPatch.notes = stepNotes;
230664
+ const stepFindings = outcome.findings;
230665
+ if (stepFindings?.length) contextPatch.findings = stepFindings;
230544
230666
  if (cfg.summaryTarget === "task" && typeof stepOutput === "string" && stepOutput.trim()) {
230545
230667
  contextPatch.summary = stepOutput.trim();
230546
230668
  }
@@ -237043,13 +237165,14 @@ CRITICAL SCOPING RULES \u2014 read before doing anything else:
237043
237165
  const isSkillStep = typeof workflowStep.skillName === "string" && workflowStep.skillName.trim().length > 0;
237044
237166
  const isSummaryProjectionStep = workflowStep.summaryTarget === "task";
237045
237167
  const requireVerdict = !isSummaryProjectionStep && (workflowStep.gateMode === "gate" || !isSkillStep);
237168
+ const reviewFindingsContract = workflowStepMetadata.reviewKind === "plan" || workflowStepMetadata.reviewKind === "code";
237046
237169
  const verdictBlock = requireVerdict ? `
237047
237170
 
237048
237171
  ## Feedback Format
237049
237172
 
237050
237173
  When your review is complete, your final line MUST be a single JSON object (no markdown fences):
237051
237174
 
237052
- {"verdict":"APPROVE|APPROVE_WITH_NOTES|REVISE","notes":"..."}
237175
+ ${reviewFindingsContract ? '{"verdict":"APPROVE|APPROVE_WITH_NOTES|REVISE","notes":"...","findings":[{"id":"stable-id","title":"concise issue","body":"actionable detail","filePath":"optional/path","line":1,"severity":"low|medium|high|critical"}]}' : '{"verdict":"APPROVE|APPROVE_WITH_NOTES|REVISE","notes":"..."}'}
237053
237176
 
237054
237177
  Rules:
237055
237178
  - Output exactly one trailing JSON object and stop.
@@ -237359,7 +237482,8 @@ ${detectedQuestion}
237359
237482
  revisionRequested,
237360
237483
  output: parsed.output,
237361
237484
  verdict: parsed.verdict,
237362
- notes: parsed.notes
237485
+ notes: parsed.notes,
237486
+ ...parsed.findings ? { findings: parsed.findings } : {}
237363
237487
  };
237364
237488
  }
237365
237489
  if (parsed.malformed) {
@@ -261461,7 +261585,7 @@ var init_project_engine = __esm({
261461
261585
  *
261462
261586
  * Readable (not private) so tests derive the cap from this single source of truth rather
261463
261587
  * than hardcoding it — the FN-8004 bump broke two suites that had baked in the old `3`. */
261464
- static MAX_AUTO_MERGE_TRANSIENT_RETRIES = 5;
261588
+ static MAX_AUTO_MERGE_TRANSIENT_RETRIES = MAX_AUTO_MERGE_TRANSIENT_RETRIES;
261465
261589
  static MERGE_REQUEST_RETRY_EXHAUSTED_AGE_MS = 30 * 60 * 1e3;
261466
261590
  /** Cap on outer in-review→in-progress bounces caused by deterministic
261467
261591
  * verification failures during auto-merge. After this many failed merges
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion/pi-claude-cli",
3
- "version": "0.75.1-beta.0",
3
+ "version": "0.75.1-beta.1",
4
4
  "type": "module",
5
5
  "private": true,
6
6
  "main": "index.ts",