@runfusion/fusion 0.73.0-beta.3 → 0.73.0-beta.4

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 (279) hide show
  1. package/dist/bin.js +994 -292
  2. package/dist/child-process-worker.js +632 -153
  3. package/dist/client/.vite/manifest.json +256 -256
  4. package/dist/client/assets/{AgentDetailView-lJqxsPOR.js → AgentDetailView-BBOL6AgZ.js} +1 -1
  5. package/dist/client/assets/{AgentPermissionPolicyEditor-De4wK_UT.js → AgentPermissionPolicyEditor-DV7OPUhR.js} +1 -1
  6. package/dist/client/assets/{AgentsView-CwizRdcA.js → AgentsView-B6xoAHyV.js} +3 -3
  7. package/dist/client/assets/{ChatView-BeQXaz7_.js → ChatView-DwVjnxM8.js} +1 -1
  8. package/dist/client/assets/{CommandCenter-BJZCaPLj.js → CommandCenter-DYWaoYFD.js} +1 -1
  9. package/dist/client/assets/{DevServerView-DQgwQXKx.js → DevServerView-BY5up-NA.js} +1 -1
  10. package/dist/client/assets/{DirectoryPicker-B2UVwp6F.js → DirectoryPicker-fM8MJa2r.js} +1 -1
  11. package/dist/client/assets/{DocumentsView-DOeYrhvg.js → DocumentsView-D2KxsPG_.js} +1 -1
  12. package/dist/client/assets/{EvalsView-LwepJ9Ud.js → EvalsView-U8dOvTRM.js} +1 -1
  13. package/dist/client/assets/{ExperimentalAgentOnboardingModal-DVNSzflw.js → ExperimentalAgentOnboardingModal-C27y8Y-1.js} +1 -1
  14. package/dist/client/assets/{GoalsView-__LpXw4S.js → GoalsView-D-2wmy-O.js} +1 -1
  15. package/dist/client/assets/{InsightsView-Dv388uaO.js → InsightsView-zLyuQL_l.js} +1 -1
  16. package/dist/client/assets/{MemoryView-ChCbEfZT.js → MemoryView-D-tSn48u.js} +1 -1
  17. package/dist/client/assets/{PiExtensionsManager-DehAjrqN.js → PiExtensionsManager-DvwmvGEY.js} +1 -1
  18. package/dist/client/assets/PluginManager-BACOwQAN.js +1 -0
  19. package/dist/client/assets/{PullRequestView-BvmajsBq.js → PullRequestView-DULyv21u.js} +1 -1
  20. package/dist/client/assets/{ReportModal-DM9B_h_w.js → ReportModal-CUlKMFWa.js} +1 -1
  21. package/dist/client/assets/{ResearchView-BzXSgUhp.js → ResearchView-DM_O3IFc.js} +1 -1
  22. package/dist/client/assets/{SecretsView-COBqEdJj.js → SecretsView-Bq3u_nAf.js} +1 -1
  23. package/dist/client/assets/{SessionTerminal-BUw_FTlh.js → SessionTerminal-D00ByR6U.js} +1 -1
  24. package/dist/client/assets/SettingsModal-Bb3pIxiX.js +21 -0
  25. package/dist/client/assets/SettingsModal-CMLHZBhX.css +1 -0
  26. package/dist/client/assets/{SettingsModal-CsLaIrqt.js → SettingsModal-QRaBE1ds.js} +1 -1
  27. package/dist/client/assets/{SettingsTextareaRow-Bv3aZ9aU.js → SettingsTextareaRow-CHOJ-qHz.js} +1 -1
  28. package/dist/client/assets/{SetupWizardModal-C-yMHTlW.js → SetupWizardModal-DriQyd81.js} +2 -2
  29. package/dist/client/assets/{SkillsView-kSHgkBar.js → SkillsView-BtDyujiZ.js} +1 -1
  30. package/dist/client/assets/{TodoView-DYoicJNY.js → TodoView-BNHUnz50.js} +1 -1
  31. package/dist/client/assets/{WorkflowNodeEditor-BtWrziOX.css → WorkflowNodeEditor-BNgkFJ_P.css} +1 -1
  32. package/dist/client/assets/WorkflowNodeEditor-BXikFpra.js +8 -0
  33. package/dist/client/assets/{agent-import-generation-D6P8OUuV.js → agent-import-generation-B2kYEm1O.js} +1 -1
  34. package/dist/client/assets/{app-DegRNirF.js → app-B_HrdDXZ.js} +1 -1
  35. package/dist/client/assets/{app-BsIXfnu-.js → app-C6yo-M_n.js} +1 -1
  36. package/dist/client/assets/{app-B-IdUeIu.js → app-CH8ZgPm4.js} +1 -1
  37. package/dist/client/assets/{app-D9ktpVhR.js → app-D4DpgDss.js} +1 -1
  38. package/dist/client/assets/{app-nBTNvNKK.js → app-Qv0blCyY.js} +1 -1
  39. package/dist/client/assets/{app-C8muVNUU.js → app-kFdtajPy.js} +1 -1
  40. package/dist/client/assets/{architectureDiagram-3BPJPVTR-DLqKCckA.js → architectureDiagram-3BPJPVTR-B-Efjj4Z.js} +1 -1
  41. package/dist/client/assets/{blockDiagram-GPEHLZMM-DRz6F8wZ.js → blockDiagram-GPEHLZMM-CaOVxrlM.js} +1 -1
  42. package/dist/client/assets/{c4Diagram-AAUBKEIU-CJ9glQAp.js → c4Diagram-AAUBKEIU-D8aYt5F1.js} +1 -1
  43. package/dist/client/assets/channel-5bPK6pTS.js +1 -0
  44. package/dist/client/assets/{chunk-2J33WTMH-CjIBb3ln.js → chunk-2J33WTMH-VSDT0J0r.js} +1 -1
  45. package/dist/client/assets/{chunk-4BX2VUAB-DrcoEr1E.js → chunk-4BX2VUAB-Chx1wQgD.js} +1 -1
  46. package/dist/client/assets/{chunk-55IACEB6-DU-WcuA9.js → chunk-55IACEB6-MlqjhIJg.js} +1 -1
  47. package/dist/client/assets/{chunk-727SXJPM-C5Lklr3l.js → chunk-727SXJPM-BheQNUi8.js} +1 -1
  48. package/dist/client/assets/{chunk-AQP2D5EJ-DlyTTghY.js → chunk-AQP2D5EJ-C5EoJhfJ.js} +1 -1
  49. package/dist/client/assets/{chunk-FMBD7UC4-D3C65m5Y.js → chunk-FMBD7UC4-B8_8qP3j.js} +1 -1
  50. package/dist/client/assets/{chunk-ND2GUHAM-BZY-4WZF.js → chunk-ND2GUHAM-BuglCGRx.js} +1 -1
  51. package/dist/client/assets/{chunk-QZHKN3VN-CKUtTYy5.js → chunk-QZHKN3VN-B7_06dxp.js} +1 -1
  52. package/dist/client/assets/classDiagram-4FO5ZUOK-Dv9RQDqG.js +1 -0
  53. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-Dv9RQDqG.js +1 -0
  54. package/dist/client/assets/{cose-bilkent-S5V4N54A-DbpsF4N5.js → cose-bilkent-S5V4N54A-Cm-ZOycx.js} +1 -1
  55. package/dist/client/assets/{dagre-BM42HDAG-BwIo4me1.js → dagre-BM42HDAG-Dj_Gwjpv.js} +1 -1
  56. package/dist/client/assets/{dashboard-view-C94UCci5.js → dashboard-view-B4CRL5Fy.js} +1 -1
  57. package/dist/client/assets/{dashboard-view-BvAsW6UZ.js → dashboard-view-noD9p0Zs.js} +1 -1
  58. package/dist/client/assets/{dashboard-view-BMQm7Lt_.js → dashboard-view-pXXSUxG9.js} +1 -1
  59. package/dist/client/assets/{diagram-2AECGRRQ-C-d8XY1c.js → diagram-2AECGRRQ-C_9BfShy.js} +1 -1
  60. package/dist/client/assets/{diagram-5GNKFQAL-ByRrlL9w.js → diagram-5GNKFQAL-Cmg2qpCj.js} +1 -1
  61. package/dist/client/assets/{diagram-KO2AKTUF-BK7jb_J-.js → diagram-KO2AKTUF-2FNo2HXb.js} +1 -1
  62. package/dist/client/assets/{diagram-LMA3HP47-u2o4bYk6.js → diagram-LMA3HP47-DgnVeCp-.js} +1 -1
  63. package/dist/client/assets/{diagram-OG6HWLK6-Dakk1V3D.js → diagram-OG6HWLK6-iAIR50HH.js} +1 -1
  64. package/dist/client/assets/{erDiagram-TEJ5UH35-Yp33v-Cf.js → erDiagram-TEJ5UH35-Da4I04eN.js} +1 -1
  65. package/dist/client/assets/{flowDiagram-I6XJVG4X-C4-dR2TA.js → flowDiagram-I6XJVG4X-Bv9r2T0m.js} +1 -1
  66. package/dist/client/assets/{folder-open-C9qq38qV.js → folder-open-CwWtrDh6.js} +1 -1
  67. package/dist/client/assets/{ganttDiagram-6RSMTGT7-C0CTCkFN.js → ganttDiagram-6RSMTGT7-BMeO84U_.js} +1 -1
  68. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-DK0Dd5mm.js → gitGraphDiagram-PVQCEYII-CWDh_RIb.js} +1 -1
  69. package/dist/client/assets/index-CB3mYxAB.css +1 -0
  70. package/dist/client/assets/{index-BqLVwYoA.js → index-CE7C_XsS.js} +294 -294
  71. package/dist/client/assets/{infoDiagram-5YYISTIA-u5MwFb7j.js → infoDiagram-5YYISTIA-BAE4KtCL.js} +1 -1
  72. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-C7R6TziI.js → ishikawaDiagram-YF4QCWOH-C_iXAuOy.js} +1 -1
  73. package/dist/client/assets/{journeyDiagram-JHISSGLW-Dom8W5Ab.js → journeyDiagram-JHISSGLW-BnxSHwDo.js} +1 -1
  74. package/dist/client/assets/{kanban-definition-UN3LZRKU-_47C02t3.js → kanban-definition-UN3LZRKU-DYNRm3Nu.js} +1 -1
  75. package/dist/client/assets/{mermaid.core-Cd3LKosp.js → mermaid.core-B3hvDDep.js} +4 -4
  76. package/dist/client/assets/{mindmap-definition-RKZ34NQL-D-qVOEin.js → mindmap-definition-RKZ34NQL-s7KBEuPD.js} +1 -1
  77. package/dist/client/assets/{pieDiagram-4H26LBE5-B0TXvVbM.js → pieDiagram-4H26LBE5-Cy1_IPUD.js} +1 -1
  78. package/dist/client/assets/{puzzle-BBYTjDQK.js → puzzle-DWc6gFQ7.js} +1 -1
  79. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-KcFvcZPm.js → quadrantDiagram-W4KKPZXB-DqgVGp41.js} +1 -1
  80. package/dist/client/assets/{requirementDiagram-4Y6WPE33-DEObokVc.js → requirementDiagram-4Y6WPE33-CA5-TDeF.js} +1 -1
  81. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-BGYnEp22.js → sankeyDiagram-5OEKKPKP-Cuvi3RgE.js} +1 -1
  82. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-BcYgyJRU.js → sequenceDiagram-3UESZ5HK-Da3GfmGP.js} +1 -1
  83. package/dist/client/assets/{shield-alert-CZg8yaFA.js → shield-alert-_iY63ED4.js} +1 -1
  84. package/dist/client/assets/{standing-instructions-template-BsTtbEqp.js → standing-instructions-template-CCd2YY9c.js} +1 -1
  85. package/dist/client/assets/{stateDiagram-AJRCARHV-CfZQIqmX.js → stateDiagram-AJRCARHV-CZ_I9ENR.js} +1 -1
  86. package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-nBEPRSH7.js → stateDiagram-v2-BHNVJYJU-BomoRVhY.js} +1 -1
  87. package/dist/client/assets/{timeline-definition-PNZ67QCA-DySyabS_.js → timeline-definition-PNZ67QCA-C3CYvIuR.js} +1 -1
  88. package/dist/client/assets/{upload-DMd3zMLx.js → upload-D0RrO65v.js} +1 -1
  89. package/dist/client/assets/{users-9Pyvnn8K.js → users-CGszBY2v.js} +1 -1
  90. package/dist/client/assets/{vennDiagram-CIIHVFJN-DPomfxp_.js → vennDiagram-CIIHVFJN-By9fi8NW.js} +1 -1
  91. package/dist/client/assets/{wardley-L42UT6IY-BPfzngS8.js → wardley-L42UT6IY-DErnXPkI.js} +1 -1
  92. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-Yp4nidAP.js → wardleyDiagram-YWT4CUSO-DFfXZVPk.js} +1 -1
  93. package/dist/client/assets/{xychartDiagram-2RQKCTM6-REgng603.js → xychartDiagram-2RQKCTM6-9Y5oZ5mi.js} +1 -1
  94. package/dist/client/index.html +4 -2
  95. package/dist/client/version.json +1 -1
  96. package/dist/extension.js +752 -207
  97. package/dist/migrations/0000_initial.sql +2 -0
  98. package/dist/migrations/0033_fn-8505_wedge_notification.sql +5 -0
  99. package/dist/plugin-sdk/index.js +1 -0
  100. package/dist/plugins/.fusion-ce-agents/.fusion-ce-upstream-provenance.json +7 -0
  101. package/dist/plugins/.fusion-ce-agents/ce-adversarial-document-reviewer.md +115 -0
  102. package/dist/plugins/.fusion-ce-agents/ce-adversarial-reviewer.md +111 -0
  103. package/dist/plugins/.fusion-ce-agents/ce-agent-native-planning-strategist.md +71 -0
  104. package/dist/plugins/.fusion-ce-agents/ce-agent-native-reviewer.md +181 -0
  105. package/dist/plugins/.fusion-ce-agents/ce-ankane-readme-writer.md +50 -0
  106. package/dist/plugins/.fusion-ce-agents/ce-api-contract-reviewer.md +52 -0
  107. package/dist/plugins/.fusion-ce-agents/ce-architecture-strategist.md +53 -0
  108. package/dist/plugins/.fusion-ce-agents/ce-best-practices-researcher.md +122 -0
  109. package/dist/plugins/.fusion-ce-agents/ce-code-simplicity-reviewer.md +87 -0
  110. package/dist/plugins/.fusion-ce-agents/ce-coherence-reviewer.md +73 -0
  111. package/dist/plugins/.fusion-ce-agents/ce-correctness-reviewer.md +52 -0
  112. package/dist/plugins/.fusion-ce-agents/ce-data-integrity-guardian.md +75 -0
  113. package/dist/plugins/.fusion-ce-agents/ce-data-migration-reviewer.md +119 -0
  114. package/dist/plugins/.fusion-ce-agents/ce-deployment-verification-agent.md +164 -0
  115. package/dist/plugins/.fusion-ce-agents/ce-design-implementation-reviewer.md +94 -0
  116. package/dist/plugins/.fusion-ce-agents/ce-design-iterator.md +197 -0
  117. package/dist/plugins/.fusion-ce-agents/ce-design-lens-reviewer.md +56 -0
  118. package/dist/plugins/.fusion-ce-agents/ce-feasibility-reviewer.md +65 -0
  119. package/dist/plugins/.fusion-ce-agents/ce-figma-design-sync.md +172 -0
  120. package/dist/plugins/.fusion-ce-agents/ce-framework-docs-researcher.md +100 -0
  121. package/dist/plugins/.fusion-ce-agents/ce-git-history-analyzer.md +47 -0
  122. package/dist/plugins/.fusion-ce-agents/ce-issue-intelligence-analyst.md +207 -0
  123. package/dist/plugins/.fusion-ce-agents/ce-julik-frontend-races-reviewer.md +52 -0
  124. package/dist/plugins/.fusion-ce-agents/ce-learnings-researcher.md +254 -0
  125. package/dist/plugins/.fusion-ce-agents/ce-maintainability-reviewer.md +77 -0
  126. package/dist/plugins/.fusion-ce-agents/ce-pattern-recognition-specialist.md +62 -0
  127. package/dist/plugins/.fusion-ce-agents/ce-performance-oracle.md +115 -0
  128. package/dist/plugins/.fusion-ce-agents/ce-performance-reviewer.md +54 -0
  129. package/dist/plugins/.fusion-ce-agents/ce-pr-comment-resolver.md +63 -0
  130. package/dist/plugins/.fusion-ce-agents/ce-previous-comments-reviewer.md +68 -0
  131. package/dist/plugins/.fusion-ce-agents/ce-product-lens-reviewer.md +92 -0
  132. package/dist/plugins/.fusion-ce-agents/ce-project-standards-reviewer.md +84 -0
  133. package/dist/plugins/.fusion-ce-agents/ce-reliability-reviewer.md +52 -0
  134. package/dist/plugins/.fusion-ce-agents/ce-repo-research-analyst.md +263 -0
  135. package/dist/plugins/.fusion-ce-agents/ce-scope-guardian-reviewer.md +79 -0
  136. package/dist/plugins/.fusion-ce-agents/ce-security-lens-reviewer.md +48 -0
  137. package/dist/plugins/.fusion-ce-agents/ce-security-reviewer.md +54 -0
  138. package/dist/plugins/.fusion-ce-agents/ce-security-sentinel.md +98 -0
  139. package/dist/plugins/.fusion-ce-agents/ce-session-historian.md +89 -0
  140. package/dist/plugins/.fusion-ce-agents/ce-slack-researcher.md +133 -0
  141. package/dist/plugins/.fusion-ce-agents/ce-spec-flow-analyzer.md +87 -0
  142. package/dist/plugins/.fusion-ce-agents/ce-swift-ios-reviewer.md +107 -0
  143. package/dist/plugins/.fusion-ce-agents/ce-testing-reviewer.md +52 -0
  144. package/dist/plugins/.fusion-ce-agents/ce-web-researcher.md +127 -0
  145. package/dist/plugins/.fusion-ce-skills/.fusion-ce-upstream-provenance.json +7 -0
  146. package/dist/plugins/.fusion-ce-skills/ce-brainstorm/SKILL.md +318 -0
  147. package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/agents/slack-researcher.md +127 -0
  148. package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/brainstorm-sections.md +354 -0
  149. package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/handoff.md +172 -0
  150. package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/html-rendering.md +662 -0
  151. package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/markdown-rendering.md +236 -0
  152. package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/synthesis-summary.md +271 -0
  153. package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/universal-brainstorming.md +71 -0
  154. package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/visual-probes.md +128 -0
  155. package/dist/plugins/.fusion-ce-skills/ce-brainstorm/scripts/visual-probe-server.js +419 -0
  156. package/dist/plugins/.fusion-ce-skills/ce-code-review/SKILL.md +821 -0
  157. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/action-class-rubric.md +26 -0
  158. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/bulk-preview.md +112 -0
  159. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/cross-model-review.md +63 -0
  160. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/diff-scope.md +41 -0
  161. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/findings-schema.json +137 -0
  162. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/persona-catalog.md +63 -0
  163. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/adversarial-reviewer.md +102 -0
  164. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/agent-native-reviewer.md +173 -0
  165. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/api-contract-reviewer.md +43 -0
  166. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/correctness-reviewer.md +43 -0
  167. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/data-migration-reviewer.md +111 -0
  168. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/deployment-verification-agent.md +157 -0
  169. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/julik-frontend-races-reviewer.md +44 -0
  170. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/learnings-researcher.md +247 -0
  171. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/maintainability-reviewer.md +68 -0
  172. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/performance-reviewer.md +45 -0
  173. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/previous-comments-reviewer.md +59 -0
  174. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/project-standards-reviewer.md +75 -0
  175. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/reliability-reviewer.md +43 -0
  176. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/security-reviewer.md +45 -0
  177. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/swift-ios-reviewer.md +99 -0
  178. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/testing-reviewer.md +43 -0
  179. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/review-output-template.md +170 -0
  180. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/subagent-template.md +199 -0
  181. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/tracker-defer.md +149 -0
  182. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/validator-template.md +89 -0
  183. package/dist/plugins/.fusion-ce-skills/ce-code-review/references/walkthrough.md +249 -0
  184. package/dist/plugins/.fusion-ce-skills/ce-code-review/scripts/cross-model-adversarial-review.sh +218 -0
  185. package/dist/plugins/.fusion-ce-skills/ce-commit/SKILL.md +105 -0
  186. package/dist/plugins/.fusion-ce-skills/ce-commit-push-pr/SKILL.md +134 -0
  187. package/dist/plugins/.fusion-ce-skills/ce-commit-push-pr/references/branch-creation.md +55 -0
  188. package/dist/plugins/.fusion-ce-skills/ce-commit-push-pr/references/pr-description-writing.md +115 -0
  189. package/dist/plugins/.fusion-ce-skills/ce-compound/SKILL.md +712 -0
  190. package/dist/plugins/.fusion-ce-skills/ce-compound/assets/resolution-template.md +94 -0
  191. package/dist/plugins/.fusion-ce-skills/ce-compound/references/agents/best-practices-researcher.md +115 -0
  192. package/dist/plugins/.fusion-ce-skills/ce-compound/references/agents/data-integrity-guardian.md +68 -0
  193. package/dist/plugins/.fusion-ce-skills/ce-compound/references/agents/framework-docs-researcher.md +93 -0
  194. package/dist/plugins/.fusion-ce-skills/ce-compound/references/agents/pattern-recognition-specialist.md +55 -0
  195. package/dist/plugins/.fusion-ce-skills/ce-compound/references/agents/performance-oracle.md +108 -0
  196. package/dist/plugins/.fusion-ce-skills/ce-compound/references/agents/security-sentinel.md +91 -0
  197. package/dist/plugins/.fusion-ce-skills/ce-compound/references/agents/session-historian.md +83 -0
  198. package/dist/plugins/.fusion-ce-skills/ce-compound/references/concepts-vocabulary.md +78 -0
  199. package/dist/plugins/.fusion-ce-skills/ce-compound/references/schema.yaml +231 -0
  200. package/dist/plugins/.fusion-ce-skills/ce-compound/references/yaml-schema.md +118 -0
  201. package/dist/plugins/.fusion-ce-skills/ce-compound/scripts/session-history/discover-sessions.sh +130 -0
  202. package/dist/plugins/.fusion-ce-skills/ce-compound/scripts/session-history/extract-errors.py +254 -0
  203. package/dist/plugins/.fusion-ce-skills/ce-compound/scripts/session-history/extract-metadata.py +456 -0
  204. package/dist/plugins/.fusion-ce-skills/ce-compound/scripts/session-history/extract-skeleton.py +570 -0
  205. package/dist/plugins/.fusion-ce-skills/ce-compound/scripts/validate-frontmatter.py +137 -0
  206. package/dist/plugins/.fusion-ce-skills/ce-debug/SKILL.md +257 -0
  207. package/dist/plugins/.fusion-ce-skills/ce-debug/references/anti-patterns.md +91 -0
  208. package/dist/plugins/.fusion-ce-skills/ce-debug/references/defense-in-depth.md +35 -0
  209. package/dist/plugins/.fusion-ce-skills/ce-debug/references/investigation-techniques.md +374 -0
  210. package/dist/plugins/.fusion-ce-skills/ce-doc-review/SKILL.md +70 -0
  211. package/dist/plugins/.fusion-ce-skills/ce-ideate/SKILL.md +401 -0
  212. package/dist/plugins/.fusion-ce-skills/ce-ideate/references/agents/issue-intelligence-analyst.md +200 -0
  213. package/dist/plugins/.fusion-ce-skills/ce-ideate/references/agents/learnings-researcher.md +247 -0
  214. package/dist/plugins/.fusion-ce-skills/ce-ideate/references/agents/slack-researcher.md +127 -0
  215. package/dist/plugins/.fusion-ce-skills/ce-ideate/references/agents/web-researcher.md +121 -0
  216. package/dist/plugins/.fusion-ce-skills/ce-ideate/references/divergent-ideation.md +89 -0
  217. package/dist/plugins/.fusion-ce-skills/ce-ideate/references/html-rendering.md +662 -0
  218. package/dist/plugins/.fusion-ce-skills/ce-ideate/references/ideation-sections.md +191 -0
  219. package/dist/plugins/.fusion-ce-skills/ce-ideate/references/markdown-rendering.md +236 -0
  220. package/dist/plugins/.fusion-ce-skills/ce-ideate/references/post-ideation-workflow.md +166 -0
  221. package/dist/plugins/.fusion-ce-skills/ce-ideate/references/universal-ideation.md +107 -0
  222. package/dist/plugins/.fusion-ce-skills/ce-ideate/references/web-research-cache.md +55 -0
  223. package/dist/plugins/.fusion-ce-skills/ce-plan/SKILL.md +858 -0
  224. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/agent-native-planning-strategist.md +62 -0
  225. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/architecture-strategist.md +46 -0
  226. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/best-practices-researcher.md +114 -0
  227. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/data-integrity-guardian.md +68 -0
  228. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/data-migration-reviewer.md +103 -0
  229. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/deployment-verification-agent.md +157 -0
  230. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/framework-docs-researcher.md +93 -0
  231. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/git-history-analyzer.md +40 -0
  232. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/learnings-researcher.md +247 -0
  233. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/pattern-recognition-specialist.md +55 -0
  234. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/performance-oracle.md +108 -0
  235. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/repo-research-analyst.md +256 -0
  236. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/security-sentinel.md +91 -0
  237. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/slack-researcher.md +127 -0
  238. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/spec-flow-analyzer.md +80 -0
  239. package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/web-researcher.md +121 -0
  240. package/dist/plugins/.fusion-ce-skills/ce-plan/references/approach-altitude.md +55 -0
  241. package/dist/plugins/.fusion-ce-skills/ce-plan/references/deepening-workflow.md +259 -0
  242. package/dist/plugins/.fusion-ce-skills/ce-plan/references/html-rendering.md +668 -0
  243. package/dist/plugins/.fusion-ce-skills/ce-plan/references/markdown-rendering.md +236 -0
  244. package/dist/plugins/.fusion-ce-skills/ce-plan/references/plan-handoff.md +126 -0
  245. package/dist/plugins/.fusion-ce-skills/ce-plan/references/plan-sections.md +405 -0
  246. package/dist/plugins/.fusion-ce-skills/ce-plan/references/synthesis-summary.md +396 -0
  247. package/dist/plugins/.fusion-ce-skills/ce-plan/references/universal-planning.md +168 -0
  248. package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/SKILL.md +53 -0
  249. package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/references/agents/pr-comment-resolver.md +56 -0
  250. package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/references/evaluation-rubric.md +106 -0
  251. package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/references/full-mode.md +283 -0
  252. package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/references/targeted-mode.md +45 -0
  253. package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/scripts/get-pr-comments +159 -0
  254. package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/scripts/get-thread-for-comment +76 -0
  255. package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/scripts/reply-to-pr-thread +33 -0
  256. package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/scripts/resolve-pr-thread +23 -0
  257. package/dist/plugins/.fusion-ce-skills/ce-strategy/SKILL.md +97 -0
  258. package/dist/plugins/.fusion-ce-skills/ce-strategy/references/interview.md +143 -0
  259. package/dist/plugins/.fusion-ce-skills/ce-strategy/references/strategy-template.md +89 -0
  260. package/dist/plugins/.fusion-ce-skills/ce-work/SKILL.md +429 -0
  261. package/dist/plugins/.fusion-ce-skills/ce-work/references/agents/figma-design-sync.md +165 -0
  262. package/dist/plugins/.fusion-ce-skills/ce-work/references/execution-engines.md +85 -0
  263. package/dist/plugins/.fusion-ce-skills/ce-work/references/non-code-execution.md +23 -0
  264. package/dist/plugins/.fusion-ce-skills/ce-work/references/review-findings-followup.md +104 -0
  265. package/dist/plugins/.fusion-ce-skills/ce-work/references/shipping-workflow.md +133 -0
  266. package/dist/plugins/.fusion-ce-skills/ce-work/references/tracker-defer.md +149 -0
  267. package/dist/plugins/fusion-plugin-compound-engineering/.bundled.reload-3.js +11266 -0
  268. package/dist/plugins/fusion-plugin-compound-engineering/.bundled.reload-4.js +11266 -0
  269. package/dist/plugins/fusion-plugin-dependency-graph/.bundled.reload-1.js +8206 -0
  270. package/dist/plugins/fusion-plugin-grok-runtime/.bundled.reload-2.js +26623 -0
  271. package/package.json +1 -1
  272. package/dist/client/assets/PluginManager-DBhJ1i27.js +0 -1
  273. package/dist/client/assets/SettingsModal-BDgH9XID.js +0 -21
  274. package/dist/client/assets/SettingsModal-BXDnzDkJ.css +0 -1
  275. package/dist/client/assets/WorkflowNodeEditor-DLno6bSJ.js +0 -8
  276. package/dist/client/assets/channel-Dj4nOgJO.js +0 -1
  277. package/dist/client/assets/classDiagram-4FO5ZUOK-DnkFo5Qy.js +0 -1
  278. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DnkFo5Qy.js +0 -1
  279. package/dist/client/assets/index-6FBJPKkr.css +0 -1
@@ -983,6 +983,7 @@ var init_workflow_steps = __esm({
983
983
  "in-review",
984
984
  "merged",
985
985
  "failed",
986
+ "task-wedged",
986
987
  "awaiting-approval",
987
988
  "awaiting-user-review",
988
989
  "planning-awaiting-input",
@@ -1056,6 +1057,50 @@ var init_documents_artifacts = __esm({
1056
1057
  }
1057
1058
  });
1058
1059
 
1060
+ // ../core/src/types/task-core.ts
1061
+ function assertNotWorkspaceTaskMerge(task) {
1062
+ if (isWorkspaceTask(task)) {
1063
+ throw new WorkspaceTaskMergeError(
1064
+ `Workspace task ${task.id} cannot merge until per-repo merge support (master-plan U6) lands`
1065
+ );
1066
+ }
1067
+ }
1068
+ function isWorkspaceTask(task) {
1069
+ const worktrees = task.workspaceWorktrees;
1070
+ return !!worktrees && Object.keys(worktrees).length > 0;
1071
+ }
1072
+ var CheckoutConflictError, DUPLICATE_OF_METADATA_KEY, WorkspaceTaskMergeError;
1073
+ var init_task_core = __esm({
1074
+ "../core/src/types/task-core.ts"() {
1075
+ "use strict";
1076
+ CheckoutConflictError = class extends Error {
1077
+ constructor(taskId, currentHolderId, requestedById) {
1078
+ super(`Task ${taskId} is already checked out by agent ${currentHolderId}`);
1079
+ this.taskId = taskId;
1080
+ this.currentHolderId = currentHolderId;
1081
+ this.requestedById = requestedById;
1082
+ this.name = "CheckoutConflictError";
1083
+ }
1084
+ };
1085
+ DUPLICATE_OF_METADATA_KEY = "duplicateOfTaskIds";
1086
+ WorkspaceTaskMergeError = class extends Error {
1087
+ constructor(message) {
1088
+ super(message);
1089
+ this.name = "WorkspaceTaskMergeError";
1090
+ }
1091
+ };
1092
+ }
1093
+ });
1094
+
1095
+ // ../core/src/types/todo-list.ts
1096
+ var SHARED_STATE_SNAPSHOT_VERSION;
1097
+ var init_todo_list = __esm({
1098
+ "../core/src/types/todo-list.ts"() {
1099
+ "use strict";
1100
+ SHARED_STATE_SNAPSHOT_VERSION = 1;
1101
+ }
1102
+ });
1103
+
1059
1104
  // ../core/src/task-helpers.ts
1060
1105
  function getPrimaryPrInfo(task) {
1061
1106
  return task.prInfos?.[0] ?? task.prInfo;
@@ -1545,10 +1590,18 @@ var init_settings_schema = __esm({
1545
1590
  "use strict";
1546
1591
  init_in_review_stall();
1547
1592
  DEFAULT_GLOBAL_SETTINGS = {
1548
- // Embedded PostgreSQL is shared by all local Fusion projects and processes.
1549
- // Keep this well above the conservative external-pool budget while still
1550
- // bounded for a local machine.
1551
- embeddedPostgresMaxConnections: 500,
1593
+ /*
1594
+ FNXC:PostgresEmbedded 2026-07-22-23:55:
1595
+ Embedded PostgreSQL is shared by all local Fusion projects and processes.
1596
+ Deliberately undefined (not 500): getSettings() merges these defaults, so a
1597
+ concrete value here would be indistinguishable from an operator choice and
1598
+ would mask the platform-aware server-side default in
1599
+ resolveEmbeddedMaxConnections (win32 150, else 500). Issue #2411: Windows
1600
+ backends are separate processes; a 500-connection cap exhausts the desktop
1601
+ heap under load and forked backends die with 0xC0000142, taking the embedded
1602
+ cluster and dashboard down.
1603
+ */
1604
+ embeddedPostgresMaxConnections: void 0,
1552
1605
  /*
1553
1606
  FNXC:DashboardTheming 2026-07-03-00:00:
1554
1607
  Fresh installs must follow the operating system theme until the user explicitly chooses Light, Dark, or System. Keep this global default aligned with dashboard and desktop pre-hydration fallbacks.
@@ -2311,6 +2364,53 @@ var init_settings_schema = __esm({
2311
2364
  }
2312
2365
  });
2313
2366
 
2367
+ // ../core/src/types/settings-scope.ts
2368
+ function isMcpSecretRef(value) {
2369
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
2370
+ const candidate = value;
2371
+ return typeof candidate.secretRef === "string" && candidate.secretRef.trim().length > 0 && (candidate.scope === "project" || candidate.scope === "global");
2372
+ }
2373
+ var init_settings_scope = __esm({
2374
+ "../core/src/types/settings-scope.ts"() {
2375
+ "use strict";
2376
+ init_settings_schema();
2377
+ }
2378
+ });
2379
+
2380
+ // ../core/src/types/board-config.ts
2381
+ var COLUMN_LABELS, COLUMN_DESCRIPTIONS, VALID_TRANSITIONS;
2382
+ var init_board_config = __esm({
2383
+ "../core/src/types/board-config.ts"() {
2384
+ "use strict";
2385
+ COLUMN_LABELS = {
2386
+ triage: "Planning",
2387
+ todo: "Todo",
2388
+ "in-progress": "In Progress",
2389
+ "in-review": "In Review",
2390
+ done: "Done",
2391
+ archived: "Archived"
2392
+ };
2393
+ COLUMN_DESCRIPTIONS = {
2394
+ triage: "Raw ideas \u2014 AI will plan these",
2395
+ "in-progress": "AI is working on this in a worktree",
2396
+ done: "Merged and closed",
2397
+ archived: "Completed and archived"
2398
+ };
2399
+ VALID_TRANSITIONS = {
2400
+ // FN-4892: intake-side heuristics may cold-archive tasks before execution starts.
2401
+ triage: ["todo", "archived"],
2402
+ // FN-4892: allow direct archival for newly specified intake tasks.
2403
+ todo: ["in-progress", "triage", "archived"],
2404
+ // NOTE: "in-progress" → "done" is enabled for mission validation tasks that complete directly.
2405
+ // Regular implementation tasks should move through "in-review" before "done".
2406
+ "in-progress": ["in-review", "todo", "triage", "done"],
2407
+ "in-review": ["done", "in-progress", "todo", "triage"],
2408
+ done: ["todo", "triage", "archived"],
2409
+ archived: ["done"]
2410
+ };
2411
+ }
2412
+ });
2413
+
2314
2414
  // ../core/src/types/docker-nodes.ts
2315
2415
  function validateDockerNodeConfig(config3) {
2316
2416
  const errors = [];
@@ -2421,6 +2521,41 @@ var init_docker_nodes = __esm({
2421
2521
  }
2422
2522
  });
2423
2523
 
2524
+ // ../core/src/types/archive-planning.ts
2525
+ function formatPlanningPlanMd(summary) {
2526
+ const normalizeListItem = (item) => item.replace(/\s+/g, " ").trim();
2527
+ const list = (items) => items && items.length > 0 ? items.map((item) => `- ${normalizeListItem(item)}`).join("\n") : "_None_";
2528
+ const proposedChanges = list(summary.proposedChanges);
2529
+ const acceptanceCriteria = list(summary.acceptanceCriteria);
2530
+ const dependencies = list(summary.suggestedDependencies);
2531
+ const deliverables = list(summary.keyDeliverables);
2532
+ return `# ${summary.title}
2533
+
2534
+ ${summary.description}
2535
+
2536
+ ## What to change
2537
+ ${proposedChanges}
2538
+
2539
+ ## Acceptance criteria
2540
+ ${acceptanceCriteria}
2541
+
2542
+ ## Size
2543
+ ${summary.suggestedSize}
2544
+
2545
+ ## Suggested dependencies
2546
+ ${dependencies}
2547
+
2548
+ ## Key deliverables
2549
+ ${deliverables}
2550
+ `;
2551
+ }
2552
+ var init_archive_planning = __esm({
2553
+ "../core/src/types/archive-planning.ts"() {
2554
+ "use strict";
2555
+ init_docker_nodes();
2556
+ }
2557
+ });
2558
+
2424
2559
  // ../core/src/types/agent-state.ts
2425
2560
  function isEphemeralAgent(agent) {
2426
2561
  const metadata = agent.metadata ?? {};
@@ -4146,49 +4281,6 @@ var init_workflow_lifecycle_validation = __esm({
4146
4281
  });
4147
4282
 
4148
4283
  // ../core/src/types.ts
4149
- function assertNotWorkspaceTaskMerge(task) {
4150
- if (isWorkspaceTask(task)) {
4151
- throw new WorkspaceTaskMergeError(
4152
- `Workspace task ${task.id} cannot merge until per-repo merge support (master-plan U6) lands`
4153
- );
4154
- }
4155
- }
4156
- function isWorkspaceTask(task) {
4157
- const worktrees = task.workspaceWorktrees;
4158
- return !!worktrees && Object.keys(worktrees).length > 0;
4159
- }
4160
- function isMcpSecretRef(value) {
4161
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
4162
- const candidate = value;
4163
- return typeof candidate.secretRef === "string" && candidate.secretRef.trim().length > 0 && (candidate.scope === "project" || candidate.scope === "global");
4164
- }
4165
- function formatPlanningPlanMd(summary) {
4166
- const normalizeListItem = (item) => item.replace(/\s+/g, " ").trim();
4167
- const list = (items) => items && items.length > 0 ? items.map((item) => `- ${normalizeListItem(item)}`).join("\n") : "_None_";
4168
- const proposedChanges = list(summary.proposedChanges);
4169
- const acceptanceCriteria = list(summary.acceptanceCriteria);
4170
- const dependencies = list(summary.suggestedDependencies);
4171
- const deliverables = list(summary.keyDeliverables);
4172
- return `# ${summary.title}
4173
-
4174
- ${summary.description}
4175
-
4176
- ## What to change
4177
- ${proposedChanges}
4178
-
4179
- ## Acceptance criteria
4180
- ${acceptanceCriteria}
4181
-
4182
- ## Size
4183
- ${summary.suggestedSize}
4184
-
4185
- ## Suggested dependencies
4186
- ${dependencies}
4187
-
4188
- ## Key deliverables
4189
- ${deliverables}
4190
- `;
4191
- }
4192
4284
  function validateMessageMetadata(metadata) {
4193
4285
  if (!metadata) {
4194
4286
  return;
@@ -4240,7 +4332,7 @@ function validateMessageMetadata(metadata) {
4240
4332
  if (metadata.proposalStatus === "pending" && (metadata.claimOwnerToken !== void 0 || metadata.claimStartedAt !== void 0)) throw new Error("pending proposal cannot have a creation lease");
4241
4333
  }
4242
4334
  }
4243
- var DEPRECATED_BUILTIN_WORKFLOW_IDS, CheckoutConflictError, DUPLICATE_OF_METADATA_KEY, WorkspaceTaskMergeError, SHARED_STATE_SNAPSHOT_VERSION, COLUMN_LABELS, COLUMN_DESCRIPTIONS, VALID_TRANSITIONS;
4335
+ var DEPRECATED_BUILTIN_WORKFLOW_IDS;
4244
4336
  var init_types = __esm({
4245
4337
  "../core/src/types.ts"() {
4246
4338
  "use strict";
@@ -4254,8 +4346,11 @@ var init_types = __esm({
4254
4346
  init_merge_policy();
4255
4347
  init_workflow_steps();
4256
4348
  init_documents_artifacts();
4257
- init_settings_schema();
4258
- init_docker_nodes();
4349
+ init_task_core();
4350
+ init_todo_list();
4351
+ init_settings_scope();
4352
+ init_board_config();
4353
+ init_archive_planning();
4259
4354
  init_agent_state();
4260
4355
  init_planner_intervention();
4261
4356
  init_agents();
@@ -4270,49 +4365,6 @@ var init_types = __esm({
4270
4365
  DEPRECATED_BUILTIN_WORKFLOW_IDS = /* @__PURE__ */ new Set([
4271
4366
  "builtin:brainstorming"
4272
4367
  ]);
4273
- CheckoutConflictError = class extends Error {
4274
- constructor(taskId, currentHolderId, requestedById) {
4275
- super(`Task ${taskId} is already checked out by agent ${currentHolderId}`);
4276
- this.taskId = taskId;
4277
- this.currentHolderId = currentHolderId;
4278
- this.requestedById = requestedById;
4279
- this.name = "CheckoutConflictError";
4280
- }
4281
- };
4282
- DUPLICATE_OF_METADATA_KEY = "duplicateOfTaskIds";
4283
- WorkspaceTaskMergeError = class extends Error {
4284
- constructor(message) {
4285
- super(message);
4286
- this.name = "WorkspaceTaskMergeError";
4287
- }
4288
- };
4289
- SHARED_STATE_SNAPSHOT_VERSION = 1;
4290
- COLUMN_LABELS = {
4291
- triage: "Planning",
4292
- todo: "Todo",
4293
- "in-progress": "In Progress",
4294
- "in-review": "In Review",
4295
- done: "Done",
4296
- archived: "Archived"
4297
- };
4298
- COLUMN_DESCRIPTIONS = {
4299
- triage: "Raw ideas \u2014 AI will plan these",
4300
- "in-progress": "AI is working on this in a worktree",
4301
- done: "Merged and closed",
4302
- archived: "Completed and archived"
4303
- };
4304
- VALID_TRANSITIONS = {
4305
- // FN-4892: intake-side heuristics may cold-archive tasks before execution starts.
4306
- triage: ["todo", "archived"],
4307
- // FN-4892: allow direct archival for newly specified intake tasks.
4308
- todo: ["in-progress", "triage", "archived"],
4309
- // NOTE: "in-progress" → "done" is enabled for mission validation tasks that complete directly.
4310
- // Regular implementation tasks should move through "in-review" before "done".
4311
- "in-progress": ["in-review", "todo", "triage", "done"],
4312
- "in-review": ["done", "in-progress", "todo", "triage"],
4313
- done: ["todo", "triage", "archived"],
4314
- archived: ["done"]
4315
- };
4316
4368
  }
4317
4369
  });
4318
4370
 
@@ -12933,6 +12985,7 @@ var init_project = __esm({
12933
12985
  paused: integer("paused").default(0),
12934
12986
  userPaused: integer("user_paused").default(0),
12935
12987
  pausedReason: text("paused_reason"),
12988
+ wedgeNotification: text("wedge_notification"),
12936
12989
  baseBranch: text("base_branch"),
12937
12990
  branch: text("branch"),
12938
12991
  autoMerge: integer("auto_merge"),
@@ -21297,6 +21350,9 @@ function validateColumns(ir2) {
21297
21350
  throw new WorkflowIrError(`Workflow IR has duplicate column id '${column.id}'`);
21298
21351
  }
21299
21352
  seen.add(column.id);
21353
+ if (column.description !== void 0 && typeof column.description !== "string") {
21354
+ throw new WorkflowIrError(`Workflow IR column '${column.id}' description must be a string`);
21355
+ }
21300
21356
  if (!Array.isArray(column.traits)) {
21301
21357
  throw new WorkflowIrError(`Workflow IR column '${column.id}' traits must be an array`);
21302
21358
  }
@@ -36520,6 +36576,7 @@ async function applySchemaBaseline(db, options = {}) {
36520
36576
  const legacyAdoptionDrainedMarkerRuntimeGrantsAlreadyApplied = applied.includes(
36521
36577
  LEGACY_ADOPTION_DRAINED_MARKER_RUNTIME_GRANTS_VERSION
36522
36578
  );
36579
+ const taskWedgeNotificationAlreadyApplied = applied.includes(TASK_WEDGE_NOTIFICATION_VERSION);
36523
36580
  assertBinaryNotOlderThanDatabase(applied);
36524
36581
  let schemaChanged = false;
36525
36582
  if (!baselineAlreadyApplied) {
@@ -36843,17 +36900,25 @@ async function applySchemaBaseline(db, options = {}) {
36843
36900
  );
36844
36901
  schemaChanged = true;
36845
36902
  }
36903
+ if (!taskWedgeNotificationAlreadyApplied) {
36904
+ const migrationSql = await readFile4(TASK_WEDGE_NOTIFICATION_MIGRATION_PATH, "utf8");
36905
+ await tx.execute(sql.raw(migrationSql));
36906
+ await tx.execute(
36907
+ sql`INSERT INTO public.${sql.identifier(MIGRATION_BOOKKEEPING_TABLE)} (version) VALUES (${TASK_WEDGE_NOTIFICATION_VERSION}) ON CONFLICT (version) DO NOTHING`
36908
+ );
36909
+ schemaChanged = true;
36910
+ }
36846
36911
  return { applied: schemaChanged, pluginHooksRun: pluginHooks.length };
36847
36912
  });
36848
36913
  }
36849
- var SCHEMA_BASELINE_VERSION, TASK_DECLARED_SYMBOLS_VERSION, INITIAL_SCHEMA_VERSION, AUTOMATION_ISOLATION_SCHEMA_VERSION, ANALYTICS_ISOLATION_SCHEMA_VERSION, MONITOR_APPROVAL_ISOLATION_SCHEMA_VERSION, LEGACY_CUTOVER_PRESERVATION_SCHEMA_VERSION, MULTI_PROJECT_CUTOVER_SCHEMA_VERSION, PROJECT_OWNERSHIP_SCHEMA_VERSION, SQLITE_SCHEMA_PARITY_VERSION, SESSION_ADVISOR_ENABLED_SCHEMA_VERSION, MISSION_FIX_IDEMPOTENCY_VERSION, IMPORT_TRANSLATION_CACHE_VERSION, IMPORT_TRANSLATION_CACHE_SCOPE_FIX_VERSION, IMPORT_TRANSLATION_CACHE_LEGACY_PARTITION_BACKFILL_VERSION, OWNER_PROJECT_ID_SPLIT_VERSION, CHAT_SESSION_PINS_VERSION, EXECUTOR_TOOL_FAILURE_RETRY_VERSION, EXECUTOR_ESCALATION_ATTEMPT_VERSION, GLOBAL_ROUTINES_SCHEMA_VERSION, TASK_MERGER_MODEL_LANE_VERSION, BULK_COMPLETION_REFUSAL_AT_VERSION, TASK_PROPOSAL_CLAIM_VERSION, CONFIGURATION_REVISIONS_VERSION, IDEATION_SCHEMA_VERSION, RESEARCH_FEATURE_PROVENANCE_VERSION, TASK_VERIFICATION_REQUEST_VERSION, SYMBOL_LOCKS_SCHEMA_VERSION, BIGINT_COUNTERS_VERSION, PLANNING_ACTIVE_TIMING_VERSION, SQLITE_MIGRATION_RUNTIME_READ_VERSION, WORKFLOW_TASK_CONTINUATIONS_VERSION, LEGACY_ADOPTION_DRAINED_MARKER_RUNTIME_GRANTS_VERSION, LEGACY_ADOPTION_DRAINED_MARKER_FUNCTION, StaleBinarySchemaError, MIGRATION_BOOKKEEPING_TABLE, LEGACY_ADOPTION_DRAINED_MARKER, __dirname, MIGRATIONS_DIR, BASELINE_MIGRATION_PATH, AUTOMATION_ISOLATION_MIGRATION_PATH, ANALYTICS_ISOLATION_MIGRATION_PATH, MONITOR_APPROVAL_ISOLATION_MIGRATION_PATH, LEGACY_CUTOVER_PRESERVATION_MIGRATION_PATH, MULTI_PROJECT_CUTOVER_MIGRATION_PATH, PROJECT_OWNERSHIP_MIGRATION_PATH, SQLITE_SCHEMA_PARITY_MIGRATION_PATH, SESSION_ADVISOR_ENABLED_MIGRATION_PATH, MISSION_FIX_IDEMPOTENCY_MIGRATION_PATH, IMPORT_TRANSLATION_CACHE_MIGRATION_PATH, IMPORT_TRANSLATION_CACHE_SCOPE_FIX_MIGRATION_PATH, IMPORT_TRANSLATION_CACHE_LEGACY_PARTITION_BACKFILL_MIGRATION_PATH, OWNER_PROJECT_ID_SPLIT_MIGRATION_PATH, CHAT_SESSION_PINS_MIGRATION_PATH, EXECUTOR_TOOL_FAILURE_RETRY_MIGRATION_PATH, EXECUTOR_ESCALATION_ATTEMPT_MIGRATION_PATH, GLOBAL_ROUTINES_MIGRATION_PATH, TASK_MERGER_MODEL_LANE_MIGRATION_PATH, BULK_COMPLETION_REFUSAL_AT_MIGRATION_PATH, TASK_PROPOSAL_CLAIM_MIGRATION_PATH, CONFIGURATION_REVISIONS_MIGRATION_PATH, IDEATION_MIGRATION_PATH, RESEARCH_FEATURE_PROVENANCE_MIGRATION_PATH, TASK_VERIFICATION_REQUEST_MIGRATION_PATH, SYMBOL_LOCKS_MIGRATION_PATH, BIGINT_COUNTERS_MIGRATION_PATH, WORKFLOW_IR_PIN_AND_LEGACY_ADOPTION_VERSION, WORKFLOW_IR_PIN_AND_LEGACY_ADOPTION_MIGRATION_PATH, PLANNING_ACTIVE_TIMING_MIGRATION_PATH, TASK_DECLARED_SYMBOLS_MIGRATION_PATH, SQLITE_MIGRATION_RUNTIME_READ_PATH, WORKFLOW_TASK_CONTINUATIONS_PATH, LEGACY_ADOPTION_DRAINED_MARKER_RUNTIME_GRANTS_PATH;
36914
+ var SCHEMA_BASELINE_VERSION, TASK_DECLARED_SYMBOLS_VERSION, INITIAL_SCHEMA_VERSION, AUTOMATION_ISOLATION_SCHEMA_VERSION, ANALYTICS_ISOLATION_SCHEMA_VERSION, MONITOR_APPROVAL_ISOLATION_SCHEMA_VERSION, LEGACY_CUTOVER_PRESERVATION_SCHEMA_VERSION, MULTI_PROJECT_CUTOVER_SCHEMA_VERSION, PROJECT_OWNERSHIP_SCHEMA_VERSION, SQLITE_SCHEMA_PARITY_VERSION, SESSION_ADVISOR_ENABLED_SCHEMA_VERSION, MISSION_FIX_IDEMPOTENCY_VERSION, IMPORT_TRANSLATION_CACHE_VERSION, IMPORT_TRANSLATION_CACHE_SCOPE_FIX_VERSION, IMPORT_TRANSLATION_CACHE_LEGACY_PARTITION_BACKFILL_VERSION, OWNER_PROJECT_ID_SPLIT_VERSION, CHAT_SESSION_PINS_VERSION, EXECUTOR_TOOL_FAILURE_RETRY_VERSION, EXECUTOR_ESCALATION_ATTEMPT_VERSION, GLOBAL_ROUTINES_SCHEMA_VERSION, TASK_MERGER_MODEL_LANE_VERSION, BULK_COMPLETION_REFUSAL_AT_VERSION, TASK_PROPOSAL_CLAIM_VERSION, CONFIGURATION_REVISIONS_VERSION, IDEATION_SCHEMA_VERSION, RESEARCH_FEATURE_PROVENANCE_VERSION, TASK_VERIFICATION_REQUEST_VERSION, SYMBOL_LOCKS_SCHEMA_VERSION, BIGINT_COUNTERS_VERSION, PLANNING_ACTIVE_TIMING_VERSION, SQLITE_MIGRATION_RUNTIME_READ_VERSION, WORKFLOW_TASK_CONTINUATIONS_VERSION, LEGACY_ADOPTION_DRAINED_MARKER_RUNTIME_GRANTS_VERSION, TASK_WEDGE_NOTIFICATION_VERSION, LEGACY_ADOPTION_DRAINED_MARKER_FUNCTION, StaleBinarySchemaError, MIGRATION_BOOKKEEPING_TABLE, LEGACY_ADOPTION_DRAINED_MARKER, __dirname, MIGRATIONS_DIR, BASELINE_MIGRATION_PATH, AUTOMATION_ISOLATION_MIGRATION_PATH, ANALYTICS_ISOLATION_MIGRATION_PATH, MONITOR_APPROVAL_ISOLATION_MIGRATION_PATH, LEGACY_CUTOVER_PRESERVATION_MIGRATION_PATH, MULTI_PROJECT_CUTOVER_MIGRATION_PATH, PROJECT_OWNERSHIP_MIGRATION_PATH, SQLITE_SCHEMA_PARITY_MIGRATION_PATH, SESSION_ADVISOR_ENABLED_MIGRATION_PATH, MISSION_FIX_IDEMPOTENCY_MIGRATION_PATH, IMPORT_TRANSLATION_CACHE_MIGRATION_PATH, IMPORT_TRANSLATION_CACHE_SCOPE_FIX_MIGRATION_PATH, IMPORT_TRANSLATION_CACHE_LEGACY_PARTITION_BACKFILL_MIGRATION_PATH, OWNER_PROJECT_ID_SPLIT_MIGRATION_PATH, CHAT_SESSION_PINS_MIGRATION_PATH, EXECUTOR_TOOL_FAILURE_RETRY_MIGRATION_PATH, EXECUTOR_ESCALATION_ATTEMPT_MIGRATION_PATH, GLOBAL_ROUTINES_MIGRATION_PATH, TASK_MERGER_MODEL_LANE_MIGRATION_PATH, BULK_COMPLETION_REFUSAL_AT_MIGRATION_PATH, TASK_PROPOSAL_CLAIM_MIGRATION_PATH, CONFIGURATION_REVISIONS_MIGRATION_PATH, IDEATION_MIGRATION_PATH, RESEARCH_FEATURE_PROVENANCE_MIGRATION_PATH, TASK_VERIFICATION_REQUEST_MIGRATION_PATH, SYMBOL_LOCKS_MIGRATION_PATH, BIGINT_COUNTERS_MIGRATION_PATH, WORKFLOW_IR_PIN_AND_LEGACY_ADOPTION_VERSION, WORKFLOW_IR_PIN_AND_LEGACY_ADOPTION_MIGRATION_PATH, PLANNING_ACTIVE_TIMING_MIGRATION_PATH, TASK_DECLARED_SYMBOLS_MIGRATION_PATH, SQLITE_MIGRATION_RUNTIME_READ_PATH, WORKFLOW_TASK_CONTINUATIONS_PATH, LEGACY_ADOPTION_DRAINED_MARKER_RUNTIME_GRANTS_PATH, TASK_WEDGE_NOTIFICATION_MIGRATION_PATH;
36850
36915
  var init_schema_applier = __esm({
36851
36916
  "../core/src/postgres/schema-applier.ts"() {
36852
36917
  "use strict";
36853
36918
  init_drizzle_orm();
36854
36919
  init_plugin_schema_hook();
36855
36920
  init_advisory_locks();
36856
- SCHEMA_BASELINE_VERSION = "0032";
36921
+ SCHEMA_BASELINE_VERSION = "0033";
36857
36922
  TASK_DECLARED_SYMBOLS_VERSION = "0028";
36858
36923
  INITIAL_SCHEMA_VERSION = "0000";
36859
36924
  AUTOMATION_ISOLATION_SCHEMA_VERSION = "0001";
@@ -36886,6 +36951,7 @@ var init_schema_applier = __esm({
36886
36951
  SQLITE_MIGRATION_RUNTIME_READ_VERSION = "0030";
36887
36952
  WORKFLOW_TASK_CONTINUATIONS_VERSION = "0031";
36888
36953
  LEGACY_ADOPTION_DRAINED_MARKER_RUNTIME_GRANTS_VERSION = "0032";
36954
+ TASK_WEDGE_NOTIFICATION_VERSION = "0033";
36889
36955
  LEGACY_ADOPTION_DRAINED_MARKER_FUNCTION = "fusion_mark_legacy_adoption_drained";
36890
36956
  StaleBinarySchemaError = class extends Error {
36891
36957
  constructor(databaseVersion, binaryVersion) {
@@ -36992,6 +37058,10 @@ var init_schema_applier = __esm({
36992
37058
  MIGRATIONS_DIR,
36993
37059
  "0032_legacy_adoption_drained_marker_runtime_grants.sql"
36994
37060
  );
37061
+ TASK_WEDGE_NOTIFICATION_MIGRATION_PATH = join8(
37062
+ MIGRATIONS_DIR,
37063
+ "0033_fn-8505_wedge_notification.sql"
37064
+ );
36995
37065
  }
36996
37066
  });
36997
37067
 
@@ -37382,6 +37452,7 @@ __export(sqlite_migrator_exports, {
37382
37452
  isSqliteMigrationComplete: () => isSqliteMigrationComplete,
37383
37453
  migrateLegacyProjectPluginRows: () => migrateLegacyProjectPluginRows,
37384
37454
  migrateSqliteToPostgres: () => migrateSqliteToPostgres,
37455
+ projectPluginSqliteMigrationKey: () => projectPluginSqliteMigrationKey,
37385
37456
  recordSqliteMigrationComplete: () => recordSqliteMigrationComplete,
37386
37457
  toSnakeCase: () => toSnakeCase2
37387
37458
  });
@@ -37924,7 +37995,12 @@ function normalizeLegacyJson(value, fallback) {
37924
37995
  return fallback;
37925
37996
  }
37926
37997
  }
37998
+ function projectPluginSqliteMigrationKey(projectPath) {
37999
+ return `project-plugins:${resolve6(projectPath)}`;
38000
+ }
37927
38001
  async function migrateLegacyProjectPluginRows(db, sqlitePath, projectPath) {
38002
+ const migrationKey = projectPluginSqliteMigrationKey(projectPath);
38003
+ if (await isSqliteMigrationComplete(db, migrationKey)) return;
37928
38004
  await db.transaction(async (tx) => {
37929
38005
  await migrateLegacyProjectPluginRowsOnSession(
37930
38006
  tx,
@@ -37934,19 +38010,14 @@ async function migrateLegacyProjectPluginRows(db, sqlitePath, projectPath) {
37934
38010
  });
37935
38011
  }
37936
38012
  async function migrateLegacyProjectPluginRowsOnSession(db, sqlitePath, projectPath) {
37937
- if (!sqliteTableExists(sqlitePath, "plugins")) return;
37938
- await acquireSqliteMigrationStateLock(db);
37939
38013
  const canonicalProjectPath = resolve6(projectPath);
37940
- const migrationKey = `project-plugins:${canonicalProjectPath}`;
38014
+ const migrationKey = projectPluginSqliteMigrationKey(projectPath);
38015
+ await acquireSqliteMigrationStateLock(db);
37941
38016
  await ensureMigrationStateTable(db);
37942
38017
  await db.execute(sql`SELECT pg_advisory_xact_lock(hashtextextended(${migrationKey}, 0))`);
37943
- const completed = await db.execute(sql`
37944
- SELECT 1 AS complete
37945
- FROM public.${sql.identifier(SQLITE_MIGRATION_STATE_TABLE)}
37946
- WHERE migration_key = ${migrationKey} AND status = 'complete'
37947
- LIMIT 1
37948
- `);
37949
- if (completed.length > 0) return;
38018
+ const completed = await isSqliteMigrationComplete(db, migrationKey);
38019
+ if (completed) return;
38020
+ if (!sqliteTableExists(sqlitePath, "plugins")) return;
37950
38021
  const sqlite = openSqlite(sqlitePath);
37951
38022
  let rows;
37952
38023
  try {
@@ -39032,6 +39103,17 @@ function buildPgCtlOptionsString(port, flags) {
39032
39103
  function buildPgCtlStartArgs(dataDir, logFile, optionsString) {
39033
39104
  return ["-D", dataDir, "-o", optionsString, "-l", logFile, "-W", "start"];
39034
39105
  }
39106
+ function withWindowsNativeBinPath(environment, nativeRoot, platform3 = process.platform) {
39107
+ if (platform3 !== "win32") return environment;
39108
+ const pathKey = Object.keys(environment).find((key) => key.toLowerCase() === "path") ?? "PATH";
39109
+ const bin = nativeRoot.replace(/[\\/]+$/, "") + "\\bin";
39110
+ const normalize8 = (value) => value.replace(/\//g, "\\").toLowerCase();
39111
+ const inherited = environment[pathKey] ?? "";
39112
+ const segments = inherited.split(";").filter(Boolean);
39113
+ const normalizedBin = normalize8(bin);
39114
+ const deduplicated = segments.filter((segment) => normalize8(segment) !== normalizedBin);
39115
+ return { ...environment, [pathKey]: [bin, ...deduplicated].join(";") };
39116
+ }
39035
39117
  function readPostgresPid(dataDir) {
39036
39118
  try {
39037
39119
  const lines = readFileSync3(join9(dataDir, "postmaster.pid"), "utf-8").split("\n");
@@ -39086,7 +39168,13 @@ async function startServerElevatedRestricted(opts) {
39086
39168
  `embedded postgres: elevated start via pg_ctl restricted token (no helper account); log ${logFile}`
39087
39169
  );
39088
39170
  let stopped = false;
39171
+ let logMonitor = null;
39172
+ const stopMonitoring = () => {
39173
+ if (logMonitor) clearInterval(logMonitor);
39174
+ logMonitor = null;
39175
+ };
39089
39176
  const killAll = () => {
39177
+ stopMonitoring();
39090
39178
  if (stopped) return;
39091
39179
  stopped = true;
39092
39180
  const r = spawnSync(pgCtl, ["-D", opts.dataDir, "-m", "fast", "-t", "30", "-w", "stop"], {
@@ -39120,14 +39208,21 @@ async function startServerElevatedRestricted(opts) {
39120
39208
  killAll();
39121
39209
  await waitForDown();
39122
39210
  },
39211
+ stopMonitoring,
39123
39212
  async stopWrapperOnly() {
39213
+ stopMonitoring();
39124
39214
  stopped = true;
39125
39215
  }
39126
39216
  };
39127
39217
  opts.onLaunched?.(handle);
39128
39218
  const launch = await new Promise(
39129
39219
  (resolve39, reject) => {
39130
- const child = spawn(pgCtl, args, { windowsHide: true });
39220
+ const child = spawn(pgCtl, args, {
39221
+ windowsHide: true,
39222
+ // Do not mutate process.env: sibling dashboard/engine children must
39223
+ // retain their inherited environment unchanged.
39224
+ env: withWindowsNativeBinPath(process.env, opts.nativeRoot)
39225
+ });
39131
39226
  let output = "";
39132
39227
  child.stdout.on("data", (d) => output += d.toString());
39133
39228
  child.stderr.on("data", (d) => output += d.toString());
@@ -39152,16 +39247,14 @@ ${readTail(logFile, 2e3)}`
39152
39247
  killAll();
39153
39248
  throw new Error("embedded postgres: elevated launch cancelled before ready.");
39154
39249
  }
39250
+ if (await probeTcpPort(opts.port, 500)) {
39251
+ ready = true;
39252
+ break;
39253
+ }
39155
39254
  const tail = readTail(logFile, 3e3);
39156
39255
  if (tail !== lastSnapshot) {
39157
39256
  lastSnapshot = tail;
39158
- opts.onLog(`elevated poll pg={${tail.slice(-400)}}`);
39159
- }
39160
- if (/database system is ready to accept connections/.test(tail)) {
39161
- if (await probeTcpPort(opts.port, 500)) {
39162
- ready = true;
39163
- break;
39164
- }
39257
+ opts.onLog(`elevated diagnostic pg={${tail.slice(-400)}}`);
39165
39258
  }
39166
39259
  if (/\bFATAL\b|\bPANIC\b|could not (bind|start|create|access|connect|load)|not permitted|Permission denied|is not the owner/i.test(tail)) {
39167
39260
  killAll();
@@ -39193,6 +39286,18 @@ ${tail}`
39193
39286
  opts.onLog(
39194
39287
  `embedded postgres: elevated server ready on 127.0.0.1:${opts.port} (pid ${postgresPid ?? 0}, restricted token)`
39195
39288
  );
39289
+ let lastLogSnapshot = "";
39290
+ const observePostReadyLog = () => {
39291
+ if (stopped) return;
39292
+ const snapshot = readTail(logFile, 16384);
39293
+ if (snapshot === "(no log file)" || snapshot === lastLogSnapshot) return;
39294
+ const next = snapshot.startsWith(lastLogSnapshot) ? snapshot.slice(lastLogSnapshot.length) : snapshot;
39295
+ lastLogSnapshot = snapshot;
39296
+ if (next) opts.onLog(next);
39297
+ };
39298
+ observePostReadyLog();
39299
+ logMonitor = setInterval(observePostReadyLog, 250);
39300
+ if (typeof logMonitor.unref === "function") logMonitor.unref();
39196
39301
  return handle;
39197
39302
  }
39198
39303
  function probeTcpPort(port, timeoutMs) {
@@ -39212,10 +39317,26 @@ function probeTcpPort(port, timeoutMs) {
39212
39317
  socket.once("error", () => finish(false));
39213
39318
  });
39214
39319
  }
39215
- var elevatedCache;
39320
+ var WindowsPostgresFatalDetector, elevatedCache;
39216
39321
  var init_embedded_windows_elevated = __esm({
39217
39322
  "../core/src/postgres/embedded-windows-elevated.ts"() {
39218
39323
  "use strict";
39324
+ WindowsPostgresFatalDetector = class {
39325
+ buffer = "";
39326
+ matched = false;
39327
+ push(chunk) {
39328
+ if (this.matched || !chunk) return false;
39329
+ this.buffer = (this.buffer + chunk).slice(-16384);
39330
+ const text2 = this.buffer.toLowerCase();
39331
+ if (/server process(?:\s+\(pid\s+\d+\))?\s+was terminated by exception\s+0xc0000142[\s\S]*?terminating any other active server processes[\s\S]*?shutting down due to startup process failure[\s\S]*?database system is shut down/.test(
39332
+ text2
39333
+ )) {
39334
+ this.matched = true;
39335
+ return true;
39336
+ }
39337
+ return false;
39338
+ }
39339
+ };
39219
39340
  elevatedCache = null;
39220
39341
  }
39221
39342
  });
@@ -39225,10 +39346,14 @@ var embedded_lifecycle_exports = {};
39225
39346
  __export(embedded_lifecycle_exports, {
39226
39347
  DEFAULT_EMBEDDED_DATABASE: () => DEFAULT_EMBEDDED_DATABASE,
39227
39348
  DEFAULT_EMBEDDED_INITDB_FLAGS: () => DEFAULT_EMBEDDED_INITDB_FLAGS,
39349
+ DEFAULT_EMBEDDED_MAX_CONNECTIONS: () => DEFAULT_EMBEDDED_MAX_CONNECTIONS,
39350
+ DEFAULT_EMBEDDED_MAX_CONNECTIONS_WIN32: () => DEFAULT_EMBEDDED_MAX_CONNECTIONS_WIN32,
39228
39351
  DEFAULT_EMBEDDED_PASSWORD: () => DEFAULT_EMBEDDED_PASSWORD,
39229
39352
  DEFAULT_EMBEDDED_POSTGRES_FLAGS: () => DEFAULT_EMBEDDED_POSTGRES_FLAGS,
39230
39353
  DEFAULT_EMBEDDED_USER: () => DEFAULT_EMBEDDED_USER,
39231
39354
  DEFAULT_START_TIMEOUT_MS: () => DEFAULT_START_TIMEOUT_MS,
39355
+ EMBEDDED_MAX_CONNECTIONS_MAX: () => EMBEDDED_MAX_CONNECTIONS_MAX,
39356
+ EMBEDDED_MAX_CONNECTIONS_MIN: () => EMBEDDED_MAX_CONNECTIONS_MIN,
39232
39357
  EmbeddedPostgresLifecycle: () => EmbeddedPostgresLifecycle,
39233
39358
  EmbeddedStartTimeoutError: () => EmbeddedStartTimeoutError,
39234
39359
  __setEmbeddedPostgresCtorForTests: () => __setEmbeddedPostgresCtorForTests,
@@ -39247,6 +39372,7 @@ __export(embedded_lifecycle_exports, {
39247
39372
  normalizeMacosEmbeddedPostgresDylibSymlinks: () => normalizeMacosEmbeddedPostgresDylibSymlinks,
39248
39373
  readPortFromPostmasterPid: () => readPortFromPostmasterPid,
39249
39374
  resolveElectronAsarUnpackedPath: () => resolveElectronAsarUnpackedPath,
39375
+ resolveEmbeddedMaxConnections: () => resolveEmbeddedMaxConnections,
39250
39376
  uninstallElectronAsarNativePathPatchForTests: () => uninstallElectronAsarNativePathPatchForTests
39251
39377
  });
39252
39378
  import {
@@ -39456,6 +39582,23 @@ function materializeEmbeddedPostgresRuntimeBinaries(nativeRoot, options) {
39456
39582
  writeFileSync2(marker, sourceMarker, "utf8");
39457
39583
  return destRoot;
39458
39584
  }
39585
+ function isWindowsEmbeddedPostgresBinary(command) {
39586
+ return process.platform === "win32" && typeof command === "string" && /[\\/]bin[\\/](?:postgres|initdb|pg_ctl)\.exe$/i.test(command);
39587
+ }
39588
+ function withWindowsPostgresSpawnEnvironment(command, rest) {
39589
+ if (!isWindowsEmbeddedPostgresBinary(command)) return rest;
39590
+ const args = [...rest];
39591
+ const optionIndex = args.length - 1;
39592
+ const existing = args[optionIndex];
39593
+ if (!existing || typeof existing !== "object" || Array.isArray(existing)) return args;
39594
+ const binDir = dirname6(command);
39595
+ const nativeRoot = dirname6(binDir);
39596
+ args[optionIndex] = {
39597
+ ...existing,
39598
+ env: withWindowsNativeBinPath(existing.env ?? process.env, nativeRoot)
39599
+ };
39600
+ return args;
39601
+ }
39459
39602
  function installElectronAsarNativePathPatch() {
39460
39603
  if (electronAsarNativePathPatchInstalled) return;
39461
39604
  electronAsarNativePathPatchInstalled = true;
@@ -39473,7 +39616,10 @@ function installElectronAsarNativePathPatch() {
39473
39616
  const originalSpawn = childProcessMod.spawn.bind(childProcessMod);
39474
39617
  childProcessMod.spawn = (command, ...rest) => {
39475
39618
  const fixedCommand = typeof command === "string" ? resolveElectronAsarUnpackedPath(command) : command;
39476
- return originalSpawn(fixedCommand, ...rest);
39619
+ return originalSpawn(
39620
+ fixedCommand,
39621
+ ...withWindowsPostgresSpawnEnvironment(fixedCommand, rest)
39622
+ );
39477
39623
  };
39478
39624
  const fsPromisesMod = require2("fs/promises");
39479
39625
  const originalStat = fsPromisesMod.stat.bind(fsPromisesMod);
@@ -39522,6 +39668,12 @@ function getEmbeddedPostgresCtor() {
39522
39668
  function defaultEmbeddedPostgresFlagsFor(platform3) {
39523
39669
  return platform3 === "win32" ? [] : ["-c", "shared_memory_type=mmap"];
39524
39670
  }
39671
+ function resolveEmbeddedMaxConnections(configured, platform3 = process.platform) {
39672
+ if (typeof configured === "number" && Number.isInteger(configured)) {
39673
+ return Math.min(EMBEDDED_MAX_CONNECTIONS_MAX, Math.max(EMBEDDED_MAX_CONNECTIONS_MIN, configured));
39674
+ }
39675
+ return platform3 === "win32" ? DEFAULT_EMBEDDED_MAX_CONNECTIONS_WIN32 : DEFAULT_EMBEDDED_MAX_CONNECTIONS;
39676
+ }
39525
39677
  function defaultEmbeddedDataDir() {
39526
39678
  const home = process.env.HOME || process.env.USERPROFILE || process.cwd();
39527
39679
  return join10(home, ".fusion", "embedded-postgres", "default");
@@ -39708,7 +39860,7 @@ function signalNumber(signal) {
39708
39860
  return 0;
39709
39861
  }
39710
39862
  }
39711
- var require2, stagedEmbeddedPgBundleCache, EMBEDDED_PG_BIN_NAMES, MATERIALIZATION_MARKER_VERSION, electronAsarNativePathPatchInstalled, electronAsarNativePathPatchRestore, embeddedPostgresCtorCache, embeddedPostgresCtorIsTestOverride, windowsElevatedAdminForTests, windowsNativeRootForTests, windowsLauncherForTests, log4, DEFAULT_EMBEDDED_USER, DEFAULT_EMBEDDED_PASSWORD, DEFAULT_EMBEDDED_DATABASE, DEFAULT_EMBEDDED_POSTGRES_FLAGS, DEFAULT_EMBEDDED_INITDB_FLAGS, DEFAULT_START_TIMEOUT_MS, PG_VERSION_FILENAME, MACOS_EMBEDDED_DYLIB_SYMLINKS, runningInstances, POSTMASTER_PID_READ_ATTEMPTS, POSTMASTER_PID_READ_RETRY_MS, EmbeddedPostgresLifecycle, EmbeddedStartCancelledError, EmbeddedStartTimeoutError;
39863
+ var require2, stagedEmbeddedPgBundleCache, EMBEDDED_PG_BIN_NAMES, MATERIALIZATION_MARKER_VERSION, electronAsarNativePathPatchInstalled, electronAsarNativePathPatchRestore, embeddedPostgresCtorCache, embeddedPostgresCtorIsTestOverride, windowsElevatedAdminForTests, windowsNativeRootForTests, windowsLauncherForTests, log4, DEFAULT_EMBEDDED_USER, DEFAULT_EMBEDDED_PASSWORD, DEFAULT_EMBEDDED_DATABASE, DEFAULT_EMBEDDED_POSTGRES_FLAGS, DEFAULT_EMBEDDED_MAX_CONNECTIONS, DEFAULT_EMBEDDED_MAX_CONNECTIONS_WIN32, EMBEDDED_MAX_CONNECTIONS_MIN, EMBEDDED_MAX_CONNECTIONS_MAX, DEFAULT_EMBEDDED_INITDB_FLAGS, DEFAULT_START_TIMEOUT_MS, PG_VERSION_FILENAME, MACOS_EMBEDDED_DYLIB_SYMLINKS, runningInstances, POSTMASTER_PID_READ_ATTEMPTS, POSTMASTER_PID_READ_RETRY_MS, EmbeddedPostgresLifecycle, EmbeddedStartCancelledError, EmbeddedStartTimeoutError;
39712
39864
  var init_embedded_lifecycle = __esm({
39713
39865
  "../core/src/postgres/embedded-lifecycle.ts"() {
39714
39866
  "use strict";
@@ -39739,6 +39891,10 @@ var init_embedded_lifecycle = __esm({
39739
39891
  DEFAULT_EMBEDDED_PASSWORD = "password";
39740
39892
  DEFAULT_EMBEDDED_DATABASE = "fusion";
39741
39893
  DEFAULT_EMBEDDED_POSTGRES_FLAGS = defaultEmbeddedPostgresFlagsFor(process.platform);
39894
+ DEFAULT_EMBEDDED_MAX_CONNECTIONS = 500;
39895
+ DEFAULT_EMBEDDED_MAX_CONNECTIONS_WIN32 = 150;
39896
+ EMBEDDED_MAX_CONNECTIONS_MIN = 32;
39897
+ EMBEDDED_MAX_CONNECTIONS_MAX = 2e3;
39742
39898
  DEFAULT_EMBEDDED_INITDB_FLAGS = [
39743
39899
  "--encoding=UTF8",
39744
39900
  "--locale=C"
@@ -39781,6 +39937,10 @@ var init_embedded_lifecycle = __esm({
39781
39937
  * on a failure that is handled before the timeout fires.
39782
39938
  */
39783
39939
  startTimer = null;
39940
+ windowsFatalDetector = new WindowsPostgresFatalDetector();
39941
+ recoveryAttempts = 0;
39942
+ recoveryInFlight = null;
39943
+ stopRequested = false;
39784
39944
  constructor(opts) {
39785
39945
  this.options = {
39786
39946
  dataDir: opts.dataDir,
@@ -39795,6 +39955,15 @@ var init_embedded_lifecycle = __esm({
39795
39955
  onError: opts.onError ?? ((err) => log4.error(String(err)))
39796
39956
  };
39797
39957
  }
39958
+ /**
39959
+ * Forward native process output to the existing sink, then schedule recovery
39960
+ * only for a confirmed owned Windows fatal shutdown sequence.
39961
+ */
39962
+ forwardPostgresLog = (message) => {
39963
+ this.options.onLog(message);
39964
+ if (process.platform !== "win32" || !this.running || !this.ownsProcess) return;
39965
+ if (this.windowsFatalDetector.push(message)) void this.recoverWindowsFatalOnce();
39966
+ };
39798
39967
  /** The configured or discovered port. Undefined until assigned (explicit or discovered in `start()`). */
39799
39968
  getPort() {
39800
39969
  return this.options.port ?? this.resolvedPort;
@@ -39891,11 +40060,19 @@ var init_embedded_lifecycle = __esm({
39891
40060
  migrationUrlOverridden: false
39892
40061
  };
39893
40062
  }
40063
+ return this.startBounded();
40064
+ }
40065
+ /**
40066
+ * Start an owned postmaster with the same cancellation and timeout contract
40067
+ * used by public startup. Recovery calls this directly because it must not
40068
+ * join a stale pid file or allocate a new endpoint between pool reconnects.
40069
+ */
40070
+ async startBounded(preferredPort) {
39894
40071
  if (this.options.startTimeoutMs <= 0) {
39895
- return this.startInternal();
40072
+ return this.startInternal(void 0, preferredPort);
39896
40073
  }
39897
40074
  const controller = new AbortController();
39898
- const startAttempt = this.startInternal(controller.signal);
40075
+ const startAttempt = this.startInternal(controller.signal, preferredPort);
39899
40076
  let timer2;
39900
40077
  const timeout = new Promise((_resolve, reject) => {
39901
40078
  timer2 = setTimeout(() => {
@@ -39921,12 +40098,9 @@ var init_embedded_lifecycle = __esm({
39921
40098
  this.startTimer = null;
39922
40099
  }
39923
40100
  }
39924
- /**
39925
- * The actual start sequence, with no timeout wrapper. Called by {@link start}
39926
- * either directly (timeout disabled) or via Promise.race with the timeout.
39927
- */
39928
- async startInternal(signal) {
39929
- const port = this.options.port ?? await findFreePort();
40101
+ /** The actual start sequence, invoked only through {@link startBounded}. */
40102
+ async startInternal(signal, preferredPort) {
40103
+ const port = this.options.port ?? preferredPort ?? this.resolvedPort ?? await findFreePort();
39930
40104
  if (signal?.aborted) throw new EmbeddedStartCancelledError(this.options.dataDir);
39931
40105
  this.resolvedPort = port;
39932
40106
  const alreadyInitialized = isDataDirInitialized(this.options.dataDir);
@@ -39940,7 +40114,7 @@ var init_embedded_lifecycle = __esm({
39940
40114
  authMethod: "password",
39941
40115
  initdbFlags: [...this.options.initdbFlags],
39942
40116
  postgresFlags: [...this.options.postgresFlags],
39943
- onLog: this.options.onLog,
40117
+ onLog: this.forwardPostgresLog,
39944
40118
  onError: this.options.onError
39945
40119
  });
39946
40120
  this.pg = pg;
@@ -39972,7 +40146,7 @@ var init_embedded_lifecycle = __esm({
39972
40146
  dataDir: this.options.dataDir,
39973
40147
  port,
39974
40148
  postgresFlags: this.options.postgresFlags,
39975
- onLog: this.options.onLog,
40149
+ onLog: this.forwardPostgresLog,
39976
40150
  onError: this.options.onError,
39977
40151
  startTimeoutMs: this.options.startTimeoutMs,
39978
40152
  signal,
@@ -40050,6 +40224,43 @@ var init_embedded_lifecycle = __esm({
40050
40224
  migrationUrlOverridden: false
40051
40225
  };
40052
40226
  }
40227
+ /**
40228
+ * FNXC:PostgresEmbedded 2026-07-22-16:25:
40229
+ * A 0xC0000142 backend crash shuts down its whole PostgreSQL cluster. One
40230
+ * lifecycle-owned retry reuses the initialized directory and same resolved
40231
+ * port; joiners, stop/detach, and a second incident are deliberately inert.
40232
+ */
40233
+ async recoverWindowsFatalOnce() {
40234
+ if (this.recoveryInFlight || this.recoveryAttempts >= 1 || this.stopRequested || !this.ownsProcess) return;
40235
+ this.recoveryAttempts += 1;
40236
+ this.recoveryInFlight = (async () => {
40237
+ this.options.onLog("embedded postgres: detected Windows DLL initialization shutdown; attempting one owned-cluster recovery");
40238
+ try {
40239
+ if (this.nonAdminHandle) await this.nonAdminHandle.stop();
40240
+ else await this.pg?.stop();
40241
+ this.pg = null;
40242
+ this.nonAdminHandle = null;
40243
+ this.running = false;
40244
+ runningInstances.delete(this.options.dataDir);
40245
+ if (this.stopRequested || !this.ownsProcess) return;
40246
+ const recoveryPort = this.resolvedPort;
40247
+ if (recoveryPort === void 0) {
40248
+ throw new Error("embedded postgres: recovery lost its resolved port");
40249
+ }
40250
+ await this.startBounded(recoveryPort);
40251
+ this.options.onLog("embedded postgres: Windows owned-cluster recovery completed; existing pools may reconnect");
40252
+ } catch (error2) {
40253
+ this.running = false;
40254
+ runningInstances.delete(this.options.dataDir);
40255
+ this.options.onError(
40256
+ `embedded postgres: Windows DLL initialization recovery failed after one retry; restart Fusion and inspect the System log. ${error2 instanceof Error ? error2.message : String(error2)}`
40257
+ );
40258
+ } finally {
40259
+ this.recoveryInFlight = null;
40260
+ }
40261
+ })();
40262
+ await this.recoveryInFlight;
40263
+ }
40053
40264
  async settleCancelledStart(pg) {
40054
40265
  if (this.nonAdminHandle) {
40055
40266
  try {
@@ -40196,6 +40407,7 @@ var init_embedded_lifecycle = __esm({
40196
40407
  */
40197
40408
  detachWithoutStop() {
40198
40409
  this.uninstallShutdownHook();
40410
+ this.nonAdminHandle?.stopMonitoring();
40199
40411
  this.pg = null;
40200
40412
  this.nonAdminHandle = null;
40201
40413
  this.running = false;
@@ -40203,6 +40415,7 @@ var init_embedded_lifecycle = __esm({
40203
40415
  runningInstances.delete(this.options.dataDir);
40204
40416
  }
40205
40417
  async stop() {
40418
+ this.stopRequested = true;
40206
40419
  this.uninstallShutdownHook();
40207
40420
  if (!this.ownsProcess) {
40208
40421
  this.running = false;
@@ -52227,10 +52440,10 @@ async function bootSchemaBackendOnce(options, bypassProjectIsolation = false) {
52227
52440
  let resolvedBackend = backend;
52228
52441
  let embeddedDataDir = null;
52229
52442
  if (backend.mode === "embedded") {
52230
- const { EmbeddedPostgresLifecycle: EmbeddedPostgresLifecycle2, defaultEmbeddedDataDir: defaultEmbeddedDataDir2, DEFAULT_EMBEDDED_DATABASE: DEFAULT_EMBEDDED_DATABASE2 } = await Promise.resolve().then(() => (init_embedded_lifecycle(), embedded_lifecycle_exports));
52443
+ const { EmbeddedPostgresLifecycle: EmbeddedPostgresLifecycle2, defaultEmbeddedDataDir: defaultEmbeddedDataDir2, DEFAULT_EMBEDDED_DATABASE: DEFAULT_EMBEDDED_DATABASE2, resolveEmbeddedMaxConnections: resolveEmbeddedMaxConnections2 } = await Promise.resolve().then(() => (init_embedded_lifecycle(), embedded_lifecycle_exports));
52231
52444
  const { GlobalSettingsStore: GlobalSettingsStore2 } = await Promise.resolve().then(() => (init_global_settings(), global_settings_exports));
52232
52445
  const configuredMaxConnections = process.env.VITEST === "true" && !options.globalSettingsDir ? void 0 : (await new GlobalSettingsStore2(options.globalSettingsDir).getSettings()).embeddedPostgresMaxConnections;
52233
- const maxConnections = Number.isInteger(configuredMaxConnections) ? Math.min(2e3, Math.max(32, configuredMaxConnections)) : 500;
52446
+ const maxConnections = resolveEmbeddedMaxConnections2(configuredMaxConnections);
52234
52447
  const dataDir = resolve8(options.embeddedDataDir ?? defaultEmbeddedDataDir2());
52235
52448
  embeddedDataDir = dataDir;
52236
52449
  log5.log(`startup-factory: starting embedded PostgreSQL (data dir ${dataDir})`);
@@ -52467,7 +52680,20 @@ async function createTaskStoreForBackend(options) {
52467
52680
  try {
52468
52681
  const fusionDir = join16(rootDir, ".fusion");
52469
52682
  const legacySqlitePath = join16(fusionDir, "fusion.db");
52470
- if (existsSync11(legacySqlitePath)) {
52683
+ const {
52684
+ migrateSqliteToPostgres: migrateSqliteToPostgres2,
52685
+ defaultMigrationSources: defaultMigrationSources2,
52686
+ formatMigrationProgress: formatMigrationProgress2,
52687
+ isSqliteMigrationComplete: isSqliteMigrationComplete2,
52688
+ completeSqliteMigration: completeSqliteMigration2,
52689
+ recordSqliteMigrationComplete: recordSqliteMigrationComplete2,
52690
+ CENTRAL_SQLITE_MIGRATION_KEY: CENTRAL_SQLITE_MIGRATION_KEY2
52691
+ } = await Promise.resolve().then(() => (init_sqlite_migrator(), sqlite_migrator_exports));
52692
+ const fallbackProjectId = fallbackProjectIdForRoot(rootDir);
52693
+ let migrationProjectId = options.projectId ?? await lookupRegisteredProjectIdByPath(connections.migration, rootDir) ?? fallbackProjectId;
52694
+ let migrationKey = `project:${migrationProjectId}`;
52695
+ let migrationComplete = await isSqliteMigrationComplete2(connections.migration, migrationKey);
52696
+ if (!migrationComplete && existsSync11(legacySqlitePath)) {
52471
52697
  let globalDir = options.globalSettingsDir;
52472
52698
  if (!globalDir) {
52473
52699
  try {
@@ -52477,21 +52703,24 @@ async function createTaskStoreForBackend(options) {
52477
52703
  globalDir = void 0;
52478
52704
  }
52479
52705
  }
52480
- let migrationProjectId = options.projectId ?? await lookupRegisteredProjectIdByPath(connections.migration, rootDir);
52706
+ let resolvedFromLegacyCentral = false;
52707
+ const centralMigrationComplete = await isSqliteMigrationComplete2(
52708
+ connections.migration,
52709
+ CENTRAL_SQLITE_MIGRATION_KEY2
52710
+ );
52481
52711
  const legacyCentralPath = globalDir ? join16(globalDir, "fusion-central.db") : void 0;
52482
- if (!migrationProjectId && legacyCentralPath && existsSync11(legacyCentralPath) && isValidSqliteDatabaseFile(legacyCentralPath)) {
52712
+ if (!centralMigrationComplete && migrationProjectId === fallbackProjectId && legacyCentralPath && existsSync11(legacyCentralPath) && isValidSqliteDatabaseFile(legacyCentralPath)) {
52483
52713
  const { DatabaseSync: DatabaseSync2 } = await Promise.resolve().then(() => (init_sqlite_adapter(), sqlite_adapter_exports));
52484
52714
  const legacyCentral = new DatabaseSync2(legacyCentralPath, { readOnly: true });
52485
52715
  try {
52486
52716
  const row = legacyCentral.prepare(`SELECT id FROM projects WHERE path = ? LIMIT 1`).get(rootDir);
52487
- migrationProjectId = row?.id;
52717
+ migrationProjectId = row?.id ?? migrationProjectId;
52718
+ resolvedFromLegacyCentral = Boolean(row?.id);
52488
52719
  } catch {
52489
52720
  } finally {
52490
52721
  legacyCentral.close();
52491
52722
  }
52492
52723
  }
52493
- const fallbackProjectId = fallbackProjectIdForRoot(rootDir);
52494
- migrationProjectId ??= fallbackProjectId;
52495
52724
  if (migrationProjectId !== fallbackProjectId) {
52496
52725
  try {
52497
52726
  await rekeyFallbackProjectPartition(connections.migration, fallbackProjectId, migrationProjectId);
@@ -52507,14 +52736,9 @@ async function createTaskStoreForBackend(options) {
52507
52736
  }
52508
52737
  }
52509
52738
  }
52510
- const migrationKey = `project:${migrationProjectId ?? rootDir}`;
52511
- const { migrateSqliteToPostgres: migrateSqliteToPostgres2, migrateLegacyProjectPluginRows: migrateLegacyProjectPluginRows2, defaultMigrationSources: defaultMigrationSources2, formatMigrationProgress: formatMigrationProgress2, isSqliteMigrationComplete: isSqliteMigrationComplete2, completeSqliteMigration: completeSqliteMigration2, recordSqliteMigrationComplete: recordSqliteMigrationComplete2, CENTRAL_SQLITE_MIGRATION_KEY: CENTRAL_SQLITE_MIGRATION_KEY2 } = await Promise.resolve().then(() => (init_sqlite_migrator(), sqlite_migrator_exports));
52512
- const migrationComplete = await isSqliteMigrationComplete2(connections.migration, migrationKey);
52739
+ migrationKey = `project:${migrationProjectId}`;
52740
+ migrationComplete = await isSqliteMigrationComplete2(connections.migration, migrationKey);
52513
52741
  if (!migrationComplete && isValidSqliteDatabaseFile(legacySqlitePath)) {
52514
- const centralMigrationComplete = await isSqliteMigrationComplete2(
52515
- connections.migration,
52516
- CENTRAL_SQLITE_MIGRATION_KEY2
52517
- );
52518
52742
  const sources = defaultMigrationSources2(fusionDir, globalDir ?? join16(fusionDir, "__no-global-dir__")).filter((source) => !centralMigrationComplete || source.pgSchema !== "central").filter((source) => existsSync11(source.sqlitePath) && isValidSqliteDatabaseFile(source.sqlitePath));
52519
52743
  if (sources.length > 0) {
52520
52744
  log5.log(`startup-factory: empty PostgreSQL database with legacy SQLite data present \u2014 auto-migrating ${sources.length} source(s) (SQLite files are kept as backups)`);
@@ -52549,6 +52773,12 @@ async function createTaskStoreForBackend(options) {
52549
52773
  rootDir
52550
52774
  });
52551
52775
  }
52776
+ if (resolvedFromLegacyCentral) {
52777
+ const registeredId = await lookupRegisteredProjectIdByPath(connections.migration, rootDir);
52778
+ if (registeredId !== migrationProjectId) {
52779
+ throw new Error(`legacy project identity ${migrationProjectId} was not materialized for ${rootDir} before migration completion`);
52780
+ }
52781
+ }
52552
52782
  await completeSqliteMigration2(connections.migration, migrationKey);
52553
52783
  if (sources.some((source) => source.pgSchema === "central")) {
52554
52784
  await recordSqliteMigrationComplete2(
@@ -52566,14 +52796,9 @@ async function createTaskStoreForBackend(options) {
52566
52796
  log5.log(`startup-factory: SQLite \u2192 PostgreSQL auto-migration complete (${migratedRows} row(s) across ${report.tables.length} table(s))`);
52567
52797
  }
52568
52798
  }
52569
- if (isValidSqliteDatabaseFile(legacySqlitePath)) {
52570
- await migrateLegacyProjectPluginRows2(
52571
- connections.migration,
52572
- legacySqlitePath,
52573
- rootDir
52574
- );
52575
- }
52576
52799
  }
52800
+ const { migrateLegacyProjectPluginRows: migrateLegacyProjectPluginRows2 } = await Promise.resolve().then(() => (init_sqlite_migrator(), sqlite_migrator_exports));
52801
+ await migrateLegacyProjectPluginRows2(connections.migration, legacySqlitePath, rootDir);
52577
52802
  } catch (err) {
52578
52803
  await connections.close().catch(() => void 0);
52579
52804
  await stopEmbeddedRuntime(
@@ -62240,6 +62465,7 @@ var init_persistence = __esm({
62240
62465
  defineTaskColumn("overlapBlockedBy", (task) => task.overlapBlockedBy ?? null),
62241
62466
  defineTaskColumn("paused", (task) => task.paused ? 1 : 0),
62242
62467
  defineTaskColumn("pausedReason", (task) => task.pausedReason ?? null),
62468
+ defineTaskColumn("wedgeNotification", (task) => toJsonNullable(task.wedgeNotification)),
62243
62469
  defineTaskColumn("userPaused", (task) => task.userPaused ? 1 : 0),
62244
62470
  defineTaskColumn("baseBranch", (task) => task.baseBranch ?? null),
62245
62471
  defineTaskColumn("branch", (task) => task.branch ?? null),
@@ -62649,6 +62875,7 @@ function rowToTask(row) {
62649
62875
  overlapBlockedBy: row.overlapBlockedBy || void 0,
62650
62876
  paused: row.paused ? true : void 0,
62651
62877
  pausedReason: row.pausedReason || void 0,
62878
+ wedgeNotification: fromJson(row.wedgeNotification) ?? void 0,
62652
62879
  userPaused: row.userPaused ? true : void 0,
62653
62880
  baseBranch: row.baseBranch || void 0,
62654
62881
  executionStartBranch: row.executionStartBranch || void 0,
@@ -84904,6 +85131,7 @@ function getTaskSelectClauseImpl2(store, slim, tableAlias) {
84904
85131
  "overlapBlockedBy",
84905
85132
  "paused",
84906
85133
  "pausedReason",
85134
+ "wedgeNotification",
84907
85135
  "userPaused",
84908
85136
  "baseBranch",
84909
85137
  "branch",
@@ -91622,7 +91850,7 @@ var init_async_eval_store = __esm({
91622
91850
  }
91623
91851
  });
91624
91852
 
91625
- // ../core/src/task-store/remaining-ops-1.ts
91853
+ // ../core/src/task-store/project-store-ops.ts
91626
91854
  import { randomUUID as randomUUID33 } from "node:crypto";
91627
91855
  import { mkdir as mkdir13, writeFile as writeFile12 } from "node:fs/promises";
91628
91856
  import { join as join33 } from "node:path";
@@ -92490,8 +92718,8 @@ function getEvalStoreImpl(store) {
92490
92718
  return store.evalStore;
92491
92719
  }
92492
92720
  var workflowDefinitionBeforeInsertForTesting;
92493
- var init_remaining_ops_1 = __esm({
92494
- "../core/src/task-store/remaining-ops-1.ts"() {
92721
+ var init_project_store_ops = __esm({
92722
+ "../core/src/task-store/project-store-ops.ts"() {
92495
92723
  "use strict";
92496
92724
  init_store();
92497
92725
  init_errors3();
@@ -99191,6 +99419,11 @@ async function updateTaskUnlockedImpl(store, id, updates, runContext) {
99191
99419
  } else if (updates.pausedReason !== void 0) {
99192
99420
  task.pausedReason = updates.pausedReason;
99193
99421
  }
99422
+ if (updates.wedgeNotification === null) {
99423
+ task.wedgeNotification = void 0;
99424
+ } else if (updates.wedgeNotification !== void 0) {
99425
+ task.wedgeNotification = updates.wedgeNotification;
99426
+ }
99194
99427
  if (updates.tokenBudgetSoftAlertedAt === null) {
99195
99428
  task.tokenBudgetSoftAlertedAt = void 0;
99196
99429
  } else if (updates.tokenBudgetSoftAlertedAt !== void 0) {
@@ -99853,7 +100086,7 @@ var init_store = __esm({
99853
100086
  init_task_store_helpers();
99854
100087
  init_task_row_mappers();
99855
100088
  init_task_mutation_ops();
99856
- init_remaining_ops_1();
100089
+ init_project_store_ops();
99857
100090
  init_workflow_integrity();
99858
100091
  init_branch_group_ops();
99859
100092
  init_archive_lifecycle_2();
@@ -100717,6 +100950,26 @@ var init_store = __esm({
100717
100950
  async updateTask(id, updates, runContext) {
100718
100951
  return updateTaskImpl(this, id, updates, runContext);
100719
100952
  }
100953
+ /**
100954
+ * Atomically opens or resolves the durable task-wedge episode. The task lock is
100955
+ * shared by SQLite and PostgreSQL persistence writes, so concurrent engine
100956
+ * observers cannot allocate two episodes for one active normalized reason.
100957
+ */
100958
+ async claimTaskWedgeNotificationEpisode(taskId, reasonKey) {
100959
+ let result = { claimed: false };
100960
+ await this.updateTaskAtomic(taskId, (current) => {
100961
+ const prior = current.wedgeNotification;
100962
+ if (reasonKey === null) {
100963
+ if (!prior || prior.status === "resolved") return null;
100964
+ return { wedgeNotification: { ...prior, status: "resolved", transitionedAt: (/* @__PURE__ */ new Date()).toISOString() } };
100965
+ }
100966
+ if (prior?.status === "active" && prior.reasonKey === reasonKey) return null;
100967
+ const episodeId = randomUUID37();
100968
+ result = { episodeId, claimed: true };
100969
+ return { wedgeNotification: { reasonKey, episodeId, status: "active", transitionedAt: (/* @__PURE__ */ new Date()).toISOString() } };
100970
+ });
100971
+ return result;
100972
+ }
100720
100973
  async claimNextToolFailureRetry(taskId, expectedCursor, maxRetries) {
100721
100974
  return claimNextToolFailureRetryImpl(this, taskId, expectedCursor, maxRetries);
100722
100975
  }
@@ -163344,6 +163597,7 @@ var init_ntfy_provider = __esm({
163344
163597
  "in-review",
163345
163598
  "merged",
163346
163599
  "failed",
163600
+ "task-wedged",
163347
163601
  "awaiting-approval",
163348
163602
  "awaiting-user-review",
163349
163603
  "planning-awaiting-input",
@@ -163447,6 +163701,15 @@ var init_ntfy_provider = __esm({
163447
163701
  message: `Task "${identifier}" has failed and needs attention`,
163448
163702
  priority: "high"
163449
163703
  },
163704
+ "task-wedged": {
163705
+ title: `Task ${taskId} needs operator action`,
163706
+ message: [
163707
+ `Task "${identifier}" is wedged${typeof payload.metadata?.reason === "string" ? `: ${payload.metadata.reason}` : " and needs operator action"}`,
163708
+ typeof payload.metadata?.gate === "string" ? `Gate: ${payload.metadata.gate}` : null,
163709
+ typeof payload.metadata?.action === "string" ? `Recommended action: ${payload.metadata.action}` : null
163710
+ ].filter((part) => part !== null).join("\n"),
163711
+ priority: "high"
163712
+ },
163450
163713
  "awaiting-approval": {
163451
163714
  title: payload.metadata?.awaitingApprovalReason === "plan-review-replan-cap" ? `Plan Review cap reached for ${taskId}` : `Plan needs approval for ${taskId}`,
163452
163715
  /*
@@ -163801,6 +164064,132 @@ var init_transient_merge_error_classifier = __esm({
163801
164064
  }
163802
164065
  });
163803
164066
 
164067
+ // ../engine/src/notification/task-wedge-notification.ts
164068
+ function describeSelfHealingNoActionWedge(task, stage, metadata) {
164069
+ const description = SELF_HEALING_NO_ACTIONS[stage];
164070
+ if (!description || task.userPaused || task.paused || task.autoMerge === false) return null;
164071
+ const proof = metadata ?? {};
164072
+ if (proof.taskActive === true || proof.hasExecutingTaskLock === true || proof.mergePending === true) return null;
164073
+ if (Array.isArray(proof.livePaths) && proof.livePaths.length > 0) return null;
164074
+ return { reasonKey: `self-healing-no-action:${stage}`, ...description };
164075
+ }
164076
+ function describeTaskWedge(task) {
164077
+ const error2 = task.error ?? "";
164078
+ if (task.pausedReason === "completed-blocked") {
164079
+ return { reasonKey: "completion-blocked", reason: "Completed work is blocked from advancing to review.", action: "Clear the blocker or reset the task to todo." };
164080
+ }
164081
+ if (task.pausedReason === "error-retry-exhausted") {
164082
+ return { reasonKey: "heartbeat-retry-exhausted", reason: "The assigned agent exhausted its heartbeat recovery budget.", action: "Repair the agent configuration, then retry the task." };
164083
+ }
164084
+ if (task.pausedReason === "error-unrecoverable") {
164085
+ return { reasonKey: "heartbeat-error-unrecoverable", reason: "The assigned agent needs operator repair before it can resume.", action: "Repair credentials, access, or configuration, then retry the task." };
164086
+ }
164087
+ const pausedDescriptors = {
164088
+ "branch-cross-contamination": { reasonKey: "branch-cross-contamination", reason: "Branch contamination recovery requires operator intervention.", action: "Inspect the branch history, repair the contamination, then retry or reset to todo." },
164089
+ "branch-conflict-tripwire": { reasonKey: "branch-conflict-tripwire", reason: "A repeated branch conflict stopped automatic recovery.", action: "Resolve the branch conflict, then retry or reset to todo." },
164090
+ "branch-conflict-recovery-exhausted": { reasonKey: "branch-conflict-recovery-exhausted", reason: "Branch conflict recovery retries were exhausted.", action: "Resolve the conflict, then retry or reset to todo." },
164091
+ "branch-conflict-unrecoverable": { reasonKey: "branch-conflict-unrecoverable", reason: "An unrecoverable branch conflict needs operator intervention.", action: "Resolve the conflict or reset the task to todo and retry." },
164092
+ "stuck-loop-exhausted-manual-intervention-required": { reasonKey: "stuck-loop-exhausted", reason: "Self-healing exhausted its stalled-task recovery loop.", action: "Inspect the task state, then retry or reset to todo." },
164093
+ "non-retryable-provider-error": { reasonKey: "non-retryable-provider-error", reason: "A non-retryable provider error stopped the task.", action: "Repair provider access or configuration, then retry the task." },
164094
+ "in-review-stall-deadlock": { reasonKey: "in-review-stall-deadlock", reason: "Review stalled in a deadlock that needs operator intervention.", action: "Inspect review ownership and retry or reset to todo." }
164095
+ };
164096
+ if (task.pausedReason && pausedDescriptors[task.pausedReason]) return pausedDescriptors[task.pausedReason];
164097
+ if (task.status !== "failed") return null;
164098
+ if (error2.startsWith("EXECUTION_DISPATCH_LOOP_EXHAUSTED")) {
164099
+ return { reasonKey: "execution-dispatch-loop-exhausted", reason: "Execution re-queued without progress until its retry budget was exhausted.", action: "Retry, decompose, or rescope the task." };
164100
+ }
164101
+ if (error2.includes("tool failure") || error2.includes("Tool failure")) {
164102
+ return { reasonKey: "tool-failure-retry-exhausted", reason: "Execution tool-failure retries were exhausted.", action: "Inspect the failing tool and retry the task." };
164103
+ }
164104
+ if (/escalat(?:ion|ed).*exhaust|exhaust.*escalat/i.test(error2)) {
164105
+ return { reasonKey: "execution-escalation-exhausted", reason: "The alternate execution escalation was exhausted.", action: "Inspect the failure and retry or rescope the task." };
164106
+ }
164107
+ if (/review.*(?:retry|rework|revision).*(?:exhaust|limit)|(?:exhaust|limit).*review/i.test(error2)) {
164108
+ return { reasonKey: "review-retry-exhausted", reason: "The configured review recovery budget was exhausted.", action: "Review the feedback, fix the task, or use the approved review recovery action." };
164109
+ }
164110
+ const gate = error2.match(/check:([\w:-]+)/)?.[1];
164111
+ if (gate) {
164112
+ return {
164113
+ reasonKey: `merge-blocked:${gate}`,
164114
+ reason: `Merge is blocked by the check:${gate} verification gate.`,
164115
+ action: gate === "changeset-format" ? "Fix the changeset format, then retry the task." : "Fix the failing gate or reset the task to todo and retry.",
164116
+ gate: `check:${gate}`
164117
+ };
164118
+ }
164119
+ if (error2.startsWith("BLOCKED:")) {
164120
+ return { reasonKey: "execution-blocked", reason: "Execution was parked because an external blocker requires operator action.", action: "Resolve the dependency or blocker, then retry the task." };
164121
+ }
164122
+ if (/merge.*(?:blocked|verification|gate)|(?:verification|gate).*(?:failed|exhaust)/i.test(error2)) {
164123
+ return { reasonKey: "merge-blocked", reason: "Merge verification cannot progress without operator action.", action: "Fix the failing verification, then retry the task." };
164124
+ }
164125
+ if (!error2 && (task.mergeRetries ?? 0) < 3) return null;
164126
+ return {
164127
+ reasonKey: "terminal-failed",
164128
+ reason: "The task entered a terminal failed state and needs operator intervention.",
164129
+ action: "Inspect the task error, fix the underlying issue, then retry or reset to todo."
164130
+ };
164131
+ }
164132
+ var SELF_HEALING_NO_ACTIONS;
164133
+ var init_task_wedge_notification = __esm({
164134
+ "../engine/src/notification/task-wedge-notification.ts"() {
164135
+ "use strict";
164136
+ SELF_HEALING_NO_ACTIONS = {
164137
+ "reclaim-pr-conflict": {
164138
+ reason: "Self-healing could not reclaim a stalled pull-request conflict.",
164139
+ action: "Inspect the branch conflict and retry or reset the task to todo."
164140
+ },
164141
+ "reclaim-self-owned-branch-conflict": {
164142
+ reason: "Self-healing could not recover a stalled branch conflict.",
164143
+ action: "Inspect the branch conflict and retry or reset the task to todo."
164144
+ },
164145
+ "reconcile-in-review-unmet-dependencies": {
164146
+ reason: "Unmet dependencies are preventing review from progressing.",
164147
+ action: "Resolve the dependencies, then retry or reset the task to todo."
164148
+ },
164149
+ "reconcile-dependency-blocking-lease": {
164150
+ reason: "A dependency-blocking task lease could not be safely reclaimed.",
164151
+ action: "Inspect the task owner and lease, then retry or reset the task to todo."
164152
+ },
164153
+ "auto-rebound-paused-scope-decay": {
164154
+ reason: "A paused task with stale scope could not be safely resumed.",
164155
+ action: "Inspect the task scope and retry or reset the task to todo."
164156
+ },
164157
+ "stuck-merge-deadlock": {
164158
+ reason: "A merge deadlock needs operator intervention.",
164159
+ action: "Inspect merge ownership and retry or reset the task to todo."
164160
+ },
164161
+ "missing-worktree-merge-active": {
164162
+ reason: "An active merge has an unusable worktree and could not be recovered.",
164163
+ action: "Repair the worktree or reset the task to todo and retry."
164164
+ },
164165
+ "missing-worktree-review": {
164166
+ reason: "Review has an unusable worktree and could not be recovered.",
164167
+ action: "Repair the worktree or reset the task to todo and retry."
164168
+ },
164169
+ "finalize-no-op-review": {
164170
+ reason: "A no-op review task could not be safely finalized.",
164171
+ action: "Inspect merge state and retry or reset the task to todo."
164172
+ },
164173
+ "stale-incomplete-review": {
164174
+ reason: "Incomplete review work could not be safely resumed.",
164175
+ action: "Inspect incomplete steps and retry or reset the task to todo."
164176
+ },
164177
+ "ghost-review": {
164178
+ reason: "A review task has no recoverable workflow owner.",
164179
+ action: "Inspect workflow state and retry or reset the task to todo."
164180
+ },
164181
+ "no-progress-no-task-done": {
164182
+ reason: "Execution stopped without progress and could not be safely requeued.",
164183
+ action: "Inspect the task worktree and retry or reset the task to todo."
164184
+ },
164185
+ "partial-progress-no-task-done": {
164186
+ reason: "Partial execution progress could not be safely resumed.",
164187
+ action: "Inspect partial work and retry or reset the task to todo."
164188
+ }
164189
+ };
164190
+ }
164191
+ });
164192
+
163804
164193
  // ../engine/src/notification/notification-service.ts
163805
164194
  var NotificationService;
163806
164195
  var init_notification_service = __esm({
@@ -163812,6 +164201,7 @@ var init_notification_service = __esm({
163812
164201
  init_transient_merge_error_classifier();
163813
164202
  init_ntfy_provider();
163814
164203
  init_webhook_provider();
164204
+ init_task_wedge_notification();
163815
164205
  NotificationService = class {
163816
164206
  constructor(store, options = {}) {
163817
164207
  this.store = store;
@@ -163842,6 +164232,8 @@ var init_notification_service = __esm({
163842
164232
  failureNotificationSuppressedCount = 0;
163843
164233
  failureNotificationDelayMs = 6e4;
163844
164234
  failureNotificationMode = "sticky-only";
164235
+ /** Compatibility fallback for lightweight test stores without the durable TaskStore CAS. */
164236
+ activeWedgeReasons = /* @__PURE__ */ new Map();
163845
164237
  attachChatStore(chatStore) {
163846
164238
  if (this.chatStore && this.chatStore !== chatStore) {
163847
164239
  this.detachChatStoreListener(this.chatStore);
@@ -163953,6 +164345,10 @@ var init_notification_service = __esm({
163953
164345
  }
163954
164346
  }
163955
164347
  handleTaskUpdated = (task) => {
164348
+ const transientFailure = task.status === "failed" ? classifyTransientMergeError(task.error) : null;
164349
+ const wedge = transientFailure ? null : describeTaskWedge(task);
164350
+ if (wedge) this.cancelPendingFailureNotification(task.id, "classified-terminal-wedge");
164351
+ if (!transientFailure) void this.maybeNotifyTaskWedge(task, wedge);
163956
164352
  void this.maybeSuppressTransientFailedNotification(task, `status=${task.status ?? "undefined"}`);
163957
164353
  if (task.status === "awaiting-approval") {
163958
164354
  void this.writeAwaitingApprovalMailboxMessage(task);
@@ -163963,7 +164359,7 @@ var init_notification_service = __esm({
163963
164359
  if (!this.notificationsEnabled) {
163964
164360
  return;
163965
164361
  }
163966
- if (task.status === "failed") {
164362
+ if (task.status === "failed" && !wedge) {
163967
164363
  const transientClass = classifyTransientMergeError(task.error);
163968
164364
  if (transientClass) {
163969
164365
  this.failureNotificationSuppressedCount += 1;
@@ -164049,6 +164445,69 @@ var init_notification_service = __esm({
164049
164445
  );
164050
164446
  }
164051
164447
  }
164448
+ /*
164449
+ FNXC:TaskWedgeNotifications 2026-07-22-12:00:
164450
+ Terminal task updates are the shared seam for merger, executor, heartbeat, and
164451
+ self-healing parks. Clear only on a non-wedge lifecycle update, allowing a
164452
+ resolved-then-reparked reason to begin a new actionable episode.
164453
+ */
164454
+ /** Delivers a self-healing no-action escalation through the durable wedge episode seam. */
164455
+ async notifyTaskWedge(task, descriptor) {
164456
+ await this.maybeNotifyTaskWedge(task, descriptor);
164457
+ }
164458
+ async maybeNotifyTaskWedge(task, suppliedDescriptor) {
164459
+ const descriptor = suppliedDescriptor ?? describeTaskWedge(task);
164460
+ let episode;
164461
+ if (!descriptor) {
164462
+ const isActiveSelfHealingNoAction = task.wedgeNotification?.status === "active" && task.wedgeNotification.reasonKey.startsWith("self-healing-no-action:");
164463
+ const hasProgressed = task.column === "todo" || task.column === "in-progress" || task.column === "done" || task.column === "archived" || !isActiveSelfHealingNoAction && typeof task.status === "string" && task.status !== "failed" || isActiveSelfHealingNoAction && ["queued", "planning", "in-progress", "merging", "merging-pr", "merged", "done"].includes(task.status ?? "");
164464
+ if (hasProgressed) {
164465
+ this.activeWedgeReasons.delete(task.id);
164466
+ await this.store.claimTaskWedgeNotificationEpisode?.(task.id, null);
164467
+ }
164468
+ return;
164469
+ }
164470
+ if (this.store.claimTaskWedgeNotificationEpisode) {
164471
+ const claim = await this.store.claimTaskWedgeNotificationEpisode(task.id, descriptor.reasonKey);
164472
+ if (!claim.claimed || !claim.episodeId) return;
164473
+ episode = claim.episodeId;
164474
+ } else {
164475
+ if (this.activeWedgeReasons.get(task.id) === descriptor.reasonKey) return;
164476
+ this.activeWedgeReasons.set(task.id, descriptor.reasonKey);
164477
+ episode = `${task.id}:${descriptor.reasonKey}:${task.updatedAt}`;
164478
+ }
164479
+ const link = buildNtfyClickUrl({ dashboardHost: this.dashboardHost, projectId: this.options.projectId, taskId: task.id });
164480
+ const content = [
164481
+ `**${formatTaskIdentifier(task)} needs operator action**`,
164482
+ "",
164483
+ descriptor.reason,
164484
+ ...descriptor.gate ? [`Gate: \`${descriptor.gate}\`.`] : [],
164485
+ `Recommended action: ${descriptor.action}`,
164486
+ ...link ? ["", `[Open ${task.id}](${link})`] : []
164487
+ ].join("\n");
164488
+ const payload = {
164489
+ taskId: task.id,
164490
+ taskTitle: task.title,
164491
+ taskDescription: task.description,
164492
+ event: "task-wedged",
164493
+ // Bounded descriptor text is operator-facing provider content, never audit metadata.
164494
+ metadata: { wedgeReason: descriptor.reasonKey, reason: descriptor.reason, action: descriptor.action, ...descriptor.gate ? { gate: descriptor.gate } : {}, notificationDedupeKey: `task-wedge:${episode}` }
164495
+ };
164496
+ void this.dispatch("task-wedged", payload);
164497
+ try {
164498
+ await this.options.messageStore?.sendMessageOnce?.({
164499
+ fromId: "system",
164500
+ fromType: "system",
164501
+ toId: DASHBOARD_USER_ID,
164502
+ toType: "user",
164503
+ type: "system",
164504
+ content,
164505
+ metadata: { taskId: task.id, kind: "task-wedge", wedgeReason: descriptor.reasonKey, ...descriptor.gate ? { gate: descriptor.gate } : {} }
164506
+ }, `task-wedge:${episode}`);
164507
+ } catch (error2) {
164508
+ schedulerLog.log(`[notify] ${task.id} wedge mailbox message failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
164509
+ }
164510
+ }
164052
164511
  isTriageDuplicateDecision(task) {
164053
164512
  return task.paused === true && task.pausedReason === "duplicate-decision-required" && task.sourceMetadata?.duplicateSource === "triage-marker" && typeof task.sourceMetadata.nearDuplicateOf === "string";
164054
164513
  }
@@ -164414,6 +164873,11 @@ var init_notification_service = __esm({
164414
164873
  );
164415
164874
  return;
164416
164875
  }
164876
+ if (describeTaskWedge(task)) {
164877
+ this.failureNotificationSuppressedCount += 1;
164878
+ schedulerLog.log(`[notify] ${taskId} classified terminal wedge at dispatch time \u2014 suppressed generic failed notification`);
164879
+ return;
164880
+ }
164417
164881
  const isTerminal2 = task.paused === true || task.column === "in-review";
164418
164882
  if (this.failureNotificationMode === "terminal-only" && !isTerminal2) {
164419
164883
  this.failureNotificationSuppressedCount += 1;
@@ -165242,7 +165706,10 @@ var init_notifier = __esm({
165242
165706
  DEFAULT_NTFY_EVENTS = [
165243
165707
  "in-review",
165244
165708
  "merged",
165709
+ // FNXC:TaskWedgeNotifications 2026-07-22-19:00: Wedge episodes are operator
165710
+ // escalation events, so normal Ntfy defaults must not silently filter them.
165245
165711
  "failed",
165712
+ "task-wedged",
165246
165713
  "awaiting-approval",
165247
165714
  "awaiting-user-review",
165248
165715
  "planning-awaiting-input",
@@ -205139,6 +205606,9 @@ var DependencyBlockedTodoReporter = class {
205139
205606
  }
205140
205607
  };
205141
205608
 
205609
+ // ../engine/src/self-healing.ts
205610
+ init_task_wedge_notification();
205611
+
205142
205612
  // ../engine/src/self-healing-constants.ts
205143
205613
  var COMPLETED_BLOCKED_PAUSE_REASON = "completed-work-blocked";
205144
205614
  var STALE_TEMP_MERGE_WORKTREE_MS = 2 * 60 * 60 * 1e3;
@@ -205779,6 +206249,15 @@ var SelfHealingManager = class _SelfHealingManager {
205779
206249
  const message = error2 instanceof Error ? error2.message : String(error2);
205780
206250
  log28.warn(`[${stage}] ${task.id}: no-action audit emission failed: ${message}`);
205781
206251
  }
206252
+ const descriptor = describeSelfHealingNoActionWedge(task, stage, proof.metadata);
206253
+ if (descriptor) {
206254
+ try {
206255
+ await getActiveNotificationService()?.notifyTaskWedge(task, descriptor);
206256
+ } catch (error2) {
206257
+ const message = error2 instanceof Error ? error2.message : String(error2);
206258
+ log28.warn(`[${stage}] ${task.id}: wedge notification failed: ${message}`);
206259
+ }
206260
+ }
205782
206261
  log28.log(`[${stage}] ${task.id}: triple-proof not satisfied \u2014 no action (operator-decides)`);
205783
206262
  }
205784
206263
  /*