@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.
- package/dist/bin.js +994 -292
- package/dist/child-process-worker.js +632 -153
- package/dist/client/.vite/manifest.json +256 -256
- package/dist/client/assets/{AgentDetailView-lJqxsPOR.js → AgentDetailView-BBOL6AgZ.js} +1 -1
- package/dist/client/assets/{AgentPermissionPolicyEditor-De4wK_UT.js → AgentPermissionPolicyEditor-DV7OPUhR.js} +1 -1
- package/dist/client/assets/{AgentsView-CwizRdcA.js → AgentsView-B6xoAHyV.js} +3 -3
- package/dist/client/assets/{ChatView-BeQXaz7_.js → ChatView-DwVjnxM8.js} +1 -1
- package/dist/client/assets/{CommandCenter-BJZCaPLj.js → CommandCenter-DYWaoYFD.js} +1 -1
- package/dist/client/assets/{DevServerView-DQgwQXKx.js → DevServerView-BY5up-NA.js} +1 -1
- package/dist/client/assets/{DirectoryPicker-B2UVwp6F.js → DirectoryPicker-fM8MJa2r.js} +1 -1
- package/dist/client/assets/{DocumentsView-DOeYrhvg.js → DocumentsView-D2KxsPG_.js} +1 -1
- package/dist/client/assets/{EvalsView-LwepJ9Ud.js → EvalsView-U8dOvTRM.js} +1 -1
- package/dist/client/assets/{ExperimentalAgentOnboardingModal-DVNSzflw.js → ExperimentalAgentOnboardingModal-C27y8Y-1.js} +1 -1
- package/dist/client/assets/{GoalsView-__LpXw4S.js → GoalsView-D-2wmy-O.js} +1 -1
- package/dist/client/assets/{InsightsView-Dv388uaO.js → InsightsView-zLyuQL_l.js} +1 -1
- package/dist/client/assets/{MemoryView-ChCbEfZT.js → MemoryView-D-tSn48u.js} +1 -1
- package/dist/client/assets/{PiExtensionsManager-DehAjrqN.js → PiExtensionsManager-DvwmvGEY.js} +1 -1
- package/dist/client/assets/PluginManager-BACOwQAN.js +1 -0
- package/dist/client/assets/{PullRequestView-BvmajsBq.js → PullRequestView-DULyv21u.js} +1 -1
- package/dist/client/assets/{ReportModal-DM9B_h_w.js → ReportModal-CUlKMFWa.js} +1 -1
- package/dist/client/assets/{ResearchView-BzXSgUhp.js → ResearchView-DM_O3IFc.js} +1 -1
- package/dist/client/assets/{SecretsView-COBqEdJj.js → SecretsView-Bq3u_nAf.js} +1 -1
- package/dist/client/assets/{SessionTerminal-BUw_FTlh.js → SessionTerminal-D00ByR6U.js} +1 -1
- package/dist/client/assets/SettingsModal-Bb3pIxiX.js +21 -0
- package/dist/client/assets/SettingsModal-CMLHZBhX.css +1 -0
- package/dist/client/assets/{SettingsModal-CsLaIrqt.js → SettingsModal-QRaBE1ds.js} +1 -1
- package/dist/client/assets/{SettingsTextareaRow-Bv3aZ9aU.js → SettingsTextareaRow-CHOJ-qHz.js} +1 -1
- package/dist/client/assets/{SetupWizardModal-C-yMHTlW.js → SetupWizardModal-DriQyd81.js} +2 -2
- package/dist/client/assets/{SkillsView-kSHgkBar.js → SkillsView-BtDyujiZ.js} +1 -1
- package/dist/client/assets/{TodoView-DYoicJNY.js → TodoView-BNHUnz50.js} +1 -1
- package/dist/client/assets/{WorkflowNodeEditor-BtWrziOX.css → WorkflowNodeEditor-BNgkFJ_P.css} +1 -1
- package/dist/client/assets/WorkflowNodeEditor-BXikFpra.js +8 -0
- package/dist/client/assets/{agent-import-generation-D6P8OUuV.js → agent-import-generation-B2kYEm1O.js} +1 -1
- package/dist/client/assets/{app-DegRNirF.js → app-B_HrdDXZ.js} +1 -1
- package/dist/client/assets/{app-BsIXfnu-.js → app-C6yo-M_n.js} +1 -1
- package/dist/client/assets/{app-B-IdUeIu.js → app-CH8ZgPm4.js} +1 -1
- package/dist/client/assets/{app-D9ktpVhR.js → app-D4DpgDss.js} +1 -1
- package/dist/client/assets/{app-nBTNvNKK.js → app-Qv0blCyY.js} +1 -1
- package/dist/client/assets/{app-C8muVNUU.js → app-kFdtajPy.js} +1 -1
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-DLqKCckA.js → architectureDiagram-3BPJPVTR-B-Efjj4Z.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-DRz6F8wZ.js → blockDiagram-GPEHLZMM-CaOVxrlM.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-CJ9glQAp.js → c4Diagram-AAUBKEIU-D8aYt5F1.js} +1 -1
- package/dist/client/assets/channel-5bPK6pTS.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-CjIBb3ln.js → chunk-2J33WTMH-VSDT0J0r.js} +1 -1
- package/dist/client/assets/{chunk-4BX2VUAB-DrcoEr1E.js → chunk-4BX2VUAB-Chx1wQgD.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-DU-WcuA9.js → chunk-55IACEB6-MlqjhIJg.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-C5Lklr3l.js → chunk-727SXJPM-BheQNUi8.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-DlyTTghY.js → chunk-AQP2D5EJ-C5EoJhfJ.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-D3C65m5Y.js → chunk-FMBD7UC4-B8_8qP3j.js} +1 -1
- package/dist/client/assets/{chunk-ND2GUHAM-BZY-4WZF.js → chunk-ND2GUHAM-BuglCGRx.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-CKUtTYy5.js → chunk-QZHKN3VN-B7_06dxp.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-Dv9RQDqG.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-Dv9RQDqG.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-DbpsF4N5.js → cose-bilkent-S5V4N54A-Cm-ZOycx.js} +1 -1
- package/dist/client/assets/{dagre-BM42HDAG-BwIo4me1.js → dagre-BM42HDAG-Dj_Gwjpv.js} +1 -1
- package/dist/client/assets/{dashboard-view-C94UCci5.js → dashboard-view-B4CRL5Fy.js} +1 -1
- package/dist/client/assets/{dashboard-view-BvAsW6UZ.js → dashboard-view-noD9p0Zs.js} +1 -1
- package/dist/client/assets/{dashboard-view-BMQm7Lt_.js → dashboard-view-pXXSUxG9.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-C-d8XY1c.js → diagram-2AECGRRQ-C_9BfShy.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-ByRrlL9w.js → diagram-5GNKFQAL-Cmg2qpCj.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-BK7jb_J-.js → diagram-KO2AKTUF-2FNo2HXb.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-u2o4bYk6.js → diagram-LMA3HP47-DgnVeCp-.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-Dakk1V3D.js → diagram-OG6HWLK6-iAIR50HH.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-Yp33v-Cf.js → erDiagram-TEJ5UH35-Da4I04eN.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-C4-dR2TA.js → flowDiagram-I6XJVG4X-Bv9r2T0m.js} +1 -1
- package/dist/client/assets/{folder-open-C9qq38qV.js → folder-open-CwWtrDh6.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-C0CTCkFN.js → ganttDiagram-6RSMTGT7-BMeO84U_.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-DK0Dd5mm.js → gitGraphDiagram-PVQCEYII-CWDh_RIb.js} +1 -1
- package/dist/client/assets/index-CB3mYxAB.css +1 -0
- package/dist/client/assets/{index-BqLVwYoA.js → index-CE7C_XsS.js} +294 -294
- package/dist/client/assets/{infoDiagram-5YYISTIA-u5MwFb7j.js → infoDiagram-5YYISTIA-BAE4KtCL.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-C7R6TziI.js → ishikawaDiagram-YF4QCWOH-C_iXAuOy.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-Dom8W5Ab.js → journeyDiagram-JHISSGLW-BnxSHwDo.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-_47C02t3.js → kanban-definition-UN3LZRKU-DYNRm3Nu.js} +1 -1
- package/dist/client/assets/{mermaid.core-Cd3LKosp.js → mermaid.core-B3hvDDep.js} +4 -4
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-D-qVOEin.js → mindmap-definition-RKZ34NQL-s7KBEuPD.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-B0TXvVbM.js → pieDiagram-4H26LBE5-Cy1_IPUD.js} +1 -1
- package/dist/client/assets/{puzzle-BBYTjDQK.js → puzzle-DWc6gFQ7.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-KcFvcZPm.js → quadrantDiagram-W4KKPZXB-DqgVGp41.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-DEObokVc.js → requirementDiagram-4Y6WPE33-CA5-TDeF.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-BGYnEp22.js → sankeyDiagram-5OEKKPKP-Cuvi3RgE.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-BcYgyJRU.js → sequenceDiagram-3UESZ5HK-Da3GfmGP.js} +1 -1
- package/dist/client/assets/{shield-alert-CZg8yaFA.js → shield-alert-_iY63ED4.js} +1 -1
- package/dist/client/assets/{standing-instructions-template-BsTtbEqp.js → standing-instructions-template-CCd2YY9c.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-CfZQIqmX.js → stateDiagram-AJRCARHV-CZ_I9ENR.js} +1 -1
- package/dist/client/assets/{stateDiagram-v2-BHNVJYJU-nBEPRSH7.js → stateDiagram-v2-BHNVJYJU-BomoRVhY.js} +1 -1
- package/dist/client/assets/{timeline-definition-PNZ67QCA-DySyabS_.js → timeline-definition-PNZ67QCA-C3CYvIuR.js} +1 -1
- package/dist/client/assets/{upload-DMd3zMLx.js → upload-D0RrO65v.js} +1 -1
- package/dist/client/assets/{users-9Pyvnn8K.js → users-CGszBY2v.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-DPomfxp_.js → vennDiagram-CIIHVFJN-By9fi8NW.js} +1 -1
- package/dist/client/assets/{wardley-L42UT6IY-BPfzngS8.js → wardley-L42UT6IY-DErnXPkI.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-Yp4nidAP.js → wardleyDiagram-YWT4CUSO-DFfXZVPk.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-REgng603.js → xychartDiagram-2RQKCTM6-9Y5oZ5mi.js} +1 -1
- package/dist/client/index.html +4 -2
- package/dist/client/version.json +1 -1
- package/dist/extension.js +752 -207
- package/dist/migrations/0000_initial.sql +2 -0
- package/dist/migrations/0033_fn-8505_wedge_notification.sql +5 -0
- package/dist/plugin-sdk/index.js +1 -0
- package/dist/plugins/.fusion-ce-agents/.fusion-ce-upstream-provenance.json +7 -0
- package/dist/plugins/.fusion-ce-agents/ce-adversarial-document-reviewer.md +115 -0
- package/dist/plugins/.fusion-ce-agents/ce-adversarial-reviewer.md +111 -0
- package/dist/plugins/.fusion-ce-agents/ce-agent-native-planning-strategist.md +71 -0
- package/dist/plugins/.fusion-ce-agents/ce-agent-native-reviewer.md +181 -0
- package/dist/plugins/.fusion-ce-agents/ce-ankane-readme-writer.md +50 -0
- package/dist/plugins/.fusion-ce-agents/ce-api-contract-reviewer.md +52 -0
- package/dist/plugins/.fusion-ce-agents/ce-architecture-strategist.md +53 -0
- package/dist/plugins/.fusion-ce-agents/ce-best-practices-researcher.md +122 -0
- package/dist/plugins/.fusion-ce-agents/ce-code-simplicity-reviewer.md +87 -0
- package/dist/plugins/.fusion-ce-agents/ce-coherence-reviewer.md +73 -0
- package/dist/plugins/.fusion-ce-agents/ce-correctness-reviewer.md +52 -0
- package/dist/plugins/.fusion-ce-agents/ce-data-integrity-guardian.md +75 -0
- package/dist/plugins/.fusion-ce-agents/ce-data-migration-reviewer.md +119 -0
- package/dist/plugins/.fusion-ce-agents/ce-deployment-verification-agent.md +164 -0
- package/dist/plugins/.fusion-ce-agents/ce-design-implementation-reviewer.md +94 -0
- package/dist/plugins/.fusion-ce-agents/ce-design-iterator.md +197 -0
- package/dist/plugins/.fusion-ce-agents/ce-design-lens-reviewer.md +56 -0
- package/dist/plugins/.fusion-ce-agents/ce-feasibility-reviewer.md +65 -0
- package/dist/plugins/.fusion-ce-agents/ce-figma-design-sync.md +172 -0
- package/dist/plugins/.fusion-ce-agents/ce-framework-docs-researcher.md +100 -0
- package/dist/plugins/.fusion-ce-agents/ce-git-history-analyzer.md +47 -0
- package/dist/plugins/.fusion-ce-agents/ce-issue-intelligence-analyst.md +207 -0
- package/dist/plugins/.fusion-ce-agents/ce-julik-frontend-races-reviewer.md +52 -0
- package/dist/plugins/.fusion-ce-agents/ce-learnings-researcher.md +254 -0
- package/dist/plugins/.fusion-ce-agents/ce-maintainability-reviewer.md +77 -0
- package/dist/plugins/.fusion-ce-agents/ce-pattern-recognition-specialist.md +62 -0
- package/dist/plugins/.fusion-ce-agents/ce-performance-oracle.md +115 -0
- package/dist/plugins/.fusion-ce-agents/ce-performance-reviewer.md +54 -0
- package/dist/plugins/.fusion-ce-agents/ce-pr-comment-resolver.md +63 -0
- package/dist/plugins/.fusion-ce-agents/ce-previous-comments-reviewer.md +68 -0
- package/dist/plugins/.fusion-ce-agents/ce-product-lens-reviewer.md +92 -0
- package/dist/plugins/.fusion-ce-agents/ce-project-standards-reviewer.md +84 -0
- package/dist/plugins/.fusion-ce-agents/ce-reliability-reviewer.md +52 -0
- package/dist/plugins/.fusion-ce-agents/ce-repo-research-analyst.md +263 -0
- package/dist/plugins/.fusion-ce-agents/ce-scope-guardian-reviewer.md +79 -0
- package/dist/plugins/.fusion-ce-agents/ce-security-lens-reviewer.md +48 -0
- package/dist/plugins/.fusion-ce-agents/ce-security-reviewer.md +54 -0
- package/dist/plugins/.fusion-ce-agents/ce-security-sentinel.md +98 -0
- package/dist/plugins/.fusion-ce-agents/ce-session-historian.md +89 -0
- package/dist/plugins/.fusion-ce-agents/ce-slack-researcher.md +133 -0
- package/dist/plugins/.fusion-ce-agents/ce-spec-flow-analyzer.md +87 -0
- package/dist/plugins/.fusion-ce-agents/ce-swift-ios-reviewer.md +107 -0
- package/dist/plugins/.fusion-ce-agents/ce-testing-reviewer.md +52 -0
- package/dist/plugins/.fusion-ce-agents/ce-web-researcher.md +127 -0
- package/dist/plugins/.fusion-ce-skills/.fusion-ce-upstream-provenance.json +7 -0
- package/dist/plugins/.fusion-ce-skills/ce-brainstorm/SKILL.md +318 -0
- package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/agents/slack-researcher.md +127 -0
- package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/brainstorm-sections.md +354 -0
- package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/handoff.md +172 -0
- package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/html-rendering.md +662 -0
- package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/markdown-rendering.md +236 -0
- package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/synthesis-summary.md +271 -0
- package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/universal-brainstorming.md +71 -0
- package/dist/plugins/.fusion-ce-skills/ce-brainstorm/references/visual-probes.md +128 -0
- package/dist/plugins/.fusion-ce-skills/ce-brainstorm/scripts/visual-probe-server.js +419 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/SKILL.md +821 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/action-class-rubric.md +26 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/bulk-preview.md +112 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/cross-model-review.md +63 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/diff-scope.md +41 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/findings-schema.json +137 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/persona-catalog.md +63 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/adversarial-reviewer.md +102 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/agent-native-reviewer.md +173 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/api-contract-reviewer.md +43 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/correctness-reviewer.md +43 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/data-migration-reviewer.md +111 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/deployment-verification-agent.md +157 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/julik-frontend-races-reviewer.md +44 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/learnings-researcher.md +247 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/maintainability-reviewer.md +68 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/performance-reviewer.md +45 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/previous-comments-reviewer.md +59 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/project-standards-reviewer.md +75 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/reliability-reviewer.md +43 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/security-reviewer.md +45 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/swift-ios-reviewer.md +99 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/personas/testing-reviewer.md +43 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/review-output-template.md +170 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/subagent-template.md +199 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/tracker-defer.md +149 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/validator-template.md +89 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/references/walkthrough.md +249 -0
- package/dist/plugins/.fusion-ce-skills/ce-code-review/scripts/cross-model-adversarial-review.sh +218 -0
- package/dist/plugins/.fusion-ce-skills/ce-commit/SKILL.md +105 -0
- package/dist/plugins/.fusion-ce-skills/ce-commit-push-pr/SKILL.md +134 -0
- package/dist/plugins/.fusion-ce-skills/ce-commit-push-pr/references/branch-creation.md +55 -0
- package/dist/plugins/.fusion-ce-skills/ce-commit-push-pr/references/pr-description-writing.md +115 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/SKILL.md +712 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/assets/resolution-template.md +94 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/references/agents/best-practices-researcher.md +115 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/references/agents/data-integrity-guardian.md +68 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/references/agents/framework-docs-researcher.md +93 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/references/agents/pattern-recognition-specialist.md +55 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/references/agents/performance-oracle.md +108 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/references/agents/security-sentinel.md +91 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/references/agents/session-historian.md +83 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/references/concepts-vocabulary.md +78 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/references/schema.yaml +231 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/references/yaml-schema.md +118 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/scripts/session-history/discover-sessions.sh +130 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/scripts/session-history/extract-errors.py +254 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/scripts/session-history/extract-metadata.py +456 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/scripts/session-history/extract-skeleton.py +570 -0
- package/dist/plugins/.fusion-ce-skills/ce-compound/scripts/validate-frontmatter.py +137 -0
- package/dist/plugins/.fusion-ce-skills/ce-debug/SKILL.md +257 -0
- package/dist/plugins/.fusion-ce-skills/ce-debug/references/anti-patterns.md +91 -0
- package/dist/plugins/.fusion-ce-skills/ce-debug/references/defense-in-depth.md +35 -0
- package/dist/plugins/.fusion-ce-skills/ce-debug/references/investigation-techniques.md +374 -0
- package/dist/plugins/.fusion-ce-skills/ce-doc-review/SKILL.md +70 -0
- package/dist/plugins/.fusion-ce-skills/ce-ideate/SKILL.md +401 -0
- package/dist/plugins/.fusion-ce-skills/ce-ideate/references/agents/issue-intelligence-analyst.md +200 -0
- package/dist/plugins/.fusion-ce-skills/ce-ideate/references/agents/learnings-researcher.md +247 -0
- package/dist/plugins/.fusion-ce-skills/ce-ideate/references/agents/slack-researcher.md +127 -0
- package/dist/plugins/.fusion-ce-skills/ce-ideate/references/agents/web-researcher.md +121 -0
- package/dist/plugins/.fusion-ce-skills/ce-ideate/references/divergent-ideation.md +89 -0
- package/dist/plugins/.fusion-ce-skills/ce-ideate/references/html-rendering.md +662 -0
- package/dist/plugins/.fusion-ce-skills/ce-ideate/references/ideation-sections.md +191 -0
- package/dist/plugins/.fusion-ce-skills/ce-ideate/references/markdown-rendering.md +236 -0
- package/dist/plugins/.fusion-ce-skills/ce-ideate/references/post-ideation-workflow.md +166 -0
- package/dist/plugins/.fusion-ce-skills/ce-ideate/references/universal-ideation.md +107 -0
- package/dist/plugins/.fusion-ce-skills/ce-ideate/references/web-research-cache.md +55 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/SKILL.md +858 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/agent-native-planning-strategist.md +62 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/architecture-strategist.md +46 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/best-practices-researcher.md +114 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/data-integrity-guardian.md +68 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/data-migration-reviewer.md +103 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/deployment-verification-agent.md +157 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/framework-docs-researcher.md +93 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/git-history-analyzer.md +40 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/learnings-researcher.md +247 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/pattern-recognition-specialist.md +55 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/performance-oracle.md +108 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/repo-research-analyst.md +256 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/security-sentinel.md +91 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/slack-researcher.md +127 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/spec-flow-analyzer.md +80 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/agents/web-researcher.md +121 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/approach-altitude.md +55 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/deepening-workflow.md +259 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/html-rendering.md +668 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/markdown-rendering.md +236 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/plan-handoff.md +126 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/plan-sections.md +405 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/synthesis-summary.md +396 -0
- package/dist/plugins/.fusion-ce-skills/ce-plan/references/universal-planning.md +168 -0
- package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/SKILL.md +53 -0
- package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/references/agents/pr-comment-resolver.md +56 -0
- package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/references/evaluation-rubric.md +106 -0
- package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/references/full-mode.md +283 -0
- package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/references/targeted-mode.md +45 -0
- package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/scripts/get-pr-comments +159 -0
- package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/scripts/get-thread-for-comment +76 -0
- package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/scripts/reply-to-pr-thread +33 -0
- package/dist/plugins/.fusion-ce-skills/ce-resolve-pr-feedback/scripts/resolve-pr-thread +23 -0
- package/dist/plugins/.fusion-ce-skills/ce-strategy/SKILL.md +97 -0
- package/dist/plugins/.fusion-ce-skills/ce-strategy/references/interview.md +143 -0
- package/dist/plugins/.fusion-ce-skills/ce-strategy/references/strategy-template.md +89 -0
- package/dist/plugins/.fusion-ce-skills/ce-work/SKILL.md +429 -0
- package/dist/plugins/.fusion-ce-skills/ce-work/references/agents/figma-design-sync.md +165 -0
- package/dist/plugins/.fusion-ce-skills/ce-work/references/execution-engines.md +85 -0
- package/dist/plugins/.fusion-ce-skills/ce-work/references/non-code-execution.md +23 -0
- package/dist/plugins/.fusion-ce-skills/ce-work/references/review-findings-followup.md +104 -0
- package/dist/plugins/.fusion-ce-skills/ce-work/references/shipping-workflow.md +133 -0
- package/dist/plugins/.fusion-ce-skills/ce-work/references/tracker-defer.md +149 -0
- package/dist/plugins/fusion-plugin-compound-engineering/.bundled.reload-3.js +11266 -0
- package/dist/plugins/fusion-plugin-compound-engineering/.bundled.reload-4.js +11266 -0
- package/dist/plugins/fusion-plugin-dependency-graph/.bundled.reload-1.js +8206 -0
- package/dist/plugins/fusion-plugin-grok-runtime/.bundled.reload-2.js +26623 -0
- package/package.json +1 -1
- package/dist/client/assets/PluginManager-DBhJ1i27.js +0 -1
- package/dist/client/assets/SettingsModal-BDgH9XID.js +0 -21
- package/dist/client/assets/SettingsModal-BXDnzDkJ.css +0 -1
- package/dist/client/assets/WorkflowNodeEditor-DLno6bSJ.js +0 -8
- package/dist/client/assets/channel-Dj4nOgJO.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-DnkFo5Qy.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-DnkFo5Qy.js +0 -1
- package/dist/client/assets/index-6FBJPKkr.css +0 -1
package/dist/extension.js
CHANGED
|
@@ -906,6 +906,7 @@ var init_workflow_steps = __esm({
|
|
|
906
906
|
"in-review",
|
|
907
907
|
"merged",
|
|
908
908
|
"failed",
|
|
909
|
+
"task-wedged",
|
|
909
910
|
"awaiting-approval",
|
|
910
911
|
"awaiting-user-review",
|
|
911
912
|
"planning-awaiting-input",
|
|
@@ -979,6 +980,50 @@ var init_documents_artifacts = __esm({
|
|
|
979
980
|
}
|
|
980
981
|
});
|
|
981
982
|
|
|
983
|
+
// ../core/src/types/task-core.ts
|
|
984
|
+
function assertNotWorkspaceTaskMerge(task) {
|
|
985
|
+
if (isWorkspaceTask(task)) {
|
|
986
|
+
throw new WorkspaceTaskMergeError(
|
|
987
|
+
`Workspace task ${task.id} cannot merge until per-repo merge support (master-plan U6) lands`
|
|
988
|
+
);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
function isWorkspaceTask(task) {
|
|
992
|
+
const worktrees = task.workspaceWorktrees;
|
|
993
|
+
return !!worktrees && Object.keys(worktrees).length > 0;
|
|
994
|
+
}
|
|
995
|
+
var CheckoutConflictError, DUPLICATE_OF_METADATA_KEY, WorkspaceTaskMergeError;
|
|
996
|
+
var init_task_core = __esm({
|
|
997
|
+
"../core/src/types/task-core.ts"() {
|
|
998
|
+
"use strict";
|
|
999
|
+
CheckoutConflictError = class extends Error {
|
|
1000
|
+
constructor(taskId, currentHolderId, requestedById) {
|
|
1001
|
+
super(`Task ${taskId} is already checked out by agent ${currentHolderId}`);
|
|
1002
|
+
this.taskId = taskId;
|
|
1003
|
+
this.currentHolderId = currentHolderId;
|
|
1004
|
+
this.requestedById = requestedById;
|
|
1005
|
+
this.name = "CheckoutConflictError";
|
|
1006
|
+
}
|
|
1007
|
+
};
|
|
1008
|
+
DUPLICATE_OF_METADATA_KEY = "duplicateOfTaskIds";
|
|
1009
|
+
WorkspaceTaskMergeError = class extends Error {
|
|
1010
|
+
constructor(message) {
|
|
1011
|
+
super(message);
|
|
1012
|
+
this.name = "WorkspaceTaskMergeError";
|
|
1013
|
+
}
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
// ../core/src/types/todo-list.ts
|
|
1019
|
+
var SHARED_STATE_SNAPSHOT_VERSION;
|
|
1020
|
+
var init_todo_list = __esm({
|
|
1021
|
+
"../core/src/types/todo-list.ts"() {
|
|
1022
|
+
"use strict";
|
|
1023
|
+
SHARED_STATE_SNAPSHOT_VERSION = 1;
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
|
|
982
1027
|
// ../core/src/task-helpers.ts
|
|
983
1028
|
function getPrimaryPrInfo(task) {
|
|
984
1029
|
return task.prInfos?.[0] ?? task.prInfo;
|
|
@@ -1468,10 +1513,18 @@ var init_settings_schema = __esm({
|
|
|
1468
1513
|
"use strict";
|
|
1469
1514
|
init_in_review_stall();
|
|
1470
1515
|
DEFAULT_GLOBAL_SETTINGS = {
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1516
|
+
/*
|
|
1517
|
+
FNXC:PostgresEmbedded 2026-07-22-23:55:
|
|
1518
|
+
Embedded PostgreSQL is shared by all local Fusion projects and processes.
|
|
1519
|
+
Deliberately undefined (not 500): getSettings() merges these defaults, so a
|
|
1520
|
+
concrete value here would be indistinguishable from an operator choice and
|
|
1521
|
+
would mask the platform-aware server-side default in
|
|
1522
|
+
resolveEmbeddedMaxConnections (win32 150, else 500). Issue #2411: Windows
|
|
1523
|
+
backends are separate processes; a 500-connection cap exhausts the desktop
|
|
1524
|
+
heap under load and forked backends die with 0xC0000142, taking the embedded
|
|
1525
|
+
cluster and dashboard down.
|
|
1526
|
+
*/
|
|
1527
|
+
embeddedPostgresMaxConnections: void 0,
|
|
1475
1528
|
/*
|
|
1476
1529
|
FNXC:DashboardTheming 2026-07-03-00:00:
|
|
1477
1530
|
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.
|
|
@@ -2234,6 +2287,53 @@ var init_settings_schema = __esm({
|
|
|
2234
2287
|
}
|
|
2235
2288
|
});
|
|
2236
2289
|
|
|
2290
|
+
// ../core/src/types/settings-scope.ts
|
|
2291
|
+
function isMcpSecretRef(value) {
|
|
2292
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
2293
|
+
const candidate = value;
|
|
2294
|
+
return typeof candidate.secretRef === "string" && candidate.secretRef.trim().length > 0 && (candidate.scope === "project" || candidate.scope === "global");
|
|
2295
|
+
}
|
|
2296
|
+
var init_settings_scope = __esm({
|
|
2297
|
+
"../core/src/types/settings-scope.ts"() {
|
|
2298
|
+
"use strict";
|
|
2299
|
+
init_settings_schema();
|
|
2300
|
+
}
|
|
2301
|
+
});
|
|
2302
|
+
|
|
2303
|
+
// ../core/src/types/board-config.ts
|
|
2304
|
+
var COLUMN_LABELS, COLUMN_DESCRIPTIONS, VALID_TRANSITIONS;
|
|
2305
|
+
var init_board_config = __esm({
|
|
2306
|
+
"../core/src/types/board-config.ts"() {
|
|
2307
|
+
"use strict";
|
|
2308
|
+
COLUMN_LABELS = {
|
|
2309
|
+
triage: "Planning",
|
|
2310
|
+
todo: "Todo",
|
|
2311
|
+
"in-progress": "In Progress",
|
|
2312
|
+
"in-review": "In Review",
|
|
2313
|
+
done: "Done",
|
|
2314
|
+
archived: "Archived"
|
|
2315
|
+
};
|
|
2316
|
+
COLUMN_DESCRIPTIONS = {
|
|
2317
|
+
triage: "Raw ideas \u2014 AI will plan these",
|
|
2318
|
+
"in-progress": "AI is working on this in a worktree",
|
|
2319
|
+
done: "Merged and closed",
|
|
2320
|
+
archived: "Completed and archived"
|
|
2321
|
+
};
|
|
2322
|
+
VALID_TRANSITIONS = {
|
|
2323
|
+
// FN-4892: intake-side heuristics may cold-archive tasks before execution starts.
|
|
2324
|
+
triage: ["todo", "archived"],
|
|
2325
|
+
// FN-4892: allow direct archival for newly specified intake tasks.
|
|
2326
|
+
todo: ["in-progress", "triage", "archived"],
|
|
2327
|
+
// NOTE: "in-progress" → "done" is enabled for mission validation tasks that complete directly.
|
|
2328
|
+
// Regular implementation tasks should move through "in-review" before "done".
|
|
2329
|
+
"in-progress": ["in-review", "todo", "triage", "done"],
|
|
2330
|
+
"in-review": ["done", "in-progress", "todo", "triage"],
|
|
2331
|
+
done: ["todo", "triage", "archived"],
|
|
2332
|
+
archived: ["done"]
|
|
2333
|
+
};
|
|
2334
|
+
}
|
|
2335
|
+
});
|
|
2336
|
+
|
|
2237
2337
|
// ../core/src/types/docker-nodes.ts
|
|
2238
2338
|
function validateDockerNodeConfig(config3) {
|
|
2239
2339
|
const errors = [];
|
|
@@ -2344,6 +2444,41 @@ var init_docker_nodes = __esm({
|
|
|
2344
2444
|
}
|
|
2345
2445
|
});
|
|
2346
2446
|
|
|
2447
|
+
// ../core/src/types/archive-planning.ts
|
|
2448
|
+
function formatPlanningPlanMd(summary) {
|
|
2449
|
+
const normalizeListItem = (item) => item.replace(/\s+/g, " ").trim();
|
|
2450
|
+
const list = (items) => items && items.length > 0 ? items.map((item) => `- ${normalizeListItem(item)}`).join("\n") : "_None_";
|
|
2451
|
+
const proposedChanges = list(summary.proposedChanges);
|
|
2452
|
+
const acceptanceCriteria = list(summary.acceptanceCriteria);
|
|
2453
|
+
const dependencies = list(summary.suggestedDependencies);
|
|
2454
|
+
const deliverables = list(summary.keyDeliverables);
|
|
2455
|
+
return `# ${summary.title}
|
|
2456
|
+
|
|
2457
|
+
${summary.description}
|
|
2458
|
+
|
|
2459
|
+
## What to change
|
|
2460
|
+
${proposedChanges}
|
|
2461
|
+
|
|
2462
|
+
## Acceptance criteria
|
|
2463
|
+
${acceptanceCriteria}
|
|
2464
|
+
|
|
2465
|
+
## Size
|
|
2466
|
+
${summary.suggestedSize}
|
|
2467
|
+
|
|
2468
|
+
## Suggested dependencies
|
|
2469
|
+
${dependencies}
|
|
2470
|
+
|
|
2471
|
+
## Key deliverables
|
|
2472
|
+
${deliverables}
|
|
2473
|
+
`;
|
|
2474
|
+
}
|
|
2475
|
+
var init_archive_planning = __esm({
|
|
2476
|
+
"../core/src/types/archive-planning.ts"() {
|
|
2477
|
+
"use strict";
|
|
2478
|
+
init_docker_nodes();
|
|
2479
|
+
}
|
|
2480
|
+
});
|
|
2481
|
+
|
|
2347
2482
|
// ../core/src/types/agent-state.ts
|
|
2348
2483
|
function isEphemeralAgent(agent) {
|
|
2349
2484
|
const metadata = agent.metadata ?? {};
|
|
@@ -4069,49 +4204,6 @@ var init_workflow_lifecycle_validation = __esm({
|
|
|
4069
4204
|
});
|
|
4070
4205
|
|
|
4071
4206
|
// ../core/src/types.ts
|
|
4072
|
-
function assertNotWorkspaceTaskMerge(task) {
|
|
4073
|
-
if (isWorkspaceTask(task)) {
|
|
4074
|
-
throw new WorkspaceTaskMergeError(
|
|
4075
|
-
`Workspace task ${task.id} cannot merge until per-repo merge support (master-plan U6) lands`
|
|
4076
|
-
);
|
|
4077
|
-
}
|
|
4078
|
-
}
|
|
4079
|
-
function isWorkspaceTask(task) {
|
|
4080
|
-
const worktrees = task.workspaceWorktrees;
|
|
4081
|
-
return !!worktrees && Object.keys(worktrees).length > 0;
|
|
4082
|
-
}
|
|
4083
|
-
function isMcpSecretRef(value) {
|
|
4084
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
4085
|
-
const candidate = value;
|
|
4086
|
-
return typeof candidate.secretRef === "string" && candidate.secretRef.trim().length > 0 && (candidate.scope === "project" || candidate.scope === "global");
|
|
4087
|
-
}
|
|
4088
|
-
function formatPlanningPlanMd(summary) {
|
|
4089
|
-
const normalizeListItem = (item) => item.replace(/\s+/g, " ").trim();
|
|
4090
|
-
const list = (items) => items && items.length > 0 ? items.map((item) => `- ${normalizeListItem(item)}`).join("\n") : "_None_";
|
|
4091
|
-
const proposedChanges = list(summary.proposedChanges);
|
|
4092
|
-
const acceptanceCriteria = list(summary.acceptanceCriteria);
|
|
4093
|
-
const dependencies = list(summary.suggestedDependencies);
|
|
4094
|
-
const deliverables = list(summary.keyDeliverables);
|
|
4095
|
-
return `# ${summary.title}
|
|
4096
|
-
|
|
4097
|
-
${summary.description}
|
|
4098
|
-
|
|
4099
|
-
## What to change
|
|
4100
|
-
${proposedChanges}
|
|
4101
|
-
|
|
4102
|
-
## Acceptance criteria
|
|
4103
|
-
${acceptanceCriteria}
|
|
4104
|
-
|
|
4105
|
-
## Size
|
|
4106
|
-
${summary.suggestedSize}
|
|
4107
|
-
|
|
4108
|
-
## Suggested dependencies
|
|
4109
|
-
${dependencies}
|
|
4110
|
-
|
|
4111
|
-
## Key deliverables
|
|
4112
|
-
${deliverables}
|
|
4113
|
-
`;
|
|
4114
|
-
}
|
|
4115
4207
|
function validateMessageMetadata(metadata) {
|
|
4116
4208
|
if (!metadata) {
|
|
4117
4209
|
return;
|
|
@@ -4163,7 +4255,7 @@ function validateMessageMetadata(metadata) {
|
|
|
4163
4255
|
if (metadata.proposalStatus === "pending" && (metadata.claimOwnerToken !== void 0 || metadata.claimStartedAt !== void 0)) throw new Error("pending proposal cannot have a creation lease");
|
|
4164
4256
|
}
|
|
4165
4257
|
}
|
|
4166
|
-
var DEPRECATED_BUILTIN_WORKFLOW_IDS
|
|
4258
|
+
var DEPRECATED_BUILTIN_WORKFLOW_IDS;
|
|
4167
4259
|
var init_types = __esm({
|
|
4168
4260
|
"../core/src/types.ts"() {
|
|
4169
4261
|
"use strict";
|
|
@@ -4177,8 +4269,11 @@ var init_types = __esm({
|
|
|
4177
4269
|
init_merge_policy();
|
|
4178
4270
|
init_workflow_steps();
|
|
4179
4271
|
init_documents_artifacts();
|
|
4180
|
-
|
|
4181
|
-
|
|
4272
|
+
init_task_core();
|
|
4273
|
+
init_todo_list();
|
|
4274
|
+
init_settings_scope();
|
|
4275
|
+
init_board_config();
|
|
4276
|
+
init_archive_planning();
|
|
4182
4277
|
init_agent_state();
|
|
4183
4278
|
init_planner_intervention();
|
|
4184
4279
|
init_agents();
|
|
@@ -4193,49 +4288,6 @@ var init_types = __esm({
|
|
|
4193
4288
|
DEPRECATED_BUILTIN_WORKFLOW_IDS = /* @__PURE__ */ new Set([
|
|
4194
4289
|
"builtin:brainstorming"
|
|
4195
4290
|
]);
|
|
4196
|
-
CheckoutConflictError = class extends Error {
|
|
4197
|
-
constructor(taskId, currentHolderId, requestedById) {
|
|
4198
|
-
super(`Task ${taskId} is already checked out by agent ${currentHolderId}`);
|
|
4199
|
-
this.taskId = taskId;
|
|
4200
|
-
this.currentHolderId = currentHolderId;
|
|
4201
|
-
this.requestedById = requestedById;
|
|
4202
|
-
this.name = "CheckoutConflictError";
|
|
4203
|
-
}
|
|
4204
|
-
};
|
|
4205
|
-
DUPLICATE_OF_METADATA_KEY = "duplicateOfTaskIds";
|
|
4206
|
-
WorkspaceTaskMergeError = class extends Error {
|
|
4207
|
-
constructor(message) {
|
|
4208
|
-
super(message);
|
|
4209
|
-
this.name = "WorkspaceTaskMergeError";
|
|
4210
|
-
}
|
|
4211
|
-
};
|
|
4212
|
-
SHARED_STATE_SNAPSHOT_VERSION = 1;
|
|
4213
|
-
COLUMN_LABELS = {
|
|
4214
|
-
triage: "Planning",
|
|
4215
|
-
todo: "Todo",
|
|
4216
|
-
"in-progress": "In Progress",
|
|
4217
|
-
"in-review": "In Review",
|
|
4218
|
-
done: "Done",
|
|
4219
|
-
archived: "Archived"
|
|
4220
|
-
};
|
|
4221
|
-
COLUMN_DESCRIPTIONS = {
|
|
4222
|
-
triage: "Raw ideas \u2014 AI will plan these",
|
|
4223
|
-
"in-progress": "AI is working on this in a worktree",
|
|
4224
|
-
done: "Merged and closed",
|
|
4225
|
-
archived: "Completed and archived"
|
|
4226
|
-
};
|
|
4227
|
-
VALID_TRANSITIONS = {
|
|
4228
|
-
// FN-4892: intake-side heuristics may cold-archive tasks before execution starts.
|
|
4229
|
-
triage: ["todo", "archived"],
|
|
4230
|
-
// FN-4892: allow direct archival for newly specified intake tasks.
|
|
4231
|
-
todo: ["in-progress", "triage", "archived"],
|
|
4232
|
-
// NOTE: "in-progress" → "done" is enabled for mission validation tasks that complete directly.
|
|
4233
|
-
// Regular implementation tasks should move through "in-review" before "done".
|
|
4234
|
-
"in-progress": ["in-review", "todo", "triage", "done"],
|
|
4235
|
-
"in-review": ["done", "in-progress", "todo", "triage"],
|
|
4236
|
-
done: ["todo", "triage", "archived"],
|
|
4237
|
-
archived: ["done"]
|
|
4238
|
-
};
|
|
4239
4291
|
}
|
|
4240
4292
|
});
|
|
4241
4293
|
|
|
@@ -12856,6 +12908,7 @@ var init_project = __esm({
|
|
|
12856
12908
|
paused: integer("paused").default(0),
|
|
12857
12909
|
userPaused: integer("user_paused").default(0),
|
|
12858
12910
|
pausedReason: text("paused_reason"),
|
|
12911
|
+
wedgeNotification: text("wedge_notification"),
|
|
12859
12912
|
baseBranch: text("base_branch"),
|
|
12860
12913
|
branch: text("branch"),
|
|
12861
12914
|
autoMerge: integer("auto_merge"),
|
|
@@ -21220,6 +21273,9 @@ function validateColumns(ir2) {
|
|
|
21220
21273
|
throw new WorkflowIrError(`Workflow IR has duplicate column id '${column.id}'`);
|
|
21221
21274
|
}
|
|
21222
21275
|
seen.add(column.id);
|
|
21276
|
+
if (column.description !== void 0 && typeof column.description !== "string") {
|
|
21277
|
+
throw new WorkflowIrError(`Workflow IR column '${column.id}' description must be a string`);
|
|
21278
|
+
}
|
|
21223
21279
|
if (!Array.isArray(column.traits)) {
|
|
21224
21280
|
throw new WorkflowIrError(`Workflow IR column '${column.id}' traits must be an array`);
|
|
21225
21281
|
}
|
|
@@ -36443,6 +36499,7 @@ async function applySchemaBaseline(db, options = {}) {
|
|
|
36443
36499
|
const legacyAdoptionDrainedMarkerRuntimeGrantsAlreadyApplied = applied.includes(
|
|
36444
36500
|
LEGACY_ADOPTION_DRAINED_MARKER_RUNTIME_GRANTS_VERSION
|
|
36445
36501
|
);
|
|
36502
|
+
const taskWedgeNotificationAlreadyApplied = applied.includes(TASK_WEDGE_NOTIFICATION_VERSION);
|
|
36446
36503
|
assertBinaryNotOlderThanDatabase(applied);
|
|
36447
36504
|
let schemaChanged = false;
|
|
36448
36505
|
if (!baselineAlreadyApplied) {
|
|
@@ -36766,17 +36823,25 @@ async function applySchemaBaseline(db, options = {}) {
|
|
|
36766
36823
|
);
|
|
36767
36824
|
schemaChanged = true;
|
|
36768
36825
|
}
|
|
36826
|
+
if (!taskWedgeNotificationAlreadyApplied) {
|
|
36827
|
+
const migrationSql = await readFile4(TASK_WEDGE_NOTIFICATION_MIGRATION_PATH, "utf8");
|
|
36828
|
+
await tx.execute(sql.raw(migrationSql));
|
|
36829
|
+
await tx.execute(
|
|
36830
|
+
sql`INSERT INTO public.${sql.identifier(MIGRATION_BOOKKEEPING_TABLE)} (version) VALUES (${TASK_WEDGE_NOTIFICATION_VERSION}) ON CONFLICT (version) DO NOTHING`
|
|
36831
|
+
);
|
|
36832
|
+
schemaChanged = true;
|
|
36833
|
+
}
|
|
36769
36834
|
return { applied: schemaChanged, pluginHooksRun: pluginHooks.length };
|
|
36770
36835
|
});
|
|
36771
36836
|
}
|
|
36772
|
-
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;
|
|
36837
|
+
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;
|
|
36773
36838
|
var init_schema_applier = __esm({
|
|
36774
36839
|
"../core/src/postgres/schema-applier.ts"() {
|
|
36775
36840
|
"use strict";
|
|
36776
36841
|
init_drizzle_orm();
|
|
36777
36842
|
init_plugin_schema_hook();
|
|
36778
36843
|
init_advisory_locks();
|
|
36779
|
-
SCHEMA_BASELINE_VERSION = "
|
|
36844
|
+
SCHEMA_BASELINE_VERSION = "0033";
|
|
36780
36845
|
TASK_DECLARED_SYMBOLS_VERSION = "0028";
|
|
36781
36846
|
INITIAL_SCHEMA_VERSION = "0000";
|
|
36782
36847
|
AUTOMATION_ISOLATION_SCHEMA_VERSION = "0001";
|
|
@@ -36809,6 +36874,7 @@ var init_schema_applier = __esm({
|
|
|
36809
36874
|
SQLITE_MIGRATION_RUNTIME_READ_VERSION = "0030";
|
|
36810
36875
|
WORKFLOW_TASK_CONTINUATIONS_VERSION = "0031";
|
|
36811
36876
|
LEGACY_ADOPTION_DRAINED_MARKER_RUNTIME_GRANTS_VERSION = "0032";
|
|
36877
|
+
TASK_WEDGE_NOTIFICATION_VERSION = "0033";
|
|
36812
36878
|
LEGACY_ADOPTION_DRAINED_MARKER_FUNCTION = "fusion_mark_legacy_adoption_drained";
|
|
36813
36879
|
StaleBinarySchemaError = class extends Error {
|
|
36814
36880
|
constructor(databaseVersion, binaryVersion) {
|
|
@@ -36915,6 +36981,10 @@ var init_schema_applier = __esm({
|
|
|
36915
36981
|
MIGRATIONS_DIR,
|
|
36916
36982
|
"0032_legacy_adoption_drained_marker_runtime_grants.sql"
|
|
36917
36983
|
);
|
|
36984
|
+
TASK_WEDGE_NOTIFICATION_MIGRATION_PATH = join8(
|
|
36985
|
+
MIGRATIONS_DIR,
|
|
36986
|
+
"0033_fn-8505_wedge_notification.sql"
|
|
36987
|
+
);
|
|
36918
36988
|
}
|
|
36919
36989
|
});
|
|
36920
36990
|
|
|
@@ -37305,6 +37375,7 @@ __export(sqlite_migrator_exports, {
|
|
|
37305
37375
|
isSqliteMigrationComplete: () => isSqliteMigrationComplete,
|
|
37306
37376
|
migrateLegacyProjectPluginRows: () => migrateLegacyProjectPluginRows,
|
|
37307
37377
|
migrateSqliteToPostgres: () => migrateSqliteToPostgres,
|
|
37378
|
+
projectPluginSqliteMigrationKey: () => projectPluginSqliteMigrationKey,
|
|
37308
37379
|
recordSqliteMigrationComplete: () => recordSqliteMigrationComplete,
|
|
37309
37380
|
toSnakeCase: () => toSnakeCase2
|
|
37310
37381
|
});
|
|
@@ -37847,7 +37918,12 @@ function normalizeLegacyJson(value, fallback) {
|
|
|
37847
37918
|
return fallback;
|
|
37848
37919
|
}
|
|
37849
37920
|
}
|
|
37921
|
+
function projectPluginSqliteMigrationKey(projectPath) {
|
|
37922
|
+
return `project-plugins:${resolve6(projectPath)}`;
|
|
37923
|
+
}
|
|
37850
37924
|
async function migrateLegacyProjectPluginRows(db, sqlitePath, projectPath) {
|
|
37925
|
+
const migrationKey = projectPluginSqliteMigrationKey(projectPath);
|
|
37926
|
+
if (await isSqliteMigrationComplete(db, migrationKey)) return;
|
|
37851
37927
|
await db.transaction(async (tx) => {
|
|
37852
37928
|
await migrateLegacyProjectPluginRowsOnSession(
|
|
37853
37929
|
tx,
|
|
@@ -37857,19 +37933,14 @@ async function migrateLegacyProjectPluginRows(db, sqlitePath, projectPath) {
|
|
|
37857
37933
|
});
|
|
37858
37934
|
}
|
|
37859
37935
|
async function migrateLegacyProjectPluginRowsOnSession(db, sqlitePath, projectPath) {
|
|
37860
|
-
if (!sqliteTableExists(sqlitePath, "plugins")) return;
|
|
37861
|
-
await acquireSqliteMigrationStateLock(db);
|
|
37862
37936
|
const canonicalProjectPath = resolve6(projectPath);
|
|
37863
|
-
const migrationKey =
|
|
37937
|
+
const migrationKey = projectPluginSqliteMigrationKey(projectPath);
|
|
37938
|
+
await acquireSqliteMigrationStateLock(db);
|
|
37864
37939
|
await ensureMigrationStateTable(db);
|
|
37865
37940
|
await db.execute(sql`SELECT pg_advisory_xact_lock(hashtextextended(${migrationKey}, 0))`);
|
|
37866
|
-
const completed = await db
|
|
37867
|
-
|
|
37868
|
-
|
|
37869
|
-
WHERE migration_key = ${migrationKey} AND status = 'complete'
|
|
37870
|
-
LIMIT 1
|
|
37871
|
-
`);
|
|
37872
|
-
if (completed.length > 0) return;
|
|
37941
|
+
const completed = await isSqliteMigrationComplete(db, migrationKey);
|
|
37942
|
+
if (completed) return;
|
|
37943
|
+
if (!sqliteTableExists(sqlitePath, "plugins")) return;
|
|
37873
37944
|
const sqlite = openSqlite(sqlitePath);
|
|
37874
37945
|
let rows;
|
|
37875
37946
|
try {
|
|
@@ -38955,6 +39026,17 @@ function buildPgCtlOptionsString(port, flags) {
|
|
|
38955
39026
|
function buildPgCtlStartArgs(dataDir, logFile, optionsString) {
|
|
38956
39027
|
return ["-D", dataDir, "-o", optionsString, "-l", logFile, "-W", "start"];
|
|
38957
39028
|
}
|
|
39029
|
+
function withWindowsNativeBinPath(environment, nativeRoot, platform4 = process.platform) {
|
|
39030
|
+
if (platform4 !== "win32") return environment;
|
|
39031
|
+
const pathKey = Object.keys(environment).find((key) => key.toLowerCase() === "path") ?? "PATH";
|
|
39032
|
+
const bin = nativeRoot.replace(/[\\/]+$/, "") + "\\bin";
|
|
39033
|
+
const normalize8 = (value) => value.replace(/\//g, "\\").toLowerCase();
|
|
39034
|
+
const inherited = environment[pathKey] ?? "";
|
|
39035
|
+
const segments = inherited.split(";").filter(Boolean);
|
|
39036
|
+
const normalizedBin = normalize8(bin);
|
|
39037
|
+
const deduplicated = segments.filter((segment) => normalize8(segment) !== normalizedBin);
|
|
39038
|
+
return { ...environment, [pathKey]: [bin, ...deduplicated].join(";") };
|
|
39039
|
+
}
|
|
38958
39040
|
function readPostgresPid(dataDir) {
|
|
38959
39041
|
try {
|
|
38960
39042
|
const lines = readFileSync3(join9(dataDir, "postmaster.pid"), "utf-8").split("\n");
|
|
@@ -39009,7 +39091,13 @@ async function startServerElevatedRestricted(opts) {
|
|
|
39009
39091
|
`embedded postgres: elevated start via pg_ctl restricted token (no helper account); log ${logFile}`
|
|
39010
39092
|
);
|
|
39011
39093
|
let stopped = false;
|
|
39094
|
+
let logMonitor = null;
|
|
39095
|
+
const stopMonitoring = () => {
|
|
39096
|
+
if (logMonitor) clearInterval(logMonitor);
|
|
39097
|
+
logMonitor = null;
|
|
39098
|
+
};
|
|
39012
39099
|
const killAll = () => {
|
|
39100
|
+
stopMonitoring();
|
|
39013
39101
|
if (stopped) return;
|
|
39014
39102
|
stopped = true;
|
|
39015
39103
|
const r = spawnSync(pgCtl, ["-D", opts.dataDir, "-m", "fast", "-t", "30", "-w", "stop"], {
|
|
@@ -39043,14 +39131,21 @@ async function startServerElevatedRestricted(opts) {
|
|
|
39043
39131
|
killAll();
|
|
39044
39132
|
await waitForDown();
|
|
39045
39133
|
},
|
|
39134
|
+
stopMonitoring,
|
|
39046
39135
|
async stopWrapperOnly() {
|
|
39136
|
+
stopMonitoring();
|
|
39047
39137
|
stopped = true;
|
|
39048
39138
|
}
|
|
39049
39139
|
};
|
|
39050
39140
|
opts.onLaunched?.(handle);
|
|
39051
39141
|
const launch = await new Promise(
|
|
39052
39142
|
(resolve51, reject) => {
|
|
39053
|
-
const child = spawn(pgCtl, args, {
|
|
39143
|
+
const child = spawn(pgCtl, args, {
|
|
39144
|
+
windowsHide: true,
|
|
39145
|
+
// Do not mutate process.env: sibling dashboard/engine children must
|
|
39146
|
+
// retain their inherited environment unchanged.
|
|
39147
|
+
env: withWindowsNativeBinPath(process.env, opts.nativeRoot)
|
|
39148
|
+
});
|
|
39054
39149
|
let output = "";
|
|
39055
39150
|
child.stdout.on("data", (d) => output += d.toString());
|
|
39056
39151
|
child.stderr.on("data", (d) => output += d.toString());
|
|
@@ -39075,16 +39170,14 @@ ${readTail(logFile, 2e3)}`
|
|
|
39075
39170
|
killAll();
|
|
39076
39171
|
throw new Error("embedded postgres: elevated launch cancelled before ready.");
|
|
39077
39172
|
}
|
|
39173
|
+
if (await probeTcpPort(opts.port, 500)) {
|
|
39174
|
+
ready = true;
|
|
39175
|
+
break;
|
|
39176
|
+
}
|
|
39078
39177
|
const tail = readTail(logFile, 3e3);
|
|
39079
39178
|
if (tail !== lastSnapshot) {
|
|
39080
39179
|
lastSnapshot = tail;
|
|
39081
|
-
opts.onLog(`elevated
|
|
39082
|
-
}
|
|
39083
|
-
if (/database system is ready to accept connections/.test(tail)) {
|
|
39084
|
-
if (await probeTcpPort(opts.port, 500)) {
|
|
39085
|
-
ready = true;
|
|
39086
|
-
break;
|
|
39087
|
-
}
|
|
39180
|
+
opts.onLog(`elevated diagnostic pg={${tail.slice(-400)}}`);
|
|
39088
39181
|
}
|
|
39089
39182
|
if (/\bFATAL\b|\bPANIC\b|could not (bind|start|create|access|connect|load)|not permitted|Permission denied|is not the owner/i.test(tail)) {
|
|
39090
39183
|
killAll();
|
|
@@ -39116,6 +39209,18 @@ ${tail}`
|
|
|
39116
39209
|
opts.onLog(
|
|
39117
39210
|
`embedded postgres: elevated server ready on 127.0.0.1:${opts.port} (pid ${postgresPid ?? 0}, restricted token)`
|
|
39118
39211
|
);
|
|
39212
|
+
let lastLogSnapshot = "";
|
|
39213
|
+
const observePostReadyLog = () => {
|
|
39214
|
+
if (stopped) return;
|
|
39215
|
+
const snapshot = readTail(logFile, 16384);
|
|
39216
|
+
if (snapshot === "(no log file)" || snapshot === lastLogSnapshot) return;
|
|
39217
|
+
const next = snapshot.startsWith(lastLogSnapshot) ? snapshot.slice(lastLogSnapshot.length) : snapshot;
|
|
39218
|
+
lastLogSnapshot = snapshot;
|
|
39219
|
+
if (next) opts.onLog(next);
|
|
39220
|
+
};
|
|
39221
|
+
observePostReadyLog();
|
|
39222
|
+
logMonitor = setInterval(observePostReadyLog, 250);
|
|
39223
|
+
if (typeof logMonitor.unref === "function") logMonitor.unref();
|
|
39119
39224
|
return handle;
|
|
39120
39225
|
}
|
|
39121
39226
|
function probeTcpPort(port, timeoutMs) {
|
|
@@ -39135,10 +39240,26 @@ function probeTcpPort(port, timeoutMs) {
|
|
|
39135
39240
|
socket.once("error", () => finish(false));
|
|
39136
39241
|
});
|
|
39137
39242
|
}
|
|
39138
|
-
var elevatedCache;
|
|
39243
|
+
var WindowsPostgresFatalDetector, elevatedCache;
|
|
39139
39244
|
var init_embedded_windows_elevated = __esm({
|
|
39140
39245
|
"../core/src/postgres/embedded-windows-elevated.ts"() {
|
|
39141
39246
|
"use strict";
|
|
39247
|
+
WindowsPostgresFatalDetector = class {
|
|
39248
|
+
buffer = "";
|
|
39249
|
+
matched = false;
|
|
39250
|
+
push(chunk) {
|
|
39251
|
+
if (this.matched || !chunk) return false;
|
|
39252
|
+
this.buffer = (this.buffer + chunk).slice(-16384);
|
|
39253
|
+
const text2 = this.buffer.toLowerCase();
|
|
39254
|
+
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(
|
|
39255
|
+
text2
|
|
39256
|
+
)) {
|
|
39257
|
+
this.matched = true;
|
|
39258
|
+
return true;
|
|
39259
|
+
}
|
|
39260
|
+
return false;
|
|
39261
|
+
}
|
|
39262
|
+
};
|
|
39142
39263
|
elevatedCache = null;
|
|
39143
39264
|
}
|
|
39144
39265
|
});
|
|
@@ -39148,10 +39269,14 @@ var embedded_lifecycle_exports = {};
|
|
|
39148
39269
|
__export(embedded_lifecycle_exports, {
|
|
39149
39270
|
DEFAULT_EMBEDDED_DATABASE: () => DEFAULT_EMBEDDED_DATABASE,
|
|
39150
39271
|
DEFAULT_EMBEDDED_INITDB_FLAGS: () => DEFAULT_EMBEDDED_INITDB_FLAGS,
|
|
39272
|
+
DEFAULT_EMBEDDED_MAX_CONNECTIONS: () => DEFAULT_EMBEDDED_MAX_CONNECTIONS,
|
|
39273
|
+
DEFAULT_EMBEDDED_MAX_CONNECTIONS_WIN32: () => DEFAULT_EMBEDDED_MAX_CONNECTIONS_WIN32,
|
|
39151
39274
|
DEFAULT_EMBEDDED_PASSWORD: () => DEFAULT_EMBEDDED_PASSWORD,
|
|
39152
39275
|
DEFAULT_EMBEDDED_POSTGRES_FLAGS: () => DEFAULT_EMBEDDED_POSTGRES_FLAGS,
|
|
39153
39276
|
DEFAULT_EMBEDDED_USER: () => DEFAULT_EMBEDDED_USER,
|
|
39154
39277
|
DEFAULT_START_TIMEOUT_MS: () => DEFAULT_START_TIMEOUT_MS,
|
|
39278
|
+
EMBEDDED_MAX_CONNECTIONS_MAX: () => EMBEDDED_MAX_CONNECTIONS_MAX,
|
|
39279
|
+
EMBEDDED_MAX_CONNECTIONS_MIN: () => EMBEDDED_MAX_CONNECTIONS_MIN,
|
|
39155
39280
|
EmbeddedPostgresLifecycle: () => EmbeddedPostgresLifecycle,
|
|
39156
39281
|
EmbeddedStartTimeoutError: () => EmbeddedStartTimeoutError,
|
|
39157
39282
|
__setEmbeddedPostgresCtorForTests: () => __setEmbeddedPostgresCtorForTests,
|
|
@@ -39170,6 +39295,7 @@ __export(embedded_lifecycle_exports, {
|
|
|
39170
39295
|
normalizeMacosEmbeddedPostgresDylibSymlinks: () => normalizeMacosEmbeddedPostgresDylibSymlinks,
|
|
39171
39296
|
readPortFromPostmasterPid: () => readPortFromPostmasterPid,
|
|
39172
39297
|
resolveElectronAsarUnpackedPath: () => resolveElectronAsarUnpackedPath,
|
|
39298
|
+
resolveEmbeddedMaxConnections: () => resolveEmbeddedMaxConnections,
|
|
39173
39299
|
uninstallElectronAsarNativePathPatchForTests: () => uninstallElectronAsarNativePathPatchForTests
|
|
39174
39300
|
});
|
|
39175
39301
|
import {
|
|
@@ -39379,6 +39505,23 @@ function materializeEmbeddedPostgresRuntimeBinaries(nativeRoot, options) {
|
|
|
39379
39505
|
writeFileSync2(marker, sourceMarker, "utf8");
|
|
39380
39506
|
return destRoot;
|
|
39381
39507
|
}
|
|
39508
|
+
function isWindowsEmbeddedPostgresBinary(command) {
|
|
39509
|
+
return process.platform === "win32" && typeof command === "string" && /[\\/]bin[\\/](?:postgres|initdb|pg_ctl)\.exe$/i.test(command);
|
|
39510
|
+
}
|
|
39511
|
+
function withWindowsPostgresSpawnEnvironment(command, rest) {
|
|
39512
|
+
if (!isWindowsEmbeddedPostgresBinary(command)) return rest;
|
|
39513
|
+
const args = [...rest];
|
|
39514
|
+
const optionIndex = args.length - 1;
|
|
39515
|
+
const existing = args[optionIndex];
|
|
39516
|
+
if (!existing || typeof existing !== "object" || Array.isArray(existing)) return args;
|
|
39517
|
+
const binDir = dirname6(command);
|
|
39518
|
+
const nativeRoot = dirname6(binDir);
|
|
39519
|
+
args[optionIndex] = {
|
|
39520
|
+
...existing,
|
|
39521
|
+
env: withWindowsNativeBinPath(existing.env ?? process.env, nativeRoot)
|
|
39522
|
+
};
|
|
39523
|
+
return args;
|
|
39524
|
+
}
|
|
39382
39525
|
function installElectronAsarNativePathPatch() {
|
|
39383
39526
|
if (electronAsarNativePathPatchInstalled) return;
|
|
39384
39527
|
electronAsarNativePathPatchInstalled = true;
|
|
@@ -39396,7 +39539,10 @@ function installElectronAsarNativePathPatch() {
|
|
|
39396
39539
|
const originalSpawn = childProcessMod.spawn.bind(childProcessMod);
|
|
39397
39540
|
childProcessMod.spawn = (command, ...rest) => {
|
|
39398
39541
|
const fixedCommand = typeof command === "string" ? resolveElectronAsarUnpackedPath(command) : command;
|
|
39399
|
-
return originalSpawn(
|
|
39542
|
+
return originalSpawn(
|
|
39543
|
+
fixedCommand,
|
|
39544
|
+
...withWindowsPostgresSpawnEnvironment(fixedCommand, rest)
|
|
39545
|
+
);
|
|
39400
39546
|
};
|
|
39401
39547
|
const fsPromisesMod = require2("fs/promises");
|
|
39402
39548
|
const originalStat = fsPromisesMod.stat.bind(fsPromisesMod);
|
|
@@ -39445,6 +39591,12 @@ function getEmbeddedPostgresCtor() {
|
|
|
39445
39591
|
function defaultEmbeddedPostgresFlagsFor(platform4) {
|
|
39446
39592
|
return platform4 === "win32" ? [] : ["-c", "shared_memory_type=mmap"];
|
|
39447
39593
|
}
|
|
39594
|
+
function resolveEmbeddedMaxConnections(configured, platform4 = process.platform) {
|
|
39595
|
+
if (typeof configured === "number" && Number.isInteger(configured)) {
|
|
39596
|
+
return Math.min(EMBEDDED_MAX_CONNECTIONS_MAX, Math.max(EMBEDDED_MAX_CONNECTIONS_MIN, configured));
|
|
39597
|
+
}
|
|
39598
|
+
return platform4 === "win32" ? DEFAULT_EMBEDDED_MAX_CONNECTIONS_WIN32 : DEFAULT_EMBEDDED_MAX_CONNECTIONS;
|
|
39599
|
+
}
|
|
39448
39600
|
function defaultEmbeddedDataDir() {
|
|
39449
39601
|
const home = process.env.HOME || process.env.USERPROFILE || process.cwd();
|
|
39450
39602
|
return join10(home, ".fusion", "embedded-postgres", "default");
|
|
@@ -39631,7 +39783,7 @@ function signalNumber(signal) {
|
|
|
39631
39783
|
return 0;
|
|
39632
39784
|
}
|
|
39633
39785
|
}
|
|
39634
|
-
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;
|
|
39786
|
+
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;
|
|
39635
39787
|
var init_embedded_lifecycle = __esm({
|
|
39636
39788
|
"../core/src/postgres/embedded-lifecycle.ts"() {
|
|
39637
39789
|
"use strict";
|
|
@@ -39662,6 +39814,10 @@ var init_embedded_lifecycle = __esm({
|
|
|
39662
39814
|
DEFAULT_EMBEDDED_PASSWORD = "password";
|
|
39663
39815
|
DEFAULT_EMBEDDED_DATABASE = "fusion";
|
|
39664
39816
|
DEFAULT_EMBEDDED_POSTGRES_FLAGS = defaultEmbeddedPostgresFlagsFor(process.platform);
|
|
39817
|
+
DEFAULT_EMBEDDED_MAX_CONNECTIONS = 500;
|
|
39818
|
+
DEFAULT_EMBEDDED_MAX_CONNECTIONS_WIN32 = 150;
|
|
39819
|
+
EMBEDDED_MAX_CONNECTIONS_MIN = 32;
|
|
39820
|
+
EMBEDDED_MAX_CONNECTIONS_MAX = 2e3;
|
|
39665
39821
|
DEFAULT_EMBEDDED_INITDB_FLAGS = [
|
|
39666
39822
|
"--encoding=UTF8",
|
|
39667
39823
|
"--locale=C"
|
|
@@ -39704,6 +39860,10 @@ var init_embedded_lifecycle = __esm({
|
|
|
39704
39860
|
* on a failure that is handled before the timeout fires.
|
|
39705
39861
|
*/
|
|
39706
39862
|
startTimer = null;
|
|
39863
|
+
windowsFatalDetector = new WindowsPostgresFatalDetector();
|
|
39864
|
+
recoveryAttempts = 0;
|
|
39865
|
+
recoveryInFlight = null;
|
|
39866
|
+
stopRequested = false;
|
|
39707
39867
|
constructor(opts) {
|
|
39708
39868
|
this.options = {
|
|
39709
39869
|
dataDir: opts.dataDir,
|
|
@@ -39718,6 +39878,15 @@ var init_embedded_lifecycle = __esm({
|
|
|
39718
39878
|
onError: opts.onError ?? ((err) => log4.error(String(err)))
|
|
39719
39879
|
};
|
|
39720
39880
|
}
|
|
39881
|
+
/**
|
|
39882
|
+
* Forward native process output to the existing sink, then schedule recovery
|
|
39883
|
+
* only for a confirmed owned Windows fatal shutdown sequence.
|
|
39884
|
+
*/
|
|
39885
|
+
forwardPostgresLog = (message) => {
|
|
39886
|
+
this.options.onLog(message);
|
|
39887
|
+
if (process.platform !== "win32" || !this.running || !this.ownsProcess) return;
|
|
39888
|
+
if (this.windowsFatalDetector.push(message)) void this.recoverWindowsFatalOnce();
|
|
39889
|
+
};
|
|
39721
39890
|
/** The configured or discovered port. Undefined until assigned (explicit or discovered in `start()`). */
|
|
39722
39891
|
getPort() {
|
|
39723
39892
|
return this.options.port ?? this.resolvedPort;
|
|
@@ -39814,11 +39983,19 @@ var init_embedded_lifecycle = __esm({
|
|
|
39814
39983
|
migrationUrlOverridden: false
|
|
39815
39984
|
};
|
|
39816
39985
|
}
|
|
39986
|
+
return this.startBounded();
|
|
39987
|
+
}
|
|
39988
|
+
/**
|
|
39989
|
+
* Start an owned postmaster with the same cancellation and timeout contract
|
|
39990
|
+
* used by public startup. Recovery calls this directly because it must not
|
|
39991
|
+
* join a stale pid file or allocate a new endpoint between pool reconnects.
|
|
39992
|
+
*/
|
|
39993
|
+
async startBounded(preferredPort) {
|
|
39817
39994
|
if (this.options.startTimeoutMs <= 0) {
|
|
39818
|
-
return this.startInternal();
|
|
39995
|
+
return this.startInternal(void 0, preferredPort);
|
|
39819
39996
|
}
|
|
39820
39997
|
const controller = new AbortController();
|
|
39821
|
-
const startAttempt = this.startInternal(controller.signal);
|
|
39998
|
+
const startAttempt = this.startInternal(controller.signal, preferredPort);
|
|
39822
39999
|
let timer2;
|
|
39823
40000
|
const timeout = new Promise((_resolve, reject) => {
|
|
39824
40001
|
timer2 = setTimeout(() => {
|
|
@@ -39844,12 +40021,9 @@ var init_embedded_lifecycle = __esm({
|
|
|
39844
40021
|
this.startTimer = null;
|
|
39845
40022
|
}
|
|
39846
40023
|
}
|
|
39847
|
-
/**
|
|
39848
|
-
|
|
39849
|
-
|
|
39850
|
-
*/
|
|
39851
|
-
async startInternal(signal) {
|
|
39852
|
-
const port = this.options.port ?? await findFreePort();
|
|
40024
|
+
/** The actual start sequence, invoked only through {@link startBounded}. */
|
|
40025
|
+
async startInternal(signal, preferredPort) {
|
|
40026
|
+
const port = this.options.port ?? preferredPort ?? this.resolvedPort ?? await findFreePort();
|
|
39853
40027
|
if (signal?.aborted) throw new EmbeddedStartCancelledError(this.options.dataDir);
|
|
39854
40028
|
this.resolvedPort = port;
|
|
39855
40029
|
const alreadyInitialized = isDataDirInitialized(this.options.dataDir);
|
|
@@ -39863,7 +40037,7 @@ var init_embedded_lifecycle = __esm({
|
|
|
39863
40037
|
authMethod: "password",
|
|
39864
40038
|
initdbFlags: [...this.options.initdbFlags],
|
|
39865
40039
|
postgresFlags: [...this.options.postgresFlags],
|
|
39866
|
-
onLog: this.
|
|
40040
|
+
onLog: this.forwardPostgresLog,
|
|
39867
40041
|
onError: this.options.onError
|
|
39868
40042
|
});
|
|
39869
40043
|
this.pg = pg;
|
|
@@ -39895,7 +40069,7 @@ var init_embedded_lifecycle = __esm({
|
|
|
39895
40069
|
dataDir: this.options.dataDir,
|
|
39896
40070
|
port,
|
|
39897
40071
|
postgresFlags: this.options.postgresFlags,
|
|
39898
|
-
onLog: this.
|
|
40072
|
+
onLog: this.forwardPostgresLog,
|
|
39899
40073
|
onError: this.options.onError,
|
|
39900
40074
|
startTimeoutMs: this.options.startTimeoutMs,
|
|
39901
40075
|
signal,
|
|
@@ -39973,6 +40147,43 @@ var init_embedded_lifecycle = __esm({
|
|
|
39973
40147
|
migrationUrlOverridden: false
|
|
39974
40148
|
};
|
|
39975
40149
|
}
|
|
40150
|
+
/**
|
|
40151
|
+
* FNXC:PostgresEmbedded 2026-07-22-16:25:
|
|
40152
|
+
* A 0xC0000142 backend crash shuts down its whole PostgreSQL cluster. One
|
|
40153
|
+
* lifecycle-owned retry reuses the initialized directory and same resolved
|
|
40154
|
+
* port; joiners, stop/detach, and a second incident are deliberately inert.
|
|
40155
|
+
*/
|
|
40156
|
+
async recoverWindowsFatalOnce() {
|
|
40157
|
+
if (this.recoveryInFlight || this.recoveryAttempts >= 1 || this.stopRequested || !this.ownsProcess) return;
|
|
40158
|
+
this.recoveryAttempts += 1;
|
|
40159
|
+
this.recoveryInFlight = (async () => {
|
|
40160
|
+
this.options.onLog("embedded postgres: detected Windows DLL initialization shutdown; attempting one owned-cluster recovery");
|
|
40161
|
+
try {
|
|
40162
|
+
if (this.nonAdminHandle) await this.nonAdminHandle.stop();
|
|
40163
|
+
else await this.pg?.stop();
|
|
40164
|
+
this.pg = null;
|
|
40165
|
+
this.nonAdminHandle = null;
|
|
40166
|
+
this.running = false;
|
|
40167
|
+
runningInstances.delete(this.options.dataDir);
|
|
40168
|
+
if (this.stopRequested || !this.ownsProcess) return;
|
|
40169
|
+
const recoveryPort = this.resolvedPort;
|
|
40170
|
+
if (recoveryPort === void 0) {
|
|
40171
|
+
throw new Error("embedded postgres: recovery lost its resolved port");
|
|
40172
|
+
}
|
|
40173
|
+
await this.startBounded(recoveryPort);
|
|
40174
|
+
this.options.onLog("embedded postgres: Windows owned-cluster recovery completed; existing pools may reconnect");
|
|
40175
|
+
} catch (error2) {
|
|
40176
|
+
this.running = false;
|
|
40177
|
+
runningInstances.delete(this.options.dataDir);
|
|
40178
|
+
this.options.onError(
|
|
40179
|
+
`embedded postgres: Windows DLL initialization recovery failed after one retry; restart Fusion and inspect the System log. ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
40180
|
+
);
|
|
40181
|
+
} finally {
|
|
40182
|
+
this.recoveryInFlight = null;
|
|
40183
|
+
}
|
|
40184
|
+
})();
|
|
40185
|
+
await this.recoveryInFlight;
|
|
40186
|
+
}
|
|
39976
40187
|
async settleCancelledStart(pg) {
|
|
39977
40188
|
if (this.nonAdminHandle) {
|
|
39978
40189
|
try {
|
|
@@ -40119,6 +40330,7 @@ var init_embedded_lifecycle = __esm({
|
|
|
40119
40330
|
*/
|
|
40120
40331
|
detachWithoutStop() {
|
|
40121
40332
|
this.uninstallShutdownHook();
|
|
40333
|
+
this.nonAdminHandle?.stopMonitoring();
|
|
40122
40334
|
this.pg = null;
|
|
40123
40335
|
this.nonAdminHandle = null;
|
|
40124
40336
|
this.running = false;
|
|
@@ -40126,6 +40338,7 @@ var init_embedded_lifecycle = __esm({
|
|
|
40126
40338
|
runningInstances.delete(this.options.dataDir);
|
|
40127
40339
|
}
|
|
40128
40340
|
async stop() {
|
|
40341
|
+
this.stopRequested = true;
|
|
40129
40342
|
this.uninstallShutdownHook();
|
|
40130
40343
|
if (!this.ownsProcess) {
|
|
40131
40344
|
this.running = false;
|
|
@@ -52150,10 +52363,10 @@ async function bootSchemaBackendOnce(options, bypassProjectIsolation = false) {
|
|
|
52150
52363
|
let resolvedBackend = backend;
|
|
52151
52364
|
let embeddedDataDir = null;
|
|
52152
52365
|
if (backend.mode === "embedded") {
|
|
52153
|
-
const { EmbeddedPostgresLifecycle: EmbeddedPostgresLifecycle2, defaultEmbeddedDataDir: defaultEmbeddedDataDir2, DEFAULT_EMBEDDED_DATABASE: DEFAULT_EMBEDDED_DATABASE2 } = await Promise.resolve().then(() => (init_embedded_lifecycle(), embedded_lifecycle_exports));
|
|
52366
|
+
const { EmbeddedPostgresLifecycle: EmbeddedPostgresLifecycle2, defaultEmbeddedDataDir: defaultEmbeddedDataDir2, DEFAULT_EMBEDDED_DATABASE: DEFAULT_EMBEDDED_DATABASE2, resolveEmbeddedMaxConnections: resolveEmbeddedMaxConnections2 } = await Promise.resolve().then(() => (init_embedded_lifecycle(), embedded_lifecycle_exports));
|
|
52154
52367
|
const { GlobalSettingsStore: GlobalSettingsStore2 } = await Promise.resolve().then(() => (init_global_settings(), global_settings_exports));
|
|
52155
52368
|
const configuredMaxConnections = process.env.VITEST === "true" && !options.globalSettingsDir ? void 0 : (await new GlobalSettingsStore2(options.globalSettingsDir).getSettings()).embeddedPostgresMaxConnections;
|
|
52156
|
-
const maxConnections =
|
|
52369
|
+
const maxConnections = resolveEmbeddedMaxConnections2(configuredMaxConnections);
|
|
52157
52370
|
const dataDir = resolve8(options.embeddedDataDir ?? defaultEmbeddedDataDir2());
|
|
52158
52371
|
embeddedDataDir = dataDir;
|
|
52159
52372
|
log5.log(`startup-factory: starting embedded PostgreSQL (data dir ${dataDir})`);
|
|
@@ -52390,7 +52603,20 @@ async function createTaskStoreForBackend(options) {
|
|
|
52390
52603
|
try {
|
|
52391
52604
|
const fusionDir = join16(rootDir, ".fusion");
|
|
52392
52605
|
const legacySqlitePath = join16(fusionDir, "fusion.db");
|
|
52393
|
-
|
|
52606
|
+
const {
|
|
52607
|
+
migrateSqliteToPostgres: migrateSqliteToPostgres2,
|
|
52608
|
+
defaultMigrationSources: defaultMigrationSources2,
|
|
52609
|
+
formatMigrationProgress: formatMigrationProgress2,
|
|
52610
|
+
isSqliteMigrationComplete: isSqliteMigrationComplete2,
|
|
52611
|
+
completeSqliteMigration: completeSqliteMigration2,
|
|
52612
|
+
recordSqliteMigrationComplete: recordSqliteMigrationComplete2,
|
|
52613
|
+
CENTRAL_SQLITE_MIGRATION_KEY: CENTRAL_SQLITE_MIGRATION_KEY2
|
|
52614
|
+
} = await Promise.resolve().then(() => (init_sqlite_migrator(), sqlite_migrator_exports));
|
|
52615
|
+
const fallbackProjectId = fallbackProjectIdForRoot(rootDir);
|
|
52616
|
+
let migrationProjectId = options.projectId ?? await lookupRegisteredProjectIdByPath(connections.migration, rootDir) ?? fallbackProjectId;
|
|
52617
|
+
let migrationKey = `project:${migrationProjectId}`;
|
|
52618
|
+
let migrationComplete = await isSqliteMigrationComplete2(connections.migration, migrationKey);
|
|
52619
|
+
if (!migrationComplete && existsSync11(legacySqlitePath)) {
|
|
52394
52620
|
let globalDir = options.globalSettingsDir;
|
|
52395
52621
|
if (!globalDir) {
|
|
52396
52622
|
try {
|
|
@@ -52400,21 +52626,24 @@ async function createTaskStoreForBackend(options) {
|
|
|
52400
52626
|
globalDir = void 0;
|
|
52401
52627
|
}
|
|
52402
52628
|
}
|
|
52403
|
-
let
|
|
52629
|
+
let resolvedFromLegacyCentral = false;
|
|
52630
|
+
const centralMigrationComplete = await isSqliteMigrationComplete2(
|
|
52631
|
+
connections.migration,
|
|
52632
|
+
CENTRAL_SQLITE_MIGRATION_KEY2
|
|
52633
|
+
);
|
|
52404
52634
|
const legacyCentralPath = globalDir ? join16(globalDir, "fusion-central.db") : void 0;
|
|
52405
|
-
if (!migrationProjectId && legacyCentralPath && existsSync11(legacyCentralPath) && isValidSqliteDatabaseFile(legacyCentralPath)) {
|
|
52635
|
+
if (!centralMigrationComplete && migrationProjectId === fallbackProjectId && legacyCentralPath && existsSync11(legacyCentralPath) && isValidSqliteDatabaseFile(legacyCentralPath)) {
|
|
52406
52636
|
const { DatabaseSync: DatabaseSync2 } = await Promise.resolve().then(() => (init_sqlite_adapter(), sqlite_adapter_exports));
|
|
52407
52637
|
const legacyCentral = new DatabaseSync2(legacyCentralPath, { readOnly: true });
|
|
52408
52638
|
try {
|
|
52409
52639
|
const row = legacyCentral.prepare(`SELECT id FROM projects WHERE path = ? LIMIT 1`).get(rootDir);
|
|
52410
|
-
migrationProjectId = row?.id;
|
|
52640
|
+
migrationProjectId = row?.id ?? migrationProjectId;
|
|
52641
|
+
resolvedFromLegacyCentral = Boolean(row?.id);
|
|
52411
52642
|
} catch {
|
|
52412
52643
|
} finally {
|
|
52413
52644
|
legacyCentral.close();
|
|
52414
52645
|
}
|
|
52415
52646
|
}
|
|
52416
|
-
const fallbackProjectId = fallbackProjectIdForRoot(rootDir);
|
|
52417
|
-
migrationProjectId ??= fallbackProjectId;
|
|
52418
52647
|
if (migrationProjectId !== fallbackProjectId) {
|
|
52419
52648
|
try {
|
|
52420
52649
|
await rekeyFallbackProjectPartition(connections.migration, fallbackProjectId, migrationProjectId);
|
|
@@ -52430,14 +52659,9 @@ async function createTaskStoreForBackend(options) {
|
|
|
52430
52659
|
}
|
|
52431
52660
|
}
|
|
52432
52661
|
}
|
|
52433
|
-
|
|
52434
|
-
|
|
52435
|
-
const migrationComplete = await isSqliteMigrationComplete2(connections.migration, migrationKey);
|
|
52662
|
+
migrationKey = `project:${migrationProjectId}`;
|
|
52663
|
+
migrationComplete = await isSqliteMigrationComplete2(connections.migration, migrationKey);
|
|
52436
52664
|
if (!migrationComplete && isValidSqliteDatabaseFile(legacySqlitePath)) {
|
|
52437
|
-
const centralMigrationComplete = await isSqliteMigrationComplete2(
|
|
52438
|
-
connections.migration,
|
|
52439
|
-
CENTRAL_SQLITE_MIGRATION_KEY2
|
|
52440
|
-
);
|
|
52441
52665
|
const sources = defaultMigrationSources2(fusionDir, globalDir ?? join16(fusionDir, "__no-global-dir__")).filter((source) => !centralMigrationComplete || source.pgSchema !== "central").filter((source) => existsSync11(source.sqlitePath) && isValidSqliteDatabaseFile(source.sqlitePath));
|
|
52442
52666
|
if (sources.length > 0) {
|
|
52443
52667
|
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)`);
|
|
@@ -52472,6 +52696,12 @@ async function createTaskStoreForBackend(options) {
|
|
|
52472
52696
|
rootDir
|
|
52473
52697
|
});
|
|
52474
52698
|
}
|
|
52699
|
+
if (resolvedFromLegacyCentral) {
|
|
52700
|
+
const registeredId = await lookupRegisteredProjectIdByPath(connections.migration, rootDir);
|
|
52701
|
+
if (registeredId !== migrationProjectId) {
|
|
52702
|
+
throw new Error(`legacy project identity ${migrationProjectId} was not materialized for ${rootDir} before migration completion`);
|
|
52703
|
+
}
|
|
52704
|
+
}
|
|
52475
52705
|
await completeSqliteMigration2(connections.migration, migrationKey);
|
|
52476
52706
|
if (sources.some((source) => source.pgSchema === "central")) {
|
|
52477
52707
|
await recordSqliteMigrationComplete2(
|
|
@@ -52489,14 +52719,9 @@ async function createTaskStoreForBackend(options) {
|
|
|
52489
52719
|
log5.log(`startup-factory: SQLite \u2192 PostgreSQL auto-migration complete (${migratedRows} row(s) across ${report.tables.length} table(s))`);
|
|
52490
52720
|
}
|
|
52491
52721
|
}
|
|
52492
|
-
if (isValidSqliteDatabaseFile(legacySqlitePath)) {
|
|
52493
|
-
await migrateLegacyProjectPluginRows2(
|
|
52494
|
-
connections.migration,
|
|
52495
|
-
legacySqlitePath,
|
|
52496
|
-
rootDir
|
|
52497
|
-
);
|
|
52498
|
-
}
|
|
52499
52722
|
}
|
|
52723
|
+
const { migrateLegacyProjectPluginRows: migrateLegacyProjectPluginRows2 } = await Promise.resolve().then(() => (init_sqlite_migrator(), sqlite_migrator_exports));
|
|
52724
|
+
await migrateLegacyProjectPluginRows2(connections.migration, legacySqlitePath, rootDir);
|
|
52500
52725
|
} catch (err) {
|
|
52501
52726
|
await connections.close().catch(() => void 0);
|
|
52502
52727
|
await stopEmbeddedRuntime(
|
|
@@ -62163,6 +62388,7 @@ var init_persistence = __esm({
|
|
|
62163
62388
|
defineTaskColumn("overlapBlockedBy", (task) => task.overlapBlockedBy ?? null),
|
|
62164
62389
|
defineTaskColumn("paused", (task) => task.paused ? 1 : 0),
|
|
62165
62390
|
defineTaskColumn("pausedReason", (task) => task.pausedReason ?? null),
|
|
62391
|
+
defineTaskColumn("wedgeNotification", (task) => toJsonNullable(task.wedgeNotification)),
|
|
62166
62392
|
defineTaskColumn("userPaused", (task) => task.userPaused ? 1 : 0),
|
|
62167
62393
|
defineTaskColumn("baseBranch", (task) => task.baseBranch ?? null),
|
|
62168
62394
|
defineTaskColumn("branch", (task) => task.branch ?? null),
|
|
@@ -62572,6 +62798,7 @@ function rowToTask(row) {
|
|
|
62572
62798
|
overlapBlockedBy: row.overlapBlockedBy || void 0,
|
|
62573
62799
|
paused: row.paused ? true : void 0,
|
|
62574
62800
|
pausedReason: row.pausedReason || void 0,
|
|
62801
|
+
wedgeNotification: fromJson(row.wedgeNotification) ?? void 0,
|
|
62575
62802
|
userPaused: row.userPaused ? true : void 0,
|
|
62576
62803
|
baseBranch: row.baseBranch || void 0,
|
|
62577
62804
|
executionStartBranch: row.executionStartBranch || void 0,
|
|
@@ -84827,6 +85054,7 @@ function getTaskSelectClauseImpl2(store, slim, tableAlias) {
|
|
|
84827
85054
|
"overlapBlockedBy",
|
|
84828
85055
|
"paused",
|
|
84829
85056
|
"pausedReason",
|
|
85057
|
+
"wedgeNotification",
|
|
84830
85058
|
"userPaused",
|
|
84831
85059
|
"baseBranch",
|
|
84832
85060
|
"branch",
|
|
@@ -91545,7 +91773,7 @@ var init_async_eval_store = __esm({
|
|
|
91545
91773
|
}
|
|
91546
91774
|
});
|
|
91547
91775
|
|
|
91548
|
-
// ../core/src/task-store/
|
|
91776
|
+
// ../core/src/task-store/project-store-ops.ts
|
|
91549
91777
|
import { randomUUID as randomUUID33 } from "node:crypto";
|
|
91550
91778
|
import { mkdir as mkdir13, writeFile as writeFile12 } from "node:fs/promises";
|
|
91551
91779
|
import { join as join33 } from "node:path";
|
|
@@ -92413,8 +92641,8 @@ function getEvalStoreImpl(store) {
|
|
|
92413
92641
|
return store.evalStore;
|
|
92414
92642
|
}
|
|
92415
92643
|
var workflowDefinitionBeforeInsertForTesting;
|
|
92416
|
-
var
|
|
92417
|
-
"../core/src/task-store/
|
|
92644
|
+
var init_project_store_ops = __esm({
|
|
92645
|
+
"../core/src/task-store/project-store-ops.ts"() {
|
|
92418
92646
|
"use strict";
|
|
92419
92647
|
init_store();
|
|
92420
92648
|
init_errors3();
|
|
@@ -99114,6 +99342,11 @@ async function updateTaskUnlockedImpl(store, id, updates, runContext) {
|
|
|
99114
99342
|
} else if (updates.pausedReason !== void 0) {
|
|
99115
99343
|
task.pausedReason = updates.pausedReason;
|
|
99116
99344
|
}
|
|
99345
|
+
if (updates.wedgeNotification === null) {
|
|
99346
|
+
task.wedgeNotification = void 0;
|
|
99347
|
+
} else if (updates.wedgeNotification !== void 0) {
|
|
99348
|
+
task.wedgeNotification = updates.wedgeNotification;
|
|
99349
|
+
}
|
|
99117
99350
|
if (updates.tokenBudgetSoftAlertedAt === null) {
|
|
99118
99351
|
task.tokenBudgetSoftAlertedAt = void 0;
|
|
99119
99352
|
} else if (updates.tokenBudgetSoftAlertedAt !== void 0) {
|
|
@@ -99776,7 +100009,7 @@ var init_store = __esm({
|
|
|
99776
100009
|
init_task_store_helpers();
|
|
99777
100010
|
init_task_row_mappers();
|
|
99778
100011
|
init_task_mutation_ops();
|
|
99779
|
-
|
|
100012
|
+
init_project_store_ops();
|
|
99780
100013
|
init_workflow_integrity();
|
|
99781
100014
|
init_branch_group_ops();
|
|
99782
100015
|
init_archive_lifecycle_2();
|
|
@@ -100640,6 +100873,26 @@ var init_store = __esm({
|
|
|
100640
100873
|
async updateTask(id, updates, runContext) {
|
|
100641
100874
|
return updateTaskImpl(this, id, updates, runContext);
|
|
100642
100875
|
}
|
|
100876
|
+
/**
|
|
100877
|
+
* Atomically opens or resolves the durable task-wedge episode. The task lock is
|
|
100878
|
+
* shared by SQLite and PostgreSQL persistence writes, so concurrent engine
|
|
100879
|
+
* observers cannot allocate two episodes for one active normalized reason.
|
|
100880
|
+
*/
|
|
100881
|
+
async claimTaskWedgeNotificationEpisode(taskId, reasonKey) {
|
|
100882
|
+
let result = { claimed: false };
|
|
100883
|
+
await this.updateTaskAtomic(taskId, (current) => {
|
|
100884
|
+
const prior = current.wedgeNotification;
|
|
100885
|
+
if (reasonKey === null) {
|
|
100886
|
+
if (!prior || prior.status === "resolved") return null;
|
|
100887
|
+
return { wedgeNotification: { ...prior, status: "resolved", transitionedAt: (/* @__PURE__ */ new Date()).toISOString() } };
|
|
100888
|
+
}
|
|
100889
|
+
if (prior?.status === "active" && prior.reasonKey === reasonKey) return null;
|
|
100890
|
+
const episodeId = randomUUID37();
|
|
100891
|
+
result = { episodeId, claimed: true };
|
|
100892
|
+
return { wedgeNotification: { reasonKey, episodeId, status: "active", transitionedAt: (/* @__PURE__ */ new Date()).toISOString() } };
|
|
100893
|
+
});
|
|
100894
|
+
return result;
|
|
100895
|
+
}
|
|
100643
100896
|
async claimNextToolFailureRetry(taskId, expectedCursor, maxRetries) {
|
|
100644
100897
|
return claimNextToolFailureRetryImpl(this, taskId, expectedCursor, maxRetries);
|
|
100645
100898
|
}
|
|
@@ -172025,6 +172278,7 @@ var init_ntfy_provider = __esm({
|
|
|
172025
172278
|
"in-review",
|
|
172026
172279
|
"merged",
|
|
172027
172280
|
"failed",
|
|
172281
|
+
"task-wedged",
|
|
172028
172282
|
"awaiting-approval",
|
|
172029
172283
|
"awaiting-user-review",
|
|
172030
172284
|
"planning-awaiting-input",
|
|
@@ -172128,6 +172382,15 @@ var init_ntfy_provider = __esm({
|
|
|
172128
172382
|
message: `Task "${identifier}" has failed and needs attention`,
|
|
172129
172383
|
priority: "high"
|
|
172130
172384
|
},
|
|
172385
|
+
"task-wedged": {
|
|
172386
|
+
title: `Task ${taskId} needs operator action`,
|
|
172387
|
+
message: [
|
|
172388
|
+
`Task "${identifier}" is wedged${typeof payload.metadata?.reason === "string" ? `: ${payload.metadata.reason}` : " and needs operator action"}`,
|
|
172389
|
+
typeof payload.metadata?.gate === "string" ? `Gate: ${payload.metadata.gate}` : null,
|
|
172390
|
+
typeof payload.metadata?.action === "string" ? `Recommended action: ${payload.metadata.action}` : null
|
|
172391
|
+
].filter((part) => part !== null).join("\n"),
|
|
172392
|
+
priority: "high"
|
|
172393
|
+
},
|
|
172131
172394
|
"awaiting-approval": {
|
|
172132
172395
|
title: payload.metadata?.awaitingApprovalReason === "plan-review-replan-cap" ? `Plan Review cap reached for ${taskId}` : `Plan needs approval for ${taskId}`,
|
|
172133
172396
|
/*
|
|
@@ -172482,6 +172745,132 @@ var init_transient_merge_error_classifier = __esm({
|
|
|
172482
172745
|
}
|
|
172483
172746
|
});
|
|
172484
172747
|
|
|
172748
|
+
// ../engine/src/notification/task-wedge-notification.ts
|
|
172749
|
+
function describeSelfHealingNoActionWedge(task, stage, metadata) {
|
|
172750
|
+
const description = SELF_HEALING_NO_ACTIONS[stage];
|
|
172751
|
+
if (!description || task.userPaused || task.paused || task.autoMerge === false) return null;
|
|
172752
|
+
const proof = metadata ?? {};
|
|
172753
|
+
if (proof.taskActive === true || proof.hasExecutingTaskLock === true || proof.mergePending === true) return null;
|
|
172754
|
+
if (Array.isArray(proof.livePaths) && proof.livePaths.length > 0) return null;
|
|
172755
|
+
return { reasonKey: `self-healing-no-action:${stage}`, ...description };
|
|
172756
|
+
}
|
|
172757
|
+
function describeTaskWedge(task) {
|
|
172758
|
+
const error2 = task.error ?? "";
|
|
172759
|
+
if (task.pausedReason === "completed-blocked") {
|
|
172760
|
+
return { reasonKey: "completion-blocked", reason: "Completed work is blocked from advancing to review.", action: "Clear the blocker or reset the task to todo." };
|
|
172761
|
+
}
|
|
172762
|
+
if (task.pausedReason === "error-retry-exhausted") {
|
|
172763
|
+
return { reasonKey: "heartbeat-retry-exhausted", reason: "The assigned agent exhausted its heartbeat recovery budget.", action: "Repair the agent configuration, then retry the task." };
|
|
172764
|
+
}
|
|
172765
|
+
if (task.pausedReason === "error-unrecoverable") {
|
|
172766
|
+
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." };
|
|
172767
|
+
}
|
|
172768
|
+
const pausedDescriptors = {
|
|
172769
|
+
"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." },
|
|
172770
|
+
"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." },
|
|
172771
|
+
"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." },
|
|
172772
|
+
"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." },
|
|
172773
|
+
"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." },
|
|
172774
|
+
"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." },
|
|
172775
|
+
"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." }
|
|
172776
|
+
};
|
|
172777
|
+
if (task.pausedReason && pausedDescriptors[task.pausedReason]) return pausedDescriptors[task.pausedReason];
|
|
172778
|
+
if (task.status !== "failed") return null;
|
|
172779
|
+
if (error2.startsWith("EXECUTION_DISPATCH_LOOP_EXHAUSTED")) {
|
|
172780
|
+
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." };
|
|
172781
|
+
}
|
|
172782
|
+
if (error2.includes("tool failure") || error2.includes("Tool failure")) {
|
|
172783
|
+
return { reasonKey: "tool-failure-retry-exhausted", reason: "Execution tool-failure retries were exhausted.", action: "Inspect the failing tool and retry the task." };
|
|
172784
|
+
}
|
|
172785
|
+
if (/escalat(?:ion|ed).*exhaust|exhaust.*escalat/i.test(error2)) {
|
|
172786
|
+
return { reasonKey: "execution-escalation-exhausted", reason: "The alternate execution escalation was exhausted.", action: "Inspect the failure and retry or rescope the task." };
|
|
172787
|
+
}
|
|
172788
|
+
if (/review.*(?:retry|rework|revision).*(?:exhaust|limit)|(?:exhaust|limit).*review/i.test(error2)) {
|
|
172789
|
+
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." };
|
|
172790
|
+
}
|
|
172791
|
+
const gate = error2.match(/check:([\w:-]+)/)?.[1];
|
|
172792
|
+
if (gate) {
|
|
172793
|
+
return {
|
|
172794
|
+
reasonKey: `merge-blocked:${gate}`,
|
|
172795
|
+
reason: `Merge is blocked by the check:${gate} verification gate.`,
|
|
172796
|
+
action: gate === "changeset-format" ? "Fix the changeset format, then retry the task." : "Fix the failing gate or reset the task to todo and retry.",
|
|
172797
|
+
gate: `check:${gate}`
|
|
172798
|
+
};
|
|
172799
|
+
}
|
|
172800
|
+
if (error2.startsWith("BLOCKED:")) {
|
|
172801
|
+
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." };
|
|
172802
|
+
}
|
|
172803
|
+
if (/merge.*(?:blocked|verification|gate)|(?:verification|gate).*(?:failed|exhaust)/i.test(error2)) {
|
|
172804
|
+
return { reasonKey: "merge-blocked", reason: "Merge verification cannot progress without operator action.", action: "Fix the failing verification, then retry the task." };
|
|
172805
|
+
}
|
|
172806
|
+
if (!error2 && (task.mergeRetries ?? 0) < 3) return null;
|
|
172807
|
+
return {
|
|
172808
|
+
reasonKey: "terminal-failed",
|
|
172809
|
+
reason: "The task entered a terminal failed state and needs operator intervention.",
|
|
172810
|
+
action: "Inspect the task error, fix the underlying issue, then retry or reset to todo."
|
|
172811
|
+
};
|
|
172812
|
+
}
|
|
172813
|
+
var SELF_HEALING_NO_ACTIONS;
|
|
172814
|
+
var init_task_wedge_notification = __esm({
|
|
172815
|
+
"../engine/src/notification/task-wedge-notification.ts"() {
|
|
172816
|
+
"use strict";
|
|
172817
|
+
SELF_HEALING_NO_ACTIONS = {
|
|
172818
|
+
"reclaim-pr-conflict": {
|
|
172819
|
+
reason: "Self-healing could not reclaim a stalled pull-request conflict.",
|
|
172820
|
+
action: "Inspect the branch conflict and retry or reset the task to todo."
|
|
172821
|
+
},
|
|
172822
|
+
"reclaim-self-owned-branch-conflict": {
|
|
172823
|
+
reason: "Self-healing could not recover a stalled branch conflict.",
|
|
172824
|
+
action: "Inspect the branch conflict and retry or reset the task to todo."
|
|
172825
|
+
},
|
|
172826
|
+
"reconcile-in-review-unmet-dependencies": {
|
|
172827
|
+
reason: "Unmet dependencies are preventing review from progressing.",
|
|
172828
|
+
action: "Resolve the dependencies, then retry or reset the task to todo."
|
|
172829
|
+
},
|
|
172830
|
+
"reconcile-dependency-blocking-lease": {
|
|
172831
|
+
reason: "A dependency-blocking task lease could not be safely reclaimed.",
|
|
172832
|
+
action: "Inspect the task owner and lease, then retry or reset the task to todo."
|
|
172833
|
+
},
|
|
172834
|
+
"auto-rebound-paused-scope-decay": {
|
|
172835
|
+
reason: "A paused task with stale scope could not be safely resumed.",
|
|
172836
|
+
action: "Inspect the task scope and retry or reset the task to todo."
|
|
172837
|
+
},
|
|
172838
|
+
"stuck-merge-deadlock": {
|
|
172839
|
+
reason: "A merge deadlock needs operator intervention.",
|
|
172840
|
+
action: "Inspect merge ownership and retry or reset the task to todo."
|
|
172841
|
+
},
|
|
172842
|
+
"missing-worktree-merge-active": {
|
|
172843
|
+
reason: "An active merge has an unusable worktree and could not be recovered.",
|
|
172844
|
+
action: "Repair the worktree or reset the task to todo and retry."
|
|
172845
|
+
},
|
|
172846
|
+
"missing-worktree-review": {
|
|
172847
|
+
reason: "Review has an unusable worktree and could not be recovered.",
|
|
172848
|
+
action: "Repair the worktree or reset the task to todo and retry."
|
|
172849
|
+
},
|
|
172850
|
+
"finalize-no-op-review": {
|
|
172851
|
+
reason: "A no-op review task could not be safely finalized.",
|
|
172852
|
+
action: "Inspect merge state and retry or reset the task to todo."
|
|
172853
|
+
},
|
|
172854
|
+
"stale-incomplete-review": {
|
|
172855
|
+
reason: "Incomplete review work could not be safely resumed.",
|
|
172856
|
+
action: "Inspect incomplete steps and retry or reset the task to todo."
|
|
172857
|
+
},
|
|
172858
|
+
"ghost-review": {
|
|
172859
|
+
reason: "A review task has no recoverable workflow owner.",
|
|
172860
|
+
action: "Inspect workflow state and retry or reset the task to todo."
|
|
172861
|
+
},
|
|
172862
|
+
"no-progress-no-task-done": {
|
|
172863
|
+
reason: "Execution stopped without progress and could not be safely requeued.",
|
|
172864
|
+
action: "Inspect the task worktree and retry or reset the task to todo."
|
|
172865
|
+
},
|
|
172866
|
+
"partial-progress-no-task-done": {
|
|
172867
|
+
reason: "Partial execution progress could not be safely resumed.",
|
|
172868
|
+
action: "Inspect partial work and retry or reset the task to todo."
|
|
172869
|
+
}
|
|
172870
|
+
};
|
|
172871
|
+
}
|
|
172872
|
+
});
|
|
172873
|
+
|
|
172485
172874
|
// ../engine/src/notification/notification-service.ts
|
|
172486
172875
|
var NotificationService;
|
|
172487
172876
|
var init_notification_service = __esm({
|
|
@@ -172493,6 +172882,7 @@ var init_notification_service = __esm({
|
|
|
172493
172882
|
init_transient_merge_error_classifier();
|
|
172494
172883
|
init_ntfy_provider();
|
|
172495
172884
|
init_webhook_provider();
|
|
172885
|
+
init_task_wedge_notification();
|
|
172496
172886
|
NotificationService = class {
|
|
172497
172887
|
constructor(store, options = {}) {
|
|
172498
172888
|
this.store = store;
|
|
@@ -172523,6 +172913,8 @@ var init_notification_service = __esm({
|
|
|
172523
172913
|
failureNotificationSuppressedCount = 0;
|
|
172524
172914
|
failureNotificationDelayMs = 6e4;
|
|
172525
172915
|
failureNotificationMode = "sticky-only";
|
|
172916
|
+
/** Compatibility fallback for lightweight test stores without the durable TaskStore CAS. */
|
|
172917
|
+
activeWedgeReasons = /* @__PURE__ */ new Map();
|
|
172526
172918
|
attachChatStore(chatStore) {
|
|
172527
172919
|
if (this.chatStore && this.chatStore !== chatStore) {
|
|
172528
172920
|
this.detachChatStoreListener(this.chatStore);
|
|
@@ -172634,6 +173026,10 @@ var init_notification_service = __esm({
|
|
|
172634
173026
|
}
|
|
172635
173027
|
}
|
|
172636
173028
|
handleTaskUpdated = (task) => {
|
|
173029
|
+
const transientFailure = task.status === "failed" ? classifyTransientMergeError(task.error) : null;
|
|
173030
|
+
const wedge = transientFailure ? null : describeTaskWedge(task);
|
|
173031
|
+
if (wedge) this.cancelPendingFailureNotification(task.id, "classified-terminal-wedge");
|
|
173032
|
+
if (!transientFailure) void this.maybeNotifyTaskWedge(task, wedge);
|
|
172637
173033
|
void this.maybeSuppressTransientFailedNotification(task, `status=${task.status ?? "undefined"}`);
|
|
172638
173034
|
if (task.status === "awaiting-approval") {
|
|
172639
173035
|
void this.writeAwaitingApprovalMailboxMessage(task);
|
|
@@ -172644,7 +173040,7 @@ var init_notification_service = __esm({
|
|
|
172644
173040
|
if (!this.notificationsEnabled) {
|
|
172645
173041
|
return;
|
|
172646
173042
|
}
|
|
172647
|
-
if (task.status === "failed") {
|
|
173043
|
+
if (task.status === "failed" && !wedge) {
|
|
172648
173044
|
const transientClass = classifyTransientMergeError(task.error);
|
|
172649
173045
|
if (transientClass) {
|
|
172650
173046
|
this.failureNotificationSuppressedCount += 1;
|
|
@@ -172730,6 +173126,69 @@ var init_notification_service = __esm({
|
|
|
172730
173126
|
);
|
|
172731
173127
|
}
|
|
172732
173128
|
}
|
|
173129
|
+
/*
|
|
173130
|
+
FNXC:TaskWedgeNotifications 2026-07-22-12:00:
|
|
173131
|
+
Terminal task updates are the shared seam for merger, executor, heartbeat, and
|
|
173132
|
+
self-healing parks. Clear only on a non-wedge lifecycle update, allowing a
|
|
173133
|
+
resolved-then-reparked reason to begin a new actionable episode.
|
|
173134
|
+
*/
|
|
173135
|
+
/** Delivers a self-healing no-action escalation through the durable wedge episode seam. */
|
|
173136
|
+
async notifyTaskWedge(task, descriptor) {
|
|
173137
|
+
await this.maybeNotifyTaskWedge(task, descriptor);
|
|
173138
|
+
}
|
|
173139
|
+
async maybeNotifyTaskWedge(task, suppliedDescriptor) {
|
|
173140
|
+
const descriptor = suppliedDescriptor ?? describeTaskWedge(task);
|
|
173141
|
+
let episode;
|
|
173142
|
+
if (!descriptor) {
|
|
173143
|
+
const isActiveSelfHealingNoAction = task.wedgeNotification?.status === "active" && task.wedgeNotification.reasonKey.startsWith("self-healing-no-action:");
|
|
173144
|
+
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 ?? "");
|
|
173145
|
+
if (hasProgressed) {
|
|
173146
|
+
this.activeWedgeReasons.delete(task.id);
|
|
173147
|
+
await this.store.claimTaskWedgeNotificationEpisode?.(task.id, null);
|
|
173148
|
+
}
|
|
173149
|
+
return;
|
|
173150
|
+
}
|
|
173151
|
+
if (this.store.claimTaskWedgeNotificationEpisode) {
|
|
173152
|
+
const claim = await this.store.claimTaskWedgeNotificationEpisode(task.id, descriptor.reasonKey);
|
|
173153
|
+
if (!claim.claimed || !claim.episodeId) return;
|
|
173154
|
+
episode = claim.episodeId;
|
|
173155
|
+
} else {
|
|
173156
|
+
if (this.activeWedgeReasons.get(task.id) === descriptor.reasonKey) return;
|
|
173157
|
+
this.activeWedgeReasons.set(task.id, descriptor.reasonKey);
|
|
173158
|
+
episode = `${task.id}:${descriptor.reasonKey}:${task.updatedAt}`;
|
|
173159
|
+
}
|
|
173160
|
+
const link = buildNtfyClickUrl({ dashboardHost: this.dashboardHost, projectId: this.options.projectId, taskId: task.id });
|
|
173161
|
+
const content = [
|
|
173162
|
+
`**${formatTaskIdentifier(task)} needs operator action**`,
|
|
173163
|
+
"",
|
|
173164
|
+
descriptor.reason,
|
|
173165
|
+
...descriptor.gate ? [`Gate: \`${descriptor.gate}\`.`] : [],
|
|
173166
|
+
`Recommended action: ${descriptor.action}`,
|
|
173167
|
+
...link ? ["", `[Open ${task.id}](${link})`] : []
|
|
173168
|
+
].join("\n");
|
|
173169
|
+
const payload = {
|
|
173170
|
+
taskId: task.id,
|
|
173171
|
+
taskTitle: task.title,
|
|
173172
|
+
taskDescription: task.description,
|
|
173173
|
+
event: "task-wedged",
|
|
173174
|
+
// Bounded descriptor text is operator-facing provider content, never audit metadata.
|
|
173175
|
+
metadata: { wedgeReason: descriptor.reasonKey, reason: descriptor.reason, action: descriptor.action, ...descriptor.gate ? { gate: descriptor.gate } : {}, notificationDedupeKey: `task-wedge:${episode}` }
|
|
173176
|
+
};
|
|
173177
|
+
void this.dispatch("task-wedged", payload);
|
|
173178
|
+
try {
|
|
173179
|
+
await this.options.messageStore?.sendMessageOnce?.({
|
|
173180
|
+
fromId: "system",
|
|
173181
|
+
fromType: "system",
|
|
173182
|
+
toId: DASHBOARD_USER_ID,
|
|
173183
|
+
toType: "user",
|
|
173184
|
+
type: "system",
|
|
173185
|
+
content,
|
|
173186
|
+
metadata: { taskId: task.id, kind: "task-wedge", wedgeReason: descriptor.reasonKey, ...descriptor.gate ? { gate: descriptor.gate } : {} }
|
|
173187
|
+
}, `task-wedge:${episode}`);
|
|
173188
|
+
} catch (error2) {
|
|
173189
|
+
schedulerLog.log(`[notify] ${task.id} wedge mailbox message failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
173190
|
+
}
|
|
173191
|
+
}
|
|
172733
173192
|
isTriageDuplicateDecision(task) {
|
|
172734
173193
|
return task.paused === true && task.pausedReason === "duplicate-decision-required" && task.sourceMetadata?.duplicateSource === "triage-marker" && typeof task.sourceMetadata.nearDuplicateOf === "string";
|
|
172735
173194
|
}
|
|
@@ -173095,6 +173554,11 @@ var init_notification_service = __esm({
|
|
|
173095
173554
|
);
|
|
173096
173555
|
return;
|
|
173097
173556
|
}
|
|
173557
|
+
if (describeTaskWedge(task)) {
|
|
173558
|
+
this.failureNotificationSuppressedCount += 1;
|
|
173559
|
+
schedulerLog.log(`[notify] ${taskId} classified terminal wedge at dispatch time \u2014 suppressed generic failed notification`);
|
|
173560
|
+
return;
|
|
173561
|
+
}
|
|
173098
173562
|
const isTerminal2 = task.paused === true || task.column === "in-review";
|
|
173099
173563
|
if (this.failureNotificationMode === "terminal-only" && !isTerminal2) {
|
|
173100
173564
|
this.failureNotificationSuppressedCount += 1;
|
|
@@ -173923,7 +174387,10 @@ var init_notifier = __esm({
|
|
|
173923
174387
|
DEFAULT_NTFY_EVENTS = [
|
|
173924
174388
|
"in-review",
|
|
173925
174389
|
"merged",
|
|
174390
|
+
// FNXC:TaskWedgeNotifications 2026-07-22-19:00: Wedge episodes are operator
|
|
174391
|
+
// escalation events, so normal Ntfy defaults must not silently filter them.
|
|
173926
174392
|
"failed",
|
|
174393
|
+
"task-wedged",
|
|
173927
174394
|
"awaiting-approval",
|
|
173928
174395
|
"awaiting-user-review",
|
|
173929
174396
|
"planning-awaiting-input",
|
|
@@ -200471,6 +200938,7 @@ var init_self_healing = __esm({
|
|
|
200471
200938
|
init_dependency_blocked_todo_reporter();
|
|
200472
200939
|
init_scheduler();
|
|
200473
200940
|
init_task_agent_sync();
|
|
200941
|
+
init_task_wedge_notification();
|
|
200474
200942
|
init_self_healing_constants();
|
|
200475
200943
|
init_self_healing_constants();
|
|
200476
200944
|
init_self_healing_branch();
|
|
@@ -200778,6 +201246,15 @@ var init_self_healing = __esm({
|
|
|
200778
201246
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
200779
201247
|
log28.warn(`[${stage}] ${task.id}: no-action audit emission failed: ${message}`);
|
|
200780
201248
|
}
|
|
201249
|
+
const descriptor = describeSelfHealingNoActionWedge(task, stage, proof.metadata);
|
|
201250
|
+
if (descriptor) {
|
|
201251
|
+
try {
|
|
201252
|
+
await getActiveNotificationService()?.notifyTaskWedge(task, descriptor);
|
|
201253
|
+
} catch (error2) {
|
|
201254
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
201255
|
+
log28.warn(`[${stage}] ${task.id}: wedge notification failed: ${message}`);
|
|
201256
|
+
}
|
|
201257
|
+
}
|
|
200781
201258
|
log28.log(`[${stage}] ${task.id}: triple-proof not satisfied \u2014 no action (operator-decides)`);
|
|
200782
201259
|
}
|
|
200783
201260
|
/*
|
|
@@ -261747,6 +262224,40 @@ async function resolvePlanningModeSystemPrompt(store, promptOverrides, workflowI
|
|
|
261747
262224
|
|
|
261748
262225
|
${PLANNING_SYSTEM_PROMPT}`;
|
|
261749
262226
|
}
|
|
262227
|
+
function isPlanningTurnActive(sessionId) {
|
|
262228
|
+
return activeGenerations.has(sessionId) || pendingTurnReservations.has(sessionId);
|
|
262229
|
+
}
|
|
262230
|
+
function reservePlanningTurn(sessionId) {
|
|
262231
|
+
if (isPlanningTurnActive(sessionId)) {
|
|
262232
|
+
throw new GenerationInProgressError("Generation already in progress");
|
|
262233
|
+
}
|
|
262234
|
+
let resolveDone;
|
|
262235
|
+
const done = new Promise((resolve51) => {
|
|
262236
|
+
resolveDone = resolve51;
|
|
262237
|
+
});
|
|
262238
|
+
const reservation = { done, resolveDone };
|
|
262239
|
+
pendingTurnReservations.set(sessionId, reservation);
|
|
262240
|
+
return () => {
|
|
262241
|
+
if (pendingTurnReservations.get(sessionId) === reservation) {
|
|
262242
|
+
pendingTurnReservations.delete(sessionId);
|
|
262243
|
+
}
|
|
262244
|
+
reservation.resolveDone();
|
|
262245
|
+
};
|
|
262246
|
+
}
|
|
262247
|
+
function trackTurnOperationSettled(sessionId, operationPromise) {
|
|
262248
|
+
const settled = operationPromise.then(
|
|
262249
|
+
() => {
|
|
262250
|
+
},
|
|
262251
|
+
() => {
|
|
262252
|
+
}
|
|
262253
|
+
);
|
|
262254
|
+
settlingTurnOperations.set(sessionId, settled);
|
|
262255
|
+
void settled.then(() => {
|
|
262256
|
+
if (settlingTurnOperations.get(sessionId) === settled) {
|
|
262257
|
+
settlingTurnOperations.delete(sessionId);
|
|
262258
|
+
}
|
|
262259
|
+
});
|
|
262260
|
+
}
|
|
261750
262261
|
function isTaskPriority2(value) {
|
|
261751
262262
|
return typeof value === "string" && TASK_PRIORITIES.includes(value);
|
|
261752
262263
|
}
|
|
@@ -262090,7 +262601,7 @@ async function getFirstQuestionFromAgent(session, message) {
|
|
|
262090
262601
|
if (!session.agent) {
|
|
262091
262602
|
throw new InvalidSessionStateError("AI agent not initialized");
|
|
262092
262603
|
}
|
|
262093
|
-
await session.agent.session
|
|
262604
|
+
await promptPlanningAgent(session.agent.session, message);
|
|
262094
262605
|
const lastMessage = session.agent.session.state.messages.filter((m2) => m2.role === "assistant").pop();
|
|
262095
262606
|
let responseText = "";
|
|
262096
262607
|
if (lastMessage?.content) {
|
|
@@ -262129,7 +262640,8 @@ async function getFirstQuestionFromAgent(session, message) {
|
|
|
262129
262640
|
lastError = err instanceof Error ? err : new Error(String(err));
|
|
262130
262641
|
if (attempt < MAX_PARSE_RETRIES2) {
|
|
262131
262642
|
try {
|
|
262132
|
-
await
|
|
262643
|
+
await promptPlanningAgent(
|
|
262644
|
+
session.agent.session,
|
|
262133
262645
|
'Your previous response could not be parsed as JSON. Please respond with ONLY a valid JSON object: {"type":"question","data":{"runningPlan":{...},...}}. No markdown, no explanation, just the JSON.'
|
|
262134
262646
|
);
|
|
262135
262647
|
const retryMessage = session.agent.session.state.messages.filter((m2) => m2.role === "assistant").pop();
|
|
@@ -262189,7 +262701,8 @@ function buildMandatoryFirstPlanningQuestion(userInput = "") {
|
|
|
262189
262701
|
}
|
|
262190
262702
|
async function requestMandatoryFirstPlanningQuestion(session, abortSignal) {
|
|
262191
262703
|
try {
|
|
262192
|
-
await
|
|
262704
|
+
await promptPlanningAgent(
|
|
262705
|
+
session.agent.session,
|
|
262193
262706
|
'Before producing a plan, ask one clarifying question. Return ONLY valid JSON: {"type":"question","data":{...}}.',
|
|
262194
262707
|
{ signal: abortSignal }
|
|
262195
262708
|
);
|
|
@@ -262212,6 +262725,8 @@ async function createPlanningAgent(session, rootDir, store, modelProvider, model
|
|
|
262212
262725
|
await ensureEngineReady();
|
|
262213
262726
|
const systemPrompt = await resolvePlanningModeSystemPrompt(store, promptOverrides, session.workflowId);
|
|
262214
262727
|
const skillContext = buildSessionSkillContextSync(null, "executor", rootDir, pluginRunner);
|
|
262728
|
+
const callbackEpoch = session.agentCallbackEpoch ?? 0;
|
|
262729
|
+
const callbacksInvalidated = () => (session.agentCallbackEpoch ?? 0) !== callbackEpoch;
|
|
262215
262730
|
return createFnAgent4({
|
|
262216
262731
|
cwd: rootDir,
|
|
262217
262732
|
systemPrompt,
|
|
@@ -262235,6 +262750,7 @@ async function createPlanningAgent(session, rootDir, store, modelProvider, model
|
|
|
262235
262750
|
} : {},
|
|
262236
262751
|
...thinkingLevel ? { defaultThinkingLevel: thinkingLevel } : {},
|
|
262237
262752
|
onThinking: (delta) => {
|
|
262753
|
+
if (callbacksInvalidated()) return;
|
|
262238
262754
|
markPlanningGenerationProgress(session.id, delta);
|
|
262239
262755
|
session.thinkingOutput += delta;
|
|
262240
262756
|
persistThinking(session.id, session.thinkingOutput);
|
|
@@ -262244,6 +262760,7 @@ async function createPlanningAgent(session, rootDir, store, modelProvider, model
|
|
|
262244
262760
|
});
|
|
262245
262761
|
},
|
|
262246
262762
|
onText: (delta) => {
|
|
262763
|
+
if (callbacksInvalidated()) return;
|
|
262247
262764
|
markPlanningGenerationProgress(session.id, delta);
|
|
262248
262765
|
session.thinkingOutput += delta;
|
|
262249
262766
|
persistThinking(session.id, session.thinkingOutput);
|
|
@@ -262290,7 +262807,7 @@ async function ensureSessionAgent(session, rootDir, historyForReplay, promptOver
|
|
|
262290
262807
|
if (abortSignal.aborted) {
|
|
262291
262808
|
throw createAbortError2();
|
|
262292
262809
|
}
|
|
262293
|
-
await session.agent.session
|
|
262810
|
+
await promptPlanningAgent(session.agent.session, contextMessage, {
|
|
262294
262811
|
signal: abortSignal
|
|
262295
262812
|
});
|
|
262296
262813
|
if (abortSignal.aborted) {
|
|
@@ -262328,7 +262845,7 @@ async function maybeNotifyPlanningAwaitingInput(session, question, proactiveClar
|
|
|
262328
262845
|
}
|
|
262329
262846
|
}
|
|
262330
262847
|
function buildRetryableParseErrorMessage(error2) {
|
|
262331
|
-
const baseMessage = (error2?.message || "Failed to parse AI response").replace(/\s*Please try again\.?\s*$/i, "").trim();
|
|
262848
|
+
const baseMessage = (error2?.message || "Failed to parse AI response").replace(/\s*Please try again\.?\s*$/i, "").replace(/[.\s]+$/, "").trim();
|
|
262332
262849
|
return `${baseMessage}. Retry this planning session or start a new one.`;
|
|
262333
262850
|
}
|
|
262334
262851
|
function setSessionError(session, message) {
|
|
@@ -262345,6 +262862,19 @@ function createAbortError2() {
|
|
|
262345
262862
|
error2.name = "AbortError";
|
|
262346
262863
|
return error2;
|
|
262347
262864
|
}
|
|
262865
|
+
async function promptPlanningAgent(agentSession, message, options) {
|
|
262866
|
+
let promptWithFallback2;
|
|
262867
|
+
try {
|
|
262868
|
+
promptWithFallback2 = promptWithFallback;
|
|
262869
|
+
} catch {
|
|
262870
|
+
promptWithFallback2 = void 0;
|
|
262871
|
+
}
|
|
262872
|
+
if (typeof promptWithFallback2 === "function") {
|
|
262873
|
+
await promptWithFallback2(agentSession, message, options);
|
|
262874
|
+
return;
|
|
262875
|
+
}
|
|
262876
|
+
await agentSession.prompt(message, options);
|
|
262877
|
+
}
|
|
262348
262878
|
function normalizeGenerationProgress(output) {
|
|
262349
262879
|
return output.replace(/\s+/g, " ").trim();
|
|
262350
262880
|
}
|
|
@@ -262420,7 +262950,9 @@ async function runGenerationWithTimeout(session, operation) {
|
|
|
262420
262950
|
);
|
|
262421
262951
|
});
|
|
262422
262952
|
try {
|
|
262423
|
-
|
|
262953
|
+
const operationPromise = operation(abortController.signal);
|
|
262954
|
+
trackTurnOperationSettled(session.id, operationPromise);
|
|
262955
|
+
return await Promise.race([operationPromise, abortPromise]);
|
|
262424
262956
|
} finally {
|
|
262425
262957
|
clearTimeout(generationRecord.timer);
|
|
262426
262958
|
if (activeGenerations.get(session.id) === generationRecord) {
|
|
@@ -262572,7 +263104,7 @@ async function continueAgentConversation(session, message) {
|
|
|
262572
263104
|
if (abortSignal.aborted) {
|
|
262573
263105
|
throw createAbortError2();
|
|
262574
263106
|
}
|
|
262575
|
-
await session.agent.session
|
|
263107
|
+
await promptPlanningAgent(session.agent.session, message, {
|
|
262576
263108
|
signal: abortSignal
|
|
262577
263109
|
});
|
|
262578
263110
|
if (abortSignal.aborted) {
|
|
@@ -262622,7 +263154,8 @@ async function continueAgentConversation(session, message) {
|
|
|
262622
263154
|
if (abortSignal.aborted) {
|
|
262623
263155
|
throw createAbortError2();
|
|
262624
263156
|
}
|
|
262625
|
-
await
|
|
263157
|
+
await promptPlanningAgent(
|
|
263158
|
+
session.agent.session,
|
|
262626
263159
|
'Your previous response could not be parsed as JSON. Please respond with ONLY a valid JSON object: {"type":"question","data":{"runningPlan":{...},...}}. No markdown, no explanation, just the JSON.',
|
|
262627
263160
|
{ signal: abortSignal }
|
|
262628
263161
|
);
|
|
@@ -262898,57 +263431,62 @@ async function submitResponse(sessionId, responses, rootDir, promptOverrides, st
|
|
|
262898
263431
|
}
|
|
262899
263432
|
if (store && !session.store) session.store = store;
|
|
262900
263433
|
if (rootDir && !session.rootDir) session.rootDir = rootDir;
|
|
262901
|
-
if (
|
|
263434
|
+
if (isPlanningTurnActive(session.id)) {
|
|
262902
263435
|
if (didSubmitSameAnswer(session, responses)) {
|
|
262903
263436
|
throw new GenerationInProgressError("Generation already in progress for this response");
|
|
262904
263437
|
}
|
|
262905
263438
|
throw new GenerationInProgressError("Generation already in progress");
|
|
262906
263439
|
}
|
|
263440
|
+
const releaseTurn = reservePlanningTurn(session.id);
|
|
262907
263441
|
let answeredQuestion;
|
|
262908
|
-
|
|
262909
|
-
|
|
262910
|
-
|
|
262911
|
-
|
|
262912
|
-
|
|
262913
|
-
|
|
262914
|
-
|
|
262915
|
-
|
|
262916
|
-
|
|
262917
|
-
|
|
262918
|
-
|
|
262919
|
-
|
|
262920
|
-
const currentQuestion = captureOtherCustomText(session.currentQuestion, responses);
|
|
262921
|
-
const historyEntry = {
|
|
262922
|
-
question: currentQuestion,
|
|
262923
|
-
response: responses,
|
|
262924
|
-
thinkingOutput: session.lastGeneratedThinking || ""
|
|
262925
|
-
};
|
|
262926
|
-
session.error = void 0;
|
|
262927
|
-
const editIndex = session.editingQuestionId ? session.history.findIndex((entry) => entry.question.id === session.editingQuestionId) : -1;
|
|
262928
|
-
const isEditingPriorAnswer = editIndex >= 0;
|
|
262929
|
-
if (isEditingPriorAnswer) {
|
|
262930
|
-
session.history[editIndex] = historyEntry;
|
|
262931
|
-
session.editingQuestionId = void 0;
|
|
262932
|
-
session.summary = buildRunningSummary(session.initialPlan, session.history);
|
|
262933
|
-
disposeSessionAgentForRetry(session);
|
|
263442
|
+
try {
|
|
263443
|
+
if (isRefineRequest(responses) && session.summary) {
|
|
263444
|
+
beginPlanningGeneration(session, "question");
|
|
263445
|
+
session.currentQuestion = void 0;
|
|
263446
|
+
session.error = void 0;
|
|
263447
|
+
await persistSession(session, "generating");
|
|
263448
|
+
await ensureSessionAgent(session, rootDir, session.history, promptOverrides, store);
|
|
263449
|
+
const focus = typeof responses.focus === "string" ? responses.focus.trim() : void 0;
|
|
263450
|
+
const refineMessage = formatRefineRequestForAgent(session.summary, focus);
|
|
263451
|
+
await continueAgentConversation(session, refineMessage);
|
|
263452
|
+
} else if (!session.currentQuestion) {
|
|
263453
|
+
throw new InvalidSessionStateError("No active question in session");
|
|
262934
263454
|
} else {
|
|
262935
|
-
session.
|
|
262936
|
-
|
|
262937
|
-
|
|
262938
|
-
|
|
262939
|
-
|
|
262940
|
-
|
|
262941
|
-
|
|
262942
|
-
|
|
262943
|
-
|
|
262944
|
-
|
|
262945
|
-
|
|
262946
|
-
|
|
262947
|
-
|
|
262948
|
-
|
|
263455
|
+
const currentQuestion = captureOtherCustomText(session.currentQuestion, responses);
|
|
263456
|
+
const historyEntry = {
|
|
263457
|
+
question: currentQuestion,
|
|
263458
|
+
response: responses,
|
|
263459
|
+
thinkingOutput: session.lastGeneratedThinking || ""
|
|
263460
|
+
};
|
|
263461
|
+
session.error = void 0;
|
|
263462
|
+
const editIndex = session.editingQuestionId ? session.history.findIndex((entry) => entry.question.id === session.editingQuestionId) : -1;
|
|
263463
|
+
const isEditingPriorAnswer = editIndex >= 0;
|
|
263464
|
+
if (isEditingPriorAnswer) {
|
|
263465
|
+
session.history[editIndex] = historyEntry;
|
|
263466
|
+
session.editingQuestionId = void 0;
|
|
263467
|
+
session.summary = buildRunningSummary(session.initialPlan, session.history);
|
|
263468
|
+
disposeSessionAgentForRetry(session);
|
|
263469
|
+
} else {
|
|
263470
|
+
session.history.push(historyEntry);
|
|
263471
|
+
}
|
|
263472
|
+
answeredQuestion = currentQuestion;
|
|
263473
|
+
beginPlanningGeneration(session, "plan_update");
|
|
263474
|
+
session.currentQuestion = void 0;
|
|
263475
|
+
await persistSession(session, "generating");
|
|
263476
|
+
if (!session.agent) {
|
|
263477
|
+
await ensureSessionAgent(
|
|
263478
|
+
session,
|
|
263479
|
+
rootDir,
|
|
263480
|
+
isEditingPriorAnswer ? session.history : session.history.slice(0, -1),
|
|
263481
|
+
promptOverrides,
|
|
263482
|
+
store
|
|
263483
|
+
);
|
|
263484
|
+
}
|
|
263485
|
+
const message = isEditingPriorAnswer ? "An earlier answer was edited. Use the complete preserved interview context above, regenerate the running plan, and ask exactly one next question." : formatResponseForAgent(currentQuestion, responses);
|
|
263486
|
+
await continueAgentConversation(session, message);
|
|
262949
263487
|
}
|
|
262950
|
-
|
|
262951
|
-
|
|
263488
|
+
} finally {
|
|
263489
|
+
releaseTurn();
|
|
262952
263490
|
}
|
|
262953
263491
|
if (session.currentQuestion) {
|
|
262954
263492
|
return { type: "question", data: session.currentQuestion };
|
|
@@ -263029,6 +263567,7 @@ Additional context: ${comment}` : formatted;
|
|
|
263029
263567
|
Regenerate the runningPlan fields (title, description, concrete proposedChanges, observable acceptanceCriteria, suggestedSize, optional priority, suggestedDependencies, concrete keyDeliverables, and all distinct high-value suggestedRefinements) informed by this answer; do not cap suggestedRefinements at three. Author the operator-facing plan in Markdown: use concise GitHub-flavored Markdown in the description, with the structured fields supplying its Markdown sections and lists. Never list interview questions as deliverables or PROMPT.md sections such as Mission, Steps, File Scope, Review Level, Completion Criteria, or Do NOT. Return type:"question" with that complete runningPlan and ask exactly one next question. Do not validate the plan; only the user can proceed with it.`;
|
|
263030
263568
|
}
|
|
263031
263569
|
function disposeSessionAgentForRetry(session) {
|
|
263570
|
+
session.agentCallbackEpoch = (session.agentCallbackEpoch ?? 0) + 1;
|
|
263032
263571
|
if (!session.agent) {
|
|
263033
263572
|
return;
|
|
263034
263573
|
}
|
|
@@ -263111,7 +263650,7 @@ async function getSession(sessionId) {
|
|
|
263111
263650
|
return void 0;
|
|
263112
263651
|
}
|
|
263113
263652
|
}
|
|
263114
|
-
var PLANNING_NO_AMBIENT_TASK_ID, PLANNING_BUILTIN_WEB_TOOLS, createFnAgent4, planningNtfyHelpers, diagnostics2, PLANNING_SYSTEM_PROMPT, SESSION_TTL_MS, CLEANUP_INTERVAL_MS2, MAX_SESSIONS_PER_IP_PER_HOUR, RATE_LIMIT_WINDOW_MS2, GENERATION_TIMEOUT_MS, GENERATION_LOOP_REPEAT_LIMIT, PLANNING_STUCK_ERROR_MESSAGE, PLANNING_LOOP_ERROR_MESSAGE, sessions, rateLimits2, activeGenerations, _aiSessionStore, sessionPersistenceQueues, cleanupInterval2, PlanningStreamManager, planningStreamManager, MAX_PARSE_RETRIES2, TruncatedPlanningCompletionError, RateLimitError3, SessionNotFoundError, InvalidSessionStateError, GenerationInProgressError;
|
|
263653
|
+
var PLANNING_NO_AMBIENT_TASK_ID, PLANNING_BUILTIN_WEB_TOOLS, createFnAgent4, planningNtfyHelpers, diagnostics2, PLANNING_SYSTEM_PROMPT, SESSION_TTL_MS, CLEANUP_INTERVAL_MS2, MAX_SESSIONS_PER_IP_PER_HOUR, RATE_LIMIT_WINDOW_MS2, GENERATION_TIMEOUT_MS, GENERATION_LOOP_REPEAT_LIMIT, PLANNING_STUCK_ERROR_MESSAGE, PLANNING_LOOP_ERROR_MESSAGE, sessions, rateLimits2, activeGenerations, pendingTurnReservations, settlingTurnOperations, _aiSessionStore, sessionPersistenceQueues, cleanupInterval2, PlanningStreamManager, planningStreamManager, MAX_PARSE_RETRIES2, TruncatedPlanningCompletionError, RateLimitError3, SessionNotFoundError, InvalidSessionStateError, GenerationInProgressError;
|
|
263115
263654
|
var init_planning = __esm({
|
|
263116
263655
|
"../dashboard/src/planning.ts"() {
|
|
263117
263656
|
"use strict";
|
|
@@ -263146,6 +263685,8 @@ Every turn must include the running-plan fields: only title, description, concre
|
|
|
263146
263685
|
sessions = /* @__PURE__ */ new Map();
|
|
263147
263686
|
rateLimits2 = /* @__PURE__ */ new Map();
|
|
263148
263687
|
activeGenerations = /* @__PURE__ */ new Map();
|
|
263688
|
+
pendingTurnReservations = /* @__PURE__ */ new Map();
|
|
263689
|
+
settlingTurnOperations = /* @__PURE__ */ new Map();
|
|
263149
263690
|
sessionPersistenceQueues = /* @__PURE__ */ new Map();
|
|
263150
263691
|
cleanupInterval2 = setInterval(cleanupExpiredSessions, CLEANUP_INTERVAL_MS2);
|
|
263151
263692
|
cleanupInterval2.unref?.();
|
|
@@ -263219,6 +263760,10 @@ Every turn must include the running-plan fields: only title, description, concre
|
|
|
263219
263760
|
}
|
|
263220
263761
|
this.pendingInitialTurns.set(sessionId, start);
|
|
263221
263762
|
}
|
|
263763
|
+
/** True while a registered initial turn has not been consumed by a stream connection yet. */
|
|
263764
|
+
hasPendingInitialTurn(sessionId) {
|
|
263765
|
+
return this.pendingInitialTurns.has(sessionId);
|
|
263766
|
+
}
|
|
263222
263767
|
consumeInitialTurn(sessionId) {
|
|
263223
263768
|
const start = this.pendingInitialTurns.get(sessionId);
|
|
263224
263769
|
if (!start) {
|
|
@@ -263258,7 +263803,7 @@ Every turn must include the running-plan fields: only title, description, concre
|
|
|
263258
263803
|
this.removeAllListeners();
|
|
263259
263804
|
}
|
|
263260
263805
|
};
|
|
263261
|
-
planningStreamManager = new PlanningStreamManager();
|
|
263806
|
+
planningStreamManager = new PlanningStreamManager(2e3);
|
|
263262
263807
|
MAX_PARSE_RETRIES2 = 1;
|
|
263263
263808
|
TruncatedPlanningCompletionError = class extends Error {
|
|
263264
263809
|
constructor() {
|
|
@@ -270646,7 +271191,7 @@ var init_chat = __esm({
|
|
|
270646
271191
|
};
|
|
270647
271192
|
CHAT_SYSTEM_PROMPT = `${FUSION_RUNTIME_SELF_AWARENESS}
|
|
270648
271193
|
|
|
270649
|
-
You are a helpful AI assistant integrated into the fn task board system. You help users with questions about their project, code, architecture, and tasks. You have coding workspace tools on the project checkout: \`read\`, \`write\`, \`edit\`, \`bash\`, \`grep\`, \`find\`, and \`ls\`. Use \`write\`, \`edit\`, and \`bash\` for user-requested code changes, file edits, or shell investigation; prefer minimal, user-directed mutations and respect any pending-approval or blocked tool result. Do not claim that you only have read access. Do not change the branch the working directory is checked out on: do not run \`git checkout <branch>\` or \`git switch <branch>\` to a different branch unless the user explicitly asks. Read-only Git and branch inspection, such as \`git status\`, \`git branch\`, and \`git log\`, is allowed. Response length policy: default to a short, crisp reply (a few sentences or a short bulleted list) that directly answers the user; avoid preamble, restating the question, and filler. If a thorough answer genuinely needs long-form content (for example multi-step plans, design proposals, deep analyses, or long file excerpts), keep the chat reply brief with a one- or two-sentence summary
|
|
271194
|
+
You are a helpful AI assistant integrated into the fn task board system. You help users with questions about their project, code, architecture, and tasks. You have coding workspace tools on the project checkout: \`read\`, \`write\`, \`edit\`, \`bash\`, \`grep\`, \`find\`, and \`ls\`. Use \`write\`, \`edit\`, and \`bash\` for user-requested code changes, file edits, or shell investigation; prefer minimal, user-directed mutations and respect any pending-approval or blocked tool result. Do not claim that you only have read access. Do not change the branch the working directory is checked out on: do not run \`git checkout <branch>\` or \`git switch <branch>\` to a different branch unless the user explicitly asks. Read-only Git and branch inspection, such as \`git status\`, \`git branch\`, and \`git log\`, is allowed. Response length policy: default to a short, crisp reply (a few sentences or a short bulleted list) that directly answers the user; avoid preamble, restating the question, and filler. For questions about this repository's code or architecture, prioritize correctness and cite real paths/symbols over maximum brevity \u2014 still lead short, but do not omit the evidence needed to be accurate. If a thorough answer genuinely needs long-form content (for example multi-step plans, design proposals, deep multi-file traces, deep analyses, or long file excerpts), keep the chat reply brief with a one- or two-sentence summary plus key citations. When \`fn_send_message\` is available in this session, send the full write-up via \`fn_send_message\` using \`type: "agent-to-user"\` and \`to_id: "dashboard"\` (additive detail that must not duplicate the chat reply). When that tool is not available, put the necessary detail in the chat reply itself rather than inventing a mailbox path.`;
|
|
270650
271195
|
RATE_LIMIT_WINDOW_MS5 = 60 * 1e3;
|
|
270651
271196
|
MAX_REFERENCED_FILE_SIZE = 50 * 1024;
|
|
270652
271197
|
ChatStreamManager = class extends EventEmitter39 {
|