@runfusion/fusion 0.77.0-beta.12 → 0.77.0-beta.13

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 (147) hide show
  1. package/dist/bin.js +1636 -903
  2. package/dist/child-process-worker.js +1064 -466
  3. package/dist/client/.vite/manifest.json +260 -260
  4. package/dist/client/assets/AgentDetailView-DPoh46Ym.css +1 -0
  5. package/dist/client/assets/{AgentDetailView-BZfDgV8f.js → AgentDetailView-DwCr9HOY.js} +1 -1
  6. package/dist/client/assets/{AgentPermissionPolicyEditor-8yBqnwbx.js → AgentPermissionPolicyEditor-CXRP1R7V.js} +1 -1
  7. package/dist/client/assets/{AgentsView-BjMOtIMq.js → AgentsView-DEVhP_Ad.js} +3 -3
  8. package/dist/client/assets/CommandCenter-BshTzOtB.css +1 -0
  9. package/dist/client/assets/{CommandCenter-CDuO3HPd.js → CommandCenter-sNTR0N1L.js} +22 -22
  10. package/dist/client/assets/{DevServerView-C96RV0QJ.js → DevServerView-X1Ncu9x-.js} +1 -1
  11. package/dist/client/assets/{DirectoryPicker-iRielXf7.js → DirectoryPicker-UrDTGJYj.js} +1 -1
  12. package/dist/client/assets/{DocumentsView-DhAUnUD_.js → DocumentsView-DyyfLF1R.js} +1 -1
  13. package/dist/client/assets/{EvalsView--n1p2Bt0.js → EvalsView-DgMdhmj1.js} +1 -1
  14. package/dist/client/assets/{ExperimentalAgentOnboardingModal-DraglCCV.js → ExperimentalAgentOnboardingModal-DqETOMkr.js} +1 -1
  15. package/dist/client/assets/{GoalsView-BOWOua5t.js → GoalsView-Cai1_q1j.js} +1 -1
  16. package/dist/client/assets/{InsightsView-C5YcJZSc.js → InsightsView-DN9i_pr2.js} +1 -1
  17. package/dist/client/assets/{MemoryView-DsCuGVGx.js → MemoryView-DpVhI_BB.js} +1 -1
  18. package/dist/client/assets/{PatchnodeView-CzgChkJV.js → PatchnodeView-C9glaWoU.js} +1 -1
  19. package/dist/client/assets/{PiExtensionsManager-qYbmaigE.js → PiExtensionsManager-DkJ3I9ur.js} +1 -1
  20. package/dist/client/assets/{PluginManager-Cklj4Smo.js → PluginManager-C3BKqDE-.js} +1 -1
  21. package/dist/client/assets/{PullRequestView-C6vozTTI.js → PullRequestView-BCPolzJY.js} +1 -1
  22. package/dist/client/assets/{ReportModal-B0LU4E4L.js → ReportModal-CBc5lSf3.js} +1 -1
  23. package/dist/client/assets/{ResearchView-CpESx46e.js → ResearchView-BInIb1tK.js} +1 -1
  24. package/dist/client/assets/{SecretsView-8ZdH9Yzs.js → SecretsView-Db2mKOcp.js} +1 -1
  25. package/dist/client/assets/SettingsModal-BEULP2a7.css +1 -0
  26. package/dist/client/assets/SettingsModal-Dn9vcqW7.js +21 -0
  27. package/dist/client/assets/{SettingsModal-BJXu-dhz.js → SettingsModal-tnr4Y2cG.js} +1 -1
  28. package/dist/client/assets/{SettingsTextareaRow-th-q0_2k.js → SettingsTextareaRow-DDIEo7kX.js} +1 -1
  29. package/dist/client/assets/{SetupWizardModal-CBElxrRA.js → SetupWizardModal-BgpCpOJi.js} +2 -2
  30. package/dist/client/assets/{SkillsView-BuoicLbJ.js → SkillsView-C4_dPxaH.js} +1 -1
  31. package/dist/client/assets/{WorkflowNodeEditor-BDw0LpWM.js → WorkflowNodeEditor-BRIoMtdz.js} +1 -1
  32. package/dist/client/assets/{agent-import-generation-CNridJHO.js → agent-import-generation-DZjrAuLD.js} +1 -1
  33. package/dist/client/assets/{agentsOrgChartLayout-BopFGp0r.js → agentsOrgChartLayout-T3vfKGm-.js} +1 -1
  34. package/dist/client/assets/{app-DKzqBaeH.js → app-BUPxz3_I.js} +1 -1
  35. package/dist/client/assets/{app-y8x9KYqa.js → app-Bsb-vSJ2.js} +3 -3
  36. package/dist/client/assets/{app-DkJZhePX.js → app-CDMzhkVk.js} +1 -1
  37. package/dist/client/assets/{app-BtBMuy2Z.js → app-Ca3_7roP.js} +3 -3
  38. package/dist/client/assets/{app-JnrgtY9I.js → app-CaiQxtA9.js} +3 -3
  39. package/dist/client/assets/{app-LrO9EOLE.js → app-D7N3gRgK.js} +3 -3
  40. package/dist/client/assets/{app-Cv-4fcPl.js → app-Du0s0Xs8.js} +1 -1
  41. package/dist/client/assets/{architectureDiagram-3BPJPVTR-2_yoUOD5.js → architectureDiagram-3BPJPVTR-CG7lqp3T.js} +1 -1
  42. package/dist/client/assets/{blockDiagram-GPEHLZMM-ueBSwDJh.js → blockDiagram-GPEHLZMM-CCQyln9-.js} +1 -1
  43. package/dist/client/assets/{c4Diagram-AAUBKEIU-D0cUU3pE.js → c4Diagram-AAUBKEIU-DgTWfMuv.js} +1 -1
  44. package/dist/client/assets/channel-DQn8tAbt.js +1 -0
  45. package/dist/client/assets/{chunk-2J33WTMH-DKJnGdD6.js → chunk-2J33WTMH-DbvgPKWu.js} +1 -1
  46. package/dist/client/assets/{chunk-4BX2VUAB-BUrgUtvt.js → chunk-4BX2VUAB-Jeug78io.js} +1 -1
  47. package/dist/client/assets/{chunk-55IACEB6-DHy2hCYz.js → chunk-55IACEB6-wSkfWEqo.js} +1 -1
  48. package/dist/client/assets/{chunk-727SXJPM-Dgbhllem.js → chunk-727SXJPM-o-cSBR4a.js} +1 -1
  49. package/dist/client/assets/{chunk-AQP2D5EJ-tPbicvl-.js → chunk-AQP2D5EJ-9iL_Co48.js} +1 -1
  50. package/dist/client/assets/{chunk-FMBD7UC4-BpHFGFmo.js → chunk-FMBD7UC4-HKJKjpLt.js} +1 -1
  51. package/dist/client/assets/{chunk-ND2GUHAM-DUTQ63ld.js → chunk-ND2GUHAM-DZUdY7Yv.js} +1 -1
  52. package/dist/client/assets/{chunk-QZHKN3VN-ChCf_usL.js → chunk-QZHKN3VN-AFzlVJep.js} +1 -1
  53. package/dist/client/assets/classDiagram-4FO5ZUOK-BVZs0DmH.js +1 -0
  54. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-BVZs0DmH.js +1 -0
  55. package/dist/client/assets/{cose-bilkent-S5V4N54A-DgWzHtF9.js → cose-bilkent-S5V4N54A-vhimfYza.js} +1 -1
  56. package/dist/client/assets/{dagre-BM42HDAG-gQ1C1xHJ.js → dagre-BM42HDAG-wPz2jgXD.js} +1 -1
  57. package/dist/client/assets/{dashboard-view-BtFepPos.js → dashboard-view-BJVPfjWI.js} +1 -1
  58. package/dist/client/assets/{dashboard-view-BXtoQ9a4.js → dashboard-view-BN6as5aN.js} +1 -1
  59. package/dist/client/assets/{dashboard-view-AQmzkBNb.js → dashboard-view-ByLTU9KO.js} +1 -1
  60. package/dist/client/assets/{dashboard-view-BLenRoXu.js → dashboard-view-HiX6AOAw.js} +1 -1
  61. package/dist/client/assets/{diagram-2AECGRRQ-Dv96I1MI.js → diagram-2AECGRRQ-DvPGnzo9.js} +1 -1
  62. package/dist/client/assets/{diagram-5GNKFQAL-BRyhjYes.js → diagram-5GNKFQAL-CUD0xVXq.js} +1 -1
  63. package/dist/client/assets/{diagram-KO2AKTUF-Bmj3ihjc.js → diagram-KO2AKTUF-p88av64o.js} +1 -1
  64. package/dist/client/assets/{diagram-LMA3HP47-BYHVCFK2.js → diagram-LMA3HP47-B2V_VFOf.js} +1 -1
  65. package/dist/client/assets/{diagram-OG6HWLK6-0WZBLayt.js → diagram-OG6HWLK6-CO02xKJJ.js} +1 -1
  66. package/dist/client/assets/{erDiagram-TEJ5UH35-Cu-yj8hA.js → erDiagram-TEJ5UH35-LiIZMOks.js} +1 -1
  67. package/dist/client/assets/{flowDiagram-I6XJVG4X-BSetu6oh.js → flowDiagram-I6XJVG4X-BMgU0xdB.js} +1 -1
  68. package/dist/client/assets/{folder-open-CkswT0lE.js → folder-open-Bfz0pfA0.js} +1 -1
  69. package/dist/client/assets/{ganttDiagram-6RSMTGT7-B5qn0KFQ.js → ganttDiagram-6RSMTGT7-C-DNnJ7F.js} +1 -1
  70. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-BVB3wm46.js → gitGraphDiagram-PVQCEYII-BKnH_s4c.js} +1 -1
  71. package/dist/client/assets/index-D6zw4rNc.js +2937 -0
  72. package/dist/client/assets/index-lxhrCjd_.css +1 -0
  73. package/dist/client/assets/{infoDiagram-5YYISTIA-ZBNKOBSK.js → infoDiagram-5YYISTIA-DrFgtiS_.js} +1 -1
  74. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-CbNKgenI.js → ishikawaDiagram-YF4QCWOH-cXcVkWVR.js} +1 -1
  75. package/dist/client/assets/{journeyDiagram-JHISSGLW-BLc2FHIF.js → journeyDiagram-JHISSGLW-2rAR6JrI.js} +1 -1
  76. package/dist/client/assets/{kanban-definition-UN3LZRKU-B08tij8f.js → kanban-definition-UN3LZRKU-uaIVKg6k.js} +1 -1
  77. package/dist/client/assets/{mermaid.core-QX5z7w8Z.js → mermaid.core-Bl1eKb-3.js} +4 -4
  78. package/dist/client/assets/{mindmap-definition-RKZ34NQL-C1md8M3c.js → mindmap-definition-RKZ34NQL-C_ZfL855.js} +1 -1
  79. package/dist/client/assets/{pieDiagram-4H26LBE5-BoQbn3Xp.js → pieDiagram-4H26LBE5-B-GWMxe6.js} +1 -1
  80. package/dist/client/assets/{puzzle-DCqPnWPE.js → puzzle--EYtEUHj.js} +1 -1
  81. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-DPvNcVK-.js → quadrantDiagram-W4KKPZXB-C4yu-vxx.js} +1 -1
  82. package/dist/client/assets/{requirementDiagram-4Y6WPE33-KfdYf15t.js → requirementDiagram-4Y6WPE33-CmsMO-mZ.js} +1 -1
  83. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-D1Eyoanf.js → sankeyDiagram-5OEKKPKP-DKXXMJDr.js} +1 -1
  84. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-CmODsbCf.js → sequenceDiagram-3UESZ5HK-DbpptsX5.js} +1 -1
  85. package/dist/client/assets/{standing-instructions-template-D_mPaGcG.js → standing-instructions-template-bCcrFYtU.js} +1 -1
  86. package/dist/client/assets/{stateDiagram-AJRCARHV-Blbw_21G.js → stateDiagram-AJRCARHV-DDwdEj_k.js} +1 -1
  87. package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-DwMgvYO8.js → stateDiagram-v2-BHNVJYJU-CjOnclTc.js} +1 -1
  88. package/dist/client/assets/{timeline-definition-PNZ67QCA-DDtndgLc.js → timeline-definition-PNZ67QCA-Q8Appf3Z.js} +1 -1
  89. package/dist/client/assets/{upload-DGCjJkMH.js → upload-Ka3GrAEL.js} +1 -1
  90. package/dist/client/assets/{users-CbWZvFZP.js → users-B7a_oi7v.js} +1 -1
  91. package/dist/client/assets/{vennDiagram-CIIHVFJN-B6Sx0OqW.js → vennDiagram-CIIHVFJN-ZsuVN3Hk.js} +1 -1
  92. package/dist/client/assets/{wardley-L42UT6IY-_SQFYU4g.js → wardley-L42UT6IY-Eh9WyxS2.js} +1 -1
  93. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-Ce5igv6s.js → wardleyDiagram-YWT4CUSO-CG1fl8Sj.js} +1 -1
  94. package/dist/client/assets/{xychartDiagram-2RQKCTM6-zI0zyvDP.js → xychartDiagram-2RQKCTM6-BnZAlrGh.js} +1 -1
  95. package/dist/client/index.html +2 -2
  96. package/dist/client/version.json +1 -1
  97. package/dist/droid-cli/package.json +1 -1
  98. package/dist/extension.js +1479 -798
  99. package/dist/pi-claude-cli/package.json +1 -1
  100. package/dist/plugin-sdk/index.d.ts +1 -1
  101. package/dist/plugin-sdk/index.js +25 -14
  102. package/dist/plugins/fusion-plugin-acp-runtime/bundled.js +25 -14
  103. package/dist/plugins/fusion-plugin-acp-runtime/package.json +1 -1
  104. package/dist/plugins/fusion-plugin-claude-runtime/bundled.js +25 -14
  105. package/dist/plugins/fusion-plugin-claude-runtime/package.json +1 -1
  106. package/dist/plugins/fusion-plugin-cli-printing-press/bundled.js +25 -14
  107. package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
  108. package/dist/plugins/fusion-plugin-compound-engineering/bundled.js +25 -14
  109. package/dist/plugins/fusion-plugin-compound-engineering/package.json +1 -1
  110. package/dist/plugins/fusion-plugin-cursor-runtime/bundled.js +25 -14
  111. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
  112. package/dist/plugins/fusion-plugin-dependency-graph/bundled.js +25 -14
  113. package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
  114. package/dist/plugins/fusion-plugin-droid-runtime/bundled.js +25 -14
  115. package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
  116. package/dist/plugins/fusion-plugin-grok-runtime/bundled.js +25 -14
  117. package/dist/plugins/fusion-plugin-grok-runtime/package.json +1 -1
  118. package/dist/plugins/fusion-plugin-hermes-runtime/bundled.js +25 -14
  119. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  120. package/dist/plugins/fusion-plugin-linear-import/bundled.js +25 -14
  121. package/dist/plugins/fusion-plugin-linear-import/package.json +1 -1
  122. package/dist/plugins/fusion-plugin-omp-runtime/bundled.js +25 -14
  123. package/dist/plugins/fusion-plugin-omp-runtime/package.json +1 -1
  124. package/dist/plugins/fusion-plugin-openclaw-runtime/bundled.js +25 -14
  125. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  126. package/dist/plugins/fusion-plugin-paperclip-runtime/bundled.js +25 -14
  127. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  128. package/dist/plugins/fusion-plugin-quality/bundled.js +25 -14
  129. package/dist/plugins/fusion-plugin-quality/package.json +1 -1
  130. package/dist/plugins/fusion-plugin-reports/bundled.js +25 -14
  131. package/dist/plugins/fusion-plugin-reports/package.json +1 -1
  132. package/dist/plugins/fusion-plugin-roadmap/bundled.js +25 -14
  133. package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
  134. package/dist/plugins/fusion-plugin-todos/bundled.js +25 -14
  135. package/dist/plugins/fusion-plugin-todos/package.json +1 -1
  136. package/dist/plugins/fusion-plugin-whatsapp-chat/bundled.js +25 -14
  137. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
  138. package/package.json +1 -1
  139. package/dist/client/assets/AgentDetailView-jzgy1BAS.css +0 -1
  140. package/dist/client/assets/CommandCenter-ilm-DbtI.css +0 -1
  141. package/dist/client/assets/SettingsModal-B1UCDc_h.js +0 -21
  142. package/dist/client/assets/SettingsModal-C5ic1ls7.css +0 -1
  143. package/dist/client/assets/channel-DfvbdnTK.js +0 -1
  144. package/dist/client/assets/classDiagram-4FO5ZUOK-CkMyClXV.js +0 -1
  145. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-CkMyClXV.js +0 -1
  146. package/dist/client/assets/index-BgE915SE.js +0 -2937
  147. package/dist/client/assets/index-e2yEk7y4.css +0 -1
package/dist/extension.js CHANGED
@@ -1513,6 +1513,199 @@ Be specific: cite the plan section or file path for every finding and explain th
1513
1513
  }
1514
1514
  });
1515
1515
 
1516
+ // ../core/src/workflows/workflow-merge-region.ts
1517
+ function isMergeRegionNode(node) {
1518
+ return MERGE_REGION_ENTRY_NODE_KINDS.has(node.kind) || node.config?.seam === "merge";
1519
+ }
1520
+ function classifyWorkflowNodeMergeRegion(ir2, nodeId) {
1521
+ if (ir2.version !== "v2" || !Array.isArray(ir2.nodes)) return "unknown";
1522
+ const node = ir2.nodes.find((candidate) => candidate.id === nodeId);
1523
+ if (!node) return "unknown";
1524
+ return isMergeRegionNode(node) ? "merge-region" : "outside-merge-region";
1525
+ }
1526
+ var MERGE_REGION_ENTRY_NODE_KINDS;
1527
+ var init_workflow_merge_region = __esm({
1528
+ "../core/src/workflows/workflow-merge-region.ts"() {
1529
+ "use strict";
1530
+ MERGE_REGION_ENTRY_NODE_KINDS = /* @__PURE__ */ new Set([
1531
+ "merge-gate",
1532
+ "merge-attempt",
1533
+ "manual-merge-hold",
1534
+ "retry-backoff",
1535
+ "recovery-router",
1536
+ "branch-group-member-integration",
1537
+ "branch-group-promotion",
1538
+ "pr-create",
1539
+ "pr-respond",
1540
+ "pr-merge"
1541
+ ]);
1542
+ }
1543
+ });
1544
+
1545
+ // ../core/src/workflows/workflow-optional-steps.ts
1546
+ function isWorkflowOptionalGroupEnabled(enabledWorkflowSteps, groupId, defaultOn = false) {
1547
+ return Array.isArray(enabledWorkflowSteps) ? enabledWorkflowSteps.includes(groupId) : defaultOn;
1548
+ }
1549
+ function isOptionalGroupNode(node) {
1550
+ return node.kind === "optional-group";
1551
+ }
1552
+ function computeNodeExecutionRanks(ir2) {
1553
+ const ranks = /* @__PURE__ */ new Map();
1554
+ if (ir2.version !== "v2" || !Array.isArray(ir2.nodes) || !Array.isArray(ir2.edges)) {
1555
+ return ranks;
1556
+ }
1557
+ const outgoing = /* @__PURE__ */ new Map();
1558
+ for (const edge of ir2.edges) {
1559
+ if (!outgoing.has(edge.from)) outgoing.set(edge.from, []);
1560
+ outgoing.get(edge.from)?.push(edge.to);
1561
+ }
1562
+ const queue = [];
1563
+ for (const node of ir2.nodes) {
1564
+ if (node.kind === "start" || node.id === "start") {
1565
+ queue.push({ id: node.id, rank: 0 });
1566
+ }
1567
+ }
1568
+ while (queue.length > 0) {
1569
+ const next = queue.shift();
1570
+ if (!next) continue;
1571
+ const current = ranks.get(next.id);
1572
+ if (current !== void 0 && current <= next.rank) continue;
1573
+ ranks.set(next.id, next.rank);
1574
+ for (const target of outgoing.get(next.id) ?? []) {
1575
+ queue.push({ id: target, rank: next.rank + 1 });
1576
+ }
1577
+ }
1578
+ return ranks;
1579
+ }
1580
+ function resolveWorkflowOptionalSteps(ir2, _pluginTemplates = []) {
1581
+ if (ir2.version !== "v2" || !Array.isArray(ir2.nodes)) return [];
1582
+ const ranks = computeNodeExecutionRanks(ir2);
1583
+ const resolved = [];
1584
+ for (const [nodeIndex, node] of ir2.nodes.entries()) {
1585
+ if (!isOptionalGroupNode(node)) continue;
1586
+ const config3 = node.config ?? {};
1587
+ resolved.push({
1588
+ // Keyed by the group node id (documented above); field name preserved.
1589
+ templateId: node.id,
1590
+ name: typeof config3.name === "string" && config3.name.trim() ? config3.name : node.id,
1591
+ description: "",
1592
+ /*
1593
+ FNXC:WorkflowOptionalSteps 2026-06-29-12:47:
1594
+ Post-merge verification is now a graph-native optional group. Task creation and detail surfaces need the resolver to preserve `config.phase` so post-merge toggles do not look like pre-merge gates.
1595
+ */
1596
+ phase: config3.phase === "post-merge" ? "post-merge" : "pre-merge",
1597
+ defaultOn: config3.defaultOn === true,
1598
+ reportingOnly: config3.reportingOnly === true,
1599
+ /*
1600
+ FNXC:WorkflowDefinitionSteps 2026-06-29-00:41:
1601
+ Definition/task creation surfaces must order optional groups by graph execution position, not raw node-array order. Derived built-ins can insert Plan Review between planning and parse while appending its node object, and operators still need the step list to show Plan Review before execution.
1602
+ */
1603
+ rank: ranks.get(node.id) ?? Number.MAX_SAFE_INTEGER,
1604
+ nodeIndex
1605
+ });
1606
+ }
1607
+ return resolved.sort((a, b3) => a.rank - b3.rank || a.nodeIndex - b3.nodeIndex).map(({ rank: _rank, nodeIndex: _nodeIndex, ...step }) => step);
1608
+ }
1609
+ function resolveDefaultOnOptionalGroupIds(ir2) {
1610
+ return resolveWorkflowOptionalSteps(ir2).filter((step) => step.defaultOn).map((step) => step.templateId);
1611
+ }
1612
+ function resolveAllOptionalGroupIds(ir2) {
1613
+ return resolveWorkflowOptionalSteps(ir2).map((step) => step.templateId);
1614
+ }
1615
+ function isReportingOnlyOptionalGroup(ir2, nodeId) {
1616
+ if (!nodeId) return false;
1617
+ return resolveWorkflowOptionalSteps(ir2).some((step) => step.templateId === nodeId && step.reportingOnly);
1618
+ }
1619
+ var init_workflow_optional_steps = __esm({
1620
+ "../core/src/workflows/workflow-optional-steps.ts"() {
1621
+ "use strict";
1622
+ }
1623
+ });
1624
+
1625
+ // ../core/src/workflows/workflow-fast-lane.ts
1626
+ function isFastExecutionMode(task) {
1627
+ return task.executionMode === "fast";
1628
+ }
1629
+ function configString(node, key) {
1630
+ const value = node.config?.[key];
1631
+ return typeof value === "string" ? value : void 0;
1632
+ }
1633
+ function isTaskStepsForeach(node) {
1634
+ return node.kind === "foreach" && node.config?.source === "task-steps";
1635
+ }
1636
+ function isFastLaneSkippableCustomNode(node, opts = {}) {
1637
+ if (node.config?.summaryTarget === "task" || node.id === "completion-summary") return false;
1638
+ if (opts.optionalGroupId) return false;
1639
+ if (node.config?.seam) return false;
1640
+ return node.kind === "prompt" || node.kind === "script" || node.kind === "gate";
1641
+ }
1642
+ function isFastLaneBypassedTemplateNode(node) {
1643
+ return node.kind === "step-review";
1644
+ }
1645
+ function inactiveRoute() {
1646
+ return {
1647
+ active: false,
1648
+ bypassedNodeIds: /* @__PURE__ */ new Set(),
1649
+ bypassedPreMergeGroups: [],
1650
+ parseStepsNodeIds: /* @__PURE__ */ new Set()
1651
+ };
1652
+ }
1653
+ function resolveFastLaneRoute(ir2, task) {
1654
+ if (!isFastExecutionMode(task)) return inactiveRoute();
1655
+ const foreachNode = ir2.nodes.find(isTaskStepsForeach);
1656
+ const executeNode = ir2.nodes.find((node) => configString(node, "seam") === "execute");
1657
+ const implementationNode = foreachNode ?? executeNode;
1658
+ if (!implementationNode) {
1659
+ return { ...inactiveRoute(), unsupportedReason: "no-implementation-node" };
1660
+ }
1661
+ const implementationKind = foreachNode ? "foreach-steps" : "execute-seam";
1662
+ const bypassedPreMergeGroups = resolveWorkflowOptionalSteps(ir2).filter((step) => step.phase === "pre-merge").map((step) => ({ nodeId: step.templateId, name: step.name }));
1663
+ const bypassedGroupIds = new Set(bypassedPreMergeGroups.map((group) => group.nodeId));
1664
+ const bypassedNodeIds = /* @__PURE__ */ new Set();
1665
+ for (const node of ir2.nodes) {
1666
+ if (isMergeRegionNode(node) || node.id === "completion-summary" || node.config?.summaryTarget === "task") continue;
1667
+ if (configString(node, "seam") === "planning") {
1668
+ bypassedNodeIds.add(node.id);
1669
+ continue;
1670
+ }
1671
+ if (bypassedGroupIds.has(node.id)) {
1672
+ bypassedNodeIds.add(node.id);
1673
+ continue;
1674
+ }
1675
+ const workflowAction = configString(node, "workflowAction");
1676
+ const groupId = configString(node, "forWorkflowStepId");
1677
+ if (workflowAction === "plan-replan" || workflowAction === "plan-review-no-op" || workflowAction === "pre-merge-remediation" || workflowAction === "review-remediation-steps" || groupId !== void 0 && bypassedGroupIds.has(groupId)) {
1678
+ bypassedNodeIds.add(node.id);
1679
+ }
1680
+ }
1681
+ const parseStepsNodeIds = new Set(ir2.nodes.filter((node) => node.kind === "parse-steps").map((node) => node.id));
1682
+ for (const parseNodeId of parseStepsNodeIds) {
1683
+ if (bypassedNodeIds.has(parseNodeId)) {
1684
+ throw new Error(`Fast lane cannot bypass parse-steps node '${parseNodeId}'`);
1685
+ }
1686
+ }
1687
+ return {
1688
+ active: true,
1689
+ bypassedNodeIds,
1690
+ bypassedPreMergeGroups,
1691
+ parseStepsNodeIds,
1692
+ implementationNodeId: implementationNode.id,
1693
+ implementationKind
1694
+ };
1695
+ }
1696
+ var FAST_LANE_STEP_NAME, FAST_LANE_SKIP_VALUE, FAST_MODE_BYPASS_ACTOR, FAST_LANE_STEP_REVIEW_ROUTE_VALUE;
1697
+ var init_workflow_fast_lane = __esm({
1698
+ "../core/src/workflows/workflow-fast-lane.ts"() {
1699
+ "use strict";
1700
+ init_workflow_merge_region();
1701
+ init_workflow_optional_steps();
1702
+ FAST_LANE_STEP_NAME = "Fast implementation";
1703
+ FAST_LANE_SKIP_VALUE = "fast-lane-skip";
1704
+ FAST_MODE_BYPASS_ACTOR = "fast-mode";
1705
+ FAST_LANE_STEP_REVIEW_ROUTE_VALUE = "approve";
1706
+ }
1707
+ });
1708
+
1516
1709
  // ../core/src/workflows/workflow-step-results.ts
1517
1710
  function isWorkflowStepNotRun(result2) {
1518
1711
  return result2.status === "skipped" && typeof result2.notRunReason === "string" && WORKFLOW_STEP_NOT_RUN_REASONS.includes(result2.notRunReason);
@@ -1813,6 +2006,31 @@ var init_workflow_step_results = __esm({
1813
2006
  });
1814
2007
 
1815
2008
  // ../core/src/merge/pre-merge-approval.ts
2009
+ function requiresContentReviewProof(workflowStepId, result2) {
2010
+ return workflowStepId === "code-review" || result2.reviewKind === "code";
2011
+ }
2012
+ function isAuditedOperatorBypass(result2) {
2013
+ if (result2.status !== "skipped") return false;
2014
+ const actor = result2.bypassedBy?.trim();
2015
+ return Boolean(
2016
+ actor && !AUTOMATED_BYPASS_ACTORS.has(actor) && result2.bypassedAt?.trim() && result2.bypassReason?.trim()
2017
+ );
2018
+ }
2019
+ function resolveUnprovenReviewApproval(result2, options) {
2020
+ if ((result2.phase ?? "pre-merge") !== "pre-merge" || !requiresContentReviewProof(result2.workflowStepId, result2) || options.workspace || result2.status !== "passed" || result2.verdict !== "APPROVE" && result2.verdict !== "APPROVE_WITH_NOTES" || result2.reviewInputFingerprint !== void 0 || result2.bypassedBy !== void 0 || result2.remediationArchivedAt != null) {
2021
+ return void 0;
2022
+ }
2023
+ const { verdict: _verdict, ...withoutVerdict } = result2;
2024
+ return {
2025
+ downgraded: {
2026
+ ...withoutVerdict,
2027
+ status: "failed",
2028
+ output: UNPROVEN_REVIEW_APPROVAL_DIAGNOSTIC,
2029
+ notes: UNPROVEN_REVIEW_APPROVAL_DIAGNOSTIC
2030
+ },
2031
+ reason: UNPROVEN_REVIEW_APPROVAL_DIAGNOSTIC
2032
+ };
2033
+ }
1816
2034
  function evaluatePreMergeApprovals(task, options = {}) {
1817
2035
  const required2 = options.requiredPreMergeStepIds;
1818
2036
  if (!required2?.size) return [];
@@ -1823,13 +2041,16 @@ function evaluateStep(workflowStepId, results, task, descriptor) {
1823
2041
  const result2 = results.filter((candidate) => candidate.workflowStepId === workflowStepId).at(-1);
1824
2042
  if (!result2 && descriptor?.kind !== "workspace") return { workflowStepId, state: "missing" };
1825
2043
  if (result2) {
1826
- const requiresExplicitVerdict = workflowStepId === "code-review" || result2.reviewKind === "code";
2044
+ const requiresExplicitVerdict = requiresContentReviewProof(workflowStepId, result2);
1827
2045
  const approvedVerdict = result2.verdict === "APPROVE" || result2.verdict === "APPROVE_WITH_NOTES";
1828
2046
  const isPlanDomain = workflowStepId === PLAN_REVIEW_GROUP_ID || result2.reviewKind === "plan";
1829
2047
  const notRunApproves = isWorkflowStepNotRun(result2) && !requiresExplicitVerdict && !isPlanDomain;
1830
2048
  const approved = result2.status === "passed" && (requiresExplicitVerdict ? approvedVerdict : result2.verdict === void 0 || approvedVerdict) || result2.status === "skipped" && !!result2.bypassedBy || notRunApproves;
1831
2049
  if (!approved || !!result2.remediationArchivedAt) return { workflowStepId, state: "not-approved" };
1832
2050
  if (result2.reviewKind === "plan") return { workflowStepId, state: "approved" };
2051
+ if (isAuditedOperatorBypass(result2) && descriptor?.kind !== "workspace") {
2052
+ return { workflowStepId, state: "approved" };
2053
+ }
1833
2054
  const bindsContent = requiresExplicitVerdict || result2.reviewInputFingerprint !== void 0;
1834
2055
  if (!bindsContent) return { workflowStepId, state: "approved" };
1835
2056
  }
@@ -1860,11 +2081,15 @@ function evaluateStep(workflowStepId, results, task, descriptor) {
1860
2081
  if (stale2.length) return { workflowStepId, state: "stale-content", repositories: stale2 };
1861
2082
  return { workflowStepId, state: "approved" };
1862
2083
  }
2084
+ var AUTOMATED_BYPASS_ACTORS, UNPROVEN_REVIEW_APPROVAL_DIAGNOSTIC;
1863
2085
  var init_pre_merge_approval = __esm({
1864
2086
  "../core/src/merge/pre-merge-approval.ts"() {
1865
2087
  "use strict";
1866
2088
  init_builtin_plan_review_group();
2089
+ init_workflow_fast_lane();
1867
2090
  init_workflow_step_results();
2091
+ AUTOMATED_BYPASS_ACTORS = /* @__PURE__ */ new Set([FAST_MODE_BYPASS_ACTOR]);
2092
+ UNPROVEN_REVIEW_APPROVAL_DIAGNOSTIC = "Content-binding review approval recorded without reviewInputFingerprint; approval invalidated so the gate can run again.";
1868
2093
  }
1869
2094
  });
1870
2095
 
@@ -11374,35 +11599,6 @@ var init_workflow_ir_types = __esm({
11374
11599
  }
11375
11600
  });
11376
11601
 
11377
- // ../core/src/workflows/workflow-merge-region.ts
11378
- function isMergeRegionNode(node) {
11379
- return MERGE_REGION_ENTRY_NODE_KINDS.has(node.kind) || node.config?.seam === "merge";
11380
- }
11381
- function classifyWorkflowNodeMergeRegion(ir2, nodeId) {
11382
- if (ir2.version !== "v2" || !Array.isArray(ir2.nodes)) return "unknown";
11383
- const node = ir2.nodes.find((candidate) => candidate.id === nodeId);
11384
- if (!node) return "unknown";
11385
- return isMergeRegionNode(node) ? "merge-region" : "outside-merge-region";
11386
- }
11387
- var MERGE_REGION_ENTRY_NODE_KINDS;
11388
- var init_workflow_merge_region = __esm({
11389
- "../core/src/workflows/workflow-merge-region.ts"() {
11390
- "use strict";
11391
- MERGE_REGION_ENTRY_NODE_KINDS = /* @__PURE__ */ new Set([
11392
- "merge-gate",
11393
- "merge-attempt",
11394
- "manual-merge-hold",
11395
- "retry-backoff",
11396
- "recovery-router",
11397
- "branch-group-member-integration",
11398
- "branch-group-promotion",
11399
- "pr-create",
11400
- "pr-respond",
11401
- "pr-merge"
11402
- ]);
11403
- }
11404
- });
11405
-
11406
11602
  // ../core/src/workflows/workflow-extension-types.ts
11407
11603
  function workflowExtensionRegistryId(pluginId, extensionId) {
11408
11604
  return `plugin:${pluginId}:${extensionId}`;
@@ -12398,6 +12594,16 @@ function validateReviewerAgentOverrides(nodes2) {
12398
12594
  if (Array.isArray(templateNodes)) validateReviewerAgentOverrides(templateNodes);
12399
12595
  }
12400
12596
  }
12597
+ function validateReadonlyMcpServersConfig(nodes2) {
12598
+ for (const node of nodes2) {
12599
+ const value = node.config?.readonlyMcpServers;
12600
+ if (value !== void 0 && (!Array.isArray(value) || value.some((name2) => typeof name2 !== "string" || !name2.trim()))) {
12601
+ throw new WorkflowIrError(`Workflow node '${node.id}' readonlyMcpServers must be an array of non-empty strings when present`);
12602
+ }
12603
+ const templateNodes = node.config?.template?.nodes;
12604
+ if (Array.isArray(templateNodes)) validateReadonlyMcpServersConfig(templateNodes);
12605
+ }
12606
+ }
12401
12607
  function validateThinkingLevelConfig(nodes2) {
12402
12608
  for (const node of nodes2) {
12403
12609
  const value = node.config?.thinkingLevel;
@@ -13012,6 +13218,7 @@ function validateV2(ir2) {
13012
13218
  const topLevelIds = new Set(ir2.nodes.map((n) => n.id));
13013
13219
  validateStepExecutePlacement(ir2.nodes);
13014
13220
  validateThinkingLevelConfig(ir2.nodes);
13221
+ validateReadonlyMcpServersConfig(ir2.nodes);
13015
13222
  validateCredentialInstanceIdConfig(ir2.nodes);
13016
13223
  validateReviewerAgentOverrides(ir2.nodes);
13017
13224
  for (const node of ir2.nodes) {
@@ -29082,169 +29289,6 @@ var init_explicit_duplicate_marker = __esm({
29082
29289
  }
29083
29290
  });
29084
29291
 
29085
- // ../core/src/workflows/workflow-optional-steps.ts
29086
- function isWorkflowOptionalGroupEnabled(enabledWorkflowSteps, groupId, defaultOn = false) {
29087
- return Array.isArray(enabledWorkflowSteps) ? enabledWorkflowSteps.includes(groupId) : defaultOn;
29088
- }
29089
- function isOptionalGroupNode(node) {
29090
- return node.kind === "optional-group";
29091
- }
29092
- function computeNodeExecutionRanks(ir2) {
29093
- const ranks = /* @__PURE__ */ new Map();
29094
- if (ir2.version !== "v2" || !Array.isArray(ir2.nodes) || !Array.isArray(ir2.edges)) {
29095
- return ranks;
29096
- }
29097
- const outgoing = /* @__PURE__ */ new Map();
29098
- for (const edge of ir2.edges) {
29099
- if (!outgoing.has(edge.from)) outgoing.set(edge.from, []);
29100
- outgoing.get(edge.from)?.push(edge.to);
29101
- }
29102
- const queue = [];
29103
- for (const node of ir2.nodes) {
29104
- if (node.kind === "start" || node.id === "start") {
29105
- queue.push({ id: node.id, rank: 0 });
29106
- }
29107
- }
29108
- while (queue.length > 0) {
29109
- const next = queue.shift();
29110
- if (!next) continue;
29111
- const current = ranks.get(next.id);
29112
- if (current !== void 0 && current <= next.rank) continue;
29113
- ranks.set(next.id, next.rank);
29114
- for (const target of outgoing.get(next.id) ?? []) {
29115
- queue.push({ id: target, rank: next.rank + 1 });
29116
- }
29117
- }
29118
- return ranks;
29119
- }
29120
- function resolveWorkflowOptionalSteps(ir2, _pluginTemplates = []) {
29121
- if (ir2.version !== "v2" || !Array.isArray(ir2.nodes)) return [];
29122
- const ranks = computeNodeExecutionRanks(ir2);
29123
- const resolved = [];
29124
- for (const [nodeIndex, node] of ir2.nodes.entries()) {
29125
- if (!isOptionalGroupNode(node)) continue;
29126
- const config3 = node.config ?? {};
29127
- resolved.push({
29128
- // Keyed by the group node id (documented above); field name preserved.
29129
- templateId: node.id,
29130
- name: typeof config3.name === "string" && config3.name.trim() ? config3.name : node.id,
29131
- description: "",
29132
- /*
29133
- FNXC:WorkflowOptionalSteps 2026-06-29-12:47:
29134
- Post-merge verification is now a graph-native optional group. Task creation and detail surfaces need the resolver to preserve `config.phase` so post-merge toggles do not look like pre-merge gates.
29135
- */
29136
- phase: config3.phase === "post-merge" ? "post-merge" : "pre-merge",
29137
- defaultOn: config3.defaultOn === true,
29138
- reportingOnly: config3.reportingOnly === true,
29139
- /*
29140
- FNXC:WorkflowDefinitionSteps 2026-06-29-00:41:
29141
- Definition/task creation surfaces must order optional groups by graph execution position, not raw node-array order. Derived built-ins can insert Plan Review between planning and parse while appending its node object, and operators still need the step list to show Plan Review before execution.
29142
- */
29143
- rank: ranks.get(node.id) ?? Number.MAX_SAFE_INTEGER,
29144
- nodeIndex
29145
- });
29146
- }
29147
- return resolved.sort((a, b3) => a.rank - b3.rank || a.nodeIndex - b3.nodeIndex).map(({ rank: _rank, nodeIndex: _nodeIndex, ...step }) => step);
29148
- }
29149
- function resolveDefaultOnOptionalGroupIds(ir2) {
29150
- return resolveWorkflowOptionalSteps(ir2).filter((step) => step.defaultOn).map((step) => step.templateId);
29151
- }
29152
- function resolveAllOptionalGroupIds(ir2) {
29153
- return resolveWorkflowOptionalSteps(ir2).map((step) => step.templateId);
29154
- }
29155
- function isReportingOnlyOptionalGroup(ir2, nodeId) {
29156
- if (!nodeId) return false;
29157
- return resolveWorkflowOptionalSteps(ir2).some((step) => step.templateId === nodeId && step.reportingOnly);
29158
- }
29159
- var init_workflow_optional_steps = __esm({
29160
- "../core/src/workflows/workflow-optional-steps.ts"() {
29161
- "use strict";
29162
- }
29163
- });
29164
-
29165
- // ../core/src/workflows/workflow-fast-lane.ts
29166
- function isFastExecutionMode(task) {
29167
- return task.executionMode === "fast";
29168
- }
29169
- function configString(node, key) {
29170
- const value = node.config?.[key];
29171
- return typeof value === "string" ? value : void 0;
29172
- }
29173
- function isTaskStepsForeach(node) {
29174
- return node.kind === "foreach" && node.config?.source === "task-steps";
29175
- }
29176
- function isFastLaneSkippableCustomNode(node, opts = {}) {
29177
- if (node.config?.summaryTarget === "task" || node.id === "completion-summary") return false;
29178
- if (opts.optionalGroupId) return false;
29179
- if (node.config?.seam) return false;
29180
- return node.kind === "prompt" || node.kind === "script" || node.kind === "gate";
29181
- }
29182
- function isFastLaneBypassedTemplateNode(node) {
29183
- return node.kind === "step-review";
29184
- }
29185
- function inactiveRoute() {
29186
- return {
29187
- active: false,
29188
- bypassedNodeIds: /* @__PURE__ */ new Set(),
29189
- bypassedPreMergeGroups: [],
29190
- parseStepsNodeIds: /* @__PURE__ */ new Set()
29191
- };
29192
- }
29193
- function resolveFastLaneRoute(ir2, task) {
29194
- if (!isFastExecutionMode(task)) return inactiveRoute();
29195
- const foreachNode = ir2.nodes.find(isTaskStepsForeach);
29196
- const executeNode = ir2.nodes.find((node) => configString(node, "seam") === "execute");
29197
- const implementationNode = foreachNode ?? executeNode;
29198
- if (!implementationNode) {
29199
- return { ...inactiveRoute(), unsupportedReason: "no-implementation-node" };
29200
- }
29201
- const implementationKind = foreachNode ? "foreach-steps" : "execute-seam";
29202
- const bypassedPreMergeGroups = resolveWorkflowOptionalSteps(ir2).filter((step) => step.phase === "pre-merge").map((step) => ({ nodeId: step.templateId, name: step.name }));
29203
- const bypassedGroupIds = new Set(bypassedPreMergeGroups.map((group) => group.nodeId));
29204
- const bypassedNodeIds = /* @__PURE__ */ new Set();
29205
- for (const node of ir2.nodes) {
29206
- if (isMergeRegionNode(node) || node.id === "completion-summary" || node.config?.summaryTarget === "task") continue;
29207
- if (configString(node, "seam") === "planning") {
29208
- bypassedNodeIds.add(node.id);
29209
- continue;
29210
- }
29211
- if (bypassedGroupIds.has(node.id)) {
29212
- bypassedNodeIds.add(node.id);
29213
- continue;
29214
- }
29215
- const workflowAction = configString(node, "workflowAction");
29216
- const groupId = configString(node, "forWorkflowStepId");
29217
- if (workflowAction === "plan-replan" || workflowAction === "plan-review-no-op" || workflowAction === "pre-merge-remediation" || workflowAction === "review-remediation-steps" || groupId !== void 0 && bypassedGroupIds.has(groupId)) {
29218
- bypassedNodeIds.add(node.id);
29219
- }
29220
- }
29221
- const parseStepsNodeIds = new Set(ir2.nodes.filter((node) => node.kind === "parse-steps").map((node) => node.id));
29222
- for (const parseNodeId of parseStepsNodeIds) {
29223
- if (bypassedNodeIds.has(parseNodeId)) {
29224
- throw new Error(`Fast lane cannot bypass parse-steps node '${parseNodeId}'`);
29225
- }
29226
- }
29227
- return {
29228
- active: true,
29229
- bypassedNodeIds,
29230
- bypassedPreMergeGroups,
29231
- parseStepsNodeIds,
29232
- implementationNodeId: implementationNode.id,
29233
- implementationKind
29234
- };
29235
- }
29236
- var FAST_LANE_STEP_NAME, FAST_LANE_SKIP_VALUE, FAST_LANE_STEP_REVIEW_ROUTE_VALUE;
29237
- var init_workflow_fast_lane = __esm({
29238
- "../core/src/workflows/workflow-fast-lane.ts"() {
29239
- "use strict";
29240
- init_workflow_merge_region();
29241
- init_workflow_optional_steps();
29242
- FAST_LANE_STEP_NAME = "Fast implementation";
29243
- FAST_LANE_SKIP_VALUE = "fast-lane-skip";
29244
- FAST_LANE_STEP_REVIEW_ROUTE_VALUE = "approve";
29245
- }
29246
- });
29247
-
29248
29292
  // ../core/src/mesh/mesh-task-replication.ts
29249
29293
  function buildBootstrapPrompt(taskId, title, description) {
29250
29294
  const heading = title ? `${taskId}: ${title}` : taskId;
@@ -66445,10 +66489,10 @@ var init_migration = __esm({
66445
66489
  return basename6(projectPath);
66446
66490
  }
66447
66491
  try {
66448
- const { execFile: execFile46 } = await import("node:child_process");
66449
- const { promisify: promisify101 } = await import("node:util");
66450
- const execFileAsync40 = promisify101(execFile46);
66451
- const { stdout } = await execFileAsync40(
66492
+ const { execFile: execFile47 } = await import("node:child_process");
66493
+ const { promisify: promisify102 } = await import("node:util");
66494
+ const execFileAsync41 = promisify102(execFile47);
66495
+ const { stdout } = await execFileAsync41(
66452
66496
  "git",
66453
66497
  ["remote", "get-url", "origin"],
66454
66498
  { cwd: projectPath, timeout: 1e3 }
@@ -68643,10 +68687,10 @@ var init_central_core = __esm({
68643
68687
  */
68644
68688
  async generateProjectName(projectPath) {
68645
68689
  try {
68646
- const { execFile: execFile46 } = await import("node:child_process");
68647
- const { promisify: promisify101 } = await import("node:util");
68648
- const execFileAsync40 = promisify101(execFile46);
68649
- const { stdout } = await execFileAsync40(
68690
+ const { execFile: execFile47 } = await import("node:child_process");
68691
+ const { promisify: promisify102 } = await import("node:util");
68692
+ const execFileAsync41 = promisify102(execFile47);
68693
+ const { stdout } = await execFileAsync41(
68650
68694
  "git",
68651
68695
  ["remote", "get-url", "origin"],
68652
68696
  { cwd: projectPath, timeout: 5e3 }
@@ -85448,14 +85492,12 @@ async function listWorkflowDefinitionsImpl(store, options) {
85448
85492
  return pluginFiltered;
85449
85493
  }
85450
85494
  async function readAllWorkflowDefinitionsImpl(store) {
85451
- if (store.workflowDefinitionsCache) return store.workflowDefinitionsCache;
85452
85495
  const layer = store.getAsyncLayer();
85453
85496
  if (!layer) {
85454
85497
  throw new Error("workflow definitions: AsyncDataLayer not initialized in backend mode");
85455
85498
  }
85456
85499
  const rows = await listWorkflowRows(layer);
85457
- store.workflowDefinitionsCache = [...BUILTIN_WORKFLOWS, ...rows.map((row) => store.toWorkflowDefinition(row))];
85458
- return store.workflowDefinitionsCache;
85500
+ return [...BUILTIN_WORKFLOWS, ...rows.map((row) => store.toWorkflowDefinition(row))];
85459
85501
  }
85460
85502
  async function getWorkflowDefinitionImpl(store, id) {
85461
85503
  const builtin = getBuiltinWorkflow(id);
@@ -85524,7 +85566,6 @@ function insertWorkflowDefinitionSyncImpl(store, input) {
85524
85566
  if (!isWorkflowDefinitionIdPrimaryKeyCollision(error3)) throw error3;
85525
85567
  continue;
85526
85568
  }
85527
- store.workflowDefinitionsCache = null;
85528
85569
  return definition;
85529
85570
  }
85530
85571
  throw new Error("Unable to allocate a free workflow definition id after repeated id collisions");
@@ -85914,11 +85955,6 @@ function getPluginStoreImpl(store) {
85914
85955
  ...pluginLayer ? { asyncLayer: pluginLayer } : {}
85915
85956
  }
85916
85957
  );
85917
- const clearWorkflowDefinitionCache = () => {
85918
- store.workflowDefinitionsCache = null;
85919
- };
85920
- store.pluginStore.on("plugin:registered", clearWorkflowDefinitionCache);
85921
- store.pluginStore.on("plugin:unregistered", clearWorkflowDefinitionCache);
85922
85958
  }
85923
85959
  return store.pluginStore;
85924
85960
  }
@@ -90290,11 +90326,11 @@ async function searchWithQmd(rootDir, options) {
90290
90326
  const command = "qmd";
90291
90327
  const limit = Math.max(1, Math.min(options.limit ?? 5, 20));
90292
90328
  try {
90293
- const execFileAsync40 = await getDefaultExecFileAsync();
90294
- await ensureQmdProjectMemoryCollection(rootDir, execFileAsync40);
90329
+ const execFileAsync41 = await getDefaultExecFileAsync();
90330
+ await ensureQmdProjectMemoryCollection(rootDir, execFileAsync41);
90295
90331
  scheduleQmdProjectMemoryRefresh(rootDir);
90296
90332
  const args = buildQmdSearchArgs(rootDir, options);
90297
- const { stdout } = await execFileAsync40(command, args, {
90333
+ const { stdout } = await execFileAsync41(command, args, {
90298
90334
  cwd: rootDir,
90299
90335
  timeout: 4e3,
90300
90336
  maxBuffer: 1024 * 1024
@@ -90319,12 +90355,12 @@ async function searchWithQmd(rootDir, options) {
90319
90355
  return [];
90320
90356
  }
90321
90357
  }
90322
- async function ensureQmdProjectMemoryCollection(rootDir, execFileAsync40) {
90358
+ async function ensureQmdProjectMemoryCollection(rootDir, execFileAsync41) {
90323
90359
  const collectionName = qmdMemoryCollectionName(rootDir);
90324
90360
  const memoryDir = memoryWorkspacePath(rootDir);
90325
90361
  await mkdir10(memoryDir, { recursive: true });
90326
90362
  try {
90327
- await execFileAsync40("qmd", buildQmdCollectionAddArgs(rootDir), {
90363
+ await execFileAsync41("qmd", buildQmdCollectionAddArgs(rootDir), {
90328
90364
  cwd: rootDir,
90329
90365
  timeout: 4e3,
90330
90366
  maxBuffer: 512 * 1024
@@ -90422,14 +90458,14 @@ async function refreshQmdProjectMemoryIndex(rootDir, options) {
90422
90458
  }
90423
90459
  }
90424
90460
  const promise = (async () => {
90425
- const execFileAsync40 = options?.execFileAsync ?? await getDefaultExecFileAsync();
90426
- await ensureQmdProjectMemoryCollection(rootDir, execFileAsync40);
90427
- await execFileAsync40("qmd", ["update"], {
90461
+ const execFileAsync41 = options?.execFileAsync ?? await getDefaultExecFileAsync();
90462
+ await ensureQmdProjectMemoryCollection(rootDir, execFileAsync41);
90463
+ await execFileAsync41("qmd", ["update"], {
90428
90464
  cwd: rootDir,
90429
90465
  timeout: 3e4,
90430
90466
  maxBuffer: 1024 * 1024
90431
90467
  });
90432
- await execFileAsync40("qmd", ["embed"], {
90468
+ await execFileAsync41("qmd", ["embed"], {
90433
90469
  cwd: rootDir,
90434
90470
  timeout: 12e4,
90435
90471
  maxBuffer: 1024 * 1024
@@ -90465,12 +90501,12 @@ async function refreshQmdAgentMemoryIndex(rootDir, agentId, options) {
90465
90501
  }
90466
90502
  }
90467
90503
  const promise = (async () => {
90468
- const execFileAsync40 = options?.execFileAsync ?? await getDefaultExecFileAsync();
90504
+ const execFileAsync41 = options?.execFileAsync ?? await getDefaultExecFileAsync();
90469
90505
  const { agentMemoryWorkspacePath: agentMemoryWorkspacePath2 } = await Promise.resolve().then(() => (init_memory_dreams(), memory_dreams_exports));
90470
90506
  const workspacePath = agentMemoryWorkspacePath2(rootDir, agentId);
90471
90507
  await mkdir10(workspacePath, { recursive: true });
90472
90508
  try {
90473
- await execFileAsync40("qmd", ["collection", "add", workspacePath, "--name", qmdAgentMemoryCollectionName(rootDir, agentId), "--mask", "**/*.md"], {
90509
+ await execFileAsync41("qmd", ["collection", "add", workspacePath, "--name", qmdAgentMemoryCollectionName(rootDir, agentId), "--mask", "**/*.md"], {
90474
90510
  cwd: rootDir,
90475
90511
  timeout: 4e3,
90476
90512
  maxBuffer: 512 * 1024
@@ -90483,8 +90519,8 @@ ${stderr}`)) {
90483
90519
  throw err;
90484
90520
  }
90485
90521
  }
90486
- await execFileAsync40("qmd", ["update"], { cwd: rootDir, timeout: 3e4, maxBuffer: 1024 * 1024 });
90487
- await execFileAsync40("qmd", ["embed"], { cwd: rootDir, timeout: 12e4, maxBuffer: 1024 * 1024 });
90522
+ await execFileAsync41("qmd", ["update"], { cwd: rootDir, timeout: 3e4, maxBuffer: 1024 * 1024 });
90523
+ await execFileAsync41("qmd", ["embed"], { cwd: rootDir, timeout: 12e4, maxBuffer: 1024 * 1024 });
90488
90524
  })();
90489
90525
  qmdAgentRefreshState.set(key, { lastStartedAt: now, inFlight: promise });
90490
90526
  try {
@@ -90505,8 +90541,8 @@ function scheduleQmdAgentMemoryRefresh(rootDir, agentId) {
90505
90541
  }
90506
90542
  async function isQmdAvailable() {
90507
90543
  try {
90508
- const execFileAsync40 = await getDefaultExecFileAsync();
90509
- await execFileAsync40("qmd", ["--help"], {
90544
+ const execFileAsync41 = await getDefaultExecFileAsync();
90545
+ await execFileAsync41("qmd", ["--help"], {
90510
90546
  timeout: 3e3,
90511
90547
  maxBuffer: 128 * 1024,
90512
90548
  keepAlive: true
@@ -90517,12 +90553,12 @@ async function isQmdAvailable() {
90517
90553
  }
90518
90554
  }
90519
90555
  async function installQmd(options) {
90520
- const execFileAsync40 = options?.execFileAsync ?? await getDefaultExecFileAsync();
90556
+ const execFileAsync41 = options?.execFileAsync ?? await getDefaultExecFileAsync();
90521
90557
  const [command, ...args] = QMD_INSTALL_COMMAND.split(" ");
90522
90558
  if (!command || args.length === 0) {
90523
90559
  throw new MemoryBackendError("BACKEND_UNAVAILABLE", "qmd install command is not configured", "qmd");
90524
90560
  }
90525
- await execFileAsync40(command, args, {
90561
+ await execFileAsync41(command, args, {
90526
90562
  timeout: 12e4,
90527
90563
  maxBuffer: 1024 * 1024
90528
90564
  });
@@ -100037,7 +100073,6 @@ async function createWorkflowDefinitionImpl(store, input) {
100037
100073
  if (!isWorkflowDefinitionIdPrimaryKeyCollision(error3)) throw error3;
100038
100074
  continue;
100039
100075
  }
100040
- store.workflowDefinitionsCache = null;
100041
100076
  return definition;
100042
100077
  }
100043
100078
  throw new Error("Unable to allocate a free workflow definition id after repeated id collisions");
@@ -103621,7 +103656,6 @@ async function updateWorkflowDefinitionImpl(store, id, updates) {
103621
103656
  eq(project_exports.workflows.id, id),
103622
103657
  projectScopeFor(project_exports.workflows.projectId, layer.projectId)
103623
103658
  ));
103624
- store.workflowDefinitionsCache = null;
103625
103659
  return next;
103626
103660
  });
103627
103661
  if (pendingRehome) {
@@ -103656,7 +103690,6 @@ async function deleteWorkflowDefinitionImpl(store, id) {
103656
103690
  projectScopeFor(project_exports.workflows.projectId, layer.projectId)
103657
103691
  )).returning();
103658
103692
  if (deleted.length === 0) throw new Error(`Workflow '${id}' not found`);
103659
- store.workflowDefinitionsCache = null;
103660
103693
  await layer.db.delete(project_exports.workflowSettings).where(and(
103661
103694
  eq(project_exports.workflowSettings.workflowId, id),
103662
103695
  projectScopeFor(project_exports.workflowSettings.projectId, layer.projectId)
@@ -108250,7 +108283,6 @@ var init_store = __esm({
108250
108283
  taskIdIntegrityReport = { status: "ok", checkedAt: (/* @__PURE__ */ new Date()).toISOString(), anomalies: [] };
108251
108284
  lastTaskIdIntegrityLogSignature = null;
108252
108285
  workflowStepsCache = null;
108253
- workflowDefinitionsCache = null;
108254
108286
  _pluginWorkflowStepTemplates = [];
108255
108287
  globalSettingsStore;
108256
108288
  donePauseBackfillDone = false;
@@ -115880,7 +115912,7 @@ function getPostMergeFinalizeBlocker(task) {
115880
115912
  }
115881
115913
  function planConfirmedMergeChecklistReconciliation(task) {
115882
115914
  return {
115883
- skippedStepIndexes: task.steps.map((step, index2) => step.status === "pending" || step.status === "in-progress" ? index2 : -1).filter((index2) => index2 >= 0),
115915
+ skippedStepIndexes: (task.steps ?? []).map((step, index2) => step.status === "pending" || step.status === "in-progress" ? index2 : -1).filter((index2) => index2 >= 0),
115884
115916
  reconciledWorkflowStepIds: (task.workflowStepResults ?? []).filter((result2) => result2.status === "pending").map((result2) => result2.workflowStepId)
115885
115917
  };
115886
115918
  }
@@ -135930,11 +135962,11 @@ var require_extract_zip = __commonJS({
135930
135962
  var { createWriteStream, promises: fs10 } = __require("fs");
135931
135963
  var getStream = require_get_stream();
135932
135964
  var path13 = __require("path");
135933
- var { promisify: promisify101 } = __require("util");
135965
+ var { promisify: promisify102 } = __require("util");
135934
135966
  var stream = __require("stream");
135935
135967
  var yauzl = require_yauzl();
135936
- var openZip = promisify101(yauzl.open);
135937
- var pipeline = promisify101(stream.pipeline);
135968
+ var openZip = promisify102(yauzl.open);
135969
+ var pipeline = promisify102(stream.pipeline);
135938
135970
  var Extractor = class {
135939
135971
  constructor(zipPath, opts) {
135940
135972
  this.zipPath = zipPath;
@@ -136016,7 +136048,7 @@ var require_extract_zip = __commonJS({
136016
136048
  await fs10.mkdir(destDir, mkdirOptions);
136017
136049
  if (isDir) return;
136018
136050
  debug("opening read stream", dest);
136019
- const readStream = await promisify101(this.zipfile.openReadStream.bind(this.zipfile))(entry);
136051
+ const readStream = await promisify102(this.zipfile.openReadStream.bind(this.zipfile))(entry);
136020
136052
  if (symlink) {
136021
136053
  const link = await getStream(readStream);
136022
136054
  debug("creating symlink", link, dest);
@@ -137455,6 +137487,7 @@ async function updateChatSession(handle2, id, input) {
137455
137487
  if (input.status !== void 0) setValues.status = input.status;
137456
137488
  if (input.modelProvider !== void 0) setValues.modelProvider = input.modelProvider;
137457
137489
  if (input.modelId !== void 0) setValues.modelId = input.modelId;
137490
+ if (input.agentId !== void 0) setValues.agentId = input.agentId;
137458
137491
  if (input.thinkingLevel !== void 0) setValues.thinkingLevel = input.thinkingLevel;
137459
137492
  if (input.memoryFocus !== void 0) setValues.memoryFocus = input.memoryFocus;
137460
137493
  if (input.pinnedAt !== void 0) setValues.pinnedAt = input.pinnedAt;
@@ -138508,6 +138541,7 @@ var init_cli_session_store = __esm({
138508
138541
  });
138509
138542
 
138510
138543
  // ../core/src/secrets/oauth-credential-interop.ts
138544
+ import { createHash as createHash22 } from "node:crypto";
138511
138545
  import { existsSync as existsSync40, readFileSync as readFileSync11 } from "node:fs";
138512
138546
  import { homedir as homedir7 } from "node:os";
138513
138547
  import { join as join55 } from "node:path";
@@ -138567,6 +138601,22 @@ function getLastRefreshFallbackExpiryMs(lastRefresh) {
138567
138601
  }
138568
138602
  return parsed + CODEX_REFRESH_FALLBACK_WINDOW_MS;
138569
138603
  }
138604
+ function isSameStoredCredentialMaterial(left, right) {
138605
+ if (!left || !right || left.type !== right.type) {
138606
+ return false;
138607
+ }
138608
+ return left.key === right.key && left.access === right.access && left.refresh === right.refresh;
138609
+ }
138610
+ function computeStoredCredentialAccountFingerprint(credential) {
138611
+ if (!credential) {
138612
+ return void 0;
138613
+ }
138614
+ const material = typeof credential.refresh === "string" && credential.refresh.length > 0 ? credential.refresh : typeof credential.access === "string" && credential.access.length > 0 ? credential.access : typeof credential.key === "string" && credential.key.length > 0 ? credential.key : void 0;
138615
+ if (!material) {
138616
+ return void 0;
138617
+ }
138618
+ return createHash22("sha256").update(`${credential.type ?? ""}\0${material}`).digest("hex").slice(0, 16);
138619
+ }
138570
138620
  function isStoredAuthCredential(value) {
138571
138621
  if (!value || typeof value !== "object" || Array.isArray(value)) {
138572
138622
  return false;
@@ -139537,7 +139587,7 @@ var init_task_timing = __esm({
139537
139587
  });
139538
139588
 
139539
139589
  // ../core/src/task-recommendation-notice.ts
139540
- import { createHash as createHash22 } from "node:crypto";
139590
+ import { createHash as createHash23 } from "node:crypto";
139541
139591
  function registerTaskRecommendationNoticeMailbox(store, mailbox) {
139542
139592
  mailboxes2.set(store, mailbox);
139543
139593
  return () => {
@@ -139562,7 +139612,7 @@ function buildTaskRecommendationNoticeContent(task, recommendations) {
139562
139612
  }
139563
139613
  function buildTaskRecommendationNoticeIdempotencyKey(taskId, recommendations) {
139564
139614
  const ids = recommendations.map(({ id }) => id).sort().join("\n");
139565
- const digest = createHash22("sha256").update(ids, "utf8").digest("hex").slice(0, 16);
139615
+ const digest = createHash23("sha256").update(ids, "utf8").digest("hex").slice(0, 16);
139566
139616
  return `task-recommendation-notice:${taskId}:${digest}`;
139567
139617
  }
139568
139618
  async function notifyOperatorOfTaskRecommendations(store, task, recommendations, settings) {
@@ -140008,6 +140058,7 @@ __export(src_exports, {
140008
140058
  APPROVAL_REQUEST_STATUSES: () => APPROVAL_REQUEST_STATUSES,
140009
140059
  ARCHIVED_TASK_DOCUMENT_ADDITION_BOUNDARY: () => ARCHIVED_TASK_DOCUMENT_ADDITION_BOUNDARY,
140010
140060
  ARCHIVED_TASK_DOCUMENT_PUBLICATION_REJECTED: () => ARCHIVED_TASK_DOCUMENT_PUBLICATION_REJECTED,
140061
+ AUTOMATED_BYPASS_ACTORS: () => AUTOMATED_BYPASS_ACTORS,
140011
140062
  AUTOMATION_PRESETS: () => AUTOMATION_PRESETS,
140012
140063
  AUTOMATION_SELECTABLE_TOOLS: () => AUTOMATION_SELECTABLE_TOOLS,
140013
140064
  AUTOPILOT_STATES: () => AUTOPILOT_STATES,
@@ -140203,6 +140254,7 @@ __export(src_exports, {
140203
140254
  FAST_LANE_SKIP_VALUE: () => FAST_LANE_SKIP_VALUE,
140204
140255
  FAST_LANE_STEP_NAME: () => FAST_LANE_STEP_NAME,
140205
140256
  FAST_LANE_STEP_REVIEW_ROUTE_VALUE: () => FAST_LANE_STEP_REVIEW_ROUTE_VALUE,
140257
+ FAST_MODE_BYPASS_ACTOR: () => FAST_MODE_BYPASS_ACTOR,
140206
140258
  FEATURE_LOOP_REPAIR_TRANSITIONS: () => FEATURE_LOOP_REPAIR_TRANSITIONS,
140207
140259
  FEATURE_LOOP_STATES: () => FEATURE_LOOP_STATES,
140208
140260
  FEATURE_STATUSES: () => FEATURE_STATUSES,
@@ -140767,6 +140819,7 @@ __export(src_exports, {
140767
140819
  computeRetrySummary: () => computeRetrySummary,
140768
140820
  computeSkillId: () => computeSkillId,
140769
140821
  computeSnapshotChecksum: () => computeSnapshotChecksum,
140822
+ computeStoredCredentialAccountFingerprint: () => computeStoredCredentialAccountFingerprint,
140770
140823
  computeWorkflowIrPin: () => computeWorkflowIrPin,
140771
140824
  configurationTargetKey: () => configurationTargetKey,
140772
140825
  configureApprovalRequestTtls: () => configureApprovalRequestTtls,
@@ -141089,6 +141142,7 @@ __export(src_exports, {
141089
141142
  isApprovalRequestExpired: () => isApprovalRequestExpired,
141090
141143
  isArchivedColumnRole: () => isArchivedColumnRole,
141091
141144
  isArchivedRemediationCarrier: () => isArchivedRemediationCarrier,
141145
+ isAuditedOperatorBypass: () => isAuditedOperatorBypass,
141092
141146
  isBlockingFinding: () => isBlockingFinding,
141093
141147
  isBranchGroupComplete: () => isBranchGroupComplete,
141094
141148
  isBranchGroupMemberLanded: () => isBranchGroupMemberLanded,
@@ -141176,6 +141230,7 @@ __export(src_exports, {
141176
141230
  isReviewColumnRole: () => isReviewColumnRole,
141177
141231
  isRunRecord: () => isRunRecord,
141178
141232
  isRunningAgentTask: () => isRunningAgentTask,
141233
+ isSameStoredCredentialMaterial: () => isSameStoredCredentialMaterial,
141179
141234
  isSanctionedEngineBackwardMove: () => isSanctionedEngineBackwardMove,
141180
141235
  isSandboxExperimentalEnabled: () => isSandboxExperimentalEnabled,
141181
141236
  isSecretAccessPolicy: () => isSecretAccessPolicy,
@@ -141454,6 +141509,7 @@ __export(src_exports, {
141454
141509
  renderTriagePolicyPlaceholders: () => renderTriagePolicyPlaceholders,
141455
141510
  renderValidationCause: () => renderValidationCause,
141456
141511
  renderValidationFailureDescription: () => renderValidationFailureDescription,
141512
+ requiresContentReviewProof: () => requiresContentReviewProof,
141457
141513
  requiresPlannerConfirmation: () => requiresPlannerConfirmation,
141458
141514
  requiresWorktrunkInstallVerification: () => requiresWorktrunkInstallVerification,
141459
141515
  resetGhAvailabilityCache: () => resetGhAvailabilityCache,
@@ -141617,6 +141673,7 @@ __export(src_exports, {
141617
141673
  resolveTitleSummarizerSettingsModel: () => resolveTitleSummarizerSettingsModel,
141618
141674
  resolveToolOutputBudget: () => resolveToolOutputBudget,
141619
141675
  resolveTrailingVerificationStepIndex: () => resolveTrailingVerificationStepIndex,
141676
+ resolveUnprovenReviewApproval: () => resolveUnprovenReviewApproval,
141620
141677
  resolveUpdateAutomationSettings: () => resolveUpdateAutomationSettings,
141621
141678
  resolveUpdateTargetVersion: () => resolveUpdateTargetVersion,
141622
141679
  resolveUpdatesExternallyManaged: () => resolveUpdatesExternallyManaged,
@@ -142251,7 +142308,7 @@ var init_logger3 = __esm({
142251
142308
  });
142252
142309
 
142253
142310
  // ../engine/src/agents/agent-logger.ts
142254
- import { createHash as createHash23 } from "node:crypto";
142311
+ import { createHash as createHash24 } from "node:crypto";
142255
142312
  function truncateToolResultDetail(value) {
142256
142313
  if (value.length <= TOOL_RESULT_DETAIL_LIMIT) return value;
142257
142314
  return `${value.slice(0, TOOL_RESULT_DETAIL_LIMIT)}${TOOL_RESULT_DETAIL_TRUNCATION_NOTICE}`;
@@ -142359,7 +142416,7 @@ function summarizeToolArgs(name2, args) {
142359
142416
  return `${key}=${clipToolArgValue(compactToolArgValue(args[key]), maximum)}`;
142360
142417
  }).join(", ");
142361
142418
  if (rendered.length <= TOOL_ARG_SUMMARY_MAX) return rendered;
142362
- const hash3 = createHash23("sha256").update(fullArgsJson).digest("hex").slice(0, STRUCTURED_ARG_HASH_HEX_LEN);
142419
+ const hash3 = createHash24("sha256").update(fullArgsJson).digest("hex").slice(0, STRUCTURED_ARG_HASH_HEX_LEN);
142363
142420
  const suffix = `\u2026#${hash3}`;
142364
142421
  const keep = Math.max(0, TOOL_ARG_SUMMARY_MAX - suffix.length);
142365
142422
  return `${rendered.slice(0, keep)}${suffix}`;
@@ -144126,6 +144183,14 @@ function resolveAiMergeRootPath(rootDir, settings) {
144126
144183
  function resolveLegacyAiMergeRootPath(rootDir) {
144127
144184
  return join58(rootDir, ".fusion", "ai-merge");
144128
144185
  }
144186
+ function resolveAiMergeSearchRoots(rootDir, settings) {
144187
+ const roots = [
144188
+ resolveAiMergeRootPath(rootDir, settings),
144189
+ resolveLegacyAiMergeRootPath(rootDir),
144190
+ ...settings?.worktreesDir ? [] : [join58(resolveLegacyWorktreesDirLayout(rootDir), AI_MERGE_DIRNAME)]
144191
+ ];
144192
+ return [...new Set(roots)];
144193
+ }
144129
144194
  function resolveWorktreesDir(rootDir, settings, workspaceContext) {
144130
144195
  return resolveWorktreesDirLayout(rootDir, settings, workspaceContext);
144131
144196
  }
@@ -145884,18 +145949,25 @@ function parseWorktreesFromPorcelain(porcelain) {
145884
145949
  if (current.path) rows.push({ path: current.path, branch: current.branch });
145885
145950
  return rows;
145886
145951
  }
145952
+ function isRegenerableIgnoredPorcelainEntry(entry) {
145953
+ const path13 = entry.slice(3).replace(/\/$/, "");
145954
+ if (!path13 || path13.startsWith('"')) return false;
145955
+ const lastSegment = path13.split("/").at(-1);
145956
+ return lastSegment !== void 0 && REGENERABLE_IGNORED_DIR_NAMES.has(lastSegment);
145957
+ }
145887
145958
  function classifyWorktreeRemovalContent(porcelain) {
145888
145959
  const entries = porcelain.split(/\r?\n/).filter((line2) => line2.trim().length > 0);
145889
145960
  if (entries.length === 0) return "clean";
145890
- return entries.every((line2) => line2.startsWith("!!")) ? "ignored-only" : "deliverable";
145961
+ if (entries.some((line2) => !line2.startsWith("!! "))) return "deliverable";
145962
+ return entries.every(isRegenerableIgnoredPorcelainEntry) ? "regenerable-ignored" : "ignored-only";
145891
145963
  }
145892
145964
  async function assertCleanForDefensiveRemoval(worktreePath) {
145893
145965
  if (!existsSync44(worktreePath)) {
145894
- return "clean";
145966
+ return { classification: "clean", entryCount: 0 };
145895
145967
  }
145896
145968
  let stdout;
145897
145969
  try {
145898
- ({ stdout } = await execFileAsync6("git", ["status", "--porcelain=v1", "--ignored", "--untracked-files=normal"], {
145970
+ ({ stdout } = await execFileAsync6("git", ["status", "--porcelain=v1", "--ignored=matching", "--untracked-files=normal"], {
145899
145971
  cwd: worktreePath,
145900
145972
  encoding: "utf-8",
145901
145973
  timeout: 15e3,
@@ -145908,7 +145980,10 @@ async function assertCleanForDefensiveRemoval(worktreePath) {
145908
145980
  if (classification === "deliverable") {
145909
145981
  throw new Error(`preserving ${worktreePath}: uncommitted or ignored content present`);
145910
145982
  }
145911
- return classification;
145983
+ return {
145984
+ classification,
145985
+ entryCount: stdout.split(/\r?\n/).filter((line2) => line2.trim().length > 0).length
145986
+ };
145912
145987
  }
145913
145988
  async function removeWorktree(input) {
145914
145989
  const logger3 = {
@@ -145925,9 +146000,12 @@ async function removeWorktree(input) {
145925
146000
  }
145926
146001
  const requiresCleanWorktree = DEFENSIVE_REMOVAL_REASONS.has(input.reason);
145927
146002
  let contentClassification;
146003
+ let contentEntryCount = 0;
145928
146004
  if (requiresCleanWorktree) {
145929
146005
  try {
145930
- contentClassification = await assertCleanForDefensiveRemoval(input.worktreePath);
146006
+ const contentProbe = await assertCleanForDefensiveRemoval(input.worktreePath);
146007
+ contentClassification = contentProbe.classification;
146008
+ contentEntryCount = contentProbe.entryCount;
145931
146009
  } catch (error3) {
145932
146010
  const classification = error3 instanceof Error && error3.message.includes(": status probe failed (") ? "unverifiable" : "deliverable";
145933
146011
  await input.audit?.git({
@@ -145944,6 +146022,17 @@ async function removeWorktree(input) {
145944
146022
  throw error3;
145945
146023
  }
145946
146024
  if (contentClassification === "ignored-only" && !input.postLandingProof) {
146025
+ await input.audit?.git({
146026
+ type: "worktree:removal-preserved",
146027
+ target: input.worktreePath,
146028
+ metadata: {
146029
+ taskId: input.taskId,
146030
+ reason: input.reason,
146031
+ source: void 0,
146032
+ classification: "ignored-only",
146033
+ hasPostLandingProof: false
146034
+ }
146035
+ }).catch(() => void 0);
145947
146036
  throw new Error(`preserving ${input.worktreePath}: uncommitted or ignored content present`);
145948
146037
  }
145949
146038
  }
@@ -145963,6 +146052,17 @@ async function removeWorktree(input) {
145963
146052
  } catch {
145964
146053
  }
145965
146054
  };
146055
+ const recordRegenerableDiscard = async () => {
146056
+ if (contentClassification !== "regenerable-ignored") return;
146057
+ try {
146058
+ await input.audit?.git({
146059
+ type: "worktree:removal-discarded-regenerable-content",
146060
+ target: input.worktreePath,
146061
+ metadata: { taskId: input.taskId, reason: input.reason, entryCount: contentEntryCount }
146062
+ });
146063
+ } catch {
146064
+ }
146065
+ };
145966
146066
  if (input.expectedOwnerTaskId && input.liveOwnerProbe) {
145967
146067
  const reconciled = reconcileSelfOwnedActiveSessionForRemoval(
145968
146068
  activeSessionRegistry,
@@ -146016,6 +146116,7 @@ async function removeWorktree(input) {
146016
146116
  try {
146017
146117
  await backend.remove(removeInput);
146018
146118
  await recordIgnoredOnlyDiscard();
146119
+ await recordRegenerableDiscard();
146019
146120
  if (input.audit) {
146020
146121
  await input.audit.git({
146021
146122
  type: backend.kind === "worktrunk" ? "worktree:worktrunk-remove" : "worktree:remove",
@@ -146043,6 +146144,7 @@ async function removeWorktree(input) {
146043
146144
  try {
146044
146145
  await native.remove(removeInput);
146045
146146
  await recordIgnoredOnlyDiscard();
146147
+ await recordRegenerableDiscard();
146046
146148
  await input.audit?.git({ type: "worktree:remove", target: input.worktreePath });
146047
146149
  return { removed: true, classification: "removed" };
146048
146150
  } catch (nativeError) {
@@ -146064,7 +146166,7 @@ function resolveWorktreeBackend(settings, deps = {}) {
146064
146166
  }
146065
146167
  return new NativeWorktreeBackend({ logger: deps.logger, settings, audit: deps.audit });
146066
146168
  }
146067
- var execAsync9, execFileAsync6, NATIVE_TIMEOUT_MS, REMOVE_TIMEOUT_MS, MAX_BUFFER3, HARMLESS_MERGE_REMOVE_ERROR_PATTERNS, WORKTRUNK_TIMEOUTS_MS, WORKTREE_BACKEND_MARKER, WorktrunkOperationError, NativeWorktreeBackend, WorktrunkWorktreeBackend, RemovalReason, ALLOWED_FORCE_REASONS, DEFENSIVE_REMOVAL_REASONS, POST_LANDING_PROOF_REASONS, InvalidForceUsageError, InvalidPostLandingProofUsageError, ActiveSessionWorktreeRemovalError;
146169
+ var execAsync9, execFileAsync6, NATIVE_TIMEOUT_MS, REMOVE_TIMEOUT_MS, MAX_BUFFER3, HARMLESS_MERGE_REMOVE_ERROR_PATTERNS, WORKTRUNK_TIMEOUTS_MS, WORKTREE_BACKEND_MARKER, WorktrunkOperationError, NativeWorktreeBackend, WorktrunkWorktreeBackend, RemovalReason, ALLOWED_FORCE_REASONS, DEFENSIVE_REMOVAL_REASONS, POST_LANDING_PROOF_REASONS, InvalidForceUsageError, InvalidPostLandingProofUsageError, ActiveSessionWorktreeRemovalError, REGENERABLE_IGNORED_DIR_NAMES;
146068
146170
  var init_worktree_backend = __esm({
146069
146171
  "../engine/src/worktree/worktree-backend.ts"() {
146070
146172
  "use strict";
@@ -146804,6 +146906,27 @@ ${getErrorStderr(error3) ?? ""}`;
146804
146906
  this.name = "ActiveSessionWorktreeRemovalError";
146805
146907
  }
146806
146908
  };
146909
+ REGENERABLE_IGNORED_DIR_NAMES = /* @__PURE__ */ new Set([
146910
+ "node_modules",
146911
+ "dist",
146912
+ "build",
146913
+ "out",
146914
+ "target",
146915
+ "bin",
146916
+ "obj",
146917
+ "coverage",
146918
+ ".next",
146919
+ ".nuxt",
146920
+ ".turbo",
146921
+ ".svelte-kit",
146922
+ ".parcel-cache",
146923
+ ".pytest_cache",
146924
+ ".mypy_cache",
146925
+ "__pycache__",
146926
+ ".gradle",
146927
+ ".venv",
146928
+ "venv"
146929
+ ]);
146807
146930
  }
146808
146931
  });
146809
146932
 
@@ -147423,7 +147546,7 @@ var init_gating_classifications = __esm({
147423
147546
  });
147424
147547
 
147425
147548
  // ../engine/src/agents/agent-action-gate.ts
147426
- import { createHash as createHash24 } from "node:crypto";
147549
+ import { createHash as createHash25 } from "node:crypto";
147427
147550
  function getExemptTools() {
147428
147551
  if (!_exemptTools) {
147429
147552
  _exemptTools = new Set(DEFAULT_EXEMPT_TOOLS);
@@ -147475,7 +147598,7 @@ function evaluateAgentActionGate(params) {
147475
147598
  if (params.toolName === "bash") {
147476
147599
  const command = extractShellCommand(args);
147477
147600
  const git11 = classifyGitCommand(command);
147478
- resourceId = command ? `cmd:${createHash24("sha256").update(command).digest("hex").slice(0, 16)}` : void 0;
147601
+ resourceId = command ? `cmd:${createHash25("sha256").update(command).digest("hex").slice(0, 16)}` : void 0;
147479
147602
  if (git11?.write) {
147480
147603
  category = "git_write";
147481
147604
  operation = git11.operation;
@@ -149241,6 +149364,15 @@ async function withOAuthRefreshLock(authPath, providerId, refresh) {
149241
149364
  await release3();
149242
149365
  }
149243
149366
  }
149367
+ async function withOAuthInstanceLoginLock(authPath, providerId, operation) {
149368
+ const safeProviderId = providerId.replace(/[^a-zA-Z0-9._-]/g, "_");
149369
+ const release3 = await import_proper_lockfile.default.lock(`${authPath}.${safeProviderId}.instance-login`, AUTH_LOCK_OPTIONS);
149370
+ try {
149371
+ return await operation();
149372
+ } finally {
149373
+ await release3();
149374
+ }
149375
+ }
149244
149376
  function readDefaultInstanceMap(data) {
149245
149377
  const candidate = data.__fusionDefaultInstances;
149246
149378
  if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) return {};
@@ -149530,7 +149662,7 @@ function createFusionAuthStorage() {
149530
149662
  primary.reload();
149531
149663
  const selectPersistedRefreshCredential = () => {
149532
149664
  const storedCredential = primary.get(storageProvider);
149533
- if (refreshLockProvider !== ANTHROPIC_PROVIDER_ID2) {
149665
+ if (storedCredential?.type === "oauth" || refreshLockProvider !== ANTHROPIC_PROVIDER_ID2) {
149534
149666
  return storedCredential;
149535
149667
  }
149536
149668
  const legacyCredential = primary.get(ANTHROPIC_PROVIDER_ID2);
@@ -149660,18 +149792,16 @@ function createFusionAuthStorage() {
149660
149792
  if (rawKey) return rawKey;
149661
149793
  }
149662
149794
  const subscriptionLoggedOut = loggedOutProviders.has(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
149663
- const legacyAnthropicOAuthCredential = rawProviderLoggedOut ? void 0 : selectStoredCredentialByType(ANTHROPIC_PROVIDER_ID2, "oauth");
149795
+ const subscriptionCredential = subscriptionLoggedOut ? void 0 : selectStoredCredential(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
149796
+ if (subscriptionCredential?.type === "oauth") {
149797
+ const subscriptionKey = await resolveRefreshableCredentialApiKey(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID, subscriptionCredential);
149798
+ if (subscriptionKey) return subscriptionKey;
149799
+ }
149800
+ const legacyAnthropicOAuthCredential = rawProviderLoggedOut || subscriptionCredential ? void 0 : selectStoredCredentialByType(ANTHROPIC_PROVIDER_ID2, "oauth");
149664
149801
  if (!subscriptionLoggedOut && legacyAnthropicOAuthCredential) {
149665
149802
  const legacyKey = await resolveRefreshableCredentialApiKey(ANTHROPIC_PROVIDER_ID2, legacyAnthropicOAuthCredential);
149666
149803
  if (legacyKey) return legacyKey;
149667
149804
  }
149668
- if (!subscriptionLoggedOut) {
149669
- const subscriptionCredential = selectStoredCredential(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
149670
- if (subscriptionCredential?.type === "oauth") {
149671
- const subscriptionKey = await resolveRefreshableCredentialApiKey(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID, subscriptionCredential);
149672
- if (subscriptionKey) return subscriptionKey;
149673
- }
149674
- }
149675
149805
  if (preferSubscription) {
149676
149806
  const rawKey = resolveRawApiKey();
149677
149807
  if (rawKey) return rawKey;
@@ -149848,8 +149978,15 @@ function createFusionAuthStorage() {
149848
149978
  return void 0;
149849
149979
  }
149850
149980
  if (sourceProvider !== ANTHROPIC_SUBSCRIPTION_PROVIDER_ID) {
149851
- await primary.set(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID, subscriptionCredential);
149852
- loggedOutProviders.delete(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
149981
+ const legacyKey = await resolveRefreshableCredentialApiKey(ANTHROPIC_PROVIDER_ID2, subscriptionCredential);
149982
+ primary.reload();
149983
+ const storedSubscription = primary.get(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
149984
+ const refreshedLegacyCredential = primary.get(ANTHROPIC_PROVIDER_ID2);
149985
+ if (!storedSubscription && refreshedLegacyCredential?.type === "oauth") {
149986
+ await primary.set(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID, refreshedLegacyCredential);
149987
+ loggedOutProviders.delete(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID);
149988
+ }
149989
+ return legacyKey;
149853
149990
  }
149854
149991
  return resolveRefreshableCredentialApiKey(ANTHROPIC_SUBSCRIPTION_PROVIDER_ID, subscriptionCredential);
149855
149992
  }
@@ -149894,6 +150031,9 @@ var init_auth_storage = __esm({
149894
150031
  }
149895
150032
  data = {};
149896
150033
  modelRuntime;
150034
+ async withProviderInstanceLoginLock(providerId, operation) {
150035
+ return withOAuthInstanceLoginLock(this.authPath, providerId, operation);
150036
+ }
149897
150037
  ensureFile() {
149898
150038
  const parent = dirname26(this.authPath);
149899
150039
  if (!existsSync45(parent)) mkdirSync7(parent, { recursive: true, mode: 448 });
@@ -150236,6 +150376,35 @@ var init_model_registry_refresh = __esm({
150236
150376
  });
150237
150377
 
150238
150378
  // ../engine/src/auth/provider-auth.ts
150379
+ async function withProviderInstanceLoginLock(authStorage, providerId, operation) {
150380
+ let locks = instanceLoginLocks.get(authStorage);
150381
+ if (!locks) {
150382
+ locks = /* @__PURE__ */ new Map();
150383
+ instanceLoginLocks.set(authStorage, locks);
150384
+ }
150385
+ const previous = locks.get(providerId);
150386
+ let release3;
150387
+ const gate = new Promise((resolve65) => {
150388
+ release3 = resolve65;
150389
+ });
150390
+ const queued = (previous ?? Promise.resolve()).catch(() => void 0).then(() => gate);
150391
+ locks.set(providerId, queued);
150392
+ await (previous ?? Promise.resolve()).catch(() => void 0);
150393
+ try {
150394
+ if (!authStorage.withProviderInstanceLoginLock) {
150395
+ return await operation();
150396
+ }
150397
+ return await authStorage.withProviderInstanceLoginLock(providerId, async () => {
150398
+ authStorage.reload();
150399
+ return await operation();
150400
+ });
150401
+ } finally {
150402
+ release3();
150403
+ if (locks.get(providerId) === queued) {
150404
+ locks.delete(providerId);
150405
+ }
150406
+ }
150407
+ }
150239
150408
  function toApiKeyStorageProviderId(providerId) {
150240
150409
  return providerId === ANTHROPIC_API_KEY_PROVIDER_ID2 ? ANTHROPIC_STORAGE_PROVIDER_ID : providerId;
150241
150410
  }
@@ -150273,7 +150442,18 @@ function wrapAuthStorageWithApiKeyProviders(authStorage, modelRegistry, readFall
150273
150442
  providerId,
150274
150443
  callbacks
150275
150444
  );
150276
- return;
150445
+ const credential = authStorage.get(providerId);
150446
+ if (credential?.type !== "oauth") {
150447
+ return credential;
150448
+ }
150449
+ const stampedCredential = {
150450
+ ...credential,
150451
+ ...computeStoredCredentialAccountFingerprint(credential) ? {
150452
+ accountFingerprint: computeStoredCredentialAccountFingerprint(credential)
150453
+ } : {}
150454
+ };
150455
+ await authStorage.set(providerId, stampedCredential);
150456
+ return stampedCredential;
150277
150457
  }
150278
150458
  const existingApiKey = mergedAuthStorage.get(ANTHROPIC_STORAGE_PROVIDER_ID);
150279
150459
  await mergedAuthStorage.login(
@@ -150282,19 +150462,29 @@ function wrapAuthStorageWithApiKeyProviders(authStorage, modelRegistry, readFall
150282
150462
  );
150283
150463
  const oauthCredential = authStorage.get(ANTHROPIC_STORAGE_PROVIDER_ID);
150284
150464
  if (oauthCredential?.type === "oauth") {
150285
- await mergedAuthStorage.set(ANTHROPIC_SUBSCRIPTION_STORAGE_PROVIDER_ID, oauthCredential);
150465
+ const stampedCredential = {
150466
+ ...oauthCredential,
150467
+ ...computeStoredCredentialAccountFingerprint(oauthCredential) ? {
150468
+ accountFingerprint: computeStoredCredentialAccountFingerprint(oauthCredential)
150469
+ } : {}
150470
+ };
150471
+ await mergedAuthStorage.set(ANTHROPIC_SUBSCRIPTION_STORAGE_PROVIDER_ID, stampedCredential);
150286
150472
  if (existingApiKey?.type === "api_key") {
150287
150473
  await mergedAuthStorage.set(ANTHROPIC_STORAGE_PROVIDER_ID, existingApiKey);
150288
150474
  } else {
150289
150475
  await authStorage.remove(ANTHROPIC_STORAGE_PROVIDER_ID);
150290
150476
  }
150477
+ return stampedCredential;
150291
150478
  }
150479
+ return void 0;
150292
150480
  };
150293
150481
  return {
150294
150482
  reload: () => mergedAuthStorage.reload(),
150295
150483
  getOAuthProviders: () => mergedAuthStorage.getOAuthProviders().map((provider) => provider.id === ANTHROPIC_STORAGE_PROVIDER_ID ? { id: ANTHROPIC_STORAGE_PROVIDER_ID, name: "Anthropic Subscription" } : { id: provider.id, name: provider.name }),
150296
150484
  hasAuth: (provider) => provider === ANTHROPIC_STORAGE_PROVIDER_ID || provider === ANTHROPIC_SUBSCRIPTION_STORAGE_PROVIDER_ID ? Boolean(getAnthropicSubscriptionCredential()) : mergedAuthStorage.hasAuth(provider),
150297
- login,
150485
+ login: async (providerId, callbacks) => {
150486
+ await login(providerId, callbacks);
150487
+ },
150298
150488
  logout: async (provider) => {
150299
150489
  if (provider !== ANTHROPIC_STORAGE_PROVIDER_ID && provider !== ANTHROPIC_SUBSCRIPTION_STORAGE_PROVIDER_ID) {
150300
150490
  await mergedAuthStorage.logout(provider);
@@ -150378,19 +150568,33 @@ function wrapAuthStorageWithApiKeyProviders(authStorage, modelRegistry, readFall
150378
150568
  },
150379
150569
  loginInstance: async (ref, callbacks, label) => {
150380
150570
  const providerId = ref.providerId === ANTHROPIC_STORAGE_PROVIDER_ID ? ANTHROPIC_SUBSCRIPTION_STORAGE_PROVIDER_ID : ref.providerId;
150381
- const target = { providerId, instanceId: ref.instanceId };
150382
- const previousDefault = mergedAuthStorage.getDefaultInstance(providerId);
150383
- const previousCredential = previousDefault && mergedAuthStorage.getInstance(previousDefault);
150384
- await login(providerId, callbacks);
150385
- const credential = mergedAuthStorage.get(providerId);
150386
- if (!credential) return;
150387
- await mergedAuthStorage.setInstance(target, { ...credential, ...label ? { label } : {} });
150388
- if (previousDefault && previousCredential && previousDefault.instanceId !== target.instanceId) {
150389
- await mergedAuthStorage.setInstance(previousDefault, previousCredential);
150390
- } else if (!previousDefault && target.instanceId !== DEFAULT_PROVIDER_INSTANCE_ID) {
150391
- await mergedAuthStorage.removeInstance({ providerId, instanceId: DEFAULT_PROVIDER_INSTANCE_ID });
150392
- await mergedAuthStorage.setDefaultInstance(target);
150393
- }
150571
+ return withProviderInstanceLoginLock(authStorage, providerId, async () => {
150572
+ const target = { providerId, instanceId: ref.instanceId };
150573
+ const previousDefault = mergedAuthStorage.getDefaultInstance(providerId);
150574
+ const previousCredential = previousDefault && mergedAuthStorage.getInstance(previousDefault);
150575
+ const preLoginInstances = mergedAuthStorage.listInstances(providerId).map((instanceRef) => ({ ref: instanceRef, credential: mergedAuthStorage.getInstance(instanceRef) })).filter((entry) => Boolean(entry.credential));
150576
+ const credential = await login(providerId, callbacks);
150577
+ if (!credential) return;
150578
+ const duplicate = preLoginInstances.find(
150579
+ (entry) => entry.ref.instanceId !== target.instanceId && isSameStoredCredentialMaterial(credential, entry.credential)
150580
+ );
150581
+ if (duplicate) {
150582
+ if (previousDefault && previousCredential) {
150583
+ await mergedAuthStorage.setInstance(previousDefault, previousCredential);
150584
+ }
150585
+ const conflictingAccount = duplicate.credential.label || duplicate.ref.instanceId;
150586
+ throw new Error(
150587
+ `This login authorized the account already stored as ${conflictingAccount}. Sign out of the provider in your browser and retry.`
150588
+ );
150589
+ }
150590
+ await mergedAuthStorage.setInstance(target, { ...credential, ...label ? { label } : {} });
150591
+ if (previousDefault && previousCredential && previousDefault.instanceId !== target.instanceId) {
150592
+ await mergedAuthStorage.setInstance(previousDefault, previousCredential);
150593
+ } else if (!previousDefault && target.instanceId !== DEFAULT_PROVIDER_INSTANCE_ID) {
150594
+ await mergedAuthStorage.removeInstance({ providerId, instanceId: DEFAULT_PROVIDER_INSTANCE_ID });
150595
+ await mergedAuthStorage.setDefaultInstance(target);
150596
+ }
150597
+ });
150394
150598
  },
150395
150599
  logoutInstance: async (ref) => {
150396
150600
  await mergedAuthStorage.removeInstance({
@@ -150634,7 +150838,7 @@ function createReadOnlyAuthFileStorage(authPaths) {
150634
150838
  }
150635
150839
  };
150636
150840
  }
150637
- var ANTHROPIC_API_KEY_PROVIDER_ID2, ANTHROPIC_STORAGE_PROVIDER_ID, ANTHROPIC_SUBSCRIPTION_STORAGE_PROVIDER_ID, BUILT_IN_API_KEY_PROVIDERS, CLI_PROVIDER_IDS;
150841
+ var ANTHROPIC_API_KEY_PROVIDER_ID2, ANTHROPIC_STORAGE_PROVIDER_ID, ANTHROPIC_SUBSCRIPTION_STORAGE_PROVIDER_ID, BUILT_IN_API_KEY_PROVIDERS, CLI_PROVIDER_IDS, instanceLoginLocks;
150638
150842
  var init_provider_auth = __esm({
150639
150843
  "../engine/src/auth/provider-auth.ts"() {
150640
150844
  "use strict";
@@ -150654,6 +150858,7 @@ var init_provider_auth = __esm({
150654
150858
  { id: "zai", name: "Zai" }
150655
150859
  ];
150656
150860
  CLI_PROVIDER_IDS = /* @__PURE__ */ new Set(["pi-claude-cli", "droid-cli"]);
150861
+ instanceLoginLocks = /* @__PURE__ */ new WeakMap();
150657
150862
  }
150658
150863
  });
150659
150864
 
@@ -151039,7 +151244,7 @@ var init_plan_review_continuation = __esm({
151039
151244
  });
151040
151245
 
151041
151246
  // ../engine/src/execution/hold-release.ts
151042
- import { createHash as createHash25 } from "node:crypto";
151247
+ import { createHash as createHash26 } from "node:crypto";
151043
151248
  import { readFile as readFile36 } from "node:fs/promises";
151044
151249
  function findColumn2(ir2, columnId) {
151045
151250
  if (ir2.version !== "v2") return void 0;
@@ -151077,9 +151282,9 @@ async function checkAndRecordUnplannedExecutionBlock(store, task, ir2) {
151077
151282
  promptContent = "";
151078
151283
  }
151079
151284
  }
151080
- const promptMarker = promptContent.length > 0 ? createHash25("sha256").update(promptContent).digest("hex") : "missing";
151285
+ const promptMarker = promptContent.length > 0 ? createHash26("sha256").update(promptContent).digest("hex") : "missing";
151081
151286
  const dependencies = [...task.dependencies ?? []].sort();
151082
- const episode = createHash25("sha256").update(JSON.stringify({
151287
+ const episode = createHash26("sha256").update(JSON.stringify({
151083
151288
  planReviewNode,
151084
151289
  promptMarker,
151085
151290
  dependencies,
@@ -175048,6 +175253,7 @@ async function connectMcpSessionTools(servers, opts = {}) {
175048
175253
  const clients = [];
175049
175254
  const closedClients = /* @__PURE__ */ new WeakSet();
175050
175255
  const usedToolNames = /* @__PURE__ */ new Set();
175256
+ const serverByToolName = /* @__PURE__ */ new Map();
175051
175257
  let disposed = false;
175052
175258
  const closeOnce = async (client) => {
175053
175259
  if (closedClients.has(client)) return;
@@ -175097,7 +175303,9 @@ async function connectMcpSessionTools(servers, opts = {}) {
175097
175303
  opts.logger?.log?.(connectMsg);
175098
175304
  }
175099
175305
  for (const tool of listedTools) {
175100
- tools.push(wrapMcpTool(server.name, tool, client, usedToolNames));
175306
+ const wrappedTool = wrapMcpTool(server.name, tool, client, usedToolNames);
175307
+ tools.push(wrappedTool);
175308
+ serverByToolName.set(wrappedTool.name, server.name);
175101
175309
  }
175102
175310
  break;
175103
175311
  } catch (error3) {
@@ -175124,7 +175332,7 @@ async function connectMcpSessionTools(servers, opts = {}) {
175124
175332
  await closeAll();
175125
175333
  }
175126
175334
  }
175127
- return { tools, connected, skipped, dispose: closeAll };
175335
+ return { tools, connected, skipped, serverByToolName, dispose: closeAll };
175128
175336
  }
175129
175337
  function normalizeMaxAttempts(value) {
175130
175338
  if (value === void 0 || !Number.isFinite(value)) return DEFAULT_MAX_ATTEMPTS;
@@ -178264,8 +178472,10 @@ async function createPiAgentSessionRaw(options) {
178264
178472
  const createSessionWithModel = async (modelOverride) => {
178265
178473
  let mcpToolset;
178266
178474
  const allowReadonlyMcpTools = options.allowMcpToolsInReadonly === true;
178267
- if (forwardedMcpServers.length > 0 && (!isReadonly || allowReadonlyMcpTools)) {
178268
- mcpToolset = await connectMcpSessionTools(forwardedMcpServers, {
178475
+ const readonlyMcpServerAllowlist = options.readonlyMcpServerAllowlist === void 0 ? void 0 : new Set(options.readonlyMcpServerAllowlist.map((name2) => name2.trim()).filter(Boolean));
178476
+ const mcpServersToConnect = isReadonly && allowReadonlyMcpTools && readonlyMcpServerAllowlist !== void 0 ? forwardedMcpServers.filter((server) => readonlyMcpServerAllowlist.has(server.name)) : forwardedMcpServers;
178477
+ if (mcpServersToConnect.length > 0 && (!isReadonly || allowReadonlyMcpTools)) {
178478
+ mcpToolset = await connectMcpSessionTools(mcpServersToConnect, {
178269
178479
  cwd: options.cwd,
178270
178480
  clientFactory: options.mcpClientFactory,
178271
178481
  logger: piLog,
@@ -178276,7 +178486,8 @@ async function createPiAgentSessionRaw(options) {
178276
178486
  piLog.warn(`MCP session continuing with unavailable servers: count=${bootstrapFailures.length}`);
178277
178487
  }
178278
178488
  } else if (forwardedMcpServers.length > 0 && isReadonly) {
178279
- piLog.debug(`readonly session \u2014 MCP servers (${forwardedMcpServers.length}) skipped`);
178489
+ const reason = !allowReadonlyMcpTools ? "no-readonly-opt-in" : "readonly-allowlist-no-match";
178490
+ piLog.log(`readonly session \u2014 MCP servers (${forwardedMcpServers.length}) skipped: reason=${reason}`);
178280
178491
  }
178281
178492
  const mcpReadonlyTools = new Set(mcpToolset?.tools ?? []);
178282
178493
  const candidateCustomTools = [
@@ -178285,7 +178496,9 @@ async function createPiAgentSessionRaw(options) {
178285
178496
  ];
178286
178497
  const readonlyFilteredCustomTools = isReadonly ? filterCustomToolsForReadonly(
178287
178498
  candidateCustomTools,
178288
- allowReadonlyMcpTools ? { allowTool: (tool) => mcpReadonlyTools.has(tool) } : {}
178499
+ allowReadonlyMcpTools ? {
178500
+ allowTool: (tool) => readonlyMcpServerAllowlist === void 0 ? mcpReadonlyTools.has(tool) : readonlyMcpServerAllowlist.has(mcpToolset?.serverByToolName?.get(tool.name) ?? "")
178501
+ } : {}
178289
178502
  ) : { allowed: candidateCustomTools, denied: [] };
178290
178503
  const allowlistFilteredCustomTools = {
178291
178504
  ...readonlyFilteredCustomTools,
@@ -180297,7 +180510,7 @@ var init_retry_burned_logger = __esm({
180297
180510
 
180298
180511
  // ../engine/src/merge/merge-dependency-sync.ts
180299
180512
  import { exec as exec18 } from "node:child_process";
180300
- import { createHash as createHash26 } from "node:crypto";
180513
+ import { createHash as createHash27 } from "node:crypto";
180301
180514
  import { existsSync as existsSync49, readFileSync as readFileSync19, writeFileSync as writeFileSync6 } from "node:fs";
180302
180515
  import { join as join67 } from "node:path";
180303
180516
  import { promisify as promisify23 } from "node:util";
@@ -180330,7 +180543,7 @@ function computeLockfileHash(rootDir) {
180330
180543
  const p2 = join67(rootDir, name2);
180331
180544
  if (existsSync49(p2)) {
180332
180545
  try {
180333
- return createHash26("sha256").update(readFileSync19(p2)).digest("hex");
180546
+ return createHash27("sha256").update(readFileSync19(p2)).digest("hex");
180334
180547
  } catch {
180335
180548
  return null;
180336
180549
  }
@@ -180460,7 +180673,7 @@ var init_merge_dependency_sync = __esm({
180460
180673
  });
180461
180674
 
180462
180675
  // ../engine/src/worktree/worktree-dependency-install.ts
180463
- import { createHash as createHash27 } from "node:crypto";
180676
+ import { createHash as createHash28 } from "node:crypto";
180464
180677
  import { existsSync as existsSync50, readFileSync as readFileSync20, readdirSync as readdirSync8, statSync as statSync11, writeFileSync as writeFileSync7 } from "node:fs";
180465
180678
  import { delimiter as delimiter2, join as join68 } from "node:path";
180466
180679
  function rootEntries(rootDir) {
@@ -180558,7 +180771,7 @@ function isCommandAvailable(binary, env = process.env) {
180558
180771
  );
180559
180772
  }
180560
180773
  function hashParts(parts) {
180561
- const hash3 = createHash27("sha256");
180774
+ const hash3 = createHash28("sha256");
180562
180775
  for (const [name2, value] of [...parts].sort(([left], [right]) => left.localeCompare(right))) {
180563
180776
  hash3.update(name2).update("\0").update(value).update("\0");
180564
180777
  }
@@ -186546,7 +186759,7 @@ var init_mission_feature_sync = __esm({
186546
186759
  // ../engine/src/agent-tools.ts
186547
186760
  import { appendFile as appendFile3, mkdir as mkdir27, readFile as readFile40, readdir as readdir11, realpath, stat as stat11, writeFile as writeFile23 } from "node:fs/promises";
186548
186761
  import { existsSync as existsSync53 } from "node:fs";
186549
- import { createHash as createHash28, randomUUID as randomUUID48 } from "node:crypto";
186762
+ import { createHash as createHash29, randomUUID as randomUUID48 } from "node:crypto";
186550
186763
  import { tmpdir as tmpdir6 } from "node:os";
186551
186764
  import { extname as extname4, isAbsolute as isAbsolute14, join as join71, relative as relative13, resolve as resolve40, sep as sep11 } from "node:path";
186552
186765
  import { Type as Type2 } from "@earendil-works/pi-ai";
@@ -186590,7 +186803,7 @@ async function readAgentMemoryWorkspaceLongTerm(rootDir, agentId) {
186590
186803
  }
186591
186804
  }
186592
186805
  function qmdAgentMemoryCollectionName2(rootDir, agentId) {
186593
- const hash3 = createHash28("sha1").update(`${rootDir}:${agentId}`).digest("hex").slice(0, 12);
186806
+ const hash3 = createHash29("sha1").update(`${rootDir}:${agentId}`).digest("hex").slice(0, 12);
186594
186807
  return `fusion-agent-memory-${sanitizeAgentMemoryId(agentId).toLowerCase()}-${hash3}`;
186595
186808
  }
186596
186809
  function buildQmdAgentMemoryCollectionAddArgs(rootDir, agentId) {
@@ -186719,11 +186932,11 @@ async function refreshAgentMemoryQmdIndex(rootDir, agentMemory) {
186719
186932
  return;
186720
186933
  }
186721
186934
  const promise = (async () => {
186722
- const { execFile: execFile46 } = await import("node:child_process");
186723
- const { promisify: promisify101 } = await import("node:util");
186724
- const execFileAsync40 = promisify101(execFile46);
186935
+ const { execFile: execFile47 } = await import("node:child_process");
186936
+ const { promisify: promisify102 } = await import("node:util");
186937
+ const execFileAsync41 = promisify102(execFile47);
186725
186938
  try {
186726
- await execFileAsync40("qmd", buildQmdAgentMemoryCollectionAddArgs(rootDir, agentMemory.agentId), {
186939
+ await execFileAsync41("qmd", buildQmdAgentMemoryCollectionAddArgs(rootDir, agentMemory.agentId), {
186727
186940
  cwd: rootDir,
186728
186941
  timeout: 4e3,
186729
186942
  maxBuffer: 512 * 1024
@@ -186736,8 +186949,8 @@ ${stderr}`)) {
186736
186949
  throw error3;
186737
186950
  }
186738
186951
  }
186739
- await execFileAsync40("qmd", ["update"], { cwd: rootDir, timeout: 3e4, maxBuffer: 1024 * 1024 });
186740
- await execFileAsync40("qmd", ["embed"], { cwd: rootDir, timeout: 12e4, maxBuffer: 1024 * 1024 });
186952
+ await execFileAsync41("qmd", ["update"], { cwd: rootDir, timeout: 3e4, maxBuffer: 1024 * 1024 });
186953
+ await execFileAsync41("qmd", ["embed"], { cwd: rootDir, timeout: 12e4, maxBuffer: 1024 * 1024 });
186741
186954
  })();
186742
186955
  agentQmdRefreshState.set(key, { lastStartedAt: now, inFlight: promise });
186743
186956
  try {
@@ -186792,10 +187005,10 @@ async function searchAgentMemoryWithQmd(rootDir, agentMemory, query, limit) {
186792
187005
  }
186793
187006
  try {
186794
187007
  await refreshAgentMemoryQmdIndex(rootDir, agentMemory);
186795
- const { execFile: execFile46 } = await import("node:child_process");
186796
- const { promisify: promisify101 } = await import("node:util");
186797
- const execFileAsync40 = promisify101(execFile46);
186798
- const { stdout } = await execFileAsync40("qmd", buildQmdAgentMemorySearchArgs(rootDir, agentMemory.agentId, query, limit), {
187008
+ const { execFile: execFile47 } = await import("node:child_process");
187009
+ const { promisify: promisify102 } = await import("node:util");
187010
+ const execFileAsync41 = promisify102(execFile47);
187011
+ const { stdout } = await execFileAsync41("qmd", buildQmdAgentMemorySearchArgs(rootDir, agentMemory.agentId, query, limit), {
186799
187012
  cwd: rootDir,
186800
187013
  timeout: 4e3,
186801
187014
  maxBuffer: 1024 * 1024
@@ -198085,7 +198298,7 @@ var init_workspace_review_remediation = __esm({
198085
198298
  });
198086
198299
 
198087
198300
  // ../engine/src/worktree/secrets-env-writer.ts
198088
- import { createHash as createHash29 } from "node:crypto";
198301
+ import { createHash as createHash30 } from "node:crypto";
198089
198302
  import { execFile as execFile14 } from "node:child_process";
198090
198303
  import { promises as fs6 } from "node:fs";
198091
198304
  import path3 from "node:path";
@@ -198094,7 +198307,7 @@ function isValidFilename(filename) {
198094
198307
  return !!filename && !filename.includes("/") && !filename.includes("\\") && !filename.includes("..") && !filename.includes("\0") && filename !== FINGERPRINT_FILE;
198095
198308
  }
198096
198309
  function sha2562(content) {
198097
- return createHash29("sha256").update(Buffer.from(content, "utf8")).digest("hex");
198310
+ return createHash30("sha256").update(Buffer.from(content, "utf8")).digest("hex");
198098
198311
  }
198099
198312
  function quote(value) {
198100
198313
  return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("\n", "\\n").replaceAll("\r", "\\r").replaceAll(" ", "\\t")}"`;
@@ -200653,7 +200866,7 @@ var init_workflow_graph_executor = __esm({
200653
200866
  phase: "pre-merge",
200654
200867
  source: "optional-group",
200655
200868
  status: "skipped",
200656
- bypassedBy: "fast-mode",
200869
+ bypassedBy: FAST_MODE_BYPASS_ACTOR,
200657
200870
  bypassedAt,
200658
200871
  bypassReason: "Fast mode bypasses pre-merge workflow gates",
200659
200872
  bypassedFromStatus: "absent",
@@ -200857,7 +201070,7 @@ var init_workflow_graph_executor = __esm({
200857
201070
  const stepFindings = this.workflowReviewKind(node) && Array.isArray(exitContextPatch?.findings) ? exitContextPatch.findings : void 0;
200858
201071
  const repositoryReviewOutcomes = this.workflowReviewKind(node) && Array.isArray(exitContextPatch?.repositoryReviewOutcomes) ? exitContextPatch.repositoryReviewOutcomes : void 0;
200859
201072
  const repositoryScopeRevision = this.workflowReviewKind(node) && typeof exitContextPatch?.repositoryScopeRevision === "number" ? exitContextPatch.repositoryScopeRevision : void 0;
200860
- const reviewInputFingerprint = this.workflowReviewKind(node) && typeof exitContextPatch?.reviewInputFingerprint === "string" ? exitContextPatch.reviewInputFingerprint : void 0;
201073
+ const reviewInputFingerprint = requiresContentReviewProof(node.id, { reviewKind: this.workflowReviewKind(node) }) && typeof exitContextPatch?.reviewInputFingerprint === "string" ? exitContextPatch.reviewInputFingerprint : void 0;
200861
201074
  const reviewedCommitSha = this.workflowReviewKind(node) && typeof exitContextPatch?.reviewedCommitSha === "string" ? exitContextPatch.reviewedCommitSha : void 0;
200862
201075
  const supersededFindingSourceWorkflowStepId = this.workflowReviewKind(node) && typeof exitContextPatch?.supersededFindingSourceWorkflowStepId === "string" ? exitContextPatch.supersededFindingSourceWorkflowStepId : void 0;
200863
201076
  const supersededFindingIds = supersededFindingSourceWorkflowStepId && this.workflowReviewKind(node) && Array.isArray(exitContextPatch?.supersededFindingIds) ? exitContextPatch.supersededFindingIds.filter((id) => typeof id === "string") : void 0;
@@ -201596,7 +201809,7 @@ ${stepOutput}` : ""}`);
201596
201809
  const findings = this.workflowReviewKind(node) && Array.isArray(contextPatch.findings) ? contextPatch.findings : void 0;
201597
201810
  const repositoryReviewOutcomes = this.workflowReviewKind(node) && Array.isArray(contextPatch.repositoryReviewOutcomes) ? contextPatch.repositoryReviewOutcomes : void 0;
201598
201811
  const repositoryScopeRevision = this.workflowReviewKind(node) && typeof contextPatch.repositoryScopeRevision === "number" ? contextPatch.repositoryScopeRevision : void 0;
201599
- const reviewInputFingerprint = this.workflowReviewKind(node) && typeof contextPatch.reviewInputFingerprint === "string" ? contextPatch.reviewInputFingerprint : void 0;
201812
+ const reviewInputFingerprint = requiresContentReviewProof(node.id, { reviewKind: this.workflowReviewKind(node) }) && typeof contextPatch.reviewInputFingerprint === "string" ? contextPatch.reviewInputFingerprint : void 0;
201600
201813
  const reviewedCommitSha = this.workflowReviewKind(node) && typeof contextPatch.reviewedCommitSha === "string" ? contextPatch.reviewedCommitSha : void 0;
201601
201814
  const supersededFindingSourceWorkflowStepId = this.workflowReviewKind(node) && typeof contextPatch.supersededFindingSourceWorkflowStepId === "string" ? contextPatch.supersededFindingSourceWorkflowStepId : void 0;
201602
201815
  const supersededFindingIds = supersededFindingSourceWorkflowStepId && this.workflowReviewKind(node) && Array.isArray(contextPatch.supersededFindingIds) ? contextPatch.supersededFindingIds.filter((id) => typeof id === "string") : void 0;
@@ -202977,17 +203190,141 @@ var init_agent_binding_pure = __esm({
202977
203190
  }
202978
203191
  });
202979
203192
 
202980
- // ../engine/src/worktree/review-diff-fingerprint.ts
202981
- import { createHash as createHash30 } from "node:crypto";
202982
- import { execFile as execFile15 } from "node:child_process";
203193
+ // ../engine/src/executor/worktree-git-refs.ts
203194
+ import { exec as exec25, execFile as execFile15, execSync as execSync3 } from "node:child_process";
202983
203195
  import { promisify as promisify32 } from "node:util";
203196
+ async function preExecutionWorktreeHasWork(worktreePath) {
203197
+ try {
203198
+ const { stdout: dirty } = await execFileAsync9("git", ["status", "--porcelain"], { cwd: worktreePath, timeout: 3e4 });
203199
+ if (dirty.trim()) return true;
203200
+ const { stdout: ahead } = await execFileAsync9("git", ["log", "--oneline", "@{upstream}..HEAD"], { cwd: worktreePath, timeout: 3e4 }).catch(async () => await execFileAsync9("git", ["log", "--oneline", "-1", "HEAD", "--not", "--remotes", "--branches=main", "--branches=master"], { cwd: worktreePath, timeout: 3e4 }));
203201
+ return Boolean(ahead.trim());
203202
+ } catch {
203203
+ return true;
203204
+ }
203205
+ }
203206
+ async function resolveContaminationBaseRef(worktreePath) {
203207
+ try {
203208
+ const { stdout } = await execAsync22(
203209
+ "git merge-base HEAD main 2>/dev/null || git merge-base HEAD origin/main",
203210
+ { cwd: worktreePath, encoding: "utf-8" }
203211
+ );
203212
+ const ref = stdout.trim();
203213
+ return ref || void 0;
203214
+ } catch (err) {
203215
+ const errorMessage2 = err instanceof Error ? err.message : String(err);
203216
+ executorLog.warn(`Failed merge-base lookup for contamination check in ${worktreePath}: ${errorMessage2}`);
203217
+ return void 0;
203218
+ }
203219
+ }
203220
+ async function resolveDiffBaseRef(worktreePath, baseCommitSha) {
203221
+ if (baseCommitSha) return baseCommitSha;
203222
+ try {
203223
+ const { stdout } = await execAsync22(
203224
+ "git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main",
203225
+ { cwd: worktreePath, encoding: "utf-8" }
203226
+ );
203227
+ const ref = stdout.trim();
203228
+ if (ref) return ref;
203229
+ } catch (mergeBaseErr) {
203230
+ const mergeBaseMsg = mergeBaseErr instanceof Error ? mergeBaseErr.message : String(mergeBaseErr);
203231
+ executorLog.warn(`Failed merge-base lookup for diff base in ${worktreePath}, trying HEAD~1 fallback: ${mergeBaseMsg}`);
203232
+ }
203233
+ try {
203234
+ const { stdout } = await execAsync22("git rev-parse HEAD~1", {
203235
+ cwd: worktreePath,
203236
+ encoding: "utf-8"
203237
+ });
203238
+ return stdout.trim() || void 0;
203239
+ } catch {
203240
+ executorLog.debug(`Could not determine base commit for diff in ${worktreePath}`);
203241
+ return void 0;
203242
+ }
203243
+ }
203244
+ async function captureBaseCommitSha(store, task, worktreePath, audit, options = { isResume: false }) {
203245
+ try {
203246
+ if (options.isResume && task.baseCommitSha) {
203247
+ try {
203248
+ execSync3(`git merge-base --is-ancestor ${task.baseCommitSha} HEAD`, {
203249
+ cwd: worktreePath,
203250
+ stdio: "pipe"
203251
+ });
203252
+ executorLog.log(`${task.id}: preserved baseCommitSha ${task.baseCommitSha.slice(0, 7)} (resume)`);
203253
+ await audit.git({
203254
+ type: "commit:create",
203255
+ target: task.baseCommitSha,
203256
+ metadata: { purpose: "base", preserved: true }
203257
+ });
203258
+ return;
203259
+ } catch {
203260
+ }
203261
+ }
203262
+ const baseCommitSha = await resolveCapturedBaseCommitSha(worktreePath, {
203263
+ warn: (msg) => executorLog.warn(`${task.id}: ${msg}`)
203264
+ });
203265
+ if (!baseCommitSha) {
203266
+ throw new Error("could not resolve base commit SHA");
203267
+ }
203268
+ await store.updateTask(task.id, { baseCommitSha });
203269
+ executorLog.debug(`${task.id}: captured baseCommitSha ${baseCommitSha.slice(0, 7)}`);
203270
+ await audit.git({ type: "commit:create", target: baseCommitSha, metadata: { purpose: "base", preserved: false } });
203271
+ } catch (err) {
203272
+ const errorMessage2 = err instanceof Error ? err.message : String(err);
203273
+ executorLog.debug(`Failed to capture baseCommitSha for ${task.id}: ${errorMessage2}`);
203274
+ }
203275
+ }
203276
+ var execAsync22, execFileAsync9;
203277
+ var init_worktree_git_refs = __esm({
203278
+ "../engine/src/executor/worktree-git-refs.ts"() {
203279
+ "use strict";
203280
+ init_base_commit_capture();
203281
+ init_logger3();
203282
+ execAsync22 = promisify32(exec25);
203283
+ execFileAsync9 = promisify32(execFile15);
203284
+ }
203285
+ });
203286
+
203287
+ // ../engine/src/worktree/review-diff-fingerprint.ts
203288
+ import { createHash as createHash31 } from "node:crypto";
203289
+ import { execFile as execFile16 } from "node:child_process";
203290
+ import { promisify as promisify33 } from "node:util";
203291
+ function gitCaptureOptions(cwd) {
203292
+ return {
203293
+ cwd,
203294
+ encoding: "utf8",
203295
+ maxBuffer: REVIEW_DIFF_GIT_MAX_BUFFER_BYTES,
203296
+ timeout: REVIEW_DIFF_GIT_TIMEOUT_MS
203297
+ };
203298
+ }
203299
+ function isGitDiffBufferOverflow(error3) {
203300
+ if (typeof error3 !== "object" || error3 === null) return false;
203301
+ const candidate = error3;
203302
+ return candidate.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER" || typeof candidate.message === "string" && candidate.message.includes("maxBuffer");
203303
+ }
203304
+ async function resolveContentReviewInputProof(worktreePath, diffBaseCommitSha) {
203305
+ let baseRef;
203306
+ try {
203307
+ baseRef = await resolveDiffBaseRef(worktreePath, diffBaseCommitSha);
203308
+ } catch {
203309
+ return { kind: "unprovable", reason: "no-diff-base" };
203310
+ }
203311
+ if (!baseRef) return { kind: "unprovable", reason: "no-diff-base" };
203312
+ const probe = await probeReviewDiffFingerprint(worktreePath, baseRef);
203313
+ if (probe.state === "empty") {
203314
+ return { kind: "fingerprint", fingerprint: EMPTY_REVIEW_DIFF_FINGERPRINT };
203315
+ }
203316
+ return probe.state === "fingerprint" ? { kind: "fingerprint", fingerprint: probe.fingerprint } : { kind: "unprovable", reason: probe.reason };
203317
+ }
202984
203318
  async function probeReviewDiffFingerprint(worktreePath, baseRef, targetRef = "HEAD") {
202985
203319
  if (!worktreePath || !baseRef) return { state: "unavailable", reason: "missing-worktree-or-base" };
202986
203320
  try {
202987
- const { stdout } = await execFileAsync9("git", ["diff", "--binary", `${baseRef}..${targetRef}`], { cwd: worktreePath, encoding: "utf8" });
202988
- return stdout ? { state: "fingerprint", fingerprint: createHash30("sha256").update(stdout).digest("hex") } : { state: "empty" };
202989
- } catch {
202990
- return { state: "unavailable", reason: "git-diff-failed" };
203321
+ const { stdout } = await execFileAsync10("git", ["diff", "--binary", `${baseRef}..${targetRef}`], gitCaptureOptions(worktreePath));
203322
+ return stdout ? { state: "fingerprint", fingerprint: createHash31("sha256").update(stdout).digest("hex") } : { state: "empty" };
203323
+ } catch (error3) {
203324
+ return {
203325
+ state: "unavailable",
203326
+ reason: isGitDiffBufferOverflow(error3) ? "git-diff-too-large" : "git-diff-failed"
203327
+ };
202991
203328
  }
202992
203329
  }
202993
203330
  async function probeReviewChangesSinceCommit(worktreePath, reviewedCommitSha) {
@@ -202995,14 +203332,11 @@ async function probeReviewChangesSinceCommit(worktreePath, reviewedCommitSha) {
202995
203332
  return { state: "unavailable", reason: "missing-worktree-or-reviewed-commit" };
202996
203333
  }
202997
203334
  try {
202998
- await execFileAsync9("git", ["cat-file", "-e", `${reviewedCommitSha}^{commit}`], {
202999
- cwd: worktreePath,
203000
- encoding: "utf8"
203001
- });
203335
+ await execFileAsync10("git", ["cat-file", "-e", `${reviewedCommitSha}^{commit}`], gitCaptureOptions(worktreePath));
203002
203336
  const [{ stdout: countOutput }, { stdout: filesOutput }, { stdout: shortstatOutput }] = await Promise.all([
203003
- execFileAsync9("git", ["rev-list", "--count", `${reviewedCommitSha}..HEAD`], { cwd: worktreePath, encoding: "utf8" }),
203004
- execFileAsync9("git", ["diff", "--name-only", "-z", `${reviewedCommitSha}..HEAD`], { cwd: worktreePath, encoding: "utf8" }),
203005
- execFileAsync9("git", ["diff", "--shortstat", `${reviewedCommitSha}..HEAD`], { cwd: worktreePath, encoding: "utf8" })
203337
+ execFileAsync10("git", ["rev-list", "--count", `${reviewedCommitSha}..HEAD`], gitCaptureOptions(worktreePath)),
203338
+ execFileAsync10("git", ["diff", "--name-only", "-z", `${reviewedCommitSha}..HEAD`], gitCaptureOptions(worktreePath)),
203339
+ execFileAsync10("git", ["diff", "--shortstat", `${reviewedCommitSha}..HEAD`], gitCaptureOptions(worktreePath))
203006
203340
  ]);
203007
203341
  const commitCount = Number.parseInt(countOutput.trim(), 10);
203008
203342
  if (!Number.isSafeInteger(commitCount) || commitCount < 0) {
@@ -203031,22 +203365,30 @@ async function computeCodeReviewInputFingerprint(worktreePath, baseRef, targetRe
203031
203365
  if (result2.state === "empty") return EMPTY_REVIEW_DIFF_FINGERPRINT;
203032
203366
  return result2.state === "fingerprint" ? result2.fingerprint : void 0;
203033
203367
  }
203034
- var execFileAsync9, MAX_REVIEW_CHANGED_FILES, EMPTY_REVIEW_DIFF_FINGERPRINT;
203368
+ var execFileAsync10, REVIEW_DIFF_GIT_MAX_BUFFER_BYTES, REVIEW_DIFF_GIT_TIMEOUT_MS, MAX_REVIEW_CHANGED_FILES, EMPTY_REVIEW_DIFF_FINGERPRINT;
203035
203369
  var init_review_diff_fingerprint = __esm({
203036
203370
  "../engine/src/worktree/review-diff-fingerprint.ts"() {
203037
203371
  "use strict";
203038
- execFileAsync9 = promisify32(execFile15);
203372
+ init_worktree_git_refs();
203373
+ execFileAsync10 = promisify33(execFile16);
203374
+ REVIEW_DIFF_GIT_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
203375
+ REVIEW_DIFF_GIT_TIMEOUT_MS = 12e4;
203039
203376
  MAX_REVIEW_CHANGED_FILES = 100;
203040
203377
  EMPTY_REVIEW_DIFF_FINGERPRINT = "empty-review-input:v1";
203041
203378
  }
203042
203379
  });
203043
203380
 
203044
203381
  // ../engine/src/worktree/workspace-review-evidence.ts
203045
- import { execFile as execFile16 } from "node:child_process";
203046
- import { promisify as promisify33 } from "node:util";
203382
+ import { execFile as execFile17 } from "node:child_process";
203383
+ import { promisify as promisify34 } from "node:util";
203047
203384
  import { join as join76 } from "node:path";
203048
203385
  async function git3(args, cwd) {
203049
- const { stdout } = await execFileAsync10("git", args, { cwd, encoding: "utf8" });
203386
+ const { stdout } = await execFileAsync11("git", args, {
203387
+ cwd,
203388
+ encoding: "utf8",
203389
+ maxBuffer: REVIEW_DIFF_GIT_MAX_BUFFER_BYTES,
203390
+ timeout: REVIEW_DIFF_GIT_TIMEOUT_MS
203391
+ });
203050
203392
  return stdout.trim();
203051
203393
  }
203052
203394
  async function captureWorkspaceReviewEvidence(options) {
@@ -203099,13 +203441,60 @@ async function captureWorkspaceReviewEvidence(options) {
203099
203441
  outOfScopeRepositories
203100
203442
  };
203101
203443
  }
203102
- var execFileAsync10;
203444
+ var execFileAsync11;
203103
203445
  var init_workspace_review_evidence = __esm({
203104
203446
  "../engine/src/worktree/workspace-review-evidence.ts"() {
203105
203447
  "use strict";
203106
203448
  init_workspace_base_branch();
203107
203449
  init_review_diff_fingerprint();
203108
- execFileAsync10 = promisify33(execFile16);
203450
+ execFileAsync11 = promisify34(execFile17);
203451
+ }
203452
+ });
203453
+
203454
+ // ../engine/src/worktree/review-inline-fix-recapture.ts
203455
+ import { execFile as execFile18 } from "node:child_process";
203456
+ import { promisify as promisify35 } from "node:util";
203457
+ function classifyReviewInlineFixRecapture(input) {
203458
+ if (input.reviewKind === "plan") return { recapture: false, reason: "plan-domain" };
203459
+ if (input.verdict !== "APPROVE" && input.verdict !== "APPROVE_WITH_NOTES") {
203460
+ return { recapture: false, reason: "not-approval-verdict" };
203461
+ }
203462
+ if (!input.reviewedCommitSha || !input.currentHeadSha || !input.baseRef) {
203463
+ return { recapture: false, reason: "missing-anchor" };
203464
+ }
203465
+ if (input.reviewedCommitSha === input.currentHeadSha) return { recapture: false, reason: "head-unchanged" };
203466
+ if (input.fastForwardAdvance === void 0 || input.baseIsAncestor === void 0) {
203467
+ return { recapture: false, reason: "probe-unavailable" };
203468
+ }
203469
+ if (!input.fastForwardAdvance) return { recapture: false, reason: "history-rewritten" };
203470
+ if (!input.baseIsAncestor) return { recapture: false, reason: "base-not-ancestor" };
203471
+ if (!input.fingerprintProbeAvailable) return { recapture: false, reason: "probe-unavailable" };
203472
+ return { recapture: true, reason: "recaptured" };
203473
+ }
203474
+ async function readHeadSha(worktreePath) {
203475
+ if (!worktreePath) return void 0;
203476
+ try {
203477
+ const { stdout } = await execFileAsync12("git", ["rev-parse", "HEAD"], { cwd: worktreePath, encoding: "utf8" });
203478
+ return stdout.trim() || void 0;
203479
+ } catch {
203480
+ return void 0;
203481
+ }
203482
+ }
203483
+ async function isFastForwardAdvance(worktreePath, fromSha, toSha) {
203484
+ if (!worktreePath || !fromSha || !toSha) return void 0;
203485
+ try {
203486
+ await execFileAsync12("git", ["merge-base", "--is-ancestor", fromSha, toSha], { cwd: worktreePath, encoding: "utf8" });
203487
+ return true;
203488
+ } catch (error3) {
203489
+ const code = error3?.code;
203490
+ return code === 1 ? false : void 0;
203491
+ }
203492
+ }
203493
+ var execFileAsync12;
203494
+ var init_review_inline_fix_recapture = __esm({
203495
+ "../engine/src/worktree/review-inline-fix-recapture.ts"() {
203496
+ "use strict";
203497
+ execFileAsync12 = promisify35(execFile18);
203109
203498
  }
203110
203499
  });
203111
203500
 
@@ -203295,8 +203684,8 @@ var init_workspace_zero_acquire = __esm({
203295
203684
  });
203296
203685
 
203297
203686
  // ../engine/src/execution/branch-attribution.ts
203298
- import { exec as exec25 } from "node:child_process";
203299
- import { promisify as promisify34 } from "node:util";
203687
+ import { exec as exec26 } from "node:child_process";
203688
+ import { promisify as promisify36 } from "node:util";
203300
203689
  function quoteShellArg6(value) {
203301
203690
  return `'${value.replace(/'/g, `'\\''`)}'`;
203302
203691
  }
@@ -203334,7 +203723,7 @@ function taskIdsMatch(a, b3) {
203334
203723
  return a.toUpperCase() === b3.toUpperCase();
203335
203724
  }
203336
203725
  async function collectOwnTaskCommitsForRange(opts) {
203337
- const execImpl = opts.execAsyncImpl ?? execAsync22;
203726
+ const execImpl = opts.execAsyncImpl ?? execAsync23;
203338
203727
  let logOutput;
203339
203728
  try {
203340
203729
  const result2 = await execImpl(
@@ -203375,7 +203764,7 @@ async function collectOwnTaskCommitsForRange(opts) {
203375
203764
  return { ownCommitCount: ownCommitShas.length, ownCommitShas };
203376
203765
  }
203377
203766
  async function filterFilesToOwnTaskCommits(opts) {
203378
- const execImpl = opts.execAsyncImpl ?? execAsync22;
203767
+ const execImpl = opts.execAsyncImpl ?? execAsync23;
203379
203768
  const runGit10 = async (command) => {
203380
203769
  try {
203381
203770
  const { stdout } = await execImpl(command, {
@@ -203441,11 +203830,11 @@ async function filterFilesToOwnTaskCommits(opts) {
203441
203830
  commitAttributions
203442
203831
  };
203443
203832
  }
203444
- var execAsync22, GIT_TIMEOUT_MS5, GIT_MAX_BUFFER2, BranchAttributionError, SilentNoOpAttributionMismatchError;
203833
+ var execAsync23, GIT_TIMEOUT_MS5, GIT_MAX_BUFFER2, BranchAttributionError, SilentNoOpAttributionMismatchError;
203445
203834
  var init_branch_attribution = __esm({
203446
203835
  "../engine/src/execution/branch-attribution.ts"() {
203447
203836
  "use strict";
203448
- execAsync22 = promisify34(exec25);
203837
+ execAsync23 = promisify36(exec26);
203449
203838
  GIT_TIMEOUT_MS5 = 3e4;
203450
203839
  GIT_MAX_BUFFER2 = 10 * 1024 * 1024;
203451
203840
  BranchAttributionError = class extends Error {
@@ -203479,103 +203868,9 @@ var init_branch_attribution = __esm({
203479
203868
  }
203480
203869
  });
203481
203870
 
203482
- // ../engine/src/executor/worktree-git-refs.ts
203483
- import { exec as exec26, execFile as execFile17, execSync as execSync3 } from "node:child_process";
203484
- import { promisify as promisify35 } from "node:util";
203485
- async function preExecutionWorktreeHasWork(worktreePath) {
203486
- try {
203487
- const { stdout: dirty } = await execFileAsync11("git", ["status", "--porcelain"], { cwd: worktreePath, timeout: 3e4 });
203488
- if (dirty.trim()) return true;
203489
- const { stdout: ahead } = await execFileAsync11("git", ["log", "--oneline", "@{upstream}..HEAD"], { cwd: worktreePath, timeout: 3e4 }).catch(async () => await execFileAsync11("git", ["log", "--oneline", "-1", "HEAD", "--not", "--remotes", "--branches=main", "--branches=master"], { cwd: worktreePath, timeout: 3e4 }));
203490
- return Boolean(ahead.trim());
203491
- } catch {
203492
- return true;
203493
- }
203494
- }
203495
- async function resolveContaminationBaseRef(worktreePath) {
203496
- try {
203497
- const { stdout } = await execAsync23(
203498
- "git merge-base HEAD main 2>/dev/null || git merge-base HEAD origin/main",
203499
- { cwd: worktreePath, encoding: "utf-8" }
203500
- );
203501
- const ref = stdout.trim();
203502
- return ref || void 0;
203503
- } catch (err) {
203504
- const errorMessage2 = err instanceof Error ? err.message : String(err);
203505
- executorLog.warn(`Failed merge-base lookup for contamination check in ${worktreePath}: ${errorMessage2}`);
203506
- return void 0;
203507
- }
203508
- }
203509
- async function resolveDiffBaseRef(worktreePath, baseCommitSha) {
203510
- if (baseCommitSha) return baseCommitSha;
203511
- try {
203512
- const { stdout } = await execAsync23(
203513
- "git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main",
203514
- { cwd: worktreePath, encoding: "utf-8" }
203515
- );
203516
- const ref = stdout.trim();
203517
- if (ref) return ref;
203518
- } catch (mergeBaseErr) {
203519
- const mergeBaseMsg = mergeBaseErr instanceof Error ? mergeBaseErr.message : String(mergeBaseErr);
203520
- executorLog.warn(`Failed merge-base lookup for diff base in ${worktreePath}, trying HEAD~1 fallback: ${mergeBaseMsg}`);
203521
- }
203522
- try {
203523
- const { stdout } = await execAsync23("git rev-parse HEAD~1", {
203524
- cwd: worktreePath,
203525
- encoding: "utf-8"
203526
- });
203527
- return stdout.trim() || void 0;
203528
- } catch {
203529
- executorLog.debug(`Could not determine base commit for diff in ${worktreePath}`);
203530
- return void 0;
203531
- }
203532
- }
203533
- async function captureBaseCommitSha(store, task, worktreePath, audit, options = { isResume: false }) {
203534
- try {
203535
- if (options.isResume && task.baseCommitSha) {
203536
- try {
203537
- execSync3(`git merge-base --is-ancestor ${task.baseCommitSha} HEAD`, {
203538
- cwd: worktreePath,
203539
- stdio: "pipe"
203540
- });
203541
- executorLog.log(`${task.id}: preserved baseCommitSha ${task.baseCommitSha.slice(0, 7)} (resume)`);
203542
- await audit.git({
203543
- type: "commit:create",
203544
- target: task.baseCommitSha,
203545
- metadata: { purpose: "base", preserved: true }
203546
- });
203547
- return;
203548
- } catch {
203549
- }
203550
- }
203551
- const baseCommitSha = await resolveCapturedBaseCommitSha(worktreePath, {
203552
- warn: (msg) => executorLog.warn(`${task.id}: ${msg}`)
203553
- });
203554
- if (!baseCommitSha) {
203555
- throw new Error("could not resolve base commit SHA");
203556
- }
203557
- await store.updateTask(task.id, { baseCommitSha });
203558
- executorLog.debug(`${task.id}: captured baseCommitSha ${baseCommitSha.slice(0, 7)}`);
203559
- await audit.git({ type: "commit:create", target: baseCommitSha, metadata: { purpose: "base", preserved: false } });
203560
- } catch (err) {
203561
- const errorMessage2 = err instanceof Error ? err.message : String(err);
203562
- executorLog.debug(`Failed to capture baseCommitSha for ${task.id}: ${errorMessage2}`);
203563
- }
203564
- }
203565
- var execAsync23, execFileAsync11;
203566
- var init_worktree_git_refs = __esm({
203567
- "../engine/src/executor/worktree-git-refs.ts"() {
203568
- "use strict";
203569
- init_base_commit_capture();
203570
- init_logger3();
203571
- execAsync23 = promisify35(exec26);
203572
- execFileAsync11 = promisify35(execFile17);
203573
- }
203574
- });
203575
-
203576
203871
  // ../engine/src/executor/worktree-capture-modified-files.ts
203577
203872
  import { exec as exec27 } from "node:child_process";
203578
- import { promisify as promisify36 } from "node:util";
203873
+ import { promisify as promisify37 } from "node:util";
203579
203874
  async function captureModifiedFiles(worktreePath, baseCommitSha, taskId, audit, source = "unspecified") {
203580
203875
  try {
203581
203876
  const baseRef = await resolveDiffBaseRef(worktreePath, baseCommitSha);
@@ -203661,7 +203956,7 @@ var init_worktree_capture_modified_files = __esm({
203661
203956
  init_branch_attribution();
203662
203957
  init_logger3();
203663
203958
  init_worktree_git_refs();
203664
- execAsync24 = promisify36(exec27);
203959
+ execAsync24 = promisify37(exec27);
203665
203960
  }
203666
203961
  });
203667
203962
 
@@ -203826,6 +204121,27 @@ ${result2.review}`);
203826
204121
  summarySections.push(`[${repoRel}] ${result2.verdict}: ${result2.summary}`);
203827
204122
  }
203828
204123
  const aggregateVerdict = reviewedResults.some(({ result: result2 }) => result2.verdict === "RETHINK") ? "RETHINK" : reviewedResults.some(({ result: result2 }) => result2.verdict === "REVISE") ? "REVISE" : reviewedResults.some(({ result: result2 }) => !isApprovalFamilyVerdict(result2.verdict)) ? "UNAVAILABLE" : "APPROVE";
204124
+ let publishedModifiedFiles = modifiedFiles;
204125
+ if (isApprovalFamilyVerdict(aggregateVerdict) && evidence && options.workspaceRootDir) {
204126
+ try {
204127
+ const refreshed = await captureWorkspaceReviewEvidence({ task, workspaceRootDir: options.workspaceRootDir, settings: options.settings ?? {} });
204128
+ if (refreshed.outOfScopeRepositories.size > 0) {
204129
+ return { verdict: "UNAVAILABLE", retryable: false, review: "Workspace Code Review cannot approve changes outside confirmed scope after review.", summary: "Unavailable: changes outside confirmed scope after review", repositoryScopeRevision };
204130
+ }
204131
+ for (const updated of refreshed.repositories) {
204132
+ const original = evidence.repositories.find((candidate) => candidate.repository === updated.repository);
204133
+ const worktreePath = workspaceWorktrees[updated.repository]?.worktreePath;
204134
+ const outcome = repositoryReviewOutcomes.find((candidate) => candidate.repository === updated.repository && candidate.status === "REVIEWED");
204135
+ if (!original || !worktreePath || !updated.fingerprint || !outcome || !repositoryScope.has(updated.repository)) continue;
204136
+ if (await isFastForwardAdvance(worktreePath, original.branch, updated.branch)) {
204137
+ repositoryDiffFingerprints[updated.repository] = updated.fingerprint;
204138
+ outcome.fingerprint = updated.fingerprint;
204139
+ }
204140
+ }
204141
+ publishedModifiedFiles = refreshed.modifiedFiles;
204142
+ } catch {
204143
+ }
204144
+ }
203829
204145
  const blockingRepositories = reviewedResults.filter(({ result: result2 }) => !isApprovalFamilyVerdict(result2.verdict)).map(({ repository }) => repository);
203830
204146
  const blockingSummary = blockingRepositories.length > 0 ? `blocking repositories: ${blockingRepositories.join(", ")}` : `all ${repoKeys.length} modified in-scope repositories approved`;
203831
204147
  const coverageNotice = noVerdictRepositories.length > 0 ? `
@@ -203837,7 +204153,7 @@ Not covered by a verdict: ${noVerdictRepositories.join(", ")}.` : "";
203837
204153
  ${reviewSections.join("\n\n")}`,
203838
204154
  summary: `${aggregateVerdict} \u2014 ${blockingSummary} \u2014 ${summarySections.join(" | ")}`,
203839
204155
  repositoryDiffFingerprints,
203840
- repositoryModifiedFiles: modifiedFiles,
204156
+ repositoryModifiedFiles: publishedModifiedFiles,
203841
204157
  repositoryReviewOutcomes,
203842
204158
  ...findings.length > 0 ? { findings } : {},
203843
204159
  repositoryScopeRevision
@@ -203848,6 +204164,7 @@ var init_workspace_review_per_repo = __esm({
203848
204164
  "../engine/src/executor/workspace-review-per-repo.ts"() {
203849
204165
  "use strict";
203850
204166
  init_workspace_review_evidence();
204167
+ init_review_inline_fix_recapture();
203851
204168
  init_workspace_zero_acquire();
203852
204169
  init_worktree_capture_modified_files();
203853
204170
  hasRepositoryPrefix = (value, repoRel, separator) => value === repoRel || value?.startsWith(`${repoRel}${separator}`) === true;
@@ -205212,6 +205529,8 @@ async function runGraphCustomNode(deps, node, nodeTask, settings, columnBinding,
205212
205529
  }
205213
205530
  const optionalGroupId = typeof graphContext?.[WORKFLOW_OPTIONAL_GROUP_CONTEXT_KEY] === "string" ? graphContext[WORKFLOW_OPTIONAL_GROUP_CONTEXT_KEY] : void 0;
205214
205531
  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;
205532
+ const effectiveStepId = optionalGroupId ?? node.id;
205533
+ const isContentBindingStep = requiresContentReviewProof(effectiveStepId, { reviewKind: declaredReviewKind });
205215
205534
  if (isFastExecutionMode(live) && graphContext?.["workflow:fast-lane-active"] === true && isFastLaneSkippableCustomNode(node, { optionalGroupId })) {
205216
205535
  executorLog.debug(`${live.id}: fast mode \u2014 skipping custom graph node '${node.id}'`);
205217
205536
  await deps.store.logEntry(
@@ -205406,6 +205725,7 @@ ${prompt}`;
205406
205725
  const now = (/* @__PURE__ */ new Date()).toISOString();
205407
205726
  const stepSkillName = executorKind === "skill" && typeof cfg.skillName === "string" && cfg.skillName.trim() ? cfg.skillName.trim() : void 0;
205408
205727
  const stepThinkingLevel = typeof cfg.thinkingLevel === "string" && WORKFLOW_THINKING_LEVEL_SET2.has(cfg.thinkingLevel) ? cfg.thinkingLevel : void 0;
205728
+ const readonlyMcpServers = Array.isArray(cfg.readonlyMcpServers) ? [...new Set(cfg.readonlyMcpServers.filter((name2) => typeof name2 === "string").map((name2) => name2.trim()).filter(Boolean))] : [];
205409
205729
  const step = {
205410
205730
  id: `graph:${node.id}`,
205411
205731
  name: typeof cfg.name === "string" && cfg.name.trim() ? cfg.name : node.id,
@@ -205422,7 +205742,8 @@ ${prompt}`;
205422
205742
  ...stepSkillName ? { skillName: stepSkillName } : {},
205423
205743
  ...cfg.requiresBrowser === true ? { requiresBrowser: true } : {},
205424
205744
  ...modelProvider && modelId ? { modelProvider, modelId } : {},
205425
- ...stepThinkingLevel ? { thinkingLevel: stepThinkingLevel } : {}
205745
+ ...stepThinkingLevel ? { thinkingLevel: stepThinkingLevel } : {},
205746
+ ...readonlyMcpServers.length > 0 ? { readonlyMcpServers } : {}
205426
205747
  };
205427
205748
  if (cfg.summaryTarget === "task") {
205428
205749
  step.summaryTarget = "task";
@@ -205536,12 +205857,36 @@ ${prompt}`;
205536
205857
  outcome = buildWorkspaceReviewOutcome(aggregate, { superseded: reviewSuperseded });
205537
205858
  }
205538
205859
  } else {
205539
- outcome = mode === "script" ? await deps.executeScriptWorkflowStep(live, step, worktreePath, settings, nodeEnv) : await deps.executeWorkflowStep(live, step, worktreePath, settings, nodeEnv, {
205540
- unattended,
205541
- principalAgentId,
205542
- outputLanguage,
205543
- ...nodeSessionBoundary ? { sessionBoundary: nodeSessionBoundary } : {}
205544
- });
205860
+ const dispatchSingularStep = async (reviewInputFingerprint) => {
205861
+ if (mode === "script") {
205862
+ const scriptOutcome = await deps.executeScriptWorkflowStep(live, step, worktreePath, settings, nodeEnv);
205863
+ return reviewInputFingerprint === void 0 ? scriptOutcome : { ...scriptOutcome, reviewInputFingerprint };
205864
+ }
205865
+ return deps.executeWorkflowStep(live, step, worktreePath, settings, nodeEnv, {
205866
+ unattended,
205867
+ principalAgentId,
205868
+ outputLanguage,
205869
+ ...nodeSessionBoundary ? { sessionBoundary: nodeSessionBoundary } : {},
205870
+ ...reviewInputFingerprint !== void 0 ? { reviewInputFingerprint } : {}
205871
+ });
205872
+ };
205873
+ if (isContentBindingStep && !workspaceConfig) {
205874
+ const proof = await resolveContentReviewInputProof(worktreePath, executionTarget.baseCommitSha);
205875
+ if (proof.kind === "unprovable") {
205876
+ const diagnostic = `${step.name} review input is unprovable (${proof.reason}); reviewer dispatch refused.`;
205877
+ await deps.store.logEntry(
205878
+ live.id,
205879
+ `[pre-merge] ${diagnostic}`,
205880
+ void 0,
205881
+ deps.getRunContextFor(live.id)
205882
+ );
205883
+ outcome = { success: false, error: diagnostic, failureValue: "review-input-unprovable" };
205884
+ } else {
205885
+ outcome = await dispatchSingularStep(proof.fingerprint);
205886
+ }
205887
+ } else {
205888
+ outcome = await dispatchSingularStep();
205889
+ }
205545
205890
  }
205546
205891
  if (declaredReviewKind && typeof outcome.output === "string") {
205547
205892
  const rawReviewOutput = outcome.output;
@@ -205628,6 +205973,7 @@ var init_run_graph_custom_node = __esm({
205628
205973
  init_create_authoritative_workflow_seams();
205629
205974
  init_verification_gate();
205630
205975
  init_worktree_dependency_install();
205976
+ init_review_diff_fingerprint();
205631
205977
  WORKFLOW_THINKING_LEVEL_SET2 = new Set(THINKING_LEVELS);
205632
205978
  WORKFLOW_STEP_NOT_RUN_REASON_SET2 = new Set(WORKFLOW_STEP_NOT_RUN_REASONS);
205633
205979
  WORKSPACE_REPO_REVIEW_NO_NOTES_NOTICE = "The repository reviewer recorded no notes for this verdict.";
@@ -207687,7 +208033,7 @@ var init_agent_heartbeat_error_recovery = __esm({
207687
208033
 
207688
208034
  // ../engine/src/agent-heartbeat.ts
207689
208035
  import { Type as Type3 } from "@earendil-works/pi-ai";
207690
- import { createHash as createHash31 } from "node:crypto";
208036
+ import { createHash as createHash32 } from "node:crypto";
207691
208037
  async function resolveHeartbeatReboundColumn(taskStore, taskId) {
207692
208038
  try {
207693
208039
  return resolveReboundTarget(await resolveWorkflowIrForTask(taskStore, taskId)) ?? "todo";
@@ -207842,7 +208188,7 @@ function truncatePrompt(text3, maxChars) {
207842
208188
  ... (truncated, ${text3.length} chars)`;
207843
208189
  }
207844
208190
  function shortContentHash(value) {
207845
- return createHash31("sha256").update(value).digest("hex").slice(0, 8);
208191
+ return createHash32("sha256").update(value).digest("hex").slice(0, 8);
207846
208192
  }
207847
208193
  function buildIdentitySnapshot(args) {
207848
208194
  const { agent, resolvedInstructions, workspaceMemory } = args;
@@ -212275,6 +212621,91 @@ var init_auto_merge_finalization = __esm({
212275
212621
  }
212276
212622
  });
212277
212623
 
212624
+ // ../engine/src/merge/merge-content-capture.ts
212625
+ async function captureMergeContentDescriptor(task, deps) {
212626
+ if (describeMergeContentShape(task) === "workspace") {
212627
+ try {
212628
+ const evidence = await captureWorkspaceReviewEvidence({
212629
+ task,
212630
+ workspaceRootDir: deps.workspaceRootDir,
212631
+ settings: deps.settings
212632
+ });
212633
+ return {
212634
+ kind: "workspace",
212635
+ repositories: {
212636
+ state: "captured",
212637
+ fingerprints: Object.fromEntries(evidence.repositories.filter((repository) => repository.fingerprint).map((repository) => [repository.repository, repository.fingerprint])),
212638
+ inScopeModified: [...evidence.modifiedRepositories].sort()
212639
+ }
212640
+ };
212641
+ } catch {
212642
+ return { kind: "workspace", repositories: { state: "unavailable", reason: "workspace-evidence-capture-failed" } };
212643
+ }
212644
+ }
212645
+ const baseRef = task.worktree ? await resolveDiffBaseRef(task.worktree, task.baseCommitSha) : void 0;
212646
+ const probe = await probeReviewDiffFingerprint(task.worktree, baseRef);
212647
+ return { kind: "singular", diff: probe };
212648
+ }
212649
+ var init_merge_content_capture = __esm({
212650
+ "../engine/src/merge/merge-content-capture.ts"() {
212651
+ "use strict";
212652
+ init_src2();
212653
+ init_worktree_git_refs();
212654
+ init_review_diff_fingerprint();
212655
+ init_workspace_review_evidence();
212656
+ }
212657
+ });
212658
+
212659
+ // ../engine/src/merge/stale-content-review-reroute.ts
212660
+ function isContentReviewNode(node) {
212661
+ if (node.kind !== "optional-group" && node.kind !== "step-review") return false;
212662
+ const name2 = typeof node.config?.name === "string" ? node.config.name : "";
212663
+ return node.id === "code-review" || node.config?.reviewKind === "code" || /code review/i.test(name2);
212664
+ }
212665
+ async function rerouteSingularStaleContentToReview(store, task, options) {
212666
+ const mergeContent = options.mergeContent;
212667
+ if (mergeContent.kind !== "singular" || task.workspaceWorktrees !== void 0) {
212668
+ return { rerouted: false, reason: "not-singular" };
212669
+ }
212670
+ if (task.paused || task.userPaused || task.deletedAt || task.autoMerge === false) {
212671
+ return { rerouted: false, reason: "operator-held" };
212672
+ }
212673
+ if (mergeContent.diff.state !== "fingerprint") return { rerouted: false, reason: "no-progress" };
212674
+ const currentFingerprint = mergeContent.diff.fingerprint;
212675
+ const ir2 = await resolveWorkflowIrForTask(store, task.id);
212676
+ const selection = store.getTaskWorkflowSelectionAsync ? await store.getTaskWorkflowSelectionAsync(task.id) : store.getTaskWorkflowSelection(task.id);
212677
+ const selected = selection?.stepIds ?? [];
212678
+ const nodes2 = ir2.nodes.filter((node2) => {
212679
+ if (!isContentReviewNode(node2) || !options.requiredPreMergeStepIds.has(node2.id)) return false;
212680
+ return node2.config?.defaultOn === true || selected.includes(node2.id);
212681
+ });
212682
+ const node = nodes2.find((candidate) => {
212683
+ const latest = task.workflowStepResults?.filter((result3) => result3.workflowStepId === candidate.id).at(-1);
212684
+ return latest?.reviewInputFingerprint !== currentFingerprint;
212685
+ });
212686
+ if (!node) return { rerouted: false, reason: nodes2.length ? "no-progress" : "no-review-route" };
212687
+ const items = await store.listWorkflowWorkItemsForTask(task.id);
212688
+ const result2 = await store.seedWorkspaceCodeReviewContinuationIfIdle({
212689
+ taskId: task.id,
212690
+ nodeId: node.id,
212691
+ kind: "task",
212692
+ state: "runnable",
212693
+ runId: `${task.id}:stale-content-review-reroute:${node.id}:${items.length}`,
212694
+ stableWorkflowRunId: `${task.id}:${ir2.name}`,
212695
+ continuationSequence: items.length,
212696
+ sourceColumn: task.column,
212697
+ targetColumn: node.column ?? task.column,
212698
+ irHash: computeWorkflowIrPin(ir2, node.id).irHash
212699
+ });
212700
+ return result2.seeded ? { rerouted: true, reason: "seeded", nodeId: node.id, workflowStepId: node.id } : { rerouted: false, reason: "active-continuation", nodeId: node.id, workflowStepId: node.id };
212701
+ }
212702
+ var init_stale_content_review_reroute = __esm({
212703
+ "../engine/src/merge/stale-content-review-reroute.ts"() {
212704
+ "use strict";
212705
+ init_src2();
212706
+ }
212707
+ });
212708
+
212278
212709
  // ../engine/src/healing/auto-recovery.ts
212279
212710
  function actionForMode(mode, failureClass) {
212280
212711
  if (mode === "off") return "pause";
@@ -212431,10 +212862,10 @@ var init_stranded_continuation_reclaim = __esm({
212431
212862
  });
212432
212863
 
212433
212864
  // ../engine/src/merge/workspace-land-predicate.ts
212434
- import { execFile as execFile18 } from "node:child_process";
212435
- import { promisify as promisify37 } from "node:util";
212865
+ import { execFile as execFile19 } from "node:child_process";
212866
+ import { promisify as promisify38 } from "node:util";
212436
212867
  async function git4(args, cwd, opts = {}) {
212437
- const { stdout } = await execFileAsync12("git", args, {
212868
+ const { stdout } = await execFileAsync13("git", args, {
212438
212869
  cwd,
212439
212870
  encoding: "utf-8",
212440
212871
  timeout: opts.timeout ?? 12e4,
@@ -212513,11 +212944,11 @@ async function isRepoLanded(repoRootDir, integrationBranch, landedSha, taskId, b
212513
212944
  await findProvenLandedCommit(repoRootDir, integrationBranch, landedSha, taskId, branch, revertBoundarySha, taskCreatedAt)
212514
212945
  );
212515
212946
  }
212516
- var execFileAsync12, FUSION_TASK_ID_TRAILER_KEY2, TRAILER_SCAN_CLOCK_SKEW_MS, UNBOUNDED_TRAILER_SCAN_WINDOW_MS, UNBOUNDED_TRAILER_SCAN_MAX_COMMITS;
212947
+ var execFileAsync13, FUSION_TASK_ID_TRAILER_KEY2, TRAILER_SCAN_CLOCK_SKEW_MS, UNBOUNDED_TRAILER_SCAN_WINDOW_MS, UNBOUNDED_TRAILER_SCAN_MAX_COMMITS;
212517
212948
  var init_workspace_land_predicate = __esm({
212518
212949
  "../engine/src/merge/workspace-land-predicate.ts"() {
212519
212950
  "use strict";
212520
- execFileAsync12 = promisify37(execFile18);
212951
+ execFileAsync13 = promisify38(execFile19);
212521
212952
  FUSION_TASK_ID_TRAILER_KEY2 = "Fusion-Task-Id";
212522
212953
  TRAILER_SCAN_CLOCK_SKEW_MS = 24 * 60 * 60 * 1e3;
212523
212954
  UNBOUNDED_TRAILER_SCAN_WINDOW_MS = 30 * 24 * 60 * 60 * 1e3;
@@ -212542,7 +212973,7 @@ var init_workspace_land_failure = __esm({
212542
212973
 
212543
212974
  // ../engine/src/merge/already-merged-detector.ts
212544
212975
  import { exec as exec28, execSync as execSync4 } from "node:child_process";
212545
- import { promisify as promisify38 } from "node:util";
212976
+ import { promisify as promisify39 } from "node:util";
212546
212977
  function shellQuote(value) {
212547
212978
  return `'${value.replace(/'/g, "'\\''")}'`;
212548
212979
  }
@@ -212818,7 +213249,7 @@ var init_already_merged_detector = __esm({
212818
213249
  "../engine/src/merge/already-merged-detector.ts"() {
212819
213250
  "use strict";
212820
213251
  init_worktree_names();
212821
- execAsync25 = promisify38(exec28);
213252
+ execAsync25 = promisify39(exec28);
212822
213253
  }
212823
213254
  });
212824
213255
 
@@ -212950,10 +213381,10 @@ var init_review_empty_content_close = __esm({
212950
213381
  });
212951
213382
 
212952
213383
  // ../engine/src/merge/merger-ref-update-advance.ts
212953
- import { execFile as execFile19 } from "node:child_process";
212954
- import { promisify as promisify39 } from "node:util";
213384
+ import { execFile as execFile20 } from "node:child_process";
213385
+ import { promisify as promisify40 } from "node:util";
212955
213386
  async function runGit3(args, cwd) {
212956
- return await execFileAsync13("git", args, {
213387
+ return await execFileAsync14("git", args, {
212957
213388
  cwd,
212958
213389
  encoding: "utf-8",
212959
213390
  timeout: 3e4
@@ -213100,11 +213531,11 @@ async function advanceIntegrationBranchRef(args) {
213100
213531
  };
213101
213532
  }
213102
213533
  }
213103
- var execFileAsync13, testHooks, IntegrationBranchConcurrentAdvanceError;
213534
+ var execFileAsync14, testHooks, IntegrationBranchConcurrentAdvanceError;
213104
213535
  var init_merger_ref_update_advance = __esm({
213105
213536
  "../engine/src/merge/merger-ref-update-advance.ts"() {
213106
213537
  "use strict";
213107
- execFileAsync13 = promisify39(execFile19);
213538
+ execFileAsync14 = promisify40(execFile20);
213108
213539
  testHooks = {
213109
213540
  runGit: runGit3
213110
213541
  };
@@ -213132,7 +213563,7 @@ var init_merger_ref_update_advance = __esm({
213132
213563
 
213133
213564
  // ../engine/src/merge/group-merge-coordinator.ts
213134
213565
  import * as childProcess2 from "node:child_process";
213135
- import { promisify as promisify40 } from "node:util";
213566
+ import { promisify as promisify41 } from "node:util";
213136
213567
  function evaluateBranchGroupCompletion(input) {
213137
213568
  const landedMemberIds = [];
213138
213569
  const pendingMemberIds = [];
@@ -213172,10 +213603,10 @@ function evaluateBranchGroupPromotion(input) {
213172
213603
  }
213173
213604
  async function ensureGroupBranchExists(rootDir, branchName, startPoint) {
213174
213605
  try {
213175
- await execFileAsync14("git", ["show-ref", "--verify", "--quiet", `refs/heads/${branchName}`], { cwd: rootDir });
213606
+ await execFileAsync15("git", ["show-ref", "--verify", "--quiet", `refs/heads/${branchName}`], { cwd: rootDir });
213176
213607
  return;
213177
213608
  } catch {
213178
- await execFileAsync14("git", ["branch", branchName, startPoint], { cwd: rootDir });
213609
+ await execFileAsync15("git", ["branch", branchName, startPoint], { cwd: rootDir });
213179
213610
  }
213180
213611
  }
213181
213612
  function throwIfPromotionAborted(signal) {
@@ -213280,14 +213711,14 @@ async function promoteBranchGroupInner(input) {
213280
213711
  if (!needsPrRepair && !isPrMode) {
213281
213712
  throwIfPromotionAborted(input.signal);
213282
213713
  await ensureGroupBranchExists(input.rootDir, group.branchName, integrationBranch);
213283
- const currentBranch2 = (await execFileAsync14("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd: input.rootDir })).stdout.trim();
213714
+ const currentBranch2 = (await execFileAsync15("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd: input.rootDir })).stdout.trim();
213284
213715
  try {
213285
213716
  throwIfPromotionAborted(input.signal);
213286
- await execFileAsync14("git", ["checkout", integrationBranch], { cwd: input.rootDir, signal: input.signal });
213717
+ await execFileAsync15("git", ["checkout", integrationBranch], { cwd: input.rootDir, signal: input.signal });
213287
213718
  throwIfPromotionAborted(input.signal);
213288
- await execFileAsync14("git", ["merge", "--no-ff", "--no-edit", group.branchName], { cwd: input.rootDir, signal: input.signal });
213719
+ await execFileAsync15("git", ["merge", "--no-ff", "--no-edit", group.branchName], { cwd: input.rootDir, signal: input.signal });
213289
213720
  } finally {
213290
- await execFileAsync14("git", ["checkout", currentBranch2], { cwd: input.rootDir });
213721
+ await execFileAsync15("git", ["checkout", currentBranch2], { cwd: input.rootDir });
213291
213722
  }
213292
213723
  }
213293
213724
  let prNumber = group.prNumber;
@@ -213411,20 +213842,20 @@ async function resolveBranchGroupMergeRouting(input) {
213411
213842
  )
213412
213843
  };
213413
213844
  }
213414
- var execFileAsync14, promotionLocks;
213845
+ var execFileAsync15, promotionLocks;
213415
213846
  var init_group_merge_coordinator = __esm({
213416
213847
  "../engine/src/merge/group-merge-coordinator.ts"() {
213417
213848
  "use strict";
213418
213849
  init_src2();
213419
213850
  init_integration_branch();
213420
- execFileAsync14 = (file, args, opts) => promisify40(childProcess2.execFile)(file, args, opts);
213851
+ execFileAsync15 = (file, args, opts) => promisify41(childProcess2.execFile)(file, args, opts);
213421
213852
  promotionLocks = /* @__PURE__ */ new Map();
213422
213853
  }
213423
213854
  });
213424
213855
 
213425
213856
  // ../engine/src/merge/merger-bare-subject.ts
213426
213857
  import { exec as exec29 } from "node:child_process";
213427
- import { promisify as promisify41 } from "node:util";
213858
+ import { promisify as promisify42 } from "node:util";
213428
213859
  function quoteArg(value) {
213429
213860
  return `'${value.replace(/'/g, "'\\''")}'`;
213430
213861
  }
@@ -213464,7 +213895,7 @@ var init_merger_bare_subject = __esm({
213464
213895
  "use strict";
213465
213896
  init_src2();
213466
213897
  init_logger3();
213467
- execAsync26 = promisify41(exec29);
213898
+ execAsync26 = promisify42(exec29);
213468
213899
  BARE_MERGE_SUBJECT_RE = /^[a-z]+(?:\([^)]+\))?!?:\s*merge\s+\S+\s*$/i;
213469
213900
  }
213470
213901
  });
@@ -213472,7 +213903,7 @@ var init_merger_bare_subject = __esm({
213472
213903
  // ../engine/src/recovery/foreign-only-contamination.ts
213473
213904
  import { exec as exec30 } from "node:child_process";
213474
213905
  import { existsSync as existsSync62 } from "node:fs";
213475
- import { promisify as promisify42 } from "node:util";
213906
+ import { promisify as promisify43 } from "node:util";
213476
213907
  function quote3(value) {
213477
213908
  return `'${value.replace(/'/g, `'\\''`)}'`;
213478
213909
  }
@@ -213580,7 +214011,7 @@ var init_foreign_only_contamination = __esm({
213580
214011
  init_lifecycle_move();
213581
214012
  init_branch_conflicts();
213582
214013
  init_worktree_pool();
213583
- execAsync27 = promisify42(exec30);
214014
+ execAsync27 = promisify43(exec30);
213584
214015
  GIT_TIMEOUT_MS6 = 3e4;
213585
214016
  GIT_MAX_BUFFER3 = 10 * 1024 * 1024;
213586
214017
  }
@@ -213677,7 +214108,7 @@ var init_surfacing_sweeps = __esm({
213677
214108
  });
213678
214109
 
213679
214110
  // ../engine/src/self-healing-git-evidence.ts
213680
- import { promisify as promisify43 } from "node:util";
214111
+ import { promisify as promisify44 } from "node:util";
213681
214112
  import { exec as exec31 } from "node:child_process";
213682
214113
  function classifyBranchProbeError(error3) {
213683
214114
  if (typeof error3 === "object" && error3 !== null && "code" in error3 && error3.code === 1 && !error3.killed && (error3.signal === null || error3.signal === void 0)) {
@@ -213721,7 +214152,7 @@ var init_self_healing_git_evidence = __esm({
213721
214152
  init_already_merged_detector();
213722
214153
  init_logger3();
213723
214154
  log32 = createLogger2("self-healing");
213724
- execAsync28 = promisify43(exec31);
214155
+ execAsync28 = promisify44(exec31);
213725
214156
  SelfHealingGitEvidence = class {
213726
214157
  async findLandedTaskCommit(task, options) {
213727
214158
  const rebaseBaseSha = task.mergeDetails?.rebaseBaseSha;
@@ -214083,12 +214514,12 @@ var init_self_healing_constants = __esm({
214083
214514
  });
214084
214515
 
214085
214516
  // ../engine/src/healing/self-healing-branch.ts
214086
- import { promisify as promisify44 } from "node:util";
214087
- import { execFile as execFile21 } from "node:child_process";
214517
+ import { promisify as promisify45 } from "node:util";
214518
+ import { execFile as execFile22 } from "node:child_process";
214088
214519
  async function isBranchAheadOfBase(task, rootDir, preferredBaseRef) {
214089
214520
  const branchName = resolveTaskWorkingBranch(task);
214090
214521
  try {
214091
- await execFileAsync15("git", ["rev-parse", "--verify", branchName], {
214522
+ await execFileAsync16("git", ["rev-parse", "--verify", branchName], {
214092
214523
  cwd: rootDir,
214093
214524
  timeout: 3e4
214094
214525
  });
@@ -214098,14 +214529,14 @@ async function isBranchAheadOfBase(task, rootDir, preferredBaseRef) {
214098
214529
  const requestedBaseRef = preferredBaseRef || task.mergeDetails?.mergeTargetBranch || await resolveIntegrationBranch(rootDir, void 0);
214099
214530
  let resolvedBaseRef = requestedBaseRef;
214100
214531
  try {
214101
- await execFileAsync15("git", ["rev-parse", "--verify", requestedBaseRef], {
214532
+ await execFileAsync16("git", ["rev-parse", "--verify", requestedBaseRef], {
214102
214533
  cwd: rootDir,
214103
214534
  timeout: 3e4
214104
214535
  });
214105
214536
  } catch {
214106
214537
  const remoteRef = `origin/${requestedBaseRef}`;
214107
214538
  try {
214108
- await execFileAsync15("git", ["rev-parse", "--verify", remoteRef], {
214539
+ await execFileAsync16("git", ["rev-parse", "--verify", remoteRef], {
214109
214540
  cwd: rootDir,
214110
214541
  timeout: 3e4
214111
214542
  });
@@ -214115,7 +214546,7 @@ async function isBranchAheadOfBase(task, rootDir, preferredBaseRef) {
214115
214546
  }
214116
214547
  }
214117
214548
  try {
214118
- const { stdout } = await execFileAsync15(
214549
+ const { stdout } = await execFileAsync16(
214119
214550
  "git",
214120
214551
  ["rev-list", "--count", `${resolvedBaseRef}..${branchName}`],
214121
214552
  { cwd: rootDir, timeout: 3e4 }
@@ -214133,7 +214564,7 @@ async function isBranchAheadOfBase(task, rootDir, preferredBaseRef) {
214133
214564
  return null;
214134
214565
  }
214135
214566
  }
214136
- var log33, execFileAsync15;
214567
+ var log33, execFileAsync16;
214137
214568
  var init_self_healing_branch = __esm({
214138
214569
  "../engine/src/healing/self-healing-branch.ts"() {
214139
214570
  "use strict";
@@ -214141,7 +214572,7 @@ var init_self_healing_branch = __esm({
214141
214572
  init_integration_branch();
214142
214573
  init_logger3();
214143
214574
  log33 = createLogger2("self-healing");
214144
- execFileAsync15 = promisify44(execFile21);
214575
+ execFileAsync16 = promisify45(execFile22);
214145
214576
  }
214146
214577
  });
214147
214578
 
@@ -214978,7 +215409,7 @@ var init_merger_workspace_test_commands = __esm({
214978
215409
  });
214979
215410
 
214980
215411
  // ../engine/src/merge/merger-file-scope.ts
214981
- import { promisify as promisify45 } from "node:util";
215412
+ import { promisify as promisify46 } from "node:util";
214982
215413
  import { exec as exec32 } from "node:child_process";
214983
215414
  function parseDiffStat(diffStat) {
214984
215415
  const entries = [];
@@ -215190,7 +215621,7 @@ var init_merger_file_scope = __esm({
215190
215621
  init_merger_glob();
215191
215622
  init_logger3();
215192
215623
  init_merge_trait();
215193
- execAsync29 = promisify45(exec32);
215624
+ execAsync29 = promisify46(exec32);
215194
215625
  FileScopeViolationError = class extends Error {
215195
215626
  taskId;
215196
215627
  stagedFiles;
@@ -215250,7 +215681,7 @@ var init_merger_errors = __esm({
215250
215681
  });
215251
215682
 
215252
215683
  // ../engine/src/merge/merger-owned-landed.ts
215253
- import { promisify as promisify46 } from "node:util";
215684
+ import { promisify as promisify47 } from "node:util";
215254
215685
  import * as childProcess3 from "node:child_process";
215255
215686
  function escapeRegexForOwnership(value) {
215256
215687
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -215267,8 +215698,8 @@ function commitOwnedByTask2(taskId, subject, body) {
215267
215698
  async function findOwnedLandedCommitForTask(rootDir, task) {
215268
215699
  const tryHydrate = async (sha) => {
215269
215700
  try {
215270
- await execFileAsync16("git", ["merge-base", "--is-ancestor", sha, "HEAD"], { cwd: rootDir });
215271
- const { stdout } = await execFileAsync16("git", ["log", "-1", "--format=%H%x1f%s%x1f%b", sha], {
215701
+ await execFileAsync17("git", ["merge-base", "--is-ancestor", sha, "HEAD"], { cwd: rootDir });
215702
+ const { stdout } = await execFileAsync17("git", ["log", "-1", "--format=%H%x1f%s%x1f%b", sha], {
215272
215703
  cwd: rootDir,
215273
215704
  encoding: "utf-8"
215274
215705
  });
@@ -215276,7 +215707,7 @@ async function findOwnedLandedCommitForTask(rootDir, task) {
215276
215707
  if (!resolvedSha || !commitOwnedByTask2(task.id, subject, body)) return null;
215277
215708
  const owned = { sha: resolvedSha, subject };
215278
215709
  try {
215279
- const { stdout: statsOut } = await execFileAsync16("git", ["show", "--shortstat", "--format=", resolvedSha], {
215710
+ const { stdout: statsOut } = await execFileAsync17("git", ["show", "--shortstat", "--format=", resolvedSha], {
215280
215711
  cwd: rootDir,
215281
215712
  encoding: "utf-8"
215282
215713
  });
@@ -215299,7 +215730,7 @@ async function findOwnedLandedCommitForTask(rootDir, task) {
215299
215730
  ];
215300
215731
  for (const args of searches) {
215301
215732
  try {
215302
- const { stdout } = await execFileAsync16("git", args, { cwd: rootDir, encoding: "utf-8" });
215733
+ const { stdout } = await execFileAsync17("git", args, { cwd: rootDir, encoding: "utf-8" });
215303
215734
  const first = stdout.trim().split("\n").find(Boolean);
215304
215735
  if (!first) continue;
215305
215736
  const [sha] = first.split("");
@@ -215320,14 +215751,14 @@ async function classifyOwnedLandedEvidence(rootDir, task, opts) {
215320
215751
  const ownedCommit = await findOwnedLandedCommitForTask(rootDir, task);
215321
215752
  if (ownedCommit) {
215322
215753
  try {
215323
- await execFileAsync16("git", ["merge-base", "--is-ancestor", ownedCommit.sha, mergeTargetBranch], { cwd: rootDir });
215754
+ await execFileAsync17("git", ["merge-base", "--is-ancestor", ownedCommit.sha, mergeTargetBranch], { cwd: rootDir });
215324
215755
  return { kind: "owned-commit", commit: ownedCommit };
215325
215756
  } catch {
215326
215757
  }
215327
215758
  }
215328
215759
  let aheadCount = null;
215329
215760
  try {
215330
- const { stdout } = await execFileAsync16("git", ["rev-list", "--count", `${mergeTargetBranch}..${branch}`], {
215761
+ const { stdout } = await execFileAsync17("git", ["rev-list", "--count", `${mergeTargetBranch}..${branch}`], {
215331
215762
  cwd: rootDir,
215332
215763
  encoding: "utf-8"
215333
215764
  });
@@ -215339,7 +215770,7 @@ async function classifyOwnedLandedEvidence(rootDir, task, opts) {
215339
215770
  let baseReachableFromTarget = false;
215340
215771
  if (task.baseCommitSha) {
215341
215772
  try {
215342
- await execFileAsync16("git", ["merge-base", "--is-ancestor", task.baseCommitSha, mergeTargetBranch], { cwd: rootDir });
215773
+ await execFileAsync17("git", ["merge-base", "--is-ancestor", task.baseCommitSha, mergeTargetBranch], { cwd: rootDir });
215343
215774
  baseReachableFromTarget = true;
215344
215775
  } catch {
215345
215776
  baseReachableFromTarget = false;
@@ -215350,7 +215781,7 @@ async function classifyOwnedLandedEvidence(rootDir, task, opts) {
215350
215781
  }
215351
215782
  if (aheadCount !== null && aheadCount > 0) {
215352
215783
  try {
215353
- const { stdout: mergeBaseOut } = await execFileAsync16(
215784
+ const { stdout: mergeBaseOut } = await execFileAsync17(
215354
215785
  "git",
215355
215786
  ["merge-base", mergeTargetBranch, branch],
215356
215787
  { cwd: rootDir, encoding: "utf-8" }
@@ -215359,7 +215790,7 @@ async function classifyOwnedLandedEvidence(rootDir, task, opts) {
215359
215790
  if (mergeBase) {
215360
215791
  let ownDiffEmpty = false;
215361
215792
  try {
215362
- await execFileAsync16(
215793
+ await execFileAsync17(
215363
215794
  "git",
215364
215795
  ["diff", "--quiet", `${mergeBase}..${branch}`],
215365
215796
  { cwd: rootDir }
@@ -215372,7 +215803,7 @@ async function classifyOwnedLandedEvidence(rootDir, task, opts) {
215372
215803
  let mergeBaseReachable = baseReachableFromTarget;
215373
215804
  if (!mergeBaseReachable) {
215374
215805
  try {
215375
- await execFileAsync16(
215806
+ await execFileAsync17(
215376
215807
  "git",
215377
215808
  ["merge-base", "--is-ancestor", mergeBase, mergeTargetBranch],
215378
215809
  { cwd: rootDir }
@@ -215392,7 +215823,7 @@ async function classifyOwnedLandedEvidence(rootDir, task, opts) {
215392
215823
  }
215393
215824
  let branchExists = false;
215394
215825
  try {
215395
- await execFileAsync16("git", ["show-ref", "--verify", "--quiet", `refs/heads/${branch}`], { cwd: rootDir });
215826
+ await execFileAsync17("git", ["show-ref", "--verify", "--quiet", `refs/heads/${branch}`], { cwd: rootDir });
215396
215827
  branchExists = true;
215397
215828
  } catch {
215398
215829
  branchExists = false;
@@ -215410,7 +215841,7 @@ async function classifyOwnedLandedEvidence(rootDir, task, opts) {
215410
215841
  }
215411
215842
  if (task.baseCommitSha && !baseReachableFromTarget) {
215412
215843
  try {
215413
- const { stdout } = await execFileAsync16("git", ["for-each-ref", "--format=%(refname:short)", "refs/heads/fusion"], {
215844
+ const { stdout } = await execFileAsync17("git", ["for-each-ref", "--format=%(refname:short)", "refs/heads/fusion"], {
215414
215845
  cwd: rootDir,
215415
215846
  encoding: "utf-8"
215416
215847
  });
@@ -215418,7 +215849,7 @@ async function classifyOwnedLandedEvidence(rootDir, task, opts) {
215418
215849
  for (const ref of refs) {
215419
215850
  if (ref === branch) continue;
215420
215851
  try {
215421
- await execFileAsync16("git", ["merge-base", "--is-ancestor", task.baseCommitSha, ref], { cwd: rootDir });
215852
+ await execFileAsync17("git", ["merge-base", "--is-ancestor", task.baseCommitSha, ref], { cwd: rootDir });
215422
215853
  return {
215423
215854
  kind: "unproven",
215424
215855
  reason: "foreign-start-point",
@@ -215432,7 +215863,7 @@ async function classifyOwnedLandedEvidence(rootDir, task, opts) {
215432
215863
  }
215433
215864
  if (aheadCount !== null && aheadCount > 0) {
215434
215865
  try {
215435
- const { stdout } = await execFileAsync16("git", ["log", "--format=%s%x1f%b", `${mergeTargetBranch}..${branch}`], {
215866
+ const { stdout } = await execFileAsync17("git", ["log", "--format=%s%x1f%b", `${mergeTargetBranch}..${branch}`], {
215436
215867
  cwd: rootDir,
215437
215868
  encoding: "utf-8"
215438
215869
  });
@@ -215473,20 +215904,20 @@ async function classifyOwnedLandedEvidence(rootDir, task, opts) {
215473
215904
  }
215474
215905
  };
215475
215906
  }
215476
- var execFileAsync16, FUSION_TASK_ID_TRAILER_KEY3;
215907
+ var execFileAsync17, FUSION_TASK_ID_TRAILER_KEY3;
215477
215908
  var init_merger_owned_landed = __esm({
215478
215909
  "../engine/src/merge/merger-owned-landed.ts"() {
215479
215910
  "use strict";
215480
215911
  init_merger_file_scope();
215481
215912
  init_worktree_names();
215482
- execFileAsync16 = (file, args, opts) => promisify46(childProcess3.execFile)(file, args, opts);
215913
+ execFileAsync17 = (file, args, opts) => promisify47(childProcess3.execFile)(file, args, opts);
215483
215914
  FUSION_TASK_ID_TRAILER_KEY3 = "Fusion-Task-Id";
215484
215915
  }
215485
215916
  });
215486
215917
 
215487
215918
  // ../engine/src/merge/merger-conflict-resolution.ts
215488
- import { promisify as promisify47 } from "node:util";
215489
- import { exec as exec33, execFile as execFile23 } from "node:child_process";
215919
+ import { promisify as promisify48 } from "node:util";
215920
+ import { exec as exec33, execFile as execFile24 } from "node:child_process";
215490
215921
  async function getConflictedFiles(cwd) {
215491
215922
  try {
215492
215923
  const { stdout } = await execAsync30("git diff --name-only --diff-filter=U", {
@@ -215502,7 +215933,7 @@ async function getConflictedFiles(cwd) {
215502
215933
  }
215503
215934
  async function isTrivialWhitespaceConflict(filePath, cwd) {
215504
215935
  try {
215505
- const { stdout } = await execFileAsync17(
215936
+ const { stdout } = await execFileAsync18(
215506
215937
  "git",
215507
215938
  ["diff", "-p", "-w", `:2:${filePath}`, `:3:${filePath}`],
215508
215939
  { cwd, encoding: "utf-8" }
@@ -215538,8 +215969,8 @@ async function classifyConflict(filePath, cwd) {
215538
215969
  }
215539
215970
  async function resolveWithOurs(filePath, cwd) {
215540
215971
  try {
215541
- await execFileAsync17("git", ["checkout", "--ours", "--", filePath], { cwd });
215542
- await execFileAsync17("git", ["add", "--", filePath], { cwd });
215972
+ await execFileAsync18("git", ["checkout", "--ours", "--", filePath], { cwd });
215973
+ await execFileAsync18("git", ["add", "--", filePath], { cwd });
215543
215974
  mergerLog.debug(`Auto-resolved ${filePath} using --ours`);
215544
215975
  } catch (error3) {
215545
215976
  throw new Error(`Failed to auto-resolve ${filePath} with ours: ${error3}`);
@@ -215547,8 +215978,8 @@ async function resolveWithOurs(filePath, cwd) {
215547
215978
  }
215548
215979
  async function resolveWithTheirs(filePath, cwd) {
215549
215980
  try {
215550
- await execFileAsync17("git", ["checkout", "--theirs", "--", filePath], { cwd });
215551
- await execFileAsync17("git", ["add", "--", filePath], { cwd });
215981
+ await execFileAsync18("git", ["checkout", "--theirs", "--", filePath], { cwd });
215982
+ await execFileAsync18("git", ["add", "--", filePath], { cwd });
215552
215983
  mergerLog.debug(`Auto-resolved ${filePath} using --theirs`);
215553
215984
  } catch (error3) {
215554
215985
  throw new Error(`Failed to auto-resolve ${filePath} with theirs: ${error3}`);
@@ -215556,8 +215987,8 @@ async function resolveWithTheirs(filePath, cwd) {
215556
215987
  }
215557
215988
  async function resolveTrivialWhitespace(filePath, cwd) {
215558
215989
  try {
215559
- await execFileAsync17("git", ["checkout", "--ours", "--", filePath], { cwd });
215560
- await execFileAsync17("git", ["add", "--", filePath], { cwd });
215990
+ await execFileAsync18("git", ["checkout", "--ours", "--", filePath], { cwd });
215991
+ await execFileAsync18("git", ["add", "--", filePath], { cwd });
215561
215992
  mergerLog.debug(`Auto-resolved ${filePath} (trivial whitespace)`);
215562
215993
  } catch (error3) {
215563
215994
  throw new Error(`Failed to auto-resolve ${filePath} trivial conflict: ${error3}`);
@@ -215603,14 +216034,14 @@ async function resolveConflicts(categories2, rootDir) {
215603
216034
  }
215604
216035
  return remainingComplex;
215605
216036
  }
215606
- var execAsync30, execFileAsync17;
216037
+ var execAsync30, execFileAsync18;
215607
216038
  var init_merger_conflict_resolution = __esm({
215608
216039
  "../engine/src/merge/merger-conflict-resolution.ts"() {
215609
216040
  "use strict";
215610
216041
  init_merger_glob();
215611
216042
  init_logger3();
215612
- execAsync30 = promisify47(exec33);
215613
- execFileAsync17 = (file, args, opts) => promisify47(execFile23)(file, args, opts);
216043
+ execAsync30 = promisify48(exec33);
216044
+ execFileAsync18 = (file, args, opts) => promisify48(execFile24)(file, args, opts);
215614
216045
  }
215615
216046
  });
215616
216047
 
@@ -215734,8 +216165,8 @@ var init_merger_autostash_labels = __esm({
215734
216165
  });
215735
216166
 
215736
216167
  // ../engine/src/merge/merger-squash-audit.ts
215737
- import { execFile as execFile24 } from "node:child_process";
215738
- import { promisify as promisify48 } from "node:util";
216168
+ import { execFile as execFile25 } from "node:child_process";
216169
+ import { promisify as promisify49 } from "node:util";
215739
216170
  async function auditSquashMerge(input) {
215740
216171
  const normalizedLookback = normalizeMergeOverlapLookback(input.lookback);
215741
216172
  if (input.strategy === "rebase") {
@@ -215853,7 +216284,7 @@ async function collectTouchedFileOverlaps(rootDir, touchedFiles, recentMainCommi
215853
216284
  return touchedFileOverlaps;
215854
216285
  }
215855
216286
  async function git5(rootDir, args) {
215856
- const { stdout } = await execFileAsync18("git", args, {
216287
+ const { stdout } = await execFileAsync19("git", args, {
215857
216288
  cwd: rootDir,
215858
216289
  encoding: "utf-8",
215859
216290
  maxBuffer: GIT_OUTPUT_MAX_BUFFER
@@ -215886,19 +216317,19 @@ function normalizeMergeOverlapLookback(value) {
215886
216317
  }
215887
216318
  return Math.trunc(value);
215888
216319
  }
215889
- var execFileAsync18, MERGER_MAIN_OVERLAP_LOOKBACK_COMMITS, GIT_OUTPUT_MAX_BUFFER;
216320
+ var execFileAsync19, MERGER_MAIN_OVERLAP_LOOKBACK_COMMITS, GIT_OUTPUT_MAX_BUFFER;
215890
216321
  var init_merger_squash_audit = __esm({
215891
216322
  "../engine/src/merge/merger-squash-audit.ts"() {
215892
216323
  "use strict";
215893
- execFileAsync18 = promisify48(execFile24);
216324
+ execFileAsync19 = promisify49(execFile25);
215894
216325
  MERGER_MAIN_OVERLAP_LOOKBACK_COMMITS = 30;
215895
216326
  GIT_OUTPUT_MAX_BUFFER = 10 * 1024 * 1024;
215896
216327
  }
215897
216328
  });
215898
216329
 
215899
216330
  // ../engine/src/merge/merger-overlap-guard.ts
215900
- import { execFile as execFile25 } from "node:child_process";
215901
- import { promisify as promisify49 } from "node:util";
216331
+ import { execFile as execFile26 } from "node:child_process";
216332
+ import { promisify as promisify50 } from "node:util";
215902
216333
  async function getBranchTouchedFiles({
215903
216334
  rootDir,
215904
216335
  branch,
@@ -215974,7 +216405,7 @@ async function restoreBranchWinsFiles({
215974
216405
  }
215975
216406
  async function gitLines(rootDir, args, context2) {
215976
216407
  try {
215977
- const { stdout } = await execFileAsync19("git", args, {
216408
+ const { stdout } = await execFileAsync20("git", args, {
215978
216409
  cwd: rootDir,
215979
216410
  encoding: "utf-8",
215980
216411
  maxBuffer: GIT_OUTPUT_MAX_BUFFER2
@@ -215992,7 +216423,7 @@ function normalizeLines3(value) {
215992
216423
  }
215993
216424
  async function gitRun(rootDir, args, context2) {
215994
216425
  try {
215995
- await execFileAsync19("git", args, {
216426
+ await execFileAsync20("git", args, {
215996
216427
  cwd: rootDir,
215997
216428
  encoding: "utf-8",
215998
216429
  maxBuffer: GIT_OUTPUT_MAX_BUFFER2
@@ -216004,7 +216435,7 @@ async function gitRun(rootDir, args, context2) {
216004
216435
  }
216005
216436
  async function gitExitCode2(rootDir, args) {
216006
216437
  try {
216007
- await execFileAsync19("git", args, {
216438
+ await execFileAsync20("git", args, {
216008
216439
  cwd: rootDir,
216009
216440
  encoding: "utf-8",
216010
216441
  maxBuffer: GIT_OUTPUT_MAX_BUFFER2
@@ -216017,20 +216448,20 @@ async function gitExitCode2(rootDir, args) {
216017
216448
  function formatErrorMessage(error3) {
216018
216449
  return error3 instanceof Error ? error3.message : String(error3);
216019
216450
  }
216020
- var execFileAsync19, GIT_OUTPUT_MAX_BUFFER2;
216451
+ var execFileAsync20, GIT_OUTPUT_MAX_BUFFER2;
216021
216452
  var init_merger_overlap_guard = __esm({
216022
216453
  "../engine/src/merge/merger-overlap-guard.ts"() {
216023
216454
  "use strict";
216024
216455
  init_logger3();
216025
216456
  init_merger_squash_audit();
216026
- execFileAsync19 = promisify49(execFile25);
216457
+ execFileAsync20 = promisify50(execFile26);
216027
216458
  GIT_OUTPUT_MAX_BUFFER2 = 10 * 1024 * 1024;
216028
216459
  }
216029
216460
  });
216030
216461
 
216031
216462
  // ../engine/src/merge/merger-auto-prerebase.ts
216032
216463
  import { exec as exec34 } from "node:child_process";
216033
- import { promisify as promisify50 } from "node:util";
216464
+ import { promisify as promisify51 } from "node:util";
216034
216465
  async function probeDivergence(opts) {
216035
216466
  const mainRef = opts.mainRef ?? "HEAD";
216036
216467
  const range = `${opts.baseCommitSha}..${mainRef}`;
@@ -216117,13 +216548,13 @@ var execAsync31;
216117
216548
  var init_merger_auto_prerebase = __esm({
216118
216549
  "../engine/src/merge/merger-auto-prerebase.ts"() {
216119
216550
  "use strict";
216120
- execAsync31 = promisify50(exec34);
216551
+ execAsync31 = promisify51(exec34);
216121
216552
  }
216122
216553
  });
216123
216554
 
216124
216555
  // ../engine/src/execution/branch-autocorrect.ts
216125
216556
  import { exec as exec35 } from "node:child_process";
216126
- import { promisify as promisify51 } from "node:util";
216557
+ import { promisify as promisify52 } from "node:util";
216127
216558
  function quoteShellArg7(value) {
216128
216559
  return `'${value.replace(/'/g, `'\\''`)}'`;
216129
216560
  }
@@ -216192,7 +216623,7 @@ var execAsync32, GIT_TIMEOUT_MS7, GIT_MAX_BUFFER4;
216192
216623
  var init_branch_autocorrect = __esm({
216193
216624
  "../engine/src/execution/branch-autocorrect.ts"() {
216194
216625
  "use strict";
216195
- execAsync32 = promisify51(exec35);
216626
+ execAsync32 = promisify52(exec35);
216196
216627
  GIT_TIMEOUT_MS7 = 1e4;
216197
216628
  GIT_MAX_BUFFER4 = 1024 * 1024;
216198
216629
  }
@@ -216656,9 +217087,9 @@ var init_mesh_lease_manager = __esm({
216656
217087
  });
216657
217088
 
216658
217089
  // ../engine/src/merge/merger-integration-worktree.ts
216659
- import { createHash as createHash32 } from "node:crypto";
216660
- import { exec as exec36, execFile as execFile26 } from "node:child_process";
216661
- import { promisify as promisify52 } from "node:util";
217090
+ import { createHash as createHash33 } from "node:crypto";
217091
+ import { exec as exec36, execFile as execFile27 } from "node:child_process";
217092
+ import { promisify as promisify53 } from "node:util";
216662
217093
  function quoteAutostashArg(value) {
216663
217094
  return `"${value.replace(/(["\\$`])/g, "\\$1")}"`;
216664
217095
  }
@@ -216735,15 +217166,15 @@ async function snapshotDirtyFilesLocal(rootDir) {
216735
217166
  const paths3 = /* @__PURE__ */ new Set();
216736
217167
  try {
216737
217168
  const [unstagedOut, stagedOut, porcelainOut] = await Promise.all([
216738
- execFileAsync20("git", ["diff", "-z", "--name-only"], { cwd: rootDir, encoding: "utf-8" }).then(
217169
+ execFileAsync21("git", ["diff", "-z", "--name-only"], { cwd: rootDir, encoding: "utf-8" }).then(
216739
217170
  (r) => r.stdout,
216740
217171
  () => ""
216741
217172
  ),
216742
- execFileAsync20("git", ["diff", "-z", "--cached", "--name-only"], { cwd: rootDir, encoding: "utf-8" }).then(
217173
+ execFileAsync21("git", ["diff", "-z", "--cached", "--name-only"], { cwd: rootDir, encoding: "utf-8" }).then(
216743
217174
  (r) => r.stdout,
216744
217175
  () => ""
216745
217176
  ),
216746
- execFileAsync20("git", ["status", "-z", "--porcelain"], { cwd: rootDir, encoding: "utf-8" }).then(
217177
+ execFileAsync21("git", ["status", "-z", "--porcelain"], { cwd: rootDir, encoding: "utf-8" }).then(
216747
217178
  (r) => r.stdout,
216748
217179
  () => ""
216749
217180
  )
@@ -216768,18 +217199,18 @@ async function snapshotDirtyFilesLocal(rootDir) {
216768
217199
  async function gitDirtyFingerprintLocal(rootDir) {
216769
217200
  try {
216770
217201
  const [diffOut, statusOut] = await Promise.all([
216771
- execFileAsync20("git", ["diff", "HEAD"], {
217202
+ execFileAsync21("git", ["diff", "HEAD"], {
216772
217203
  cwd: rootDir,
216773
217204
  encoding: "utf-8",
216774
217205
  maxBuffer: 64 * 1024 * 1024
216775
217206
  }).then((r) => r.stdout, () => ""),
216776
- execFileAsync20("git", ["status", "-z", "--porcelain"], { cwd: rootDir, encoding: "utf-8" }).then(
217207
+ execFileAsync21("git", ["status", "-z", "--porcelain"], { cwd: rootDir, encoding: "utf-8" }).then(
216777
217208
  (r) => r.stdout,
216778
217209
  () => ""
216779
217210
  )
216780
217211
  ]);
216781
217212
  if (!diffOut && !statusOut) return "";
216782
- return createHash32("sha256").update(diffOut).update("\0").update(statusOut).digest("hex");
217213
+ return createHash33("sha256").update(diffOut).update("\0").update(statusOut).digest("hex");
216783
217214
  } catch {
216784
217215
  return "";
216785
217216
  }
@@ -216796,7 +217227,7 @@ async function probeIntegrationWorktreeState(input) {
216796
217227
  const dirtyFingerprint = await gitDirtyFingerprintLocal(registeredPath);
216797
217228
  let untrackedCount = 0;
216798
217229
  try {
216799
- const { stdout } = await execFileAsync20("git", ["status", "-z", "--porcelain"], {
217230
+ const { stdout } = await execFileAsync21("git", ["status", "-z", "--porcelain"], {
216800
217231
  cwd: registeredPath,
216801
217232
  encoding: "utf-8"
216802
217233
  });
@@ -217157,7 +217588,7 @@ async function releaseReuseHandoff(input) {
217157
217588
  }
217158
217589
  });
217159
217590
  }
217160
- var execAsync33, execFileAsync20, MERGE_HANDOFF_WORKER_ID, MergeHandoffRefusedError;
217591
+ var execAsync33, execFileAsync21, MERGE_HANDOFF_WORKER_ID, MergeHandoffRefusedError;
217161
217592
  var init_merger_integration_worktree = __esm({
217162
217593
  "../engine/src/merge/merger-integration-worktree.ts"() {
217163
217594
  "use strict";
@@ -217168,8 +217599,8 @@ var init_merger_integration_worktree = __esm({
217168
217599
  init_mesh_lease_manager();
217169
217600
  init_worktree_pool();
217170
217601
  init_worktree_names();
217171
- execAsync33 = promisify52(exec36);
217172
- execFileAsync20 = promisify52(execFile26);
217602
+ execAsync33 = promisify53(exec36);
217603
+ execFileAsync21 = promisify53(execFile27);
217173
217604
  MERGE_HANDOFF_WORKER_ID = "merger-reuse-handoff";
217174
217605
  MergeHandoffRefusedError = class extends Error {
217175
217606
  reason;
@@ -217198,13 +217629,13 @@ var init_push_after_merge_policy = __esm({
217198
217629
  });
217199
217630
 
217200
217631
  // ../engine/src/worktree/worktree-ref-sync.ts
217201
- import { execFile as execFile27, spawn as spawn7 } from "node:child_process";
217202
- import { promisify as promisify53 } from "node:util";
217632
+ import { execFile as execFile28, spawn as spawn7 } from "node:child_process";
217633
+ import { promisify as promisify54 } from "node:util";
217203
217634
  import { copyFileSync, existsSync as existsSync64, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync2, readFileSync as readFileSync22, rmSync as rmSync5, writeFileSync as writeFileSync8 } from "node:fs";
217204
217635
  import { dirname as dirname39, join as join80 } from "node:path";
217205
217636
  import { tmpdir as tmpdir7 } from "node:os";
217206
217637
  async function runGit5(args, cwd, timeoutMs) {
217207
- const result2 = await execFileAsync21("git", ["-c", "core.quotePath=false", ...args], {
217638
+ const result2 = await execFileAsync22("git", ["-c", "core.quotePath=false", ...args], {
217208
217639
  cwd,
217209
217640
  timeout: timeoutMs,
217210
217641
  maxBuffer: 64 * 1024 * 1024,
@@ -217438,11 +217869,11 @@ async function syncWorktreeToHead(input) {
217438
217869
  }
217439
217870
  }
217440
217871
  }
217441
- var execFileAsync21;
217872
+ var execFileAsync22;
217442
217873
  var init_worktree_ref_sync = __esm({
217443
217874
  "../engine/src/worktree/worktree-ref-sync.ts"() {
217444
217875
  "use strict";
217445
- execFileAsync21 = promisify53(execFile27);
217876
+ execFileAsync22 = promisify54(execFile28);
217446
217877
  }
217447
217878
  });
217448
217879
 
@@ -217450,7 +217881,7 @@ var init_worktree_ref_sync = __esm({
217450
217881
  import { exec as exec37 } from "node:child_process";
217451
217882
  import { readFile as readFile44, writeFile as writeFile26 } from "node:fs/promises";
217452
217883
  import { join as join81 } from "node:path";
217453
- import { promisify as promisify54 } from "node:util";
217884
+ import { promisify as promisify55 } from "node:util";
217454
217885
  function quoteArg4(value) {
217455
217886
  return `'${value.replace(/'/g, `'\\''`)}'`;
217456
217887
  }
@@ -217626,7 +218057,7 @@ var init_merger_scope_auto_widen = __esm({
217626
218057
  "use strict";
217627
218058
  init_src2();
217628
218059
  init_merger();
217629
- execAsync34 = promisify54(exec37);
218060
+ execAsync34 = promisify55(exec37);
217630
218061
  GIT_MAX_BUFFER5 = 10 * 1024 * 1024;
217631
218062
  ScopeAutoWidenPersistError = class extends Error {
217632
218063
  constructor(message) {
@@ -217760,9 +218191,9 @@ __export(merger_exports, {
217760
218191
  });
217761
218192
  import { execSync as execSync6, exec as exec38 } from "node:child_process";
217762
218193
  import * as childProcess4 from "node:child_process";
217763
- import { promisify as promisify55 } from "node:util";
218194
+ import { promisify as promisify56 } from "node:util";
217764
218195
  import { existsSync as existsSync65, readFileSync as readFileSync23, writeFileSync as writeFileSync9, unlinkSync as unlinkSync3, renameSync as renameSync4 } from "node:fs";
217765
- import { createHash as createHash33 } from "node:crypto";
218196
+ import { createHash as createHash34 } from "node:crypto";
217766
218197
  import { join as join82, resolve as resolve48 } from "node:path";
217767
218198
  import { hostname as hostname3 } from "node:os";
217768
218199
  import { Type as Type4 } from "typebox";
@@ -217973,15 +218404,15 @@ async function snapshotDirtyFiles(rootDir) {
217973
218404
  const paths3 = /* @__PURE__ */ new Set();
217974
218405
  try {
217975
218406
  const [unstagedOut, stagedOut, porcelainOut] = await Promise.all([
217976
- execFileAsync22("git", ["diff", "-z", "--name-only"], { cwd: rootDir, encoding: "utf-8" }).then(
218407
+ execFileAsync23("git", ["diff", "-z", "--name-only"], { cwd: rootDir, encoding: "utf-8" }).then(
217977
218408
  (r) => r.stdout,
217978
218409
  () => ""
217979
218410
  ),
217980
- execFileAsync22("git", ["diff", "-z", "--cached", "--name-only"], { cwd: rootDir, encoding: "utf-8" }).then(
218411
+ execFileAsync23("git", ["diff", "-z", "--cached", "--name-only"], { cwd: rootDir, encoding: "utf-8" }).then(
217981
218412
  (r) => r.stdout,
217982
218413
  () => ""
217983
218414
  ),
217984
- execFileAsync22("git", ["status", "-z", "--porcelain"], { cwd: rootDir, encoding: "utf-8" }).then(
218415
+ execFileAsync23("git", ["status", "-z", "--porcelain"], { cwd: rootDir, encoding: "utf-8" }).then(
217985
218416
  (r) => r.stdout,
217986
218417
  () => ""
217987
218418
  )
@@ -218006,18 +218437,18 @@ async function snapshotDirtyFiles(rootDir) {
218006
218437
  async function gitDirtyFingerprint(rootDir) {
218007
218438
  try {
218008
218439
  const [diffOut, statusOut] = await Promise.all([
218009
- execFileAsync22("git", ["diff", "HEAD"], {
218440
+ execFileAsync23("git", ["diff", "HEAD"], {
218010
218441
  cwd: rootDir,
218011
218442
  encoding: "utf-8",
218012
218443
  maxBuffer: 64 * 1024 * 1024
218013
218444
  }).then((r) => r.stdout, () => ""),
218014
- execFileAsync22("git", ["status", "-z", "--porcelain"], { cwd: rootDir, encoding: "utf-8" }).then(
218445
+ execFileAsync23("git", ["status", "-z", "--porcelain"], { cwd: rootDir, encoding: "utf-8" }).then(
218015
218446
  (r) => r.stdout,
218016
218447
  () => ""
218017
218448
  )
218018
218449
  ]);
218019
218450
  if (!diffOut && !statusOut) return "";
218020
- return createHash33("sha256").update(diffOut).update("\0").update(statusOut).digest("hex");
218451
+ return createHash34("sha256").update(diffOut).update("\0").update(statusOut).digest("hex");
218021
218452
  } catch {
218022
218453
  return "";
218023
218454
  }
@@ -219979,7 +220410,7 @@ function splitNulDelimited(output2) {
219979
220410
  return text3.split(NUL).filter((entry) => entry.length > 0);
219980
220411
  }
219981
220412
  async function countStagedPaths(rootDir) {
219982
- const { stdout } = await execFileAsync22("git", ["diff", "--cached", "--name-only", "-z"], {
220413
+ const { stdout } = await execFileAsync23("git", ["diff", "--cached", "--name-only", "-z"], {
219983
220414
  cwd: rootDir,
219984
220415
  encoding: "buffer",
219985
220416
  maxBuffer: 10 * 1024 * 1024
@@ -219988,7 +220419,7 @@ async function countStagedPaths(rootDir) {
219988
220419
  }
219989
220420
  async function filterStagedGitignoredPaths(rootDir, taskId) {
219990
220421
  try {
219991
- const { stdout: stagedOut } = await execFileAsync22("git", ["diff", "--cached", "--name-only", "-z"], {
220422
+ const { stdout: stagedOut } = await execFileAsync23("git", ["diff", "--cached", "--name-only", "-z"], {
219992
220423
  cwd: rootDir,
219993
220424
  encoding: "buffer",
219994
220425
  maxBuffer: 10 * 1024 * 1024
@@ -220002,7 +220433,7 @@ async function filterStagedGitignoredPaths(rootDir, taskId) {
220002
220433
  for (let i = 0; i < stagedPaths.length; i += batchSize) {
220003
220434
  const batch = stagedPaths.slice(i, i + batchSize);
220004
220435
  try {
220005
- const { stdout } = await execFileAsync22("git", ["check-ignore", "--no-index", "--", ...batch], {
220436
+ const { stdout } = await execFileAsync23("git", ["check-ignore", "--no-index", "--", ...batch], {
220006
220437
  cwd: rootDir,
220007
220438
  encoding: "utf-8",
220008
220439
  maxBuffer: 10 * 1024 * 1024
@@ -220025,7 +220456,7 @@ async function filterStagedGitignoredPaths(rootDir, taskId) {
220025
220456
  `${taskId}: refusing to stage gitignored path "${path13}" \u2014 unstaging (agents must not bypass .gitignore via \`git add -f\`)`
220026
220457
  );
220027
220458
  try {
220028
- await execFileAsync22("git", ["reset", "HEAD", "--", path13], {
220459
+ await execFileAsync23("git", ["reset", "HEAD", "--", path13], {
220029
220460
  cwd: rootDir,
220030
220461
  encoding: "utf-8",
220031
220462
  maxBuffer: 10 * 1024 * 1024
@@ -220057,7 +220488,7 @@ async function commitOrAmendMergeWithFixes(rootDir, taskId, branch, commitLog, i
220057
220488
  encoding: "utf-8"
220058
220489
  });
220059
220490
  const unstaged = new Set(unstagedOut.split("\n").map((l) => l.trim()).filter(Boolean));
220060
- const { stdout: porcelainOut } = await execFileAsync22("git", ["status", "-z", "--porcelain"], {
220491
+ const { stdout: porcelainOut } = await execFileAsync23("git", ["status", "-z", "--porcelain"], {
220061
220492
  cwd: rootDir,
220062
220493
  encoding: "utf-8"
220063
220494
  });
@@ -220078,7 +220509,7 @@ async function commitOrAmendMergeWithFixes(rootDir, taskId, branch, commitLog, i
220078
220509
  }
220079
220510
  }
220080
220511
  if (unstagedToStage.length > 0) {
220081
- await execFileAsync22("git", ["add", "--", ...unstagedToStage], { cwd: rootDir });
220512
+ await execFileAsync23("git", ["add", "--", ...unstagedToStage], { cwd: rootDir });
220082
220513
  }
220083
220514
  const untrackedToStage = [];
220084
220515
  for (const p2 of untracked) {
@@ -220091,7 +220522,7 @@ async function commitOrAmendMergeWithFixes(rootDir, taskId, branch, commitLog, i
220091
220522
  }
220092
220523
  }
220093
220524
  if (untrackedToStage.length > 0) {
220094
- await execFileAsync22("git", ["add", "--", ...untrackedToStage], { cwd: rootDir });
220525
+ await execFileAsync23("git", ["add", "--", ...untrackedToStage], { cwd: rootDir });
220095
220526
  }
220096
220527
  const cap = (arr, n = 20) => arr.length <= n ? arr.join(", ") : `${arr.slice(0, n).join(", ")} ... (+${arr.length - n} more)`;
220097
220528
  mergerLog.debug(
@@ -221562,7 +221993,7 @@ function isNonFastForwardPushError(message) {
221562
221993
  }
221563
221994
  async function probeRebaseInProgress(rootDir) {
221564
221995
  const gitPath = async (name2) => {
221565
- const { stdout } = await execFileAsync22("git", ["rev-parse", "--git-path", name2], {
221996
+ const { stdout } = await execFileAsync23("git", ["rev-parse", "--git-path", name2], {
221566
221997
  cwd: rootDir,
221567
221998
  encoding: "utf-8",
221568
221999
  timeout: PUSH_TIMEOUT_MS
@@ -225747,7 +226178,7 @@ async function completeTask(store, taskId, result2) {
225747
226178
  }
225748
226179
  store.emit("task:merged", result2);
225749
226180
  }
225750
- var execAsync35, execFileAsync22, LEGACY_COMPLETE_LANES2, DEPENDENCY_SYNC_TRIGGER_PATTERNS, PULL_REBASE_TIMEOUT_MS, PUSH_TIMEOUT_MS, PUSH_NON_FF_MAX_RETRIES, PUSH_NON_FF_RETRY_BACKOFF_MS, PUSH_TRANSIENT_RETRY_BACKOFF_MS, TRANSIENT_GIT_PUSH_PATTERNS, MERGE_COMMIT_LOG_MAX_CHARS, MERGE_DIFF_STAT_MAX_CHARS, MERGE_USER_COMMENTS_MAX_CHARS, summarizeVerificationOutputLocal, VERIFICATION_EXTRA_ENV, ACTIVE_MERGER_STATUS_FILENAME, __test__, AutostashCreationFailedError, NUL, SquashAuditError;
226181
+ var execAsync35, execFileAsync23, LEGACY_COMPLETE_LANES2, DEPENDENCY_SYNC_TRIGGER_PATTERNS, PULL_REBASE_TIMEOUT_MS, PUSH_TIMEOUT_MS, PUSH_NON_FF_MAX_RETRIES, PUSH_NON_FF_RETRY_BACKOFF_MS, PUSH_TRANSIENT_RETRY_BACKOFF_MS, TRANSIENT_GIT_PUSH_PATTERNS, MERGE_COMMIT_LOG_MAX_CHARS, MERGE_DIFF_STAT_MAX_CHARS, MERGE_USER_COMMENTS_MAX_CHARS, summarizeVerificationOutputLocal, VERIFICATION_EXTRA_ENV, ACTIVE_MERGER_STATUS_FILENAME, __test__, AutostashCreationFailedError, NUL, SquashAuditError;
225751
226182
  var init_merger = __esm({
225752
226183
  "../engine/src/merger.ts"() {
225753
226184
  "use strict";
@@ -225819,8 +226250,8 @@ var init_merger = __esm({
225819
226250
  init_merger_scope_auto_widen();
225820
226251
  init_lifecycle_move();
225821
226252
  init_merger_ref_update_advance();
225822
- execAsync35 = promisify55(exec38);
225823
- execFileAsync22 = (file, args, opts) => promisify55(childProcess4.execFile)(file, args, opts);
226253
+ execAsync35 = promisify56(exec38);
226254
+ execFileAsync23 = (file, args, opts) => promisify56(childProcess4.execFile)(file, args, opts);
225824
226255
  LEGACY_COMPLETE_LANES2 = ["done"];
225825
226256
  DEPENDENCY_SYNC_TRIGGER_PATTERNS = [
225826
226257
  "package.json",
@@ -225924,9 +226355,6 @@ function isDependencySatisfiedWithoutWorkflowMetadata(column) {
225924
226355
  function isLegacyCompleteColumnForWorkspaceTeardown(column) {
225925
226356
  return column === "done";
225926
226357
  }
225927
- function resolveRepoLocalAiMergeRoot(rootDir, settings) {
225928
- return resolveAiMergeRootPath(rootDir, settings);
225929
- }
225930
226358
  async function classifyOwnedLandedEvidenceForSelfHealing(rootDir, task, mergeTargetBranch) {
225931
226359
  const { classifyOwnedLandedEvidence: classifyOwnedLandedEvidence2 } = await Promise.resolve().then(() => (init_merger(), merger_exports));
225932
226360
  return classifyOwnedLandedEvidence2(rootDir, task, { mergeTargetBranch });
@@ -226013,6 +226441,8 @@ var init_self_healing = __esm({
226013
226441
  init_branch_conflicts();
226014
226442
  init_run_audit();
226015
226443
  init_auto_merge_finalization();
226444
+ init_merge_content_capture();
226445
+ init_stale_content_review_reroute();
226016
226446
  init_post_landing_worktree_cleanup();
226017
226447
  init_auto_recovery();
226018
226448
  init_active_session_registry();
@@ -226181,6 +226611,7 @@ var init_self_healing = __esm({
226181
226611
  symbolLockNoActionAudited = false;
226182
226612
  maintenanceTickCounter = 0;
226183
226613
  taskLifecycleRetentionLastPrunedAt = /* @__PURE__ */ new Map();
226614
+ staleContentRerouteAuditKeys = /* @__PURE__ */ new Set();
226184
226615
  githubCheckStateRetentionLastPrunedAt = /* @__PURE__ */ new Map();
226185
226616
  processBootStartedAt = Date.now();
226186
226617
  lastDbCorruptionNotifiedAt = null;
@@ -226896,6 +227327,7 @@ var init_self_healing = __esm({
226896
227327
  // flight" to all of them (the merge gate included), which is the two-hour
226897
227328
  // stall-deadlock ride this sweep exists to prevent.
226898
227329
  { name: "reconcile-orphaned-pending-step-results", fn: () => this.reconcileOrphanedPendingStepResults().then(() => void 0) },
227330
+ { name: "reconcile-unproven-review-approvals", fn: () => this.reconcileUnprovenReviewApprovals().then(() => void 0) },
226899
227331
  /*
226900
227332
  FNXC:WorkspaceContention 2026-08-23-08:00:
226901
227333
  `contention-hold` is owned by an in-memory retry timer. After a process restart that
@@ -227776,6 +228208,7 @@ var init_self_healing = __esm({
227776
228208
  Keep them adjacent and in this order.
227777
228209
  */
227778
228210
  { name: "reconcile-orphaned-pending-step-results", fn: () => this.reconcileOrphanedPendingStepResults() },
228211
+ { name: "reconcile-unproven-review-approvals", fn: () => this.reconcileUnprovenReviewApprovals() },
227779
228212
  { name: "recover-failed-pre-merge-steps", fn: () => this.recoverReviewTasksWithFailedPreMergeSteps() },
227780
228213
  { name: "recover-missing-worktree-review-failures", fn: () => this.recoverMissingWorktreeReviewFailures() },
227781
228214
  { name: "recover-interrupted-merging", fn: () => this.recoverInterruptedMergingTasks() },
@@ -232222,6 +232655,95 @@ var init_self_healing = __esm({
232222
232655
  return 0;
232223
232656
  }
232224
232657
  }
232658
+ /*
232659
+ FNXC:ReviewInputProof 2026-09-01-11:28:
232660
+ Prevention cannot release cards that already persisted a proofless `passed` content review. Repair
232661
+ only the invalid result in place, including when auto-merge is off, so automatic recovery can re-run
232662
+ eligible gates and a human-held card gains the failed result its audited bypass needs. The
232663
+ `needsOperatorBypass` label is therefore truthful rather than aspirational; no lifecycle state moves.
232664
+
232665
+ FNXC:ReviewInputProof 2026-09-01-11:57:
232666
+ Reconciliation must recompute from the lock-held task inside `updateTaskAtomic`; a graph writer can
232667
+ publish a proof-bound approval or another gate after the preliminary read, and a stale array write
232668
+ would discard that valid result. Re-check lane, user pause, workspace ownership, and session liveness
232669
+ in the callback, then log and audit only a repair whose atomic mutation actually applied.
232670
+ */
232671
+ async reconcileUnprovenReviewApprovals() {
232672
+ try {
232673
+ const reviewColumns = await resolveProjectColumnsForRoles(this.store, REVIEW_ROLES);
232674
+ const candidates = /* @__PURE__ */ new Map();
232675
+ for (const column of reviewColumns) {
232676
+ for (const task of await this.store.listTasks({ column, slim: true })) candidates.set(task.id, task);
232677
+ }
232678
+ const settings = await this.store.getSettings().catch(() => void 0);
232679
+ let repairedTasks = 0;
232680
+ const isSessionLive = (taskId) => {
232681
+ const livePaths = activeSessionRegistry.pathsForTask(taskId);
232682
+ return livePaths.some((path13) => activeSessionRegistry.isPathActive(path13)) || executingTaskLock.has(taskId) || this.options.isTaskActive?.(taskId) === true;
232683
+ };
232684
+ for (const candidate of candidates.values()) {
232685
+ if (candidate.userPaused === true || candidate.workspaceWorktrees !== void 0 || isSessionLive(candidate.id)) continue;
232686
+ if (!candidate.workflowStepResults?.some((result2) => resolveUnprovenReviewApproval(result2, { workspace: false }))) continue;
232687
+ const fresh = await this.store.getTask(candidate.id);
232688
+ if (!fresh || !reviewColumns.has(fresh.column) || fresh.userPaused === true || fresh.workspaceWorktrees !== void 0 || isSessionLive(fresh.id)) continue;
232689
+ let repair;
232690
+ try {
232691
+ await this.store.updateTaskAtomic(fresh.id, (live) => {
232692
+ repair = void 0;
232693
+ if (!reviewColumns.has(live.column) || live.userPaused === true || live.workspaceWorktrees !== void 0 || isSessionLive(live.id)) return null;
232694
+ const repairedStepIds = [];
232695
+ let repairReason;
232696
+ const results = (live.workflowStepResults ?? []).map((result2) => {
232697
+ const resolution = resolveUnprovenReviewApproval(result2, { workspace: false });
232698
+ if (!resolution) return result2;
232699
+ repairedStepIds.push(result2.workflowStepId);
232700
+ repairReason ??= resolution.reason;
232701
+ return resolution.downgraded;
232702
+ });
232703
+ if (repairedStepIds.length === 0 || !repairReason) return null;
232704
+ repair = {
232705
+ stepIds: repairedStepIds,
232706
+ reason: repairReason,
232707
+ column: live.column,
232708
+ resultCount: results.length,
232709
+ needsOperatorBypass: settings ? !allowsAutoMergeProcessing(live, settings) : void 0
232710
+ };
232711
+ return { workflowStepResults: results };
232712
+ });
232713
+ if (!repair) continue;
232714
+ repairedTasks += 1;
232715
+ } catch (error3) {
232716
+ log34.warn(`reconcileUnprovenReviewApprovals: failed for ${fresh.id}: ${error3 instanceof Error ? error3.message : String(error3)}`);
232717
+ continue;
232718
+ }
232719
+ await this.store.logEntry(
232720
+ fresh.id,
232721
+ `[pre-merge] Invalid proofless approval repaired for ${repair.stepIds.join(", ")}: ${repair.reason}`
232722
+ ).catch(() => void 0);
232723
+ await emitBoundedRunAudit2(this.store, {
232724
+ taskId: fresh.id,
232725
+ agentId: "self-healing",
232726
+ runId: generateSyntheticRunId("reconcile-unproven-review-approval", fresh.id),
232727
+ domain: "database",
232728
+ mutationType: "task:reconcile-unproven-review-approval",
232729
+ target: fresh.id,
232730
+ metadata: {
232731
+ taskId: fresh.id,
232732
+ column: repair.column,
232733
+ workflowStepId: repair.stepIds[0],
232734
+ repairedCount: repair.stepIds.length,
232735
+ resultCount: repair.resultCount,
232736
+ needsOperatorBypass: repair.needsOperatorBypass
232737
+ }
232738
+ }, { log: log34 });
232739
+ }
232740
+ if (repairedTasks > 0) log34.log(`Repaired unproven review approvals on ${repairedTasks} task(s)`);
232741
+ return repairedTasks;
232742
+ } catch (error3) {
232743
+ log34.error(`reconcileUnprovenReviewApprovals failed: ${error3 instanceof Error ? error3.message : String(error3)}`);
232744
+ return 0;
232745
+ }
232746
+ }
232225
232747
  /**
232226
232748
  * Backward lifecycle move gated on triple proof (FN-5335).
232227
232749
  * When the unproven fallback predicate fails, emits `task:finalize-no-op-review-no-action` and skips lifecycle mutation.
@@ -232575,6 +233097,66 @@ var init_self_healing = __esm({
232575
233097
  }
232576
233098
  return allowsAutoMergeProcessing(task, settings) && resolveEffectiveAutoMerge(task, settings) !== false;
232577
233099
  }
233100
+ /*
233101
+ FNXC:PreMergeApproval 2026-09-01-14:05:
233102
+ Self-healing must not treat a stale content-bound approval as mergeable just because the cheap
233103
+ blocker check lacks a fresh Git descriptor. Capture the same merge content the merge queue uses and
233104
+ seed the graph back at Code Review, so cards like FN-9234 stop looping through doomed merge retries.
233105
+ */
233106
+ async routeStaleSingularApprovalBackToReview(task, reviewColumns, settings) {
233107
+ let mergeGate;
233108
+ try {
233109
+ mergeGate = await resolvePreMergeGateForTask(this.store, task.id, task.enabledWorkflowSteps, task);
233110
+ } catch {
233111
+ return false;
233112
+ }
233113
+ if (mergeGate.provenance === "default" && !mergeGate.selectionAbsent) return false;
233114
+ const mergeContent = await captureMergeContentDescriptor(task, {
233115
+ workspaceRootDir: this.options.rootDir,
233116
+ settings
233117
+ });
233118
+ const blocker = getTaskMergeBlocker(task, {
233119
+ reviewColumns,
233120
+ requiredPreMergeStepIds: mergeGate.requiredPreMergeStepIds,
233121
+ mergeContent
233122
+ });
233123
+ if (blocker !== "task has a pre-merge approval recorded against different content" || mergeContent.kind !== "singular") {
233124
+ return false;
233125
+ }
233126
+ const reroute = await rerouteSingularStaleContentToReview(this.store, task, {
233127
+ requiredPreMergeStepIds: mergeGate.requiredPreMergeStepIds,
233128
+ mergeContent
233129
+ }).catch(() => ({
233130
+ rerouted: false,
233131
+ reason: "no-progress",
233132
+ nodeId: void 0,
233133
+ workflowStepId: void 0
233134
+ }));
233135
+ if (reroute.rerouted) {
233136
+ await this.store.logEntry(task.id, "[pre-merge] Self-healing re-seeded Code Review after stale content evidence blocked merge.");
233137
+ log34.warn(`Stale content approval for ${task.id} re-seeded at ${reroute.nodeId ?? "code-review"}`);
233138
+ }
233139
+ const auditKey = `${task.id}:${reroute.reason}:${reroute.nodeId ?? ""}`;
233140
+ if (!this.staleContentRerouteAuditKeys.has(auditKey)) {
233141
+ this.staleContentRerouteAuditKeys.add(auditKey);
233142
+ await emitBoundedRunAudit2(this.store, {
233143
+ taskId: task.id,
233144
+ agentId: "self-healing",
233145
+ runId: generateSyntheticRunId("self-healing", task.id),
233146
+ domain: "database",
233147
+ mutationType: "task:merge-stale-content-review-rerouted",
233148
+ target: task.id,
233149
+ metadata: {
233150
+ taskId: task.id,
233151
+ nodeId: reroute.nodeId,
233152
+ workflowStepId: reroute.workflowStepId,
233153
+ reason: reroute.reason,
233154
+ source: "self-healing"
233155
+ }
233156
+ });
233157
+ }
233158
+ return true;
233159
+ }
232578
233160
  /**
232579
233161
  * Recover `in-review` tasks that are fully mergeable but never had
232580
233162
  * `mergeTask()` invoked.
@@ -232628,6 +233210,7 @@ var init_self_healing = __esm({
232628
233210
  for (const task of mergeable) {
232629
233211
  const reviewColumns = await ownReviewLanesFor(task);
232630
233212
  if (!reviewColumns.has(task.column)) continue;
233213
+ if (await this.routeStaleSingularApprovalBackToReview(task, reviewColumns, settings)) continue;
232631
233214
  if (getTaskMergeBlocker(task, { reviewColumns }) !== void 0) continue;
232632
233215
  laneQualifiedMergeable.push(task);
232633
233216
  }
@@ -235194,8 +235777,7 @@ This review is not retried until its findings change. Re-run the review after ad
235194
235777
  }
235195
235778
  async listAiMergeWorktreeCandidates(taskId, settings) {
235196
235779
  const roots = Array.from(/* @__PURE__ */ new Set([
235197
- resolveRepoLocalAiMergeRoot(this.options.rootDir, settings),
235198
- resolveLegacyAiMergeRootPath(this.options.rootDir),
235780
+ ...resolveAiMergeSearchRoots(this.options.rootDir, settings),
235199
235781
  tmpdir8()
235200
235782
  ]));
235201
235783
  const testWorkerRoot = process.env.FUSION_TEST_WORKER_ROOT;
@@ -237729,9 +238311,7 @@ This review is not retried until its findings change. Re-run the review after ad
237729
238311
  log34.debug("[self-healing] temp-dir sweep: worktrunk enabled \u2014 AI merge clean-room worktrees use Fusion's dedicated clean-room root, proceeding with native sweep");
237730
238312
  }
237731
238313
  const roots = Array.from(/* @__PURE__ */ new Set([
237732
- resolveRepoLocalAiMergeRoot(this.options.rootDir, settings),
237733
- resolveLegacyAiMergeRootPath(this.options.rootDir),
237734
- ...settings.worktreesDir ? [] : [join83(resolveLegacyWorktreesDirLayout(this.options.rootDir), ".ai-merge")],
238314
+ ...resolveAiMergeSearchRoots(this.options.rootDir, settings),
237735
238315
  tmpdir8()
237736
238316
  ]));
237737
238317
  const auditor = createRunAuditor(this.store, {
@@ -238284,7 +238864,7 @@ import { exec as exec39 } from "node:child_process";
238284
238864
  import { existsSync as existsSync67 } from "node:fs";
238285
238865
  import { readFile as readFile46, writeFile as writeFile27, rm as rm11 } from "node:fs/promises";
238286
238866
  import { join as join84 } from "node:path";
238287
- import { promisify as promisify56 } from "node:util";
238867
+ import { promisify as promisify57 } from "node:util";
238288
238868
  function getPlanningLifecycleLockTransportFailure(task) {
238289
238869
  const candidate = task.customFields?.[PLANNING_LIFECYCLE_LOCK_TRANSPORT_FAILURE_KEY];
238290
238870
  if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) return null;
@@ -241681,7 +242261,7 @@ ${lines.join("\n")}` }],
241681
242261
  written,
241682
242262
  {
241683
242263
  cwd: this.rootDir,
241684
- exec: promisify56(exec39)
242264
+ exec: promisify57(exec39)
241685
242265
  }
241686
242266
  ),
241687
242267
  new Promise((resolve65) => setTimeout(() => resolve65(null), 15e3))
@@ -241935,7 +242515,7 @@ var init_workflow_gate_activity = __esm({
241935
242515
 
241936
242516
  // ../engine/src/executor/browser-probe.ts
241937
242517
  import { exec as exec40 } from "node:child_process";
241938
- import { promisify as promisify57 } from "node:util";
242518
+ import { promisify as promisify58 } from "node:util";
241939
242519
  function isAgentBrowserNotFoundError(error3) {
241940
242520
  const err = error3;
241941
242521
  const code = typeof err?.code === "string" || typeof err?.code === "number" ? String(err.code) : void 0;
@@ -241991,7 +242571,7 @@ var execAsync36, AGENT_BROWSER_NAVIGATION_SKILL_ID;
241991
242571
  var init_browser_probe = __esm({
241992
242572
  "../engine/src/executor/browser-probe.ts"() {
241993
242573
  "use strict";
241994
- execAsync36 = promisify57(exec40);
242574
+ execAsync36 = promisify58(exec40);
241995
242575
  AGENT_BROWSER_NAVIGATION_SKILL_ID = "agent-browser-navigation";
241996
242576
  }
241997
242577
  });
@@ -242510,7 +243090,7 @@ var init_workflow_failure_scope_guard = __esm({
242510
243090
  // ../engine/src/executor/worktree-registry-helpers.ts
242511
243091
  import { isAbsolute as isAbsolute21, relative as relative20, resolve as resolvePath3 } from "node:path";
242512
243092
  import { exec as exec41 } from "node:child_process";
242513
- import { promisify as promisify58 } from "node:util";
243093
+ import { promisify as promisify59 } from "node:util";
242514
243094
  async function isRegisteredWorktree(rootDir, path13) {
242515
243095
  return isRegisteredGitWorktree(rootDir, path13);
242516
243096
  }
@@ -242554,7 +243134,7 @@ var init_worktree_registry_helpers = __esm({
242554
243134
  "../engine/src/executor/worktree-registry-helpers.ts"() {
242555
243135
  "use strict";
242556
243136
  init_worktree_pool();
242557
- execAsync37 = promisify58(exec41);
243137
+ execAsync37 = promisify59(exec41);
242558
243138
  NonRetryableWorktreeError = class extends Error {
242559
243139
  };
242560
243140
  }
@@ -242783,7 +243363,7 @@ var init_worktree_ownership = __esm({
242783
243363
 
242784
243364
  // ../engine/src/executor/worktree-stale-branch.ts
242785
243365
  import { exec as exec42 } from "node:child_process";
242786
- import { promisify as promisify59 } from "node:util";
243366
+ import { promisify as promisify60 } from "node:util";
242787
243367
  async function cleanupStaleBranch(rootDir, store, branch, taskId) {
242788
243368
  const task = await store.getTask?.(taskId);
242789
243369
  if (!task || !isFusionDeletableBranch(task, branch)) {
@@ -242839,13 +243419,13 @@ var init_worktree_stale_branch = __esm({
242839
243419
  "../engine/src/executor/worktree-stale-branch.ts"() {
242840
243420
  "use strict";
242841
243421
  init_src2();
242842
- execAsync38 = promisify59(exec42);
243422
+ execAsync38 = promisify60(exec42);
242843
243423
  }
242844
243424
  });
242845
243425
 
242846
243426
  // ../engine/src/executor/worktree-squash-import-plan.ts
242847
243427
  import { exec as exec43 } from "node:child_process";
242848
- import { promisify as promisify60 } from "node:util";
243428
+ import { promisify as promisify61 } from "node:util";
242849
243429
  async function planSquashImportFromDep(rootDir, store, _taskId, depTip, originalStartPoint) {
242850
243430
  let settings;
242851
243431
  try {
@@ -242919,7 +243499,7 @@ var init_worktree_squash_import_plan = __esm({
242919
243499
  "../engine/src/executor/worktree-squash-import-plan.ts"() {
242920
243500
  "use strict";
242921
243501
  init_shell_quote();
242922
- execAsync39 = promisify60(exec43);
243502
+ execAsync39 = promisify61(exec43);
242923
243503
  }
242924
243504
  });
242925
243505
 
@@ -243670,7 +244250,7 @@ var init_optional_step_revision = __esm({
243670
244250
 
243671
244251
  // ../engine/src/executor/execute-workflow-step.ts
243672
244252
  import { exec as exec44 } from "node:child_process";
243673
- import { promisify as promisify61 } from "node:util";
244253
+ import { promisify as promisify62 } from "node:util";
243674
244254
  function findReusableReviewResult(task, workflowStepId, reviewInputFingerprint, repositoryScopeRevision) {
243675
244255
  if (!reviewInputFingerprint) return void 0;
243676
244256
  return (task.workflowStepResults ?? []).find(
@@ -243708,6 +244288,8 @@ async function executeWorkflowStep(deps, task, workflowStep, worktreePath, setti
243708
244288
  const unattended = stepOptions?.unattended === true;
243709
244289
  const workflowStepMetadata = workflowStep;
243710
244290
  const optionalGroupId = workflowStepMetadata.optionalGroupId;
244291
+ const effectiveWorkflowStepId = optionalGroupId ?? workflowStep.id.replace(/^graph:/, "");
244292
+ const isContentBindingStep = requiresContentReviewProof(effectiveWorkflowStepId, workflowStepMetadata);
243711
244293
  const isPlanReviewStep = workflowStep.id === "graph:plan-review-step" || workflowStep.name === "Plan Review" || optionalGroupId === PLAN_REVIEW_GROUP_ID;
243712
244294
  const planReviewRevisionKey = optionalStepRevisionKey2(optionalGroupId, workflowStep.name);
243713
244295
  const isReviewTypeWorkflowStep = isPlanReviewStep || workflowStepMetadata.reviewCanFixInline === true || /(?:^|\b)(?:review|verification)(?:\b|$)/i.test(workflowStep.name) || optionalGroupId === "plan-review" || optionalGroupId === "code-review" || optionalGroupId === "browser-verification";
@@ -243718,6 +244300,8 @@ async function executeWorkflowStep(deps, task, workflowStep, worktreePath, setti
243718
244300
  toolMode = "coding";
243719
244301
  }
243720
244302
  const requireExternalIntegrationEvidence = workflowStepMetadata.requireExternalIntegrationEvidence === true;
244303
+ const readonlyMcpServerAllowlist = toolMode === "readonly" ? [...new Set((workflowStepMetadata.readonlyMcpServers ?? []).map((name2) => name2.trim()).filter(Boolean))] : [];
244304
+ const allowReadonlyMcpTools = toolMode === "readonly" && readonlyMcpServerAllowlist.length > 0;
243721
244305
  let workflowReviewSpecArtifact;
243722
244306
  if (isReviewTypeWorkflowStep) {
243723
244307
  try {
@@ -243736,7 +244320,7 @@ async function executeWorkflowStep(deps, task, workflowStep, worktreePath, setti
243736
244320
  const workflowReviewSpecText = typeof workflowReviewSpecArtifact === "string" ? workflowReviewSpecArtifact : "";
243737
244321
  const planReviewSpecText = isPlanReviewStep ? workflowReviewSpecText : "";
243738
244322
  const latestTaskForUserComments = await deps.store.getTask(task.id).catch(() => task);
243739
- const sameGateStepId = workflowStep.id.replace(/^graph:/, "");
244323
+ const sameGateStepId = effectiveWorkflowStepId;
243740
244324
  const planReviewConvergenceContext = isPlanReviewStep ? buildGraphPlanReviewConvergenceContext(latestTaskForUserComments, planReviewRevisionKey) : "";
243741
244325
  const planReviewEnvironmentCapabilities = isPlanReviewStep ? await probeEnvironmentCapabilities({
243742
244326
  extraCommands: [
@@ -243784,21 +244368,44 @@ async function executeWorkflowStep(deps, task, workflowStep, worktreePath, setti
243784
244368
  let diffShortstat;
243785
244369
  let reviewInputFingerprint;
243786
244370
  let reviewedCommitSha;
244371
+ let baseRef;
243787
244372
  try {
243788
- const baseRef = await resolveDiffBaseRef(worktreePath, diffBaseCommitSha);
243789
- if (baseRef) {
243790
- const { stdout } = await execAsync40(`git diff --shortstat ${baseRef}..HEAD`, {
243791
- cwd: worktreePath,
243792
- encoding: "utf-8"
243793
- });
243794
- diffShortstat = stdout.trim() || void 0;
244373
+ baseRef = await resolveDiffBaseRef(worktreePath, diffBaseCommitSha);
244374
+ } catch {
244375
+ }
244376
+ if (isContentBindingStep && task.workspaceWorktrees === void 0) {
244377
+ const suppliedFingerprint = stepOptions?.reviewInputFingerprint?.trim();
244378
+ const proof = suppliedFingerprint ? { kind: "fingerprint", fingerprint: suppliedFingerprint } : await resolveContentReviewInputProof(worktreePath, diffBaseCommitSha);
244379
+ if (proof.kind === "unprovable") {
244380
+ const diagnostic = `${workflowStep.name} review input is unprovable (${proof.reason}); reviewer dispatch refused.`;
244381
+ await deps.store.logEntry(
244382
+ task.id,
244383
+ `[pre-merge] ${diagnostic}`,
244384
+ void 0,
244385
+ deps.getRunContextFor(task.id)
244386
+ );
244387
+ return { success: false, error: diagnostic, failureValue: "review-input-unprovable" };
244388
+ }
244389
+ reviewInputFingerprint = proof.fingerprint;
244390
+ } else if (baseRef) {
244391
+ try {
243795
244392
  if (workflowStepMetadata.reviewKind === "code") {
243796
244393
  reviewInputFingerprint = await computeCodeReviewInputFingerprint(worktreePath, baseRef);
243797
244394
  } else if (isReviewTypeWorkflowStep) {
243798
244395
  reviewInputFingerprint = await computeReviewDiffFingerprint(worktreePath, baseRef);
243799
244396
  }
244397
+ } catch {
244398
+ }
244399
+ }
244400
+ if (baseRef) {
244401
+ try {
244402
+ const { stdout } = await execAsync40(`git diff --shortstat ${baseRef}..HEAD`, {
244403
+ cwd: worktreePath,
244404
+ encoding: "utf-8"
244405
+ });
244406
+ diffShortstat = stdout.trim() || void 0;
244407
+ } catch {
243800
244408
  }
243801
- } catch {
243802
244409
  }
243803
244410
  if (isReviewTypeWorkflowStep) {
243804
244411
  try {
@@ -244108,6 +244715,12 @@ ${workflowStepUserCommentSection}` : ""}${priorFindingsBlock}
244108
244715
  const workflowStepThinkingSource = workflowStep.thinkingLevel ?? (isReviewTypeWorkflowStep ? task.validatorThinkingLevel ?? task.thinkingLevel : task.thinkingLevel);
244109
244716
  const workflowStepThinkingLevel = attemptLabel === "fallback" ? isReviewTypeWorkflowStep ? resolveValidatorFallbackThinkingLevel(workflowStepThinkingSource, settings) : resolveExecutorFallbackThinkingLevel(workflowStepThinkingSource, settings) : isReviewTypeWorkflowStep ? resolveValidatorThinkingLevel(workflowStepThinkingSource, settings) : resolveExecutorThinkingLevel(workflowStepThinkingSource, settings);
244110
244717
  const workflowStepFallbackThinkingLevel = isReviewTypeWorkflowStep ? resolveValidatorFallbackThinkingLevel(workflowStepThinkingSource, settings) : resolveExecutorFallbackThinkingLevel(workflowStepThinkingSource, settings);
244718
+ if (allowReadonlyMcpTools) {
244719
+ await deps.store.logEntry(
244720
+ task.id,
244721
+ `Workflow step '${workflowStep.name}' enabled read-only MCP servers: ${readonlyMcpServerAllowlist.join(", ")}`
244722
+ );
244723
+ }
244111
244724
  const { session } = await createResolvedAgentSession({
244112
244725
  sessionPurpose: "executor",
244113
244726
  taskExecutionSession: true,
@@ -244128,6 +244741,10 @@ ${workflowStepUserCommentSection}` : ""}${priorFindingsBlock}
244128
244741
  settings,
244129
244742
  taskEnv: stepEnv,
244130
244743
  mcpServers: await deps.resolveMcpServers(void 0),
244744
+ ...allowReadonlyMcpTools ? {
244745
+ allowMcpToolsInReadonly: true,
244746
+ readonlyMcpServerAllowlist
244747
+ } : {},
244131
244748
  // FNXC:SessionRouting 2026-06-24-11:20:
244132
244749
  // #1675: propagate task id so workflow-step requests carry the same
244133
244750
  // X-Session-Id/X-Session-Affinity as the primary session.
@@ -244343,6 +244960,60 @@ ${detectedQuestion}
244343
244960
  });
244344
244961
  }
244345
244962
  const revisionRequested = effectiveVerdict === "REVISE";
244963
+ if (isReviewTypeWorkflowStep && !isPlanReviewStep && !revisionRequested) {
244964
+ const priorReviewedCommitSha = reviewedCommitSha;
244965
+ const currentHeadSha = await readHeadSha(worktreePath);
244966
+ const fastForwardAdvance = await isFastForwardAdvance(worktreePath, priorReviewedCommitSha, currentHeadSha);
244967
+ const baseIsAncestor = await isFastForwardAdvance(worktreePath, baseRef, currentHeadSha);
244968
+ const decision = classifyReviewInlineFixRecapture({
244969
+ verdict: effectiveVerdict,
244970
+ reviewKind: workflowStepMetadata.reviewKind,
244971
+ reviewedCommitSha: priorReviewedCommitSha,
244972
+ currentHeadSha,
244973
+ baseRef,
244974
+ fastForwardAdvance,
244975
+ baseIsAncestor,
244976
+ fingerprintProbeAvailable: true
244977
+ });
244978
+ if (decision.recapture) {
244979
+ try {
244980
+ const recapturedFingerprint = workflowStepMetadata.reviewKind === "code" ? await computeCodeReviewInputFingerprint(worktreePath, baseRef) : await computeReviewDiffFingerprint(worktreePath, baseRef);
244981
+ const finalDecision = classifyReviewInlineFixRecapture({
244982
+ verdict: effectiveVerdict,
244983
+ reviewKind: workflowStepMetadata.reviewKind,
244984
+ reviewedCommitSha: priorReviewedCommitSha,
244985
+ currentHeadSha,
244986
+ baseRef,
244987
+ fastForwardAdvance,
244988
+ baseIsAncestor,
244989
+ fingerprintProbeAvailable: recapturedFingerprint !== void 0
244990
+ });
244991
+ if (finalDecision.recapture && currentHeadSha) {
244992
+ reviewInputFingerprint = recapturedFingerprint;
244993
+ reviewedCommitSha = currentHeadSha;
244994
+ const resolvedInReviewFindingCount = parsed.findings?.filter((finding) => finding.resolution === "resolved-in-review").length ?? 0;
244995
+ await deps.store.logEntry(task.id, `[pre-merge] ${workflowStep.name} re-captured its own review identity after fast-forward ${priorReviewedCommitSha?.slice(0, 7)} \u2192 ${currentHeadSha.slice(0, 7)} (${finalDecision.reason})`);
244996
+ const runContext = deps.getRunContextFor(task.id);
244997
+ if (runContext) await emitBoundedRunAudit2(deps.store, {
244998
+ taskId: task.id,
244999
+ agentId: runContext.agentId,
245000
+ runId: runContext.runId,
245001
+ domain: "git",
245002
+ mutationType: "task:review-input-recaptured",
245003
+ target: task.id,
245004
+ metadata: {
245005
+ taskId: task.id,
245006
+ workflowStepId: workflowStep.id,
245007
+ verdict: effectiveVerdict,
245008
+ resolvedInReviewFindingCount,
245009
+ reason: finalDecision.reason
245010
+ }
245011
+ });
245012
+ }
245013
+ } catch {
245014
+ }
245015
+ }
245016
+ }
244346
245017
  if (workflowStep.requiresBrowser === true) {
244347
245018
  await logBrowserVerificationActivity(`[browser-verification] finished browser verification for task ${task.id}: verdict ${effectiveVerdict}`);
244348
245019
  }
@@ -244487,9 +245158,10 @@ var init_execute_workflow_step = __esm({
244487
245158
  init_workflow_step_verdict();
244488
245159
  init_worktree_git_refs();
244489
245160
  init_review_diff_fingerprint();
245161
+ init_review_inline_fix_recapture();
244490
245162
  init_optional_step_revision();
244491
245163
  init_agent_usage_telemetry();
244492
- execAsync40 = promisify61(exec44);
245164
+ execAsync40 = promisify62(exec44);
244493
245165
  WORKFLOW_STEP_NOTES_REPAIR_TIMEOUT_MS = 12e4;
244494
245166
  }
244495
245167
  });
@@ -245123,7 +245795,7 @@ var init_public_reexports = __esm({
245123
245795
 
245124
245796
  // ../engine/src/executor/worktree-create-conflict.ts
245125
245797
  import { exec as exec45 } from "node:child_process";
245126
- import { promisify as promisify62 } from "node:util";
245798
+ import { promisify as promisify63 } from "node:util";
245127
245799
  import { existsSync as existsSync69 } from "node:fs";
245128
245800
  import { rm as rm12 } from "node:fs/promises";
245129
245801
  async function tryCreateWorktree(deps, branch, path13, taskId, startPoint, attemptNumber = 0, recoveryDepth = 0, allowSiblingBranchRename = false, settings = {}) {
@@ -245418,13 +246090,13 @@ var init_worktree_create_conflict = __esm({
245418
246090
  init_logger3();
245419
246091
  init_worktree_conflict_info();
245420
246092
  init_worktree_registry_helpers();
245421
- execAsync41 = promisify62(exec45);
246093
+ execAsync41 = promisify63(exec45);
245422
246094
  }
245423
246095
  });
245424
246096
 
245425
246097
  // ../engine/src/executor/worktree-cleanup-conflicting.ts
245426
246098
  import { exec as exec46 } from "node:child_process";
245427
- import { promisify as promisify63 } from "node:util";
246099
+ import { promisify as promisify64 } from "node:util";
245428
246100
  import { existsSync as existsSync70, lstatSync as lstatSync3, realpathSync as realpathSync11 } from "node:fs";
245429
246101
  import { rm as rm13 } from "node:fs/promises";
245430
246102
  async function cleanupConflictingWorktree(deps, worktreePath, branch, taskId) {
@@ -245543,13 +246215,13 @@ var init_worktree_cleanup_conflicting = __esm({
245543
246215
  init_src2();
245544
246216
  init_worktree_pool();
245545
246217
  init_logger3();
245546
- execAsync42 = promisify63(exec46);
246218
+ execAsync42 = promisify64(exec46);
245547
246219
  }
245548
246220
  });
245549
246221
 
245550
246222
  // ../engine/src/executor/worktree-create-outer.ts
245551
246223
  import { exec as exec47 } from "node:child_process";
245552
- import { promisify as promisify64 } from "node:util";
246224
+ import { promisify as promisify65 } from "node:util";
245553
246225
  import { existsSync as existsSync71 } from "node:fs";
245554
246226
  import { isAbsolute as isAbsolute22 } from "node:path";
245555
246227
  async function resolveWorktreeStartPoint(rootDir, store, startPoint, taskId) {
@@ -245754,13 +246426,13 @@ var init_worktree_create_outer = __esm({
245754
246426
  init_logger3();
245755
246427
  init_shell_quote();
245756
246428
  init_worktree_registry_helpers();
245757
- execAsync43 = promisify64(exec47);
246429
+ execAsync43 = promisify65(exec47);
245758
246430
  }
245759
246431
  });
245760
246432
 
245761
246433
  // ../engine/src/executor/worktree-branch-conflict-handle.ts
245762
246434
  import { exec as exec48 } from "node:child_process";
245763
- import { promisify as promisify65 } from "node:util";
246435
+ import { promisify as promisify66 } from "node:util";
245764
246436
  async function reclaimExistingWorktree(deps, task, livePath, branch, tipSha, count2, settings) {
245765
246437
  const targetPath = preservedWorktreeTargetPathForTask(task.id, livePath, settings, deps.rootDir);
245766
246438
  const normalizedPath = await deps.normalizeReclaimableWorktreePath(livePath, targetPath, task.id, settings);
@@ -245909,7 +246581,7 @@ var init_worktree_branch_conflict_handle = __esm({
245909
246581
  init_worktree_git_refs();
245910
246582
  init_worktree_registry_helpers();
245911
246583
  init_branch_conflict_format();
245912
- execAsync44 = promisify65(exec48);
246584
+ execAsync44 = promisify66(exec48);
245913
246585
  }
245914
246586
  });
245915
246587
 
@@ -246064,10 +246736,10 @@ var init_session_worktree_paths = __esm({
246064
246736
  });
246065
246737
 
246066
246738
  // ../engine/src/execution/external-execution-checkout.ts
246067
- import { execFile as execFile29 } from "node:child_process";
246739
+ import { execFile as execFile30 } from "node:child_process";
246068
246740
  import { existsSync as existsSync72, realpathSync as realpathSync13, statSync as statSync14 } from "node:fs";
246069
246741
  import { isAbsolute as isAbsolute23 } from "node:path";
246070
- import { promisify as promisify66 } from "node:util";
246742
+ import { promisify as promisify67 } from "node:util";
246071
246743
  function readSourceMetadata(task) {
246072
246744
  if (!task || typeof task !== "object") return void 0;
246073
246745
  const sourceMetadata = task.sourceMetadata;
@@ -246086,7 +246758,7 @@ async function inspectExternalGitCheckout(candidate, options = {}) {
246086
246758
  return { valid: false, reason: `checkoutPath is not a directory: ${checkoutPath}` };
246087
246759
  }
246088
246760
  const canonicalCheckout = realpathSync13(checkoutPath);
246089
- const { stdout: topLevelOutput } = await execFileAsync23("git", ["rev-parse", "--show-toplevel"], {
246761
+ const { stdout: topLevelOutput } = await execFileAsync24("git", ["rev-parse", "--show-toplevel"], {
246090
246762
  cwd: canonicalCheckout,
246091
246763
  encoding: "utf-8",
246092
246764
  timeout: 1e4
@@ -246099,7 +246771,7 @@ async function inspectExternalGitCheckout(candidate, options = {}) {
246099
246771
  reason: `checkoutPath must be the Git top-level (observed ${canonicalTopLevel})`
246100
246772
  };
246101
246773
  }
246102
- const { stdout: branchOutput } = await execFileAsync23("git", ["symbolic-ref", "--quiet", "--short", "HEAD"], {
246774
+ const { stdout: branchOutput } = await execFileAsync24("git", ["symbolic-ref", "--quiet", "--short", "HEAD"], {
246103
246775
  cwd: canonicalCheckout,
246104
246776
  encoding: "utf-8",
246105
246777
  timeout: 1e4
@@ -246109,7 +246781,7 @@ async function inspectExternalGitCheckout(candidate, options = {}) {
246109
246781
  return { valid: false, reason: "checkoutPath must have a checked-out branch" };
246110
246782
  }
246111
246783
  if (options.requireClean) {
246112
- const { stdout: statusOutput } = await execFileAsync23("git", ["status", "--porcelain=v1"], {
246784
+ const { stdout: statusOutput } = await execFileAsync24("git", ["status", "--porcelain=v1"], {
246113
246785
  cwd: canonicalCheckout,
246114
246786
  encoding: "utf-8",
246115
246787
  timeout: 1e4
@@ -246157,11 +246829,11 @@ async function resolveExternalExecutionCheckoutRoute(task) {
246157
246829
  }
246158
246830
  return { configured: true, ...inspection };
246159
246831
  }
246160
- var execFileAsync23;
246832
+ var execFileAsync24;
246161
246833
  var init_external_execution_checkout = __esm({
246162
246834
  "../engine/src/execution/external-execution-checkout.ts"() {
246163
246835
  "use strict";
246164
- execFileAsync23 = promisify66(execFile29);
246836
+ execFileAsync24 = promisify67(execFile30);
246165
246837
  }
246166
246838
  });
246167
246839
 
@@ -246185,7 +246857,7 @@ var init_resolve_authoritative_external_execution_route = __esm({
246185
246857
  import { exec as exec49 } from "node:child_process";
246186
246858
  import { existsSync as existsSync73, promises as fs7 } from "node:fs";
246187
246859
  import path4 from "node:path";
246188
- import { promisify as promisify67 } from "node:util";
246860
+ import { promisify as promisify68 } from "node:util";
246189
246861
  function workspaceExecutionAnchor(task) {
246190
246862
  const executionValues = [task.firstExecutionAt, task.executionStartedAt].map((value) => typeof value === "string" ? Date.parse(value) : Number.NaN).filter(Number.isFinite);
246191
246863
  const values2 = executionValues.length ? executionValues : [typeof task.createdAt === "string" ? Date.parse(task.createdAt) : Number.NaN].filter(Number.isFinite);
@@ -246309,14 +246981,14 @@ var init_workspace_main_checkout_guard = __esm({
246309
246981
  init_workspace_paths();
246310
246982
  init_worktree_paths();
246311
246983
  init_workflow_feedback_paths();
246312
- execAsync45 = promisify67(exec49);
246984
+ execAsync45 = promisify68(exec49);
246313
246985
  probeOptions = { encoding: "utf-8", timeout: 1e4, maxBuffer: 1024 * 1024 };
246314
246986
  }
246315
246987
  });
246316
246988
 
246317
246989
  // ../engine/src/executor/worktree-verify-invariants.ts
246318
246990
  import { exec as exec50 } from "node:child_process";
246319
- import { promisify as promisify68 } from "node:util";
246991
+ import { promisify as promisify69 } from "node:util";
246320
246992
  import { existsSync as existsSync74 } from "node:fs";
246321
246993
  async function verifyWorktreeInvariants(deps, task, worktreePathOverride, allowReanchor = true, options) {
246322
246994
  const workspaceConfig = deps.ensureWorkspaceConfig ? await deps.ensureWorkspaceConfig() : deps.workspaceConfig;
@@ -246737,17 +247409,17 @@ var init_worktree_verify_invariants = __esm({
246737
247409
  init_no_commit_eligibility();
246738
247410
  init_resolve_authoritative_external_execution_route();
246739
247411
  init_workspace_main_checkout_guard();
246740
- execAsync46 = promisify68(exec50);
247412
+ execAsync46 = promisify69(exec50);
246741
247413
  }
246742
247414
  });
246743
247415
 
246744
247416
  // ../engine/src/executor/worktree-task-done-scope-leak.ts
246745
- import { execFile as execFile30 } from "node:child_process";
247417
+ import { execFile as execFile31 } from "node:child_process";
246746
247418
  import { access as access10 } from "node:fs/promises";
246747
- import { promisify as promisify69 } from "node:util";
247419
+ import { promisify as promisify70 } from "node:util";
246748
247420
  async function verifyRepositoryCaptureEvidence(worktreePath) {
246749
247421
  await access10(worktreePath);
246750
- const { stdout } = await execFileAsync24("git", ["rev-parse", "--is-inside-work-tree"], {
247422
+ const { stdout } = await execFileAsync25("git", ["rev-parse", "--is-inside-work-tree"], {
246751
247423
  cwd: worktreePath,
246752
247424
  encoding: "utf8"
246753
247425
  });
@@ -246764,7 +247436,7 @@ async function captureRepositoryChangeEvidence(worktreePath, baseCommitSha) {
246764
247436
  } else {
246765
247437
  commands.push(["rev-parse", "--verify", "HEAD"]);
246766
247438
  }
246767
- const results = await Promise.all(commands.map((args) => execFileAsync24("git", args, {
247439
+ const results = await Promise.all(commands.map((args) => execFileAsync25("git", args, {
246768
247440
  cwd: worktreePath,
246769
247441
  encoding: "utf8"
246770
247442
  })));
@@ -246893,7 +247565,7 @@ async function evaluateTaskDoneScopeLeak(deps, task, worktreePath, promptContent
246893
247565
  }
246894
247566
  return { blocked: false };
246895
247567
  }
246896
- var execFileAsync24;
247568
+ var execFileAsync25;
246897
247569
  var init_worktree_task_done_scope_leak = __esm({
246898
247570
  "../engine/src/executor/worktree-task-done-scope-leak.ts"() {
246899
247571
  "use strict";
@@ -246901,7 +247573,7 @@ var init_worktree_task_done_scope_leak = __esm({
246901
247573
  init_logger3();
246902
247574
  init_prompt_derived_eligibility();
246903
247575
  init_workflow_feedback_paths();
246904
- execFileAsync24 = promisify69(execFile30);
247576
+ execFileAsync25 = promisify70(execFile31);
246905
247577
  }
246906
247578
  });
246907
247579
 
@@ -247311,7 +247983,7 @@ var init_task_done_refusal_handler = __esm({
247311
247983
 
247312
247984
  // ../engine/src/executor/dep-abort-cleanup.ts
247313
247985
  import { exec as exec51 } from "node:child_process";
247314
- import { promisify as promisify70 } from "node:util";
247986
+ import { promisify as promisify71 } from "node:util";
247315
247987
  async function handleDepAbortCleanup(deps, taskId, worktreePath) {
247316
247988
  executorLog.log(`${taskId} dependency added \u2014 work discarded, moved to triage for re-planning`);
247317
247989
  const task = await deps.store.getTask(taskId);
@@ -247362,7 +248034,7 @@ var init_dep_abort_cleanup = __esm({
247362
248034
  init_logger3();
247363
248035
  init_external_execution_checkout();
247364
248036
  init_lifecycle_columns();
247365
- execAsync47 = promisify70(exec51);
248037
+ execAsync47 = promisify71(exec51);
247366
248038
  }
247367
248039
  });
247368
248040
 
@@ -247886,7 +248558,7 @@ var init_no_merge_complete_column = __esm({
247886
248558
  // ../engine/src/execution/step-runner.ts
247887
248559
  import { exec as exec52 } from "node:child_process";
247888
248560
  import { existsSync as existsSync75, statSync as statSync15 } from "node:fs";
247889
- import { promisify as promisify71 } from "node:util";
248561
+ import { promisify as promisify72 } from "node:util";
247890
248562
  async function runTaskStep(deps, task, stepIndex, opts = {}) {
247891
248563
  const { store, worktreePath } = deps;
247892
248564
  const gitRevParse = deps.gitRevParse ?? defaultGitRevParse;
@@ -248070,7 +248742,7 @@ var init_step_runner = __esm({
248070
248742
  "../engine/src/execution/step-runner.ts"() {
248071
248743
  "use strict";
248072
248744
  init_logger3();
248073
- execAsync48 = promisify71(exec52);
248745
+ execAsync48 = promisify72(exec52);
248074
248746
  }
248075
248747
  });
248076
248748
 
@@ -250029,7 +250701,7 @@ var init_recover_failed_pre_merge_step = __esm({
250029
250701
 
250030
250702
  // ../engine/src/executor/reconcile-steps-from-git-history.ts
250031
250703
  import { exec as exec53 } from "node:child_process";
250032
- import { promisify as promisify72 } from "node:util";
250704
+ import { promisify as promisify73 } from "node:util";
250033
250705
  async function reconcileStepsFromGitHistory(deps, taskId, detail, worktreePath) {
250034
250706
  const baseCommitSha = detail.baseCommitSha;
250035
250707
  if (!baseCommitSha) return;
@@ -250117,7 +250789,7 @@ var init_reconcile_steps_from_git_history = __esm({
250117
250789
  "use strict";
250118
250790
  init_src2();
250119
250791
  init_logger3();
250120
- execAsync49 = promisify72(exec53);
250792
+ execAsync49 = promisify73(exec53);
250121
250793
  }
250122
250794
  });
250123
250795
 
@@ -252401,7 +253073,14 @@ async function persistWorkflowStepResultWithOutcome(deps, taskId, result2, fence
252401
253073
  scopeSuperseded = true;
252402
253074
  return null;
252403
253075
  }
252404
- const built = buildWorkflowStepResultPatch(current, result2, isPlanReviewResult);
253076
+ const unprovenApproval = resolveUnprovenReviewApproval(result2, {
253077
+ workspace: current.workspaceWorktrees !== void 0
253078
+ });
253079
+ const built = buildWorkflowStepResultPatch(
253080
+ current,
253081
+ unprovenApproval?.downgraded ?? result2,
253082
+ isPlanReviewResult
253083
+ );
252405
253084
  activityResult = built.resultToPersist;
252406
253085
  activityResults = built.results;
252407
253086
  return built.patch;
@@ -252438,21 +253117,30 @@ async function persistWorkflowStepResultWithOutcome(deps, taskId, result2, fence
252438
253117
  if (scopeSuperseded) return { scopeCurrent: false, persisted: false };
252439
253118
  if (fenceRefused) return { scopeCurrent: true, persisted: false };
252440
253119
  const persistedResult = activityResults?.find((entry) => entry.workflowStepId === result2.workflowStepId) ?? activityResult;
252441
- if (isTerminalStepResult(result2)) {
252442
- const passed = result2.status === "passed" || result2.status === "skipped" || result2.verdict === "APPROVE" || result2.verdict === "APPROVE_WITH_NOTES" || result2.verdict === "CLOSE_NO_OP";
253120
+ const approvalDowngraded = result2.status === "passed" && persistedResult.status === "failed" && result2.reviewInputFingerprint === void 0 && persistedResult.verdict === void 0;
253121
+ if (approvalDowngraded) {
253122
+ await deps.store.logEntry(
253123
+ taskId,
253124
+ `[pre-merge] ${result2.workflowStepName} approval invalidated: ${persistedResult.notes ?? persistedResult.output ?? "review input proof missing"}`,
253125
+ void 0,
253126
+ deps.getRunContextFor(taskId)
253127
+ ).catch(() => void 0);
253128
+ }
253129
+ if (isTerminalStepResult(persistedResult)) {
253130
+ const passed = persistedResult.status === "passed" || persistedResult.status === "skipped" || persistedResult.verdict === "APPROVE" || persistedResult.verdict === "APPROVE_WITH_NOTES" || persistedResult.verdict === "CLOSE_NO_OP";
252443
253131
  try {
252444
253132
  await deps.store.recordAgentActivity({
252445
253133
  type: passed ? "workflow:gate-passed" : "workflow:gate-failed",
252446
253134
  attributionClaim: resolveWorkflowGateActivityClaim(
252447
- deps.workflowGateActivityPrincipals?.get(`${taskId}\0${result2.workflowStepId}`) ?? deps.activeWorkflowPrincipals?.get(taskId)?.agentId,
253135
+ deps.workflowGateActivityPrincipals?.get(`${taskId}\0${persistedResult.workflowStepId}`) ?? deps.activeWorkflowPrincipals?.get(taskId)?.agentId,
252448
253136
  live?.assignedAgentId
252449
253137
  ),
252450
253138
  taskId,
252451
- occurredAt: result2.completedAt ?? result2.startedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
252452
- discriminator: `${result2.workflowStepId}:${result2.startedAt ?? result2.completedAt ?? result2.status}`,
252453
- metadata: buildWorkflowGateActivityMetadata(result2, persistedResult)
253139
+ occurredAt: persistedResult.completedAt ?? persistedResult.startedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
253140
+ discriminator: `${persistedResult.workflowStepId}:${persistedResult.startedAt ?? persistedResult.completedAt ?? persistedResult.status}`,
253141
+ metadata: buildWorkflowGateActivityMetadata(persistedResult, persistedResult)
252454
253142
  });
252455
- deps.workflowGateActivityPrincipals?.delete(`${taskId}\0${result2.workflowStepId}`);
253143
+ deps.workflowGateActivityPrincipals?.delete(`${taskId}\0${persistedResult.workflowStepId}`);
252456
253144
  } catch (error3) {
252457
253145
  executorLog.warn(`[agent-activity] ${taskId}: failed to record workflow gate activity: ${error3 instanceof Error ? error3.message : String(error3)}`);
252458
253146
  }
@@ -254463,7 +255151,7 @@ var init_run_spawned_child = __esm({
254463
255151
 
254464
255152
  // ../engine/src/auto-recovery-handlers/file-scope.ts
254465
255153
  import { exec as exec54 } from "node:child_process";
254466
- import { promisify as promisify73 } from "node:util";
255154
+ import { promisify as promisify74 } from "node:util";
254467
255155
  function createFileScopeAutoRecoveryHandler(deps) {
254468
255156
  return new FileScopeAutoRecoveryHandler({
254469
255157
  ...deps,
@@ -254474,7 +255162,7 @@ var execAsync50, FileScopeAutoRecoveryHandler;
254474
255162
  var init_file_scope2 = __esm({
254475
255163
  "../engine/src/auto-recovery-handlers/file-scope.ts"() {
254476
255164
  "use strict";
254477
- execAsync50 = promisify73(exec54);
255165
+ execAsync50 = promisify74(exec54);
254478
255166
  FileScopeAutoRecoveryHandler = class {
254479
255167
  constructor(deps) {
254480
255168
  this.deps = deps;
@@ -254490,7 +255178,7 @@ var init_file_scope2 = __esm({
254490
255178
  // ../engine/src/auto-recovery-handlers/branch-worktree.ts
254491
255179
  import { exec as exec55 } from "node:child_process";
254492
255180
  import { existsSync as existsSync78 } from "node:fs";
254493
- import { promisify as promisify74 } from "node:util";
255181
+ import { promisify as promisify75 } from "node:util";
254494
255182
  var execAsync51, baseLog2, GIT_TIMEOUT_MS8, GIT_MAX_BUFFER6, BranchWorktreeAutoRecoveryHandler;
254495
255183
  var init_branch_worktree = __esm({
254496
255184
  "../engine/src/auto-recovery-handlers/branch-worktree.ts"() {
@@ -254500,7 +255188,7 @@ var init_branch_worktree = __esm({
254500
255188
  init_active_session_registry();
254501
255189
  init_integration_branch();
254502
255190
  init_logger3();
254503
- execAsync51 = promisify74(exec55);
255191
+ execAsync51 = promisify75(exec55);
254504
255192
  baseLog2 = createLogger2("auto-recovery:branch-worktree");
254505
255193
  GIT_TIMEOUT_MS8 = 3e4;
254506
255194
  GIT_MAX_BUFFER6 = 10 * 1024 * 1024;
@@ -255567,7 +256255,7 @@ var init_run_raw_cli_command = __esm({
255567
256255
 
255568
256256
  // ../engine/src/executor/reset-steps-if-work-lost.ts
255569
256257
  import { exec as exec56 } from "node:child_process";
255570
- import { promisify as promisify75 } from "node:util";
256258
+ import { promisify as promisify76 } from "node:util";
255571
256259
  async function resetStepsIfWorkLost(deps, task) {
255572
256260
  const completedSteps = task.steps.filter(
255573
256261
  (s3) => s3.status === "done" || s3.status === "in-progress"
@@ -255608,7 +256296,7 @@ var init_reset_steps_if_work_lost = __esm({
255608
256296
  init_src2();
255609
256297
  init_worktree_names();
255610
256298
  init_logger3();
255611
- execAsync52 = promisify75(exec56);
256299
+ execAsync52 = promisify76(exec56);
255612
256300
  }
255613
256301
  });
255614
256302
 
@@ -255655,7 +256343,7 @@ var init_route_retryable_remediation = __esm({
255655
256343
 
255656
256344
  // ../engine/src/executor/build-foreach-worktree-deps.ts
255657
256345
  import { exec as exec57 } from "node:child_process";
255658
- import { promisify as promisify76 } from "node:util";
256346
+ import { promisify as promisify77 } from "node:util";
255659
256347
  function buildForeachWorktreeDeps(deps, task, runId) {
255660
256348
  const taskId = task.id;
255661
256349
  const instancePaths = /* @__PURE__ */ new Map();
@@ -255849,20 +256537,20 @@ var init_build_foreach_worktree_deps = __esm({
255849
256537
  init_worktree_names();
255850
256538
  init_worktree_paths();
255851
256539
  init_logger3();
255852
- execAsync53 = promisify76(exec57);
256540
+ execAsync53 = promisify77(exec57);
255853
256541
  WORKSPACE_ISOLATION_UNSUPPORTED_MESSAGE = "per-instance worktree isolation is not supported for workspace projects";
255854
256542
  }
255855
256543
  });
255856
256544
 
255857
256545
  // ../engine/src/executor/derive-remediation-steps.ts
255858
- import { createHash as createHash34 } from "node:crypto";
256546
+ import { createHash as createHash35 } from "node:crypto";
255859
256547
  function normalizeVerificationEvidence(output2) {
255860
256548
  if (!output2?.trim()) return "";
255861
256549
  return output2.replace(ansiEscapeSequence, "").replace(/\r\n?/g, "\n").split("\n").map((line2) => line2.trim().replace(isoTimestamp, "<timestamp>").replace(bareTimestamp, "<timestamp>").replace(elapsedDuration, "<duration>").replace(/\s+/g, " ")).filter(Boolean).join("\n");
255862
256550
  }
255863
256551
  function verificationEvidenceDigest(output2) {
255864
256552
  const evidence = normalizeVerificationEvidence(output2);
255865
- return evidence ? createHash34("sha256").update(evidence).digest("hex").slice(0, 16) : void 0;
256553
+ return evidence ? createHash35("sha256").update(evidence).digest("hex").slice(0, 16) : void 0;
255866
256554
  }
255867
256555
  function verificationCandidates(input) {
255868
256556
  const detail = input.verificationCommandLabel ?? "verification command";
@@ -260565,10 +261253,10 @@ var init_pending_review_block = __esm({
260565
261253
  });
260566
261254
 
260567
261255
  // ../engine/src/merge/merger-orphan-rehome.ts
260568
- import { execFile as execFile31 } from "node:child_process";
260569
- import { promisify as promisify77 } from "node:util";
261256
+ import { execFile as execFile32 } from "node:child_process";
261257
+ import { promisify as promisify78 } from "node:util";
260570
261258
  async function runGit6(args, cwd) {
260571
- const { stdout } = await execFileAsync25("git", args, {
261259
+ const { stdout } = await execFileAsync26("git", args, {
260572
261260
  cwd,
260573
261261
  encoding: "utf-8",
260574
261262
  timeout: 3e4
@@ -260577,7 +261265,7 @@ async function runGit6(args, cwd) {
260577
261265
  }
260578
261266
  async function isAncestor3(repoDir, ancestor, descendant) {
260579
261267
  try {
260580
- await execFileAsync25(
261268
+ await execFileAsync26(
260581
261269
  "git",
260582
261270
  ["merge-base", "--is-ancestor", ancestor, descendant],
260583
261271
  { cwd: repoDir, encoding: "utf-8", timeout: 3e4 }
@@ -260672,13 +261360,13 @@ async function rehomeOrphanOntoIntegration(input) {
260672
261360
  newTipSha: advanceResult.newSha
260673
261361
  };
260674
261362
  }
260675
- var execFileAsync25;
261363
+ var execFileAsync26;
260676
261364
  var init_merger_orphan_rehome = __esm({
260677
261365
  "../engine/src/merge/merger-orphan-rehome.ts"() {
260678
261366
  "use strict";
260679
261367
  init_src2();
260680
261368
  init_merger_ref_update_advance();
260681
- execFileAsync25 = promisify77(execFile31);
261369
+ execFileAsync26 = promisify78(execFile32);
260682
261370
  }
260683
261371
  });
260684
261372
 
@@ -260705,7 +261393,7 @@ var init_merge_execution_exclusion = __esm({
260705
261393
 
260706
261394
  // ../engine/src/executor/run-implementation.ts
260707
261395
  import { exec as exec58 } from "node:child_process";
260708
- import { promisify as promisify78 } from "node:util";
261396
+ import { promisify as promisify79 } from "node:util";
260709
261397
  import { existsSync as existsSync81 } from "node:fs";
260710
261398
  import { join as join93 } from "node:path";
260711
261399
  import { SessionManager as SessionManager2 } from "@earendil-works/pi-coding-agent";
@@ -263541,7 +264229,7 @@ var init_run_implementation = __esm({
263541
264229
  init_worktree_acquisition();
263542
264230
  init_worktree_paths();
263543
264231
  init_worktree_pool();
263544
- execAsync54 = promisify78(exec58);
264232
+ execAsync54 = promisify79(exec58);
263545
264233
  MAX_TASK_DONE_SESSION_RETRIES = 3;
263546
264234
  }
263547
264235
  });
@@ -267267,8 +267955,8 @@ var init_worktree_create_binders = __esm({
267267
267955
  });
267268
267956
 
267269
267957
  // ../engine/src/executor/wire-executor-lifecycle.ts
267270
- import { execFile as execFile32 } from "node:child_process";
267271
- import { promisify as promisify79 } from "node:util";
267958
+ import { execFile as execFile33 } from "node:child_process";
267959
+ import { promisify as promisify80 } from "node:util";
267272
267960
  async function releaseWorkspaceAcquireClaims(store, taskId) {
267273
267961
  for (const entry of activeSessionRegistry.entriesByKind("workspace-repo-acquire")) {
267274
267962
  if (entry.taskId === taskId) activeSessionRegistry.unregisterPath(entry.path);
@@ -267316,7 +268004,7 @@ function wireExecutorLifecycle(deps) {
267316
268004
  if (await canonicalizeWorktreePath(entry.worktreePath) === await canonicalizeWorktreePath(entry.repoRootDir)) throw new Error("Refusing to remove workspace repository root");
267317
268005
  activeSessionRegistry.unregisterPath(entry.worktreePath);
267318
268006
  await removeWorktree({ worktreePath: entry.worktreePath, rootDir: entry.repoRootDir, settings: await deps.store.getSettings(), taskId: task.id, reason: RemovalReason.ExecutorDispose, force: true });
267319
- await execFileAsync26("git", ["branch", "-D", entry.branch], { cwd: entry.repoRootDir, timeout: 12e4, maxBuffer: 10 * 1024 * 1024 });
268007
+ await execFileAsync27("git", ["branch", "-D", entry.branch], { cwd: entry.repoRootDir, timeout: 12e4, maxBuffer: 10 * 1024 * 1024 });
267320
268008
  if (task.workspaceWorktrees) for (const repoRel of [entry.repoRel, ...entry.aliasRepoRels]) delete task.workspaceWorktrees[repoRel];
267321
268009
  removed.push(entry.repoRel);
267322
268010
  } catch (error3) {
@@ -267744,7 +268432,7 @@ function wireTaskExecutorLifecycle(host) {
267744
268432
  h.workflowAgentCapacity = new WorkflowAgentCapacity(h.options?.agentStore ?? void 0);
267745
268433
  applyWireExecutorLifecycleDisposers(host, wireExecutorLifecycle(buildWireExecutorLifecycleDeps(host)));
267746
268434
  }
267747
- var execFileAsync26, WIRE_LIFECYCLE_FIELDS, WIRE_LIFECYCLE_METHODS;
268435
+ var execFileAsync27, WIRE_LIFECYCLE_FIELDS, WIRE_LIFECYCLE_METHODS;
267748
268436
  var init_wire_executor_lifecycle = __esm({
267749
268437
  "../engine/src/executor/wire-executor-lifecycle.ts"() {
267750
268438
  "use strict";
@@ -267761,7 +268449,7 @@ var init_wire_executor_lifecycle = __esm({
267761
268449
  init_task_predicates();
267762
268450
  init_facade_methods();
267763
268451
  init_workflow_agent_capacity();
267764
- execFileAsync26 = promisify79(execFile32);
268452
+ execFileAsync27 = promisify80(execFile33);
267765
268453
  WIRE_LIFECYCLE_FIELDS = [
267766
268454
  "activeConfiguredCommandControllers",
267767
268455
  "activeSessions",
@@ -270658,7 +271346,7 @@ import { promises as fs9 } from "node:fs";
270658
271346
  import os7 from "node:os";
270659
271347
  import path5 from "node:path";
270660
271348
  import { exec as exec59 } from "node:child_process";
270661
- import { promisify as promisify80 } from "node:util";
271349
+ import { promisify as promisify81 } from "node:util";
270662
271350
  var execAsync55, verifyLog, GitCheckoutMaterializer;
270663
271351
  var init_mission_verification = __esm({
270664
271352
  "../engine/src/missions/mission-verification.ts"() {
@@ -270668,7 +271356,7 @@ var init_mission_verification = __esm({
270668
271356
  init_sandbox_exec_detect();
270669
271357
  init_verification_utils();
270670
271358
  init_logger3();
270671
- execAsync55 = promisify80(exec59);
271359
+ execAsync55 = promisify81(exec59);
270672
271360
  verifyLog = createLogger2("mission-verify");
270673
271361
  GitCheckoutMaterializer = class {
270674
271362
  async materialize(rootDir, revision) {
@@ -270711,14 +271399,14 @@ ${stdout.trim()}`);
270711
271399
 
270712
271400
  // ../engine/src/missions/mission-execution-loop.ts
270713
271401
  import { EventEmitter as EventEmitter25 } from "node:events";
270714
- import { createHash as createHash35 } from "node:crypto";
271402
+ import { createHash as createHash36 } from "node:crypto";
270715
271403
  import { exec as exec60 } from "node:child_process";
270716
- import { promisify as promisify81 } from "node:util";
271404
+ import { promisify as promisify82 } from "node:util";
270717
271405
  function quoteShellArg8(value) {
270718
271406
  return `'${value.replace(/'/g, `'\\''`)}'`;
270719
271407
  }
270720
271408
  function fingerprintMissionValidationInput(landedSha, provider, modelId, systemPrompt, userPrompt) {
270721
- return createHash35("sha256").update(Buffer.from(JSON.stringify(["mission-validation-input-v1", landedSha, provider, modelId, systemPrompt, userPrompt]), "utf8")).digest("hex");
271409
+ return createHash36("sha256").update(Buffer.from(JSON.stringify(["mission-validation-input-v1", landedSha, provider, modelId, systemPrompt, userPrompt]), "utf8")).digest("hex");
270722
271410
  }
270723
271411
  var execAsync56, loopLog, VALIDATION_TIMEOUT_MS, MAX_VALIDATION_RESPONSE_BYTES, MAX_VALIDATION_JSON_CANDIDATES, VALIDATION_FAILURE_BUDGET_PER_FINGERPRINT, MissionExecutionLoop;
270724
271412
  var init_mission_execution_loop = __esm({
@@ -270734,7 +271422,7 @@ var init_mission_execution_loop = __esm({
270734
271422
  init_fallback_model_observer();
270735
271423
  init_mcp_resolution();
270736
271424
  init_run_audit();
270737
- execAsync56 = promisify81(exec60);
271425
+ execAsync56 = promisify82(exec60);
270738
271426
  loopLog = createLogger2("mission-loop");
270739
271427
  VALIDATION_TIMEOUT_MS = 10 * 60 * 1e3;
270740
271428
  MAX_VALIDATION_RESPONSE_BYTES = 256 * 1024;
@@ -272248,44 +272936,9 @@ ${taskContext}` : ""}`;
272248
272936
  }
272249
272937
  });
272250
272938
 
272251
- // ../engine/src/merge/merge-content-capture.ts
272252
- async function captureMergeContentDescriptor(task, deps) {
272253
- if (describeMergeContentShape(task) === "workspace") {
272254
- try {
272255
- const evidence = await captureWorkspaceReviewEvidence({
272256
- task,
272257
- workspaceRootDir: deps.workspaceRootDir,
272258
- settings: deps.settings
272259
- });
272260
- return {
272261
- kind: "workspace",
272262
- repositories: {
272263
- state: "captured",
272264
- fingerprints: Object.fromEntries(evidence.repositories.filter((repository) => repository.fingerprint).map((repository) => [repository.repository, repository.fingerprint])),
272265
- inScopeModified: [...evidence.modifiedRepositories].sort()
272266
- }
272267
- };
272268
- } catch {
272269
- return { kind: "workspace", repositories: { state: "unavailable", reason: "workspace-evidence-capture-failed" } };
272270
- }
272271
- }
272272
- const baseRef = task.worktree ? await resolveDiffBaseRef(task.worktree, task.baseCommitSha) : void 0;
272273
- const probe = await probeReviewDiffFingerprint(task.worktree, baseRef);
272274
- return { kind: "singular", diff: probe };
272275
- }
272276
- var init_merge_content_capture = __esm({
272277
- "../engine/src/merge/merge-content-capture.ts"() {
272278
- "use strict";
272279
- init_src2();
272280
- init_worktree_git_refs();
272281
- init_review_diff_fingerprint();
272282
- init_workspace_review_evidence();
272283
- }
272284
- });
272285
-
272286
272939
  // ../engine/src/merge/merger-ai-squash-gates.ts
272287
- import { execFile as execFile33 } from "node:child_process";
272288
- import { promisify as promisify82 } from "node:util";
272940
+ import { execFile as execFile34 } from "node:child_process";
272941
+ import { promisify as promisify83 } from "node:util";
272289
272942
  function resolveRepoDeclaredScopeTransform({ repoRel, repoKeys }) {
272290
272943
  return {
272291
272944
  transform(scope) {
@@ -272316,8 +272969,8 @@ async function enforceAiMergeSquashGates(params) {
272316
272969
  });
272317
272970
  } catch (error3) {
272318
272971
  if (!(error3 instanceof FileScopeViolationError)) throw error3;
272319
- await execFileAsync27("git", ["reset", "--hard", params.tipSha], { cwd: params.mergeRoot });
272320
- await execFileAsync27("git", ["clean", "-fd"], { cwd: params.mergeRoot });
272972
+ await execFileAsync28("git", ["reset", "--hard", params.tipSha], { cwd: params.mergeRoot });
272973
+ await execFileAsync28("git", ["clean", "-fd"], { cwd: params.mergeRoot });
272321
272974
  try {
272322
272975
  await params.store.updateTask(params.taskId, { aiMergeReviewReconciliation: null });
272323
272976
  } catch {
@@ -272325,13 +272978,13 @@ async function enforceAiMergeSquashGates(params) {
272325
272978
  throw error3;
272326
272979
  }
272327
272980
  }
272328
- var execFileAsync27;
272981
+ var execFileAsync28;
272329
272982
  var init_merger_ai_squash_gates = __esm({
272330
272983
  "../engine/src/merge/merger-ai-squash-gates.ts"() {
272331
272984
  "use strict";
272332
272985
  init_workspace_paths();
272333
272986
  init_merger_file_scope();
272334
- execFileAsync27 = promisify82(execFile33);
272987
+ execFileAsync28 = promisify83(execFile34);
272335
272988
  }
272336
272989
  });
272337
272990
 
@@ -272831,11 +273484,11 @@ var init_workspace_merge_readiness = __esm({
272831
273484
  });
272832
273485
 
272833
273486
  // ../engine/src/merge/workspace-fence-ref.ts
272834
- import { execFile as execFile34 } from "node:child_process";
272835
- import { createHash as createHash36 } from "node:crypto";
272836
- import { promisify as promisify83 } from "node:util";
273487
+ import { execFile as execFile35 } from "node:child_process";
273488
+ import { createHash as createHash37 } from "node:crypto";
273489
+ import { promisify as promisify84 } from "node:util";
272837
273490
  async function git6(args, cwd) {
272838
- const { stdout } = await execFileAsync28("git", args, {
273491
+ const { stdout } = await execFileAsync29("git", args, {
272839
273492
  cwd,
272840
273493
  encoding: "utf8",
272841
273494
  maxBuffer: 1024 * 1024
@@ -272848,7 +273501,7 @@ async function remoteRefSha(remote, ref, cwd) {
272848
273501
  return /^[0-9a-f]{40,64}$/i.test(sha ?? "") ? sha : void 0;
272849
273502
  }
272850
273503
  function workspaceLandFenceRef(repoRelPath) {
272851
- const slug2 = createHash36("sha256").update(repoRelPath).digest("hex").slice(0, 24);
273504
+ const slug2 = createHash37("sha256").update(repoRelPath).digest("hex").slice(0, 24);
272852
273505
  return `refs/fusion/workspace-lease/${slug2}`;
272853
273506
  }
272854
273507
  function mergeDispatchFenceRef(taskId) {
@@ -272857,7 +273510,7 @@ function mergeDispatchFenceRef(taskId) {
272857
273510
  async function createFenceObject(cwd, handle2) {
272858
273511
  const tree = await git6(["hash-object", "-w", "-t", "tree", "/dev/null"], cwd);
272859
273512
  const message = `workspace lease ${handle2.leaseKey} ${handle2.owner.taskId} ${handle2.owner.nodeId} ${handle2.owner.incarnationId} ${handle2.fenceToken}`;
272860
- const { stdout } = await execFileAsync28("git", [
273513
+ const { stdout } = await execFileAsync29("git", [
272861
273514
  "-c",
272862
273515
  "user.name=Fusion",
272863
273516
  "-c",
@@ -272987,11 +273640,11 @@ async function publishWorkspaceIntegrationRef(input) {
272987
273640
  await pushWithWorkspaceFence({ ...input, expectedTargetSha: observedTargetSha });
272988
273641
  return { republishedFromObservedTip: true, observedTargetSha };
272989
273642
  }
272990
- var execFileAsync28, WorkspaceFenceRefError;
273643
+ var execFileAsync29, WorkspaceFenceRefError;
272991
273644
  var init_workspace_fence_ref = __esm({
272992
273645
  "../engine/src/merge/workspace-fence-ref.ts"() {
272993
273646
  "use strict";
272994
- execFileAsync28 = promisify83(execFile34);
273647
+ execFileAsync29 = promisify84(execFile35);
272995
273648
  WorkspaceFenceRefError = class extends Error {
272996
273649
  constructor(message, kind) {
272997
273650
  super(message);
@@ -273003,10 +273656,10 @@ var init_workspace_fence_ref = __esm({
273003
273656
  });
273004
273657
 
273005
273658
  // ../engine/src/merge/workspace-integration-target.ts
273006
- import { execFile as execFile35 } from "node:child_process";
273007
- import { promisify as promisify84 } from "node:util";
273659
+ import { execFile as execFile36 } from "node:child_process";
273660
+ import { promisify as promisify85 } from "node:util";
273008
273661
  async function git7(args, cwd) {
273009
- const { stdout } = await execFileAsync29("git", args, { cwd, encoding: "utf8" });
273662
+ const { stdout } = await execFileAsync30("git", args, { cwd, encoding: "utf8" });
273010
273663
  return stdout.trim();
273011
273664
  }
273012
273665
  async function resolveWorkspaceIntegrationTarget(input) {
@@ -273046,11 +273699,11 @@ async function resolveWorkspaceIntegrationTarget(input) {
273046
273699
  `Workspace repository ${input.repository} has ambiguous integration remotes: ${remotes.join(", ")}`
273047
273700
  );
273048
273701
  }
273049
- var execFileAsync29, WorkspaceEnvironmentError, WorkspaceIntegrationTargetError;
273702
+ var execFileAsync30, WorkspaceEnvironmentError, WorkspaceIntegrationTargetError;
273050
273703
  var init_workspace_integration_target = __esm({
273051
273704
  "../engine/src/merge/workspace-integration-target.ts"() {
273052
273705
  "use strict";
273053
- execFileAsync29 = promisify84(execFile35);
273706
+ execFileAsync30 = promisify85(execFile36);
273054
273707
  WorkspaceEnvironmentError = class extends Error {
273055
273708
  constructor(repository, resource, action, message) {
273056
273709
  super(message);
@@ -273073,14 +273726,14 @@ var init_workspace_integration_target = __esm({
273073
273726
  });
273074
273727
 
273075
273728
  // ../engine/src/merge/merger-ai-worktree.ts
273076
- import { execFile as execFile36 } from "node:child_process";
273729
+ import { execFile as execFile37 } from "node:child_process";
273077
273730
  import { appendFileSync as appendFileSync2, existsSync as existsSync84, mkdirSync as mkdirSync10, readdirSync as readdirSync12, readFileSync as readFileSync26, realpathSync as realpathSync14, rmSync as rmSync7, statSync as statSync16 } from "node:fs";
273078
273731
  import { rm as rm17 } from "node:fs/promises";
273079
273732
  import { tmpdir as tmpdir11 } from "node:os";
273080
273733
  import { isAbsolute as isAbsolute25, join as join95, relative as relative22 } from "node:path";
273081
- import { promisify as promisify85 } from "node:util";
273734
+ import { promisify as promisify86 } from "node:util";
273082
273735
  async function git8(args, cwd, opts = {}) {
273083
- const { stdout } = await execFileAsync30("git", args, {
273736
+ const { stdout } = await execFileAsync31("git", args, {
273084
273737
  cwd,
273085
273738
  encoding: "utf-8",
273086
273739
  timeout: opts.timeout ?? 12e4,
@@ -273109,14 +273762,7 @@ function ensureAiMergeRootIgnored(projectRootDir, settings) {
273109
273762
  if (!existsSync84(excludePath)) return;
273110
273763
  try {
273111
273764
  const current = readFileSync26(excludePath, "utf-8");
273112
- const legacyAiMergeRoot = resolveLegacyAiMergeRootPath(projectRootDir);
273113
- const legacyRelativeAiMergeRoot = relative22(projectRootDir, legacyAiMergeRoot);
273114
- const entries = [`${legacyRelativeAiMergeRoot.replaceAll("\\", "/")}/`];
273115
- const aiMergeRoot = resolveAiMergeRootPath(projectRootDir, settings);
273116
- const relativeAiMergeRoot = relative22(projectRootDir, aiMergeRoot);
273117
- if (relativeAiMergeRoot && !relativeAiMergeRoot.startsWith("..") && !isAbsolute25(relativeAiMergeRoot)) {
273118
- entries.push(`${relativeAiMergeRoot.replaceAll("\\", "/")}/`);
273119
- }
273765
+ const entries = resolveAiMergeSearchRoots(projectRootDir, settings).map((root) => relative22(projectRootDir, root)).filter((root) => root && !root.startsWith("..") && !isAbsolute25(root)).map((root) => `${root.replaceAll("\\", "/")}/`);
273120
273766
  const missing = entries.filter((entry) => !current.split(/\r?\n/).includes(entry));
273121
273767
  if (missing.length > 0) {
273122
273768
  appendFileSync2(excludePath, `${current.endsWith("\n") ? "" : "\n"}${missing.join("\n")}
@@ -273132,7 +273778,7 @@ function resolveAiMergeRoot(projectRootDir, settings) {
273132
273778
  return root;
273133
273779
  }
273134
273780
  function getAiMergeTempSearchRoots(projectRootDir, settings) {
273135
- const roots = [resolveAiMergeRoot(projectRootDir, settings), resolveLegacyAiMergeRootPath(projectRootDir), tmpdir11()];
273781
+ const roots = [resolveAiMergeRoot(projectRootDir, settings), ...resolveAiMergeSearchRoots(projectRootDir, settings), tmpdir11()];
273136
273782
  const testWorkerRoot = process.env.FUSION_TEST_WORKER_ROOT;
273137
273783
  if (testWorkerRoot) {
273138
273784
  try {
@@ -273185,7 +273831,7 @@ async function pruneExistingAiMergeWorktrees(taskId, projectRootDir, audit, log4
273185
273831
  let alreadyAbsent = false;
273186
273832
  try {
273187
273833
  cleanupAttempted = true;
273188
- await execFileAsync30("git", ["worktree", "remove", "--force", canonicalPath], {
273834
+ await execFileAsync31("git", ["worktree", "remove", "--force", canonicalPath], {
273189
273835
  cwd: projectRootDir,
273190
273836
  timeout: 3e4
273191
273837
  });
@@ -273216,7 +273862,7 @@ async function pruneExistingAiMergeWorktrees(taskId, projectRootDir, audit, log4
273216
273862
  }
273217
273863
  if (cleanupAttempted) {
273218
273864
  try {
273219
- await execFileAsync30("git", ["worktree", "prune"], { cwd: projectRootDir, timeout: 3e4 });
273865
+ await execFileAsync31("git", ["worktree", "prune"], { cwd: projectRootDir, timeout: 3e4 });
273220
273866
  } catch (err) {
273221
273867
  await log42(`AI merge pre-merge prune: git worktree prune failed: ${describeCleanupError(err)}`);
273222
273868
  }
@@ -273282,7 +273928,7 @@ async function cleanupAiMergeWorktree(input) {
273282
273928
  await audit.git({ type: "merge:ai-worktree-cleanup", target: canonicalRoot, metadata: { ...cleanupMetadata, phase: "git-prune", success: false, error: error3, ...code ? { code } : {} } });
273283
273929
  }
273284
273930
  }
273285
- var execFileAsync30;
273931
+ var execFileAsync31;
273286
273932
  var init_merger_ai_worktree = __esm({
273287
273933
  "../engine/src/merge/merger-ai-worktree.ts"() {
273288
273934
  "use strict";
@@ -273290,7 +273936,7 @@ var init_merger_ai_worktree = __esm({
273290
273936
  init_self_healing();
273291
273937
  init_worktree_paths();
273292
273938
  init_worktree_removal_retry();
273293
- execFileAsync30 = promisify85(execFile36);
273939
+ execFileAsync31 = promisify86(execFile37);
273294
273940
  }
273295
273941
  });
273296
273942
 
@@ -273642,8 +274288,8 @@ var init_merger_ai_prompts = __esm({
273642
274288
  });
273643
274289
 
273644
274290
  // ../engine/src/merge/merger-ai.ts
273645
- import { execFile as execFile37 } from "node:child_process";
273646
- import { promisify as promisify86 } from "node:util";
274291
+ import { execFile as execFile38 } from "node:child_process";
274292
+ import { promisify as promisify87 } from "node:util";
273647
274293
  import { realpathSync as realpathSync15, readdirSync as readdirSync13 } from "node:fs";
273648
274294
  import { mkdtemp as mkdtemp5 } from "node:fs/promises";
273649
274295
  import { tmpdir as tmpdir12 } from "node:os";
@@ -273671,7 +274317,7 @@ function writeTransientMergeStatus(store, taskId, signal, status) {
273671
274317
  return fence.write("lifecycle", () => store.updateTask(taskId, { status }).catch(() => void 0));
273672
274318
  }
273673
274319
  async function git9(args, cwd, opts = {}) {
273674
- const { stdout } = await execFileAsync31("git", args, {
274320
+ const { stdout } = await execFileAsync32("git", args, {
273675
274321
  cwd,
273676
274322
  encoding: "utf-8",
273677
274323
  timeout: opts.timeout ?? 12e4,
@@ -273711,7 +274357,7 @@ function boundBlockingReviewReasons(reasons) {
273711
274357
  }
273712
274358
  function listAiMergeWorktreeCandidates(taskId, projectRootDir, settings) {
273713
274359
  const prefix = `fusion-ai-merge-${taskId.toLowerCase()}-`;
273714
- const roots = Array.from(/* @__PURE__ */ new Set([resolveAiMergeRoot(projectRootDir, settings), resolveLegacyAiMergeRootPath(projectRootDir), tmpdir12()]));
274360
+ const roots = Array.from(/* @__PURE__ */ new Set([resolveAiMergeRoot(projectRootDir, settings), ...resolveAiMergeSearchRoots(projectRootDir, settings), tmpdir12()]));
273715
274361
  const testWorkerRoot = process.env.FUSION_TEST_WORKER_ROOT;
273716
274362
  if (testWorkerRoot) {
273717
274363
  try {
@@ -276060,7 +276706,7 @@ async function finalizeTask(store, taskId, result2, audit, log42, rootDir, fence
276060
276706
  function throwIfAborted3(signal, taskId) {
276061
276707
  assertMergeGenerationOwned(signal, taskId);
276062
276708
  }
276063
- var execFileAsync31, aiMergeLog, MAX_CONCURRENT_ADVANCE_RETRIES, MAX_BLOCKING_REVIEW_REASONS, AiMergeBlockedError, AiMergeReviewReconciliationInvalidatedError, LEGACY_COMPLETE_COLUMN, LEGACY_ARCHIVED_COLUMN, LEGACY_TERMINAL_COLUMNS3, LEGACY_REBOUND_COLUMN2, STRONG_LANDED_STRATEGIES, RecordedMergeBranchTipChangedError, WORKSPACE_REPO_LAND_OWNER_KEY, WorkspaceRepoLandBusyError, WorkspaceMergeTechnicalError, WorkspacePartialLandError, WorkspaceFinalizeBlockedError, WorkspaceReviewRequiredError, WorkspaceMergeDispatchSupersededError;
276709
+ var execFileAsync32, aiMergeLog, MAX_CONCURRENT_ADVANCE_RETRIES, MAX_BLOCKING_REVIEW_REASONS, AiMergeBlockedError, AiMergeReviewReconciliationInvalidatedError, LEGACY_COMPLETE_COLUMN, LEGACY_ARCHIVED_COLUMN, LEGACY_TERMINAL_COLUMNS3, LEGACY_REBOUND_COLUMN2, STRONG_LANDED_STRATEGIES, RecordedMergeBranchTipChangedError, WORKSPACE_REPO_LAND_OWNER_KEY, WorkspaceRepoLandBusyError, WorkspaceMergeTechnicalError, WorkspacePartialLandError, WorkspaceFinalizeBlockedError, WorkspaceReviewRequiredError, WorkspaceMergeDispatchSupersededError;
276064
276710
  var init_merger_ai = __esm({
276065
276711
  "../engine/src/merge/merger-ai.ts"() {
276066
276712
  "use strict";
@@ -276110,7 +276756,7 @@ var init_merger_ai = __esm({
276110
276756
  init_merger_ai_prompts();
276111
276757
  init_merger_ai_worktree();
276112
276758
  init_merger_ai_prompts();
276113
- execFileAsync31 = promisify86(execFile37);
276759
+ execFileAsync32 = promisify87(execFile38);
276114
276760
  aiMergeLog = createLogger2("merger-ai");
276115
276761
  MAX_CONCURRENT_ADVANCE_RETRIES = 3;
276116
276762
  MAX_BLOCKING_REVIEW_REASONS = 8;
@@ -276262,7 +276908,7 @@ var init_workspace_merge_dispatch_lease = __esm({
276262
276908
  // ../engine/src/execution/task-revert.ts
276263
276909
  import { exec as exec61 } from "node:child_process";
276264
276910
  import { join as join97 } from "node:path";
276265
- import { promisify as promisify87 } from "node:util";
276911
+ import { promisify as promisify88 } from "node:util";
276266
276912
  function quoteShellArg9(value) {
276267
276913
  return `'${value.replace(/'/g, `'\\''`)}'`;
276268
276914
  }
@@ -277131,7 +277777,7 @@ var init_task_revert = __esm({
277131
277777
  init_branch_attribution();
277132
277778
  init_workspace_base_branch();
277133
277779
  init_run_audit();
277134
- defaultExecAsync2 = promisify87(exec61);
277780
+ defaultExecAsync2 = promisify88(exec61);
277135
277781
  GIT_TIMEOUT_MS9 = 3e4;
277136
277782
  GIT_MAX_BUFFER7 = 10 * 1024 * 1024;
277137
277783
  TaskRevertError = class extends Error {
@@ -277150,10 +277796,10 @@ var init_task_revert = __esm({
277150
277796
  });
277151
277797
 
277152
277798
  // ../engine/src/merge/smart-pull.ts
277153
- import { execFile as execFile38 } from "node:child_process";
277154
- import { promisify as promisify88 } from "node:util";
277799
+ import { execFile as execFile39 } from "node:child_process";
277800
+ import { promisify as promisify89 } from "node:util";
277155
277801
  async function runGit8(args, cwd, timeoutMs) {
277156
- const result2 = await execFileAsync32("git", args, {
277802
+ const result2 = await execFileAsync33("git", args, {
277157
277803
  cwd,
277158
277804
  timeout: timeoutMs,
277159
277805
  maxBuffer: 10 * 1024 * 1024,
@@ -277304,11 +277950,11 @@ async function smartPull(input) {
277304
277950
  return { kind: "stash-pop-conflict", fromSha, toSha, stashSha, stashLabel, conflictedFiles };
277305
277951
  }
277306
277952
  }
277307
- var execFileAsync32;
277953
+ var execFileAsync33;
277308
277954
  var init_smart_pull = __esm({
277309
277955
  "../engine/src/merge/smart-pull.ts"() {
277310
277956
  "use strict";
277311
- execFileAsync32 = promisify88(execFile38);
277957
+ execFileAsync33 = promisify89(execFile39);
277312
277958
  }
277313
277959
  });
277314
277960
 
@@ -278954,7 +279600,7 @@ var init_finalize_types = __esm({
278954
279600
 
278955
279601
  // ../engine/src/experiment/git-ops.ts
278956
279602
  import { exec as exec62 } from "node:child_process";
278957
- import { promisify as promisify89 } from "node:util";
279603
+ import { promisify as promisify90 } from "node:util";
278958
279604
  async function runGit9(cwd, args) {
278959
279605
  const command = `git ${args.join(" ")}`;
278960
279606
  try {
@@ -279061,7 +279707,7 @@ var init_git_ops = __esm({
279061
279707
  "use strict";
279062
279708
  init_git_identity();
279063
279709
  init_finalize_types();
279064
- execAsync57 = promisify89(exec62);
279710
+ execAsync57 = promisify90(exec62);
279065
279711
  GIT_TIMEOUT_MS10 = 3e4;
279066
279712
  GIT_MAX_BUFFER8 = 10 * 1024 * 1024;
279067
279713
  }
@@ -283685,9 +284331,9 @@ var init_routine_scheduler = __esm({
283685
284331
  });
283686
284332
 
283687
284333
  // ../engine/src/healing/stuck-task-detector.ts
283688
- import { createHash as createHash37 } from "node:crypto";
284334
+ import { createHash as createHash38 } from "node:crypto";
283689
284335
  function hashToolDetail(detail) {
283690
- return createHash37("sha256").update(detail).digest("hex").slice(0, TOOL_DETAIL_HASH_HEX_LEN);
284336
+ return createHash38("sha256").update(detail).digest("hex").slice(0, TOOL_DETAIL_HASH_HEX_LEN);
283691
284337
  }
283692
284338
  function buildToolFingerprint(toolName, toolDetail) {
283693
284339
  const name2 = toolName.trim().toLowerCase() || "tool";
@@ -286963,11 +287609,11 @@ var init_adapters = __esm({
286963
287609
 
286964
287610
  // ../engine/src/cli-agent/resume-coordinator.ts
286965
287611
  import { existsSync as existsSync87 } from "node:fs";
286966
- import { execFile as execFile39 } from "node:child_process";
286967
- import { promisify as promisify90 } from "node:util";
287612
+ import { execFile as execFile40 } from "node:child_process";
287613
+ import { promisify as promisify91 } from "node:util";
286968
287614
  async function defaultIsWorktreeDirty(worktreePath) {
286969
287615
  try {
286970
- const { stdout } = await execFileAsync33("git", ["status", "--porcelain"], {
287616
+ const { stdout } = await execFileAsync34("git", ["status", "--porcelain"], {
286971
287617
  cwd: worktreePath
286972
287618
  });
286973
287619
  return stdout.trim().length > 0;
@@ -286975,13 +287621,13 @@ async function defaultIsWorktreeDirty(worktreePath) {
286975
287621
  return false;
286976
287622
  }
286977
287623
  }
286978
- var execFileAsync33, ORPHANED_LIVE_STATES, DEFAULT_MAX_RESUME_ATTEMPTS, DEFAULT_RESUME_BACKOFF_BASE_MS, CliResumeCoordinator;
287624
+ var execFileAsync34, ORPHANED_LIVE_STATES, DEFAULT_MAX_RESUME_ATTEMPTS, DEFAULT_RESUME_BACKOFF_BASE_MS, CliResumeCoordinator;
286979
287625
  var init_resume_coordinator = __esm({
286980
287626
  "../engine/src/cli-agent/resume-coordinator.ts"() {
286981
287627
  "use strict";
286982
287628
  init_session_manager();
286983
287629
  init_state_machine();
286984
- execFileAsync33 = promisify90(execFile39);
287630
+ execFileAsync34 = promisify91(execFile40);
286985
287631
  ORPHANED_LIVE_STATES = /* @__PURE__ */ new Set([
286986
287632
  "starting",
286987
287633
  "ready",
@@ -287268,7 +287914,7 @@ var init_node_dispatch_validation = __esm({
287268
287914
  });
287269
287915
 
287270
287916
  // ../engine/src/runtimes/in-process-runtime.ts
287271
- import { createHash as createHash38 } from "node:crypto";
287917
+ import { createHash as createHash39 } from "node:crypto";
287272
287918
  import { EventEmitter as EventEmitter26 } from "node:events";
287273
287919
  import { setImmediate as setImmediateCb4 } from "node:timers";
287274
287920
  function createDiscoveryPluginLoaderOptions(scopedStore) {
@@ -287533,7 +288179,7 @@ function stableNotificationJson(value) {
287533
288179
  return `{${fields.join(",")}}`;
287534
288180
  }
287535
288181
  function buildCliAgentNotificationDedupeKey(input) {
287536
- const notificationFingerprint = createHash38("sha256").update(stableNotificationJson(input.info.notification ?? null)).digest("hex").slice(0, 16);
288182
+ const notificationFingerprint = createHash39("sha256").update(stableNotificationJson(input.info.notification ?? null)).digest("hex").slice(0, 16);
287537
288183
  const waitingEpoch = input.session?.updatedAt ?? "unknown-waiting-epoch";
287538
288184
  return [
287539
288185
  "cli-agent",
@@ -291614,8 +292260,8 @@ var init_provider_adapters = __esm({
291614
292260
 
291615
292261
  // ../engine/src/remote-access/tunnel-process-manager.ts
291616
292262
  import { EventEmitter as EventEmitter31 } from "node:events";
291617
- import { exec as exec64, execFile as execFile40, spawn as spawn9 } from "node:child_process";
291618
- import { promisify as promisify91 } from "node:util";
292263
+ import { exec as exec64, execFile as execFile41, spawn as spawn9 } from "node:child_process";
292264
+ import { promisify as promisify92 } from "node:util";
291619
292265
  function serveConfigScopes(config3) {
291620
292266
  const foreground = Object.values(config3.Foreground ?? {}).filter(
291621
292267
  (scope) => Boolean(scope)
@@ -291661,7 +292307,7 @@ function toStateError(code, err) {
291661
292307
  at: nowIso2()
291662
292308
  };
291663
292309
  }
291664
- var DEFAULT_MAX_LOG_ENTRIES, DEFAULT_STOP_TIMEOUT_MS2, DEFAULT_RESTART_BASE_DELAY_MS, DEFAULT_RESTART_MAX_DELAY_MS, execFileAsync34, execAsync58, LineBuffer, TunnelProcessManager;
292310
+ var DEFAULT_MAX_LOG_ENTRIES, DEFAULT_STOP_TIMEOUT_MS2, DEFAULT_RESTART_BASE_DELAY_MS, DEFAULT_RESTART_MAX_DELAY_MS, execFileAsync35, execAsync58, LineBuffer, TunnelProcessManager;
291665
292311
  var init_tunnel_process_manager = __esm({
291666
292312
  "../engine/src/remote-access/tunnel-process-manager.ts"() {
291667
292313
  "use strict";
@@ -291672,8 +292318,8 @@ var init_tunnel_process_manager = __esm({
291672
292318
  DEFAULT_STOP_TIMEOUT_MS2 = 5e3;
291673
292319
  DEFAULT_RESTART_BASE_DELAY_MS = 1e3;
291674
292320
  DEFAULT_RESTART_MAX_DELAY_MS = 3e4;
291675
- execFileAsync34 = promisify91(execFile40);
291676
- execAsync58 = promisify91(exec64);
292321
+ execFileAsync35 = promisify92(execFile41);
292322
+ execAsync58 = promisify92(exec64);
291677
292323
  LineBuffer = class {
291678
292324
  pending = "";
291679
292325
  push(chunk) {
@@ -291778,7 +292424,7 @@ var init_tunnel_process_manager = __esm({
291778
292424
  return null;
291779
292425
  }
291780
292426
  try {
291781
- const { stdout } = await execFileAsync34("tailscale", ["status", "--json"], { timeout: 3e3 });
292427
+ const { stdout } = await execFileAsync35("tailscale", ["status", "--json"], { timeout: 3e3 });
291782
292428
  const data = JSON.parse(String(stdout));
291783
292429
  const dnsName = data.Self?.DNSName?.replace(/\.$/, "");
291784
292430
  if (!dnsName) {
@@ -291801,7 +292447,7 @@ var init_tunnel_process_manager = __esm({
291801
292447
  ];
291802
292448
  for (const resetCommand of resetCommands) {
291803
292449
  try {
291804
- await execFileAsync34(resetCommand.command, resetCommand.args, { timeout: 5e3 });
292450
+ await execFileAsync35(resetCommand.command, resetCommand.args, { timeout: 5e3 });
291805
292451
  return;
291806
292452
  } catch {
291807
292453
  }
@@ -291907,7 +292553,7 @@ var init_tunnel_process_manager = __esm({
291907
292553
  async detectActiveFunnel() {
291908
292554
  let stdout = "";
291909
292555
  try {
291910
- const result2 = await execFileAsync34("tailscale", ["serve", "status", "--json"], { timeout: 5e3 });
292556
+ const result2 = await execFileAsync35("tailscale", ["serve", "status", "--json"], { timeout: 5e3 });
291911
292557
  stdout = String(result2.stdout ?? "");
291912
292558
  } catch (error3) {
291913
292559
  const failure = error3;
@@ -292325,8 +292971,8 @@ var init_tunnel_process_manager = __esm({
292325
292971
  });
292326
292972
 
292327
292973
  // ../engine/src/remote-access/remote-tunnel-service.ts
292328
- import { execFile as execFile41 } from "node:child_process";
292329
- import { promisify as promisify92 } from "node:util";
292974
+ import { execFile as execFile42 } from "node:child_process";
292975
+ import { promisify as promisify93 } from "node:util";
292330
292976
  function remoteTunnelScopeKey(input) {
292331
292977
  const projectId2 = input.projectId?.trim();
292332
292978
  if (projectId2) return `project:${projectId2}`;
@@ -292369,14 +293015,14 @@ async function shutdownAllRemoteTunnels() {
292369
293015
  function __resetRemoteTunnelServicesForTests() {
292370
293016
  remoteTunnelServices.clear();
292371
293017
  }
292372
- var execFileAsync35, isRemoteActive, RemoteTunnelService, remoteTunnelServices;
293018
+ var execFileAsync36, isRemoteActive, RemoteTunnelService, remoteTunnelServices;
292373
293019
  var init_remote_tunnel_service = __esm({
292374
293020
  "../engine/src/remote-access/remote-tunnel-service.ts"() {
292375
293021
  "use strict";
292376
293022
  init_logger3();
292377
293023
  init_local_dashboard_port();
292378
293024
  init_tunnel_process_manager();
292379
- execFileAsync35 = promisify92(execFile41);
293025
+ execFileAsync36 = promisify93(execFile42);
292380
293026
  isRemoteActive = (ra) => ra?.activeProvider != null && (ra.providers[ra.activeProvider]?.enabled ?? false);
292381
293027
  RemoteTunnelService = class {
292382
293028
  manager = new TunnelProcessManager();
@@ -292725,7 +293371,7 @@ var init_remote_tunnel_service = __esm({
292725
293371
  async checkTailscaleDaemonReady() {
292726
293372
  let stdout = "";
292727
293373
  try {
292728
- const result2 = await execFileAsync35("tailscale", ["status", "--json"], {
293374
+ const result2 = await execFileAsync36("tailscale", ["status", "--json"], {
292729
293375
  timeout: 5e3,
292730
293376
  maxBuffer: 8 * 1024 * 1024
292731
293377
  });
@@ -292773,7 +293419,7 @@ var init_remote_tunnel_service = __esm({
292773
293419
  async checkExecutableAvailable(command) {
292774
293420
  const checker = process.platform === "win32" ? "where" : "which";
292775
293421
  try {
292776
- await execFileAsync35(checker, [command]);
293422
+ await execFileAsync36(checker, [command]);
292777
293423
  return { available: true };
292778
293424
  } catch {
292779
293425
  return {
@@ -292788,8 +293434,8 @@ var init_remote_tunnel_service = __esm({
292788
293434
  });
292789
293435
 
292790
293436
  // ../engine/src/project-engine.ts
292791
- import { execFile as execFile42 } from "node:child_process";
292792
- import { promisify as promisify93 } from "node:util";
293437
+ import { execFile as execFile43 } from "node:child_process";
293438
+ import { promisify as promisify94 } from "node:util";
292793
293439
  function emitMergeRequestShadowDequeueParityAudit(store, legacyTaskId, shadowTaskId) {
292794
293440
  const agree = shadowTaskId === legacyTaskId;
292795
293441
  void emitBoundedRunAudit2(store, {
@@ -292844,7 +293490,7 @@ async function verifyMergeConfirmedReachability(args) {
292844
293490
  return { reachable: true, skipped: "no-integration-branch" };
292845
293491
  }
292846
293492
  try {
292847
- await execFileAsync36("git", ["cat-file", "-e", `${commitSha}^{commit}`], {
293493
+ await execFileAsync37("git", ["cat-file", "-e", `${commitSha}^{commit}`], {
292848
293494
  cwd,
292849
293495
  timeout: 1e4
292850
293496
  });
@@ -292853,7 +293499,7 @@ async function verifyMergeConfirmedReachability(args) {
292853
293499
  return { reachable: false, reason: "commit-missing", diagnostic };
292854
293500
  }
292855
293501
  try {
292856
- await execFileAsync36(
293502
+ await execFileAsync37(
292857
293503
  "git",
292858
293504
  ["merge-base", "--is-ancestor", commitSha, `refs/heads/${integrationBranch}`],
292859
293505
  { cwd, timeout: 1e4 }
@@ -292869,7 +293515,7 @@ async function verifyMergeConfirmedReachability(args) {
292869
293515
  return { reachable: false, reason: "git-error", diagnostic };
292870
293516
  }
292871
293517
  }
292872
- var WorkspaceMergeDispatchBusyError2, execFileAsync36, MERGE_HANDOFF_GRACE_MS, PR_MERGE_RETRY_BACKOFF_BASE_MS, deterministicMergerModeDeprecationWarnedProjects, ProjectEngine;
293518
+ var WorkspaceMergeDispatchBusyError2, execFileAsync37, MERGE_HANDOFF_GRACE_MS, PR_MERGE_RETRY_BACKOFF_BASE_MS, deterministicMergerModeDeprecationWarnedProjects, ProjectEngine;
292873
293519
  var init_project_engine = __esm({
292874
293520
  "../engine/src/project-engine.ts"() {
292875
293521
  "use strict";
@@ -292902,6 +293548,7 @@ var init_project_engine = __esm({
292902
293548
  init_merger_ai();
292903
293549
  init_group_merge_coordinator();
292904
293550
  init_workspace_review_reroute();
293551
+ init_stale_content_review_reroute();
292905
293552
  init_workspace_integration_target();
292906
293553
  init_concurrency();
292907
293554
  init_merge_reclaim_policy();
@@ -292928,7 +293575,7 @@ var init_project_engine = __esm({
292928
293575
  }
292929
293576
  retryable = true;
292930
293577
  };
292931
- execFileAsync36 = promisify93(execFile42);
293578
+ execFileAsync37 = promisify94(execFile43);
292932
293579
  MERGE_HANDOFF_GRACE_MS = 300;
292933
293580
  PR_MERGE_RETRY_BACKOFF_BASE_MS = 5e3;
292934
293581
  deterministicMergerModeDeprecationWarnedProjects = /* @__PURE__ */ new Set();
@@ -292992,6 +293639,7 @@ var init_project_engine = __esm({
292992
293639
  }
292993
293640
  });
292994
293641
  }
293642
+ staleContentRerouteAuditKeys = /* @__PURE__ */ new Set();
292995
293643
  runtime;
292996
293644
  started = false;
292997
293645
  specDriftReconciler;
@@ -294788,11 +295436,44 @@ ${detail}`);
294788
295436
  workspaceRootDir: this.config.workingDirectory,
294789
295437
  settings
294790
295438
  });
294791
- return getTaskMergeBlocker(task, {
295439
+ const blocker = getTaskMergeBlocker(task, {
294792
295440
  reviewColumns: mergeGate.reviewColumns.size > 0 ? mergeGate.reviewColumns : /* @__PURE__ */ new Set(["in-review"]),
294793
295441
  requiredPreMergeStepIds: mergeGate.requiredPreMergeStepIds,
294794
295442
  mergeContent
294795
295443
  });
295444
+ if (blocker === "task has a pre-merge approval recorded against different content" && mergeContent.kind === "singular") {
295445
+ const reroute = await rerouteSingularStaleContentToReview(store, task, {
295446
+ requiredPreMergeStepIds: mergeGate.requiredPreMergeStepIds,
295447
+ mergeContent
295448
+ }).catch(() => ({
295449
+ rerouted: false,
295450
+ reason: "no-progress",
295451
+ nodeId: void 0,
295452
+ workflowStepId: void 0
295453
+ }));
295454
+ if (reroute.rerouted) {
295455
+ await store.logEntry(task.id, `[pre-merge] Code Review re-entry is owned by the workflow graph after stale content evidence was refused.`);
295456
+ }
295457
+ const auditKey = `${task.id}:${reroute.reason}`;
295458
+ if (!this.staleContentRerouteAuditKeys.has(auditKey)) {
295459
+ this.staleContentRerouteAuditKeys.add(auditKey);
295460
+ await emitBoundedRunAudit2(store, {
295461
+ taskId: task.id,
295462
+ agentId: "merge-gate",
295463
+ runId: `${task.id}:merge-gate`,
295464
+ domain: "database",
295465
+ mutationType: "task:merge-stale-content-review-rerouted",
295466
+ target: task.id,
295467
+ metadata: {
295468
+ taskId: task.id,
295469
+ nodeId: reroute.nodeId,
295470
+ workflowStepId: reroute.workflowStepId,
295471
+ reason: reroute.reason
295472
+ }
295473
+ });
295474
+ }
295475
+ }
295476
+ return blocker;
294796
295477
  }
294797
295478
  /**
294798
295479
  * Remove and return the highest-priority taskId from the merge queue.
@@ -295638,7 +296319,7 @@ ${detail}`);
295638
296319
  }
295639
296320
  const checklist = planConfirmedMergeChecklistReconciliation(task);
295640
296321
  if (checklist.skippedStepIndexes.length > 0 || checklist.reconciledWorkflowStepIds.length > 0) {
295641
- const steps = task.steps.map((step, index2) => checklist.skippedStepIndexes.includes(index2) ? { ...step, status: "skipped" } : step);
296322
+ const steps = (task.steps ?? []).map((step, index2) => checklist.skippedStepIndexes.includes(index2) ? { ...step, status: "skipped" } : step);
295642
296323
  const workflowStepResults = (task.workflowStepResults ?? []).map((result2) => checklist.reconciledWorkflowStepIds.includes(result2.workflowStepId) ? { ...result2, status: "skipped" } : result2);
295643
296324
  await store.updateTask(taskId, { steps, workflowStepResults });
295644
296325
  task.steps = steps;
@@ -297384,9 +298065,9 @@ import { access as access12, unlink as unlink12, writeFile as writeFile31 } from
297384
298065
  import net2 from "node:net";
297385
298066
  import { platform as platform3, tmpdir as tmpdir13 } from "node:os";
297386
298067
  import { join as join100 } from "node:path";
297387
- import { createHash as createHash39 } from "node:crypto";
298068
+ import { createHash as createHash40 } from "node:crypto";
297388
298069
  function projectHash(projectId2) {
297389
- return createHash39("sha1").update(projectId2).digest("hex").slice(0, 16);
298070
+ return createHash40("sha1").update(projectId2).digest("hex").slice(0, 16);
297390
298071
  }
297391
298072
  function computeEngineSocketPath(projectId2) {
297392
298073
  const hash3 = projectHash(projectId2);
@@ -299004,8 +299685,8 @@ var init_remote_access = __esm({
299004
299685
  });
299005
299686
 
299006
299687
  // ../engine/src/healing/archive-worktree-disposer-install.ts
299007
- import { execFile as execFile43 } from "node:child_process";
299008
- import { promisify as promisify94 } from "node:util";
299688
+ import { execFile as execFile44 } from "node:child_process";
299689
+ import { promisify as promisify95 } from "node:util";
299009
299690
  function installBaselineArchiveWorktreeDisposer(store, input) {
299010
299691
  const allowLiveRemoval = input.allowLiveRemoval ?? (() => false);
299011
299692
  const unregisterSingle = getArchiveWorktreeDisposer(store) ? () => {
@@ -299027,7 +299708,7 @@ function installBaselineArchiveWorktreeDisposer(store, input) {
299027
299708
  try {
299028
299709
  if (await canonicalizeWorktreePath(entry.worktreePath) === await canonicalizeWorktreePath(entry.repoRootDir)) throw new Error("Refusing to remove workspace repository root");
299029
299710
  await removeWorktree({ worktreePath: entry.worktreePath, rootDir: entry.repoRootDir, settings: await input.getSettings(), taskId: task.id, reason: RemovalReason.ExecutorDispose, force: true });
299030
- await execFileAsync37("git", ["branch", "-D", entry.branch], { cwd: entry.repoRootDir, timeout: 12e4, maxBuffer: 10 * 1024 * 1024 });
299711
+ await execFileAsync38("git", ["branch", "-D", entry.branch], { cwd: entry.repoRootDir, timeout: 12e4, maxBuffer: 10 * 1024 * 1024 });
299031
299712
  if (task.workspaceWorktrees) for (const repoRel of [entry.repoRel, ...entry.aliasRepoRels]) delete task.workspaceWorktrees[repoRel];
299032
299713
  removed.push(entry.repoRel);
299033
299714
  } catch (error3) {
@@ -299041,13 +299722,13 @@ function installBaselineArchiveWorktreeDisposer(store, input) {
299041
299722
  unregisterSingle();
299042
299723
  };
299043
299724
  }
299044
- var execFileAsync37;
299725
+ var execFileAsync38;
299045
299726
  var init_archive_worktree_disposer_install = __esm({
299046
299727
  "../engine/src/healing/archive-worktree-disposer-install.ts"() {
299047
299728
  "use strict";
299048
299729
  init_src2();
299049
299730
  init_worktree_backend();
299050
- execFileAsync37 = promisify94(execFile43);
299731
+ execFileAsync38 = promisify95(execFile44);
299051
299732
  }
299052
299733
  });
299053
299734
 
@@ -300900,7 +301581,7 @@ import { exec as exec65 } from "node:child_process";
300900
301581
  import { mkdtemp as mkdtemp7, rm as rm18 } from "node:fs/promises";
300901
301582
  import { tmpdir as tmpdir14 } from "node:os";
300902
301583
  import { join as join101 } from "node:path";
300903
- import { promisify as promisify95 } from "node:util";
301584
+ import { promisify as promisify96 } from "node:util";
300904
301585
  function resolveCommentAuthor(input) {
300905
301586
  const login = input.login || "unknown";
300906
301587
  const authorIsBot = Boolean(
@@ -301369,7 +302050,7 @@ var init_github = __esm({
301369
302050
  "use strict";
301370
302051
  init_src2();
301371
302052
  init_issue_image_attachments();
301372
- execAsync59 = promisify95(exec65);
302053
+ execAsync59 = promisify96(exec65);
301373
302054
  DiscussionsDisabledError = class extends Error {
301374
302055
  name = "DiscussionsDisabledError";
301375
302056
  constructor(owner, repo, cause) {
@@ -308726,7 +309407,7 @@ var init_knowledge_index_refresh = __esm({
308726
309407
  });
308727
309408
 
308728
309409
  // ../dashboard/src/pr-metadata-generator.ts
308729
- import { promisify as promisify96 } from "node:util";
309410
+ import { promisify as promisify97 } from "node:util";
308730
309411
  import { exec as execCb } from "node:child_process";
308731
309412
  import { access as access13, readFile as readFile52 } from "node:fs/promises";
308732
309413
  import { join as join102 } from "node:path";
@@ -309018,7 +309699,7 @@ var init_pr_metadata_generator = __esm({
309018
309699
  "use strict";
309019
309700
  init_src2();
309020
309701
  init_src5();
309021
- execAsync60 = promisify96(execCb);
309702
+ execAsync60 = promisify97(execCb);
309022
309703
  PR_METADATA_TIMEOUT_MS = 6e4;
309023
309704
  PR_METADATA_SYSTEM_PROMPT = [
309024
309705
  "You generate GitHub pull request metadata for Fusion tasks.",
@@ -309035,13 +309716,13 @@ var init_pr_metadata_generator = __esm({
309035
309716
  });
309036
309717
 
309037
309718
  // ../dashboard/src/routes/resolve-diff-base.ts
309038
- import { execFile as execFile44 } from "node:child_process";
309039
- import { promisify as promisify97 } from "node:util";
309040
- var execFileAsync38;
309719
+ import { execFile as execFile45 } from "node:child_process";
309720
+ import { promisify as promisify98 } from "node:util";
309721
+ var execFileAsync39;
309041
309722
  var init_resolve_diff_base = __esm({
309042
309723
  "../dashboard/src/routes/resolve-diff-base.ts"() {
309043
309724
  "use strict";
309044
- execFileAsync38 = promisify97(execFile44);
309725
+ execFileAsync39 = promisify98(execFile45);
309045
309726
  }
309046
309727
  });
309047
309728
 
@@ -309082,7 +309763,7 @@ var init_git_worktree_safety = __esm({
309082
309763
 
309083
309764
  // ../dashboard/src/routes/register-git-github.ts
309084
309765
  import { exec as execCb2, spawn as spawn10 } from "node:child_process";
309085
- import { promisify as promisify98 } from "node:util";
309766
+ import { promisify as promisify99 } from "node:util";
309086
309767
  var severityAuditLog30, execAsync61, PR_ROUTE_MAX_BUFFER_BYTES, GITHUB_TRACKING_RECONCILE_INTERVAL_MS;
309087
309768
  var init_register_git_github = __esm({
309088
309769
  "../dashboard/src/routes/register-git-github.ts"() {
@@ -309114,7 +309795,7 @@ var init_register_git_github = __esm({
309114
309795
  init_resolve_diff_base();
309115
309796
  init_git_worktree_safety();
309116
309797
  severityAuditLog30 = createLogger("dashboard-register-git-github");
309117
- execAsync61 = promisify98(execCb2);
309798
+ execAsync61 = promisify99(execCb2);
309118
309799
  PR_ROUTE_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
309119
309800
  GITHUB_TRACKING_RECONCILE_INTERVAL_MS = 15 * 60 * 1e3;
309120
309801
  }
@@ -316051,13 +316732,13 @@ var init_register_agents_projects_nodes = __esm({
316051
316732
  });
316052
316733
 
316053
316734
  // ../dashboard/src/exec-file.ts
316054
- import { execFile as execFile45 } from "node:child_process";
316055
- import { promisify as promisify99 } from "node:util";
316056
- var execFileAsync39;
316735
+ import { execFile as execFile46 } from "node:child_process";
316736
+ import { promisify as promisify100 } from "node:util";
316737
+ var execFileAsync40;
316057
316738
  var init_exec_file = __esm({
316058
316739
  "../dashboard/src/exec-file.ts"() {
316059
316740
  "use strict";
316060
- execFileAsync39 = promisify99(execFile45);
316741
+ execFileAsync40 = promisify100(execFile46);
316061
316742
  }
316062
316743
  });
316063
316744
 
@@ -327335,7 +328016,7 @@ var init_register_fn_binary_routes = __esm({
327335
328016
 
327336
328017
  // ../dashboard/src/update-check.ts
327337
328018
  import { exec as exec66 } from "node:child_process";
327338
- import { promisify as promisify100 } from "node:util";
328019
+ import { promisify as promisify101 } from "node:util";
327339
328020
  var INSTALL_MAX_BUFFER, DAY_MS, execAsync62;
327340
328021
  var init_update_check = __esm({
327341
328022
  "../dashboard/src/update-check.ts"() {
@@ -327343,7 +328024,7 @@ var init_update_check = __esm({
327343
328024
  init_src2();
327344
328025
  INSTALL_MAX_BUFFER = 10 * 1024 * 1024;
327345
328026
  DAY_MS = 24 * 60 * 60 * 1e3;
327346
- execAsync62 = promisify100(exec66);
328027
+ execAsync62 = promisify101(exec66);
327347
328028
  }
327348
328029
  });
327349
328030
 
@@ -327434,7 +328115,7 @@ var init_types5 = __esm({
327434
328115
  });
327435
328116
 
327436
328117
  // ../dashboard/src/stt/model-manager.ts
327437
- import { createHash as createHash40, randomUUID as randomUUID63 } from "node:crypto";
328118
+ import { createHash as createHash41, randomUUID as randomUUID63 } from "node:crypto";
327438
328119
  import { mkdir as mkdir34, open as open5, readFile as readFile56, readdir as readdir14, rename as rename13, rm as rm21, stat as stat15, writeFile as writeFile33 } from "node:fs/promises";
327439
328120
  import { join as join121, relative as relative25, resolve as resolve62, sep as sep20 } from "node:path";
327440
328121
  function parseSafeTarListing(listing) {
@@ -327523,7 +328204,7 @@ function createVoiceModelManager(options = {}) {
327523
328204
  if (!response.ok || !response.body) throw Object.assign(new Error("download failed"), { voiceReason: "network" });
327524
328205
  if (!current(g2, signal)) return state;
327525
328206
  const total = Number(response.headers.get("content-length")) || void 0;
327526
- const hash3 = createHash40("sha256");
328207
+ const hash3 = createHash41("sha256");
327527
328208
  let bytes = 0;
327528
328209
  for await (const chunk of response.body) {
327529
328210
  if (!current(g2, signal)) return state;