specrails-desktop 2.21.0 → 2.23.0
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/README.md +3 -3
- package/client/dist/assets/{ActivityFeedPage-BPkf89Xk.js → ActivityFeedPage-Cq4UlyrP.js} +1 -1
- package/client/dist/assets/AgentBrowserCapture-BqGtoL0L.js +1 -0
- package/client/dist/assets/{AgentModeCodePane-DhVkOSdv.js → AgentModeCodePane-W7XIIcKj.js} +2 -2
- package/client/dist/assets/AgentModeJobsPane-CryUvMB9.js +1 -0
- package/client/dist/assets/AgentsPage-Re0K2JCa.js +86 -0
- package/client/dist/assets/AnalyticsPage-27FMsav_.js +1 -0
- package/client/dist/assets/{BarChart-9_p1-qtv.js → BarChart-BiFF8sw8.js} +1 -1
- package/client/dist/assets/CodePage-Ud12s91j.js +2 -0
- package/client/dist/assets/DesktopAnalyticsPage-BdjWlYgU.js +1 -0
- package/client/dist/assets/DocsDialog-DG_c7_6k.js +11 -0
- package/client/dist/assets/DocsPage-CDieUvMv.js +11 -0
- package/client/dist/assets/{ExportDropdown-Clt8DyCs.js → ExportDropdown-Cokk4zlC.js} +1 -1
- package/client/dist/assets/IntegrationsPage-oyvHxjdV.js +3 -0
- package/client/dist/assets/InteractiveJobComposer-C2w9yVm8.js +19 -0
- package/client/dist/assets/JobDetailModal-DEStK2P4.js +1 -0
- package/client/dist/assets/JobDetailPage-BqdQ1wOs.js +1 -0
- package/client/dist/assets/JobsPage-BH5pl9o_.js +1 -0
- package/client/dist/assets/LoopBuilderPage-B8QhQ4FV.js +7 -0
- package/client/dist/assets/LoopPreviewModal-CK58XIQ_.js +1 -0
- package/client/dist/assets/LoopsPage-C0aVmXxN.js +1 -0
- package/client/dist/assets/ProjectSettingsDialog-Bf_x-MSF.js +1 -0
- package/client/dist/assets/TemplatePreviewModal-Rtc2P5v3.js +1 -0
- package/client/dist/assets/agent-A0LpODvj2.js +1 -0
- package/client/dist/assets/agent-BCi1xJEH.js +1 -0
- package/client/dist/assets/agent-BmmZdeg7.js +1 -0
- package/client/dist/assets/agent-Bpm3uEw7.js +1 -0
- package/client/dist/assets/agent-BrmiC8zZ.js +1 -0
- package/client/dist/assets/agent-CBOOT08j2.js +1 -0
- package/client/dist/assets/agent-CZ7HdyTA.js +1 -0
- package/client/dist/assets/agent-DPGlEboi2.js +1 -0
- package/client/dist/assets/{upload-DPRq2dC-.js → brain-DDEGUEos.js} +1 -1
- package/client/dist/assets/{browser-DEEO-OSi.js → browser-BPkhILSJ.js} +1 -1
- package/client/dist/assets/{browser-BTivfZKE2.js → browser-BijVYG0Y2.js} +1 -1
- package/client/dist/assets/{browser-bpO3onlS.js → browser-BqLqJVVT.js} +1 -1
- package/client/dist/assets/{browser-DlSXtfu5.js → browser-Cc0iDqUi.js} +1 -1
- package/client/dist/assets/browser-CdS6O1Qb.js +1 -0
- package/client/dist/assets/{browser-BKP6hqQC2.js → browser-Cvg-QHvd2.js} +1 -1
- package/client/dist/assets/{browser-INCUyduh.js → browser-FRv8P02E.js} +1 -1
- package/client/dist/assets/{browser-DlKLfT612.js → browser-rWKj-RR_2.js} +1 -1
- package/client/dist/assets/code-BRcDlze52.js +1 -0
- package/client/dist/assets/code-BdMy3Ffq.js +1 -0
- package/client/dist/assets/code-CeQ0FZpC.js +1 -0
- package/client/dist/assets/code-CqCcRThR.js +1 -0
- package/client/dist/assets/code-DgeHz9CB.js +1 -0
- package/client/dist/assets/code-DzC1rMk12.js +1 -0
- package/client/dist/assets/code-UPVvmAKM2.js +1 -0
- package/client/dist/assets/code-thSEptMx.js +1 -0
- package/client/dist/assets/{common-QjVnq9XP2.js → common-BM3LFLCE2.js} +1 -1
- package/client/dist/assets/{common-CeQUwuHt2.js → common-Bwafujnc2.js} +1 -1
- package/client/dist/assets/{common-Bb64s3Bm.js → common-C-vU-j-I.js} +1 -1
- package/client/dist/assets/{common-KbQuTSGg.js → common-C5HKSbbz.js} +1 -1
- package/client/dist/assets/{common-BPQQkgJZ.js → common-CYaT2yHp.js} +1 -1
- package/client/dist/assets/{common-DPxotRK9.js → common-DhWTkocg.js} +1 -1
- package/client/dist/assets/{common-k5MTOHpn.js → common-DiPTT7V_2.js} +1 -1
- package/client/dist/assets/{common-C8ZD5upH2.js → common-DmqBPwZG.js} +1 -1
- package/client/dist/assets/{cssMode-DsArsSCT.js → cssMode-DBHbkBvI.js} +1 -1
- package/client/dist/assets/dashboard-4WX7agHF2.js +1 -0
- package/client/dist/assets/dashboard-5Z_esXIB.js +1 -0
- package/client/dist/assets/dashboard-DQ-po1MG2.js +1 -0
- package/client/dist/assets/dashboard-IbEztmJ52.js +1 -0
- package/client/dist/assets/dashboard-nc-Raovv.js +1 -0
- package/client/dist/assets/dashboard-ojWdDq6S.js +1 -0
- package/client/dist/assets/dashboard-oqS7VRrK.js +1 -0
- package/client/dist/assets/dashboard-zfoJcdFW.js +1 -0
- package/client/dist/assets/{dist-js-wMFtEMAw.js → dist-js-BP83ZCIg.js} +1 -1
- package/client/dist/assets/{dist-js-4mmVovCB.js → dist-js-Qk8DW7W3.js} +1 -1
- package/client/dist/assets/{editor.main-G3Sl9C67.js → editor.main-C9J2ikJK.js} +2 -2
- package/client/dist/assets/{freemarker2-pBzQNgFi.js → freemarker2-J5iIIIK-.js} +1 -1
- package/client/dist/assets/{handlebars-CtBTCnBI.js → handlebars-DSw1l_tw.js} +1 -1
- package/client/dist/assets/{html-Dx3DYBzY.js → html-h2-wE1Lj.js} +1 -1
- package/client/dist/assets/{htmlMode-In7frFOo.js → htmlMode-Cc_ij7lW.js} +1 -1
- package/client/dist/assets/index-BQbiBIg_.js +155 -0
- package/client/dist/assets/index-DPX6_xIC.css +2 -0
- package/client/dist/assets/{javascript-BKcn-YkN.js → javascript-C1q3xv6N.js} +1 -1
- package/client/dist/assets/jira-B3613-gj.js +1 -0
- package/client/dist/assets/jira-BHAKtc4B.js +1 -0
- package/client/dist/assets/jira-Be369RIR2.js +1 -0
- package/client/dist/assets/jira-CPpgA-5z2.js +1 -0
- package/client/dist/assets/jira-D5efgwp_.js +1 -0
- package/client/dist/assets/jira-DS7ownDy.js +1 -0
- package/client/dist/assets/jira-bDs7Im2C.js +1 -0
- package/client/dist/assets/jira-uNH1gETL2.js +1 -0
- package/client/dist/assets/jobs-1GV2-4zd2.js +1 -0
- package/client/dist/assets/jobs-26F9gGcE.js +1 -0
- package/client/dist/assets/jobs-BgQzB0Sx2.js +1 -0
- package/client/dist/assets/jobs-BqWui9_f.js +1 -0
- package/client/dist/assets/jobs-CE8qeIYj.js +1 -0
- package/client/dist/assets/jobs-D5sZzgLs.js +1 -0
- package/client/dist/assets/jobs-DzeuASRf.js +1 -0
- package/client/dist/assets/jobs-Wh7dn28q2.js +1 -0
- package/client/dist/assets/{jsonMode-jNREoQ3C.js → jsonMode-CeaCdEhr.js} +1 -1
- package/client/dist/assets/{lib-Cz65p1sn.js → lib-CtyGolSR.js} +1 -1
- package/client/dist/assets/{liquid-CtRkGqBu.js → liquid-eFsVK0V-.js} +1 -1
- package/client/dist/assets/loops-BvEenWBy.js +1 -0
- package/client/dist/assets/loops-CBiWd9Hf.js +1 -0
- package/client/dist/assets/loops-DNGiYKll2.js +1 -0
- package/client/dist/assets/{loops-Y3FQsUCh.js → loops-DjOtVXRo.js} +1 -1
- package/client/dist/assets/loops-HTHf-xu32.js +1 -0
- package/client/dist/assets/loops-YYV2bwjd.js +1 -0
- package/client/dist/assets/loops-hXgncEpF2.js +1 -0
- package/client/dist/assets/loops-kYbydDyN.js +1 -0
- package/client/dist/assets/{lspLanguageFeatures-Cl3gvD_W.js → lspLanguageFeatures-DT3-bbhn.js} +1 -1
- package/client/dist/assets/{mdx-B_nJldHz.js → mdx-Fuwnh1cX.js} +1 -1
- package/client/dist/assets/{monaco.contribution-PUeaZk8T.js → monaco.contribution-Desq7oq4.js} +2 -2
- package/client/dist/assets/{python-DS1Ce-A6.js → python-BgoEs6Cj.js} +1 -1
- package/client/dist/assets/{razor-L41Qg9OK.js → razor-CM1sPMMq.js} +1 -1
- package/client/dist/assets/setup-B590KsTX.js +1 -0
- package/client/dist/assets/setup-BkyGoby6.js +1 -0
- package/client/dist/assets/setup-CEj6uY3-2.js +1 -0
- package/client/dist/assets/setup-CbIerFGf2.js +1 -0
- package/client/dist/assets/setup-CmU6bTCV2.js +1 -0
- package/client/dist/assets/setup-D674kWQH.js +1 -0
- package/client/dist/assets/setup-VNqXyB6Y.js +1 -0
- package/client/dist/assets/setup-iY8vH8pB.js +1 -0
- package/client/dist/assets/specs-C9Sd7BhH2.js +1 -0
- package/client/dist/assets/specs-CBDvEYKv.js +1 -0
- package/client/dist/assets/specs-CIPr9reA2.js +1 -0
- package/client/dist/assets/specs-CWtKcVDC.js +1 -0
- package/client/dist/assets/specs-CmEZY57v.js +1 -0
- package/client/dist/assets/specs-D2clrt2c2.js +1 -0
- package/client/dist/assets/specs-DTplt2XM.js +1 -0
- package/client/dist/assets/specs-PozUNhqb.js +1 -0
- package/client/dist/assets/{tsMode-BC1g186U.js → tsMode-BmT8WogI.js} +1 -1
- package/client/dist/assets/{typescript-BGlRGvJW.js → typescript-CQrQPsoW.js} +1 -1
- package/client/dist/assets/upload-BOOCdPin.js +1 -0
- package/client/dist/assets/{value-DJMRojPA.js → value-BHbZ4o6V.js} +1 -1
- package/client/dist/assets/{workers-CXcXtO3b.js → workers-U0UXyLUf.js} +1 -1
- package/client/dist/assets/{xml-JdZZaIhJ.js → xml-WRxJs8_I.js} +1 -1
- package/client/dist/assets/{yaml-Cm82BVBt.js → yaml-CjpSTjJU.js} +1 -1
- package/client/dist/index.html +13 -13
- package/docs/customizing.md +2 -2
- package/docs/gemini.md +15 -4
- package/docs/guide/de/insights/3-code-explorer.md +6 -0
- package/docs/guide/de/integrations/3-jira-integration.md +1 -1
- package/docs/guide/de/integrations/6-agent-chat.md +5 -0
- package/docs/guide/de/pipeline/1-rails-and-jobs.md +6 -6
- package/docs/guide/de/pipeline/2-the-job-detail-view.md +27 -2
- package/docs/guide/de/pipeline/3-batch-implement-and-multi-feature.md +5 -4
- package/docs/guide/de/pipeline/5-the-loop-builder.md +1 -1
- package/docs/guide/de/specs/1-specs-and-the-backlog.md +3 -2
- package/docs/guide/en/insights/3-code-explorer.md +6 -0
- package/docs/guide/en/integrations/3-jira-integration.md +1 -1
- package/docs/guide/en/integrations/6-agent-chat.md +5 -0
- package/docs/guide/en/pipeline/1-rails-and-jobs.md +6 -6
- package/docs/guide/en/pipeline/2-the-job-detail-view.md +27 -2
- package/docs/guide/en/pipeline/3-batch-implement-and-multi-feature.md +5 -4
- package/docs/guide/en/pipeline/5-the-loop-builder.md +1 -1
- package/docs/guide/en/specs/1-specs-and-the-backlog.md +3 -2
- package/docs/guide/es/insights/3-code-explorer.md +6 -0
- package/docs/guide/es/integrations/3-jira-integration.md +1 -1
- package/docs/guide/es/integrations/6-agent-chat.md +5 -0
- package/docs/guide/es/pipeline/1-rails-and-jobs.md +6 -6
- package/docs/guide/es/pipeline/2-the-job-detail-view.md +27 -2
- package/docs/guide/es/pipeline/3-batch-implement-and-multi-feature.md +5 -4
- package/docs/guide/es/pipeline/5-the-loop-builder.md +1 -1
- package/docs/guide/es/specs/1-specs-and-the-backlog.md +3 -2
- package/docs/guide/fr/insights/3-code-explorer.md +6 -0
- package/docs/guide/fr/integrations/3-jira-integration.md +1 -1
- package/docs/guide/fr/integrations/6-agent-chat.md +5 -0
- package/docs/guide/fr/pipeline/1-rails-and-jobs.md +6 -6
- package/docs/guide/fr/pipeline/2-the-job-detail-view.md +27 -2
- package/docs/guide/fr/pipeline/3-batch-implement-and-multi-feature.md +5 -4
- package/docs/guide/fr/pipeline/5-the-loop-builder.md +1 -1
- package/docs/guide/fr/specs/1-specs-and-the-backlog.md +3 -2
- package/docs/guide/it/insights/3-code-explorer.md +6 -0
- package/docs/guide/it/integrations/3-jira-integration.md +1 -1
- package/docs/guide/it/integrations/6-agent-chat.md +5 -0
- package/docs/guide/it/pipeline/1-rails-and-jobs.md +6 -6
- package/docs/guide/it/pipeline/2-the-job-detail-view.md +27 -2
- package/docs/guide/it/pipeline/3-batch-implement-and-multi-feature.md +5 -4
- package/docs/guide/it/pipeline/5-the-loop-builder.md +1 -1
- package/docs/guide/it/specs/1-specs-and-the-backlog.md +3 -2
- package/docs/guide/ja/insights/3-code-explorer.md +6 -0
- package/docs/guide/ja/integrations/3-jira-integration.md +1 -1
- package/docs/guide/ja/integrations/6-agent-chat.md +5 -0
- package/docs/guide/ja/pipeline/1-rails-and-jobs.md +6 -6
- package/docs/guide/ja/pipeline/2-the-job-detail-view.md +27 -2
- package/docs/guide/ja/pipeline/3-batch-implement-and-multi-feature.md +5 -4
- package/docs/guide/ja/pipeline/5-the-loop-builder.md +1 -1
- package/docs/guide/ja/specs/1-specs-and-the-backlog.md +3 -2
- package/docs/guide/pt/insights/3-code-explorer.md +6 -0
- package/docs/guide/pt/integrations/3-jira-integration.md +1 -1
- package/docs/guide/pt/integrations/6-agent-chat.md +5 -0
- package/docs/guide/pt/pipeline/1-rails-and-jobs.md +6 -6
- package/docs/guide/pt/pipeline/2-the-job-detail-view.md +27 -2
- package/docs/guide/pt/pipeline/3-batch-implement-and-multi-feature.md +5 -4
- package/docs/guide/pt/pipeline/5-the-loop-builder.md +1 -1
- package/docs/guide/pt/specs/1-specs-and-the-backlog.md +3 -2
- package/docs/guide/zh/insights/3-code-explorer.md +6 -0
- package/docs/guide/zh/integrations/3-jira-integration.md +1 -1
- package/docs/guide/zh/integrations/6-agent-chat.md +5 -0
- package/docs/guide/zh/pipeline/1-rails-and-jobs.md +6 -6
- package/docs/guide/zh/pipeline/2-the-job-detail-view.md +27 -2
- package/docs/guide/zh/pipeline/3-batch-implement-and-multi-feature.md +5 -4
- package/docs/guide/zh/pipeline/5-the-loop-builder.md +1 -1
- package/docs/guide/zh/specs/1-specs-and-the-backlog.md +3 -2
- package/docs/internals/README.md +5 -0
- package/docs/internals/adding-a-provider.md +15 -3
- package/docs/internals/api-reference.md +6 -5
- package/docs/internals/browser-capture-performance.md +93 -0
- package/docs/internals/code-explorer-story.md +135 -0
- package/docs/internals/gemini-mcp-registration.md +53 -0
- package/docs/internals/interactive-jobs.md +212 -0
- package/docs/internals/loop-step-log-explorer.md +146 -0
- package/docs/internals/safe-pr-review-flow.md +382 -0
- package/docs/mcp.md +1 -1
- package/docs/running-pipelines.md +5 -3
- package/package.json +1 -1
- package/server/dist/agent-chat-manager.js +211 -0
- package/server/dist/agent-chat-registry.js +20 -0
- package/server/dist/agent-chat-router.js +22 -0
- package/server/dist/agent-mcp-config.js +45 -4
- package/server/dist/agent-operator-prompt.js +158 -56
- package/server/dist/agent-store.js +25 -0
- package/server/dist/agent-tier.js +6 -1
- package/server/dist/browser-capture-manager.js +184 -34
- package/server/dist/browser-playwright.js +98 -13
- package/server/dist/code-explorer-router.js +92 -0
- package/server/dist/db.js +92 -0
- package/server/dist/file-provenance.js +54 -1
- package/server/dist/file-story-manager.js +170 -0
- package/server/dist/file-story.js +148 -0
- package/server/dist/file-summary-generator.js +5 -4
- package/server/dist/index.js +5 -0
- package/server/dist/interactive-job-session.js +226 -18
- package/server/dist/jira/jira-adf.js +9 -0
- package/server/dist/jira/jira-materializer.js +27 -4
- package/server/dist/jira/jira-status-resolver.js +12 -4
- package/server/dist/jira/jira-sync-manager.js +130 -2
- package/server/dist/jira-router.js +1 -1
- package/server/dist/loop-executors.js +91 -28
- package/server/dist/loop-run-manager.js +354 -28
- package/server/dist/mcp/guide.js +18 -7
- package/server/dist/mcp/tools/jira.js +1 -1
- package/server/dist/mcp/tools/jobs.js +14 -5
- package/server/dist/mcp/tools/rails.js +137 -12
- package/server/dist/mcp/tools/specs.js +35 -9
- package/server/dist/mcp/tools/types.js +49 -0
- package/server/dist/mobile/mobile-ws.js +4 -0
- package/server/dist/path-resolver.js +46 -0
- package/server/dist/pr-body.js +240 -0
- package/server/dist/pr-naming.js +210 -0
- package/server/dist/project-registry.js +77 -17
- package/server/dist/project-router-jobs.js +53 -13
- package/server/dist/project-router-terminals.js +16 -0
- package/server/dist/project-router-tickets.js +57 -3
- package/server/dist/project-router.js +52 -13
- package/server/dist/queue-manager.js +261 -84
- package/server/dist/rail-isolated-launch.js +315 -66
- package/server/dist/rail-isolation.js +18 -5
- package/server/dist/rail-pr-decision.js +629 -0
- package/server/dist/rail-pr-delivery.js +21 -18
- package/server/dist/rail-pr-store.js +175 -0
- package/server/dist/rail-worktrees-store.js +18 -0
- package/server/dist/rails-router.js +234 -38
- package/server/dist/rails-store.js +78 -1
- package/server/dist/setup-prerequisites.js +105 -0
- package/server/dist/smash-runner.js +3 -1
- package/server/dist/ticket-store.js +7 -3
- package/server/dist/workspace-resolution.js +27 -0
- package/server/dist/worktree-manager.js +42 -7
- package/server/dist/worktree-overlay.js +261 -0
- package/client/dist/assets/AgentBrowserCapture-DkA8FLp8.js +0 -1
- package/client/dist/assets/AgentModeJobsPane-TLYCqNAw.js +0 -1
- package/client/dist/assets/AgentsPage-BKsPH-l1.js +0 -86
- package/client/dist/assets/AnalyticsPage-Da9pDQrq.js +0 -1
- package/client/dist/assets/CodePage-DlwvWKCo.js +0 -2
- package/client/dist/assets/DesktopAnalyticsPage-DpVVhXKF.js +0 -1
- package/client/dist/assets/DocsDialog-BSdgftgR.js +0 -11
- package/client/dist/assets/DocsPage-9SGL4_zz.js +0 -11
- package/client/dist/assets/IntegrationsPage-BW5mofSA.js +0 -3
- package/client/dist/assets/JobDetailPage-CqiJ9vwR.js +0 -1
- package/client/dist/assets/JobsPage-CVinOe6p.js +0 -1
- package/client/dist/assets/LogViewer-Cf6s1TDs.js +0 -16
- package/client/dist/assets/LoopBuilderPage-CqgUH5Vw.js +0 -7
- package/client/dist/assets/LoopsPage-C6h2gjPP.js +0 -1
- package/client/dist/assets/ProjectSettingsDialog-BU-JR7wI.js +0 -1
- package/client/dist/assets/agent-B7GdHP3Z.js +0 -1
- package/client/dist/assets/agent-BHmcgoJf.js +0 -1
- package/client/dist/assets/agent-BdY_fii4.js +0 -1
- package/client/dist/assets/agent-C32FOi9v.js +0 -1
- package/client/dist/assets/agent-CiFQxoaZ2.js +0 -1
- package/client/dist/assets/agent-CtAag7V6.js +0 -1
- package/client/dist/assets/agent-DE4Mp1fY2.js +0 -1
- package/client/dist/assets/agent-DK8qovyG2.js +0 -1
- package/client/dist/assets/browser-ZB1afzjZ.js +0 -1
- package/client/dist/assets/code-BFxE1Yt62.js +0 -1
- package/client/dist/assets/code-BefYOm5Q.js +0 -1
- package/client/dist/assets/code-BkXpJt99.js +0 -1
- package/client/dist/assets/code-C6Sq7_t8.js +0 -1
- package/client/dist/assets/code-CGj3w-2N.js +0 -1
- package/client/dist/assets/code-Dfsxc9o82.js +0 -1
- package/client/dist/assets/code-Y5urks5s2.js +0 -1
- package/client/dist/assets/code-wtcs0ivb.js +0 -1
- package/client/dist/assets/dashboard-B-AiVq5X.js +0 -1
- package/client/dist/assets/dashboard-BpYYrPl8.js +0 -1
- package/client/dist/assets/dashboard-Bunv-uon2.js +0 -1
- package/client/dist/assets/dashboard-CYciEbov.js +0 -1
- package/client/dist/assets/dashboard-CvFg-_JQ.js +0 -1
- package/client/dist/assets/dashboard-DAyPERCJ.js +0 -1
- package/client/dist/assets/dashboard-DJ-6T44N2.js +0 -1
- package/client/dist/assets/dashboard-DnBGqZkZ2.js +0 -1
- package/client/dist/assets/index-BHPbzyg6.css +0 -2
- package/client/dist/assets/index-D4R3rVF5.js +0 -152
- package/client/dist/assets/jira-BcZzX9122.js +0 -1
- package/client/dist/assets/jira-CTYs7LA12.js +0 -1
- package/client/dist/assets/jira-D2nN39e92.js +0 -1
- package/client/dist/assets/jira-DJxmIkyr.js +0 -1
- package/client/dist/assets/jira-DXMoAKWD.js +0 -1
- package/client/dist/assets/jira-IhC1ROIc.js +0 -1
- package/client/dist/assets/jira-Iw575fN8.js +0 -1
- package/client/dist/assets/jira-kbWZY7jH.js +0 -1
- package/client/dist/assets/jobs-BqF79kHz2.js +0 -1
- package/client/dist/assets/jobs-C1XM5urS.js +0 -1
- package/client/dist/assets/jobs-C5UjG0262.js +0 -1
- package/client/dist/assets/jobs-DBfaHTxC.js +0 -1
- package/client/dist/assets/jobs-DM4BDPdg.js +0 -1
- package/client/dist/assets/jobs-Da5OkZmf2.js +0 -1
- package/client/dist/assets/jobs-JJdnuQ03.js +0 -1
- package/client/dist/assets/jobs-SI34ML8I.js +0 -1
- package/client/dist/assets/loops-BR4FmOv12.js +0 -1
- package/client/dist/assets/loops-BgX_uudn.js +0 -1
- package/client/dist/assets/loops-Bpl2j2LP.js +0 -1
- package/client/dist/assets/loops-CQuuMlyZ.js +0 -1
- package/client/dist/assets/loops-DW8hSMdS2.js +0 -1
- package/client/dist/assets/loops-Q2muu8hW2.js +0 -1
- package/client/dist/assets/loops-q7CNDvfK.js +0 -1
- package/client/dist/assets/setup-CNMdCHHt2.js +0 -1
- package/client/dist/assets/setup-Cag4XrbL2.js +0 -1
- package/client/dist/assets/setup-D9IHGoWU.js +0 -1
- package/client/dist/assets/setup-Dg6Ba3JT.js +0 -1
- package/client/dist/assets/setup-DyK36RIW.js +0 -1
- package/client/dist/assets/setup-G4ZvDKxX.js +0 -1
- package/client/dist/assets/setup-aTlGxuwi2.js +0 -1
- package/client/dist/assets/setup-kWsoAeHQ.js +0 -1
- package/client/dist/assets/specs-BFSUPa122.js +0 -1
- package/client/dist/assets/specs-BMzip1WY2.js +0 -1
- package/client/dist/assets/specs-BYeAbIEy.js +0 -1
- package/client/dist/assets/specs-C-mtLcXw.js +0 -1
- package/client/dist/assets/specs-CAzpvADd2.js +0 -1
- package/client/dist/assets/specs-CyRIw_IR.js +0 -1
- package/client/dist/assets/specs-DMm7gB_l.js +0 -1
- package/client/dist/assets/specs-DuottM0Z.js +0 -1
- /package/client/dist/assets/{abap-CpHUwCVK.js → abap-D0E4FfVW.js} +0 -0
- /package/client/dist/assets/{activity-DemHQS7l.js → activity--iN4Ad2R2.js} +0 -0
- /package/client/dist/assets/{activity-B_71BWg3.js → activity-6hM_ZSg9.js} +0 -0
- /package/client/dist/assets/{activity-DHv2V5Oi.js → activity-BZNfOdiS.js} +0 -0
- /package/client/dist/assets/{activity-D0rfjQzT2.js → activity-BuVo5sPB.js} +0 -0
- /package/client/dist/assets/{activity-BpTTj_PH.js → activity-CIOLxGvh.js} +0 -0
- /package/client/dist/assets/{activity-D2e62vbV2.js → activity-D2r2h3SE2.js} +0 -0
- /package/client/dist/assets/{activity-Ch-wbr0C2.js → activity-DtxrAUMo2.js} +0 -0
- /package/client/dist/assets/{addon-image-Ba-TY3wr.js → addon-image-CwoZj17F.js} +0 -0
- /package/client/dist/assets/{addon-ligatures-T4ARLiuu.js → addon-ligatures-CWDrED80.js} +0 -0
- /package/client/dist/assets/{addon-webgl-Cd73n8eh.js → addon-webgl-DMbGeI_u.js} +0 -0
- /package/client/dist/assets/{addspec-xwRX_Pnf.js → addspec-BMtLZLW62.js} +0 -0
- /package/client/dist/assets/{addspec-l_zU5gla.js → addspec-CP0HRuxY.js} +0 -0
- /package/client/dist/assets/{addspec-Dio-H5z0.js → addspec-CRuvWn8d.js} +0 -0
- /package/client/dist/assets/{addspec-D6L4ZteP.js → addspec-D-JLDsUV.js} +0 -0
- /package/client/dist/assets/{addspec-CrEm6Fzr2.js → addspec-DfhDbg5c.js} +0 -0
- /package/client/dist/assets/{addspec-B6Ns8KU02.js → addspec-bsNDdqRm2.js} +0 -0
- /package/client/dist/assets/{addspec-qGyH7MHy2.js → addspec-mgPOt5q02.js} +0 -0
- /package/client/dist/assets/{agents-OzxCLVW1.js → agents-78bTZGZh.js} +0 -0
- /package/client/dist/assets/{agents-hv3sqmPm2.js → agents-BLhWCmDS2.js} +0 -0
- /package/client/dist/assets/{agents-CHgCudUV.js → agents-BUdEi3-N.js} +0 -0
- /package/client/dist/assets/{agents-Dumx4JiM2.js → agents-BpoUaoW92.js} +0 -0
- /package/client/dist/assets/{agents-CnaPeSyw.js → agents-CWo-KyAB.js} +0 -0
- /package/client/dist/assets/{agents-Xh-zYHUx2.js → agents-DDtCJ5M02.js} +0 -0
- /package/client/dist/assets/{agents-DuhLEaQ_.js → agents-bvyRLczL.js} +0 -0
- /package/client/dist/assets/{agentstudio-CCthUdzR.js → agentstudio-BMQxc_bz.js} +0 -0
- /package/client/dist/assets/{agentstudio-CcH8Ckql2.js → agentstudio-COZriimI2.js} +0 -0
- /package/client/dist/assets/{agentstudio-Bo91kfUd2.js → agentstudio-CWgXG5W52.js} +0 -0
- /package/client/dist/assets/{agentstudio-VJOa_NVO.js → agentstudio-C_Jq8Tl4.js} +0 -0
- /package/client/dist/assets/{agentstudio-BIxikDf_.js → agentstudio-Dtq3dGYk.js} +0 -0
- /package/client/dist/assets/{agentstudio-Bz8cP8_c.js → agentstudio-jKMTdT70.js} +0 -0
- /package/client/dist/assets/{agentstudio-DARgYg5Z2.js → agentstudio-sI27TpBu2.js} +0 -0
- /package/client/dist/assets/{aiedit-5ZXN4cep2.js → aiedit-6CHdb_iv2.js} +0 -0
- /package/client/dist/assets/{aiedit-B7gAJZVC.js → aiedit-B03pD_Na.js} +0 -0
- /package/client/dist/assets/{aiedit-D92V-kUW.js → aiedit-BtRqRxML.js} +0 -0
- /package/client/dist/assets/{aiedit-D9ualLVJ.js → aiedit-eMN4eQPF.js} +0 -0
- /package/client/dist/assets/{aiedit-h48tJU0V2.js → aiedit-hknZlly82.js} +0 -0
- /package/client/dist/assets/{aiedit-xkA_mR2a2.js → aiedit-igmw-ZoZ2.js} +0 -0
- /package/client/dist/assets/{aiedit-7B2dvCv-.js → aiedit-pc5JDUq1.js} +0 -0
- /package/client/dist/assets/{analytics-slx4X1mu2.js → analytics-BWMUZ2Pq2.js} +0 -0
- /package/client/dist/assets/{analytics-uRNP6yAJ.js → analytics-Bj-SmKHa.js} +0 -0
- /package/client/dist/assets/{analytics-WF1I49ln.js → analytics-C5dpiS0o.js} +0 -0
- /package/client/dist/assets/{analytics-CBvaxOId.js → analytics-CCprAqk3.js} +0 -0
- /package/client/dist/assets/{analytics-BakymH7Z2.js → analytics-CR1TJqUi2.js} +0 -0
- /package/client/dist/assets/{analytics-B7bPj6u_2.js → analytics-DfNdXR0y2.js} +0 -0
- /package/client/dist/assets/{analytics-DZ74aQ54.js → analytics-rmHuJv0V.js} +0 -0
- /package/client/dist/assets/{apex-DlD7oJX6.js → apex-D_X_8J4d.js} +0 -0
- /package/client/dist/assets/{atom-one-dark-BrRN8wBy.js → atom-one-dark-BMDPFwRZ.js} +0 -0
- /package/client/dist/assets/{attachments-C11tOKZ_.js → attachments-BgBNSqQd.js} +0 -0
- /package/client/dist/assets/{attachments-Bnbyj2PN.js → attachments-BjyMmrwE.js} +0 -0
- /package/client/dist/assets/{attachments-CIeLa8l12.js → attachments-C9GTTJsx2.js} +0 -0
- /package/client/dist/assets/{attachments-DslHfa-L.js → attachments-DCZOL1RU.js} +0 -0
- /package/client/dist/assets/{attachments-C-gyrCOb.js → attachments-DL-bPy9E.js} +0 -0
- /package/client/dist/assets/{attachments-Cxrs0pyL2.js → attachments-DPCmkFZu2.js} +0 -0
- /package/client/dist/assets/{attachments-TTPsc0a52.js → attachments-rNn1ekRy2.js} +0 -0
- /package/client/dist/assets/{azcli-CmXFAbc-.js → azcli-PZLnZ3jH.js} +0 -0
- /package/client/dist/assets/{bat-DdNJq4hH.js → bat-KlBOxpO4.js} +0 -0
- /package/client/dist/assets/{bicep-Bppz7WOA.js → bicep-CgG9oF3V.js} +0 -0
- /package/client/dist/assets/{cameligo-0MRMdSmg.js → cameligo-6R45j6Ph.js} +0 -0
- /package/client/dist/assets/{chat-BvHrebKC2.js → chat-BgL3zv6x2.js} +0 -0
- /package/client/dist/assets/{chat-CZyiLJvQ.js → chat-Bh3NdgJs.js} +0 -0
- /package/client/dist/assets/{chat-DKYP7NnC.js → chat-Bom6bqK3.js} +0 -0
- /package/client/dist/assets/{chat-5mdg_YIc2.js → chat-DdwZjT8K2.js} +0 -0
- /package/client/dist/assets/{chat-wkTIy9rX.js → chat-Dnwg-NpQ.js} +0 -0
- /package/client/dist/assets/{chat-BpYxnkr4.js → chat-DsbwJhus.js} +0 -0
- /package/client/dist/assets/{chat-BGax2nV62.js → chat-vylxqR0P2.js} +0 -0
- /package/client/dist/assets/{clojure-B5dKj863.js → clojure-CLAAMO7J.js} +0 -0
- /package/client/dist/assets/{clsx-1dnHRn8W.js → clsx-CNmW0Nip.js} +0 -0
- /package/client/dist/assets/{coffee-DSbWjzk7.js → coffee-AruSygo-.js} +0 -0
- /package/client/dist/assets/{commands-uz_uKT242.js → commands-C4Y3C-PF2.js} +0 -0
- /package/client/dist/assets/{commands-Bb7MnPqn2.js → commands-CSDs9q_2.js} +0 -0
- /package/client/dist/assets/{commands-C_7zZwJf.js → commands-DkU0qliq.js} +0 -0
- /package/client/dist/assets/{commands-D_6B8lfU.js → commands-JWMfGDmr.js} +0 -0
- /package/client/dist/assets/{commands-DBc5llLi2.js → commands-RHOchN4n2.js} +0 -0
- /package/client/dist/assets/{commands-CQkdthjF.js → commands-u-4eEHCN.js} +0 -0
- /package/client/dist/assets/{commands-DhZNhSbl.js → commands-xHDDGfcP2.js} +0 -0
- /package/client/dist/assets/{cpp-SBF8SAh9.js → cpp-DEE5r4Pw.js} +0 -0
- /package/client/dist/assets/{csharp-Lzuq_1t-.js → csharp-BVXJUvbK.js} +0 -0
- /package/client/dist/assets/{csp-BEzxZqi1.js → csp-cXOF0JoV.js} +0 -0
- /package/client/dist/assets/{css-C3D3PKln.js → css-C_zQuAoy.js} +0 -0
- /package/client/dist/assets/{cypher-CQ3dEPmv.js → cypher-t95m_Q-O.js} +0 -0
- /package/client/dist/assets/{dart-DCPmxolI.js → dart-B4r1Tg-e.js} +0 -0
- /package/client/dist/assets/{dockerfile-B_2_aaTO.js → dockerfile-6mt7zHQw.js} +0 -0
- /package/client/dist/assets/{ecl-rADUeXsV.js → ecl-DEY_Fz_Q.js} +0 -0
- /package/client/dist/assets/{editor.api2-T7u8kQWG.js → editor.api2-C3B0tp2x.js} +0 -0
- /package/client/dist/assets/{elixir-DOd-TuJO.js → elixir-R6-q1c5t.js} +0 -0
- /package/client/dist/assets/{explore-BHEhNekP2.js → explore-B7fblXBb2.js} +0 -0
- /package/client/dist/assets/{explore-DAsroA482.js → explore-BHtEpoNN2.js} +0 -0
- /package/client/dist/assets/{explore-UwHHj2ux.js → explore-C0k8HrkN.js} +0 -0
- /package/client/dist/assets/{explore-DaXiW9-6.js → explore-CNBzrEPS.js} +0 -0
- /package/client/dist/assets/{explore-CWlAXx0f2.js → explore-D_mWBYCS2.js} +0 -0
- /package/client/dist/assets/{explore-DG1CtYqT.js → explore-Dahc1lOx.js} +0 -0
- /package/client/dist/assets/{explore-DMSGAnhK.js → explore-UvW1jEMa.js} +0 -0
- /package/client/dist/assets/{flow9-Bf7zg_j0.js → flow9-CNQvHBOt.js} +0 -0
- /package/client/dist/assets/{format-command-BHymDa4r.js → format-command-CuWuRvka.js} +0 -0
- /package/client/dist/assets/{fsharp-BqROZjbA.js → fsharp-vPZkFXwv.js} +0 -0
- /package/client/dist/assets/{go-oQTP5uLe.js → go-KUzBMYJ_.js} +0 -0
- /package/client/dist/assets/{graphql-CSHfTU3q.js → graphql-C3W0rCsD.js} +0 -0
- /package/client/dist/assets/{hcl-CeG-RoFJ.js → hcl-BOOMFSNX.js} +0 -0
- /package/client/dist/assets/{ini-B2Dv4ohc.js → ini-CFat1WJr.js} +0 -0
- /package/client/dist/assets/{integrations-CAF21FbQ.js → integrations-4KZnYECp.js} +0 -0
- /package/client/dist/assets/{integrations-CHCgning2.js → integrations-7W266oqF2.js} +0 -0
- /package/client/dist/assets/{integrations-B-JVE1_D.js → integrations-BNuauK3o.js} +0 -0
- /package/client/dist/assets/{integrations-BAujIDoE.js → integrations-CHy8tnpV.js} +0 -0
- /package/client/dist/assets/{integrations-DS5FFMes.js → integrations-Cl_wD5AI.js} +0 -0
- /package/client/dist/assets/{integrations-axZN4--n2.js → integrations-Cy8nZ_dv2.js} +0 -0
- /package/client/dist/assets/{integrations-CtsOpq2D2.js → integrations-zMqY4VU12.js} +0 -0
- /package/client/dist/assets/{java-aUDDeufb.js → java-Dee-CNAM.js} +0 -0
- /package/client/dist/assets/{julia-C5LbruO5.js → julia-CGNlLYuU.js} +0 -0
- /package/client/dist/assets/{kotlin-C6mOuSKk.js → kotlin-CY7lhknJ.js} +0 -0
- /package/client/dist/assets/{less-D5qC3caW.js → less-D0KN7hfJ.js} +0 -0
- /package/client/dist/assets/{lexon-Dr2La-fj.js → lexon-CuRJufPs.js} +0 -0
- /package/client/dist/assets/{lua-Zy6u5z6Z.js → lua-DHvH62Zf.js} +0 -0
- /package/client/dist/assets/{m3-C7XHeDz_.js → m3-tlthQ8Fo.js} +0 -0
- /package/client/dist/assets/{markdown-PiF7r-2h.js → markdown-Dbx1LgUZ.js} +0 -0
- /package/client/dist/assets/{mcp-B_nWlxZa2.js → mcp-CjVKXAhD2.js} +0 -0
- /package/client/dist/assets/{mcp-B8omp_Cd.js → mcp-Dcl-XxkR.js} +0 -0
- /package/client/dist/assets/{mcp-DTCCrYHz2.js → mcp-DtbxuH3V2.js} +0 -0
- /package/client/dist/assets/{mcp-DytBbASZ.js → mcp-H-gnQUdN.js} +0 -0
- /package/client/dist/assets/{mcp-D_oPS6Zc.js → mcp-N1nzp8oL.js} +0 -0
- /package/client/dist/assets/{mcp-Cb2jtHP72.js → mcp-XJNRfxVp2.js} +0 -0
- /package/client/dist/assets/{mcp-DPqm2C8-.js → mcp-sRmWE8WJ.js} +0 -0
- /package/client/dist/assets/{mips-nn07GiyE.js → mips-D_O3IUz_.js} +0 -0
- /package/client/dist/assets/{msdax-DaKFVMST.js → msdax-C_ZmCnRt.js} +0 -0
- /package/client/dist/assets/{mysql-C6d6xrbU.js → mysql-C-dCEYSX.js} +0 -0
- /package/client/dist/assets/{nav-Cibp2KWF.js → nav-40HzpIFb.js} +0 -0
- /package/client/dist/assets/{nav-DtTnF9xd.js → nav-8yPhBn00.js} +0 -0
- /package/client/dist/assets/{nav-Danf5sRf2.js → nav-B6PkGfTk2.js} +0 -0
- /package/client/dist/assets/{nav-Bqhyfbcj2.js → nav-BHqMLrS72.js} +0 -0
- /package/client/dist/assets/{nav-CQb9y1km.js → nav-CGy4yx3C.js} +0 -0
- /package/client/dist/assets/{nav-BAsYcqdw2.js → nav-CXEDcRdv2.js} +0 -0
- /package/client/dist/assets/{nav-BRrNlZkr.js → nav-EI_OhEAo.js} +0 -0
- /package/client/dist/assets/{objective-c-B6KMtI-k.js → objective-c-DZY9Aqxd.js} +0 -0
- /package/client/dist/assets/{pascal-DYr8MPE7.js → pascal-BVHLXoor.js} +0 -0
- /package/client/dist/assets/{pascaligo-B3pd-jJ_.js → pascaligo-XdG_6u3k.js} +0 -0
- /package/client/dist/assets/{perl-z2xUzoaL.js → perl-b9QV0BcD.js} +0 -0
- /package/client/dist/assets/{pgsql-DUvT-09-.js → pgsql-Du5FDOgT.js} +0 -0
- /package/client/dist/assets/{php-CGyOmJfy.js → php-WJD0z2Z_.js} +0 -0
- /package/client/dist/assets/{pla-CMqgvyD0.js → pla-CbciTf2w.js} +0 -0
- /package/client/dist/assets/{postiats-Dx5LUn4Z.js → postiats-C1QxmvVq.js} +0 -0
- /package/client/dist/assets/{powerquery-DazYxvJ6.js → powerquery-BEYDhPLZ.js} +0 -0
- /package/client/dist/assets/{powershell-B3nwlDka.js → powershell-CfaYw4XL.js} +0 -0
- /package/client/dist/assets/{protobuf-BGuu2u2s.js → protobuf-pwZEDOYa.js} +0 -0
- /package/client/dist/assets/{pug-Dbte1MXA.js → pug-5ftqSPVe.js} +0 -0
- /package/client/dist/assets/{qsharp-DJLwBOvG.js → qsharp-uI6qZMq4.js} +0 -0
- /package/client/dist/assets/{r-DmGBRSHj.js → r-BK54P1EG.js} +0 -0
- /package/client/dist/assets/{redis-VvUYn0a4.js → redis-DI0yd7kN.js} +0 -0
- /package/client/dist/assets/{redshift-6GdDrxg3.js → redshift-Dov26eyI.js} +0 -0
- /package/client/dist/assets/{restructuredtext-CfAB8aRU.js → restructuredtext-QqJ_1dC-.js} +0 -0
- /package/client/dist/assets/{ruby-CIYK6MXY.js → ruby-5WjveeVb.js} +0 -0
- /package/client/dist/assets/{rust-CTHZfjj9.js → rust-BzVSfqFH.js} +0 -0
- /package/client/dist/assets/{sb-CkKTdkz_.js → sb-DMIUfT-3.js} +0 -0
- /package/client/dist/assets/{scala-Bx-Wr9TM.js → scala-CSKA7lqt.js} +0 -0
- /package/client/dist/assets/{scheme-Dcfi6f83.js → scheme-CojOP2Qc.js} +0 -0
- /package/client/dist/assets/{scss-ByL-7PFQ.js → scss-DoBZGJG6.js} +0 -0
- /package/client/dist/assets/{settings-D3rfdI1i.js → settings-BOHOmHkb.js} +0 -0
- /package/client/dist/assets/{settings-DoUJb93K2.js → settings-BlEA_7h02.js} +0 -0
- /package/client/dist/assets/{settings-CgjmTpR8.js → settings-BsJMsWGc.js} +0 -0
- /package/client/dist/assets/{settings-BbxrZlv7.js → settings-D6qY9_UI.js} +0 -0
- /package/client/dist/assets/{settings-BmA06FIJ.js → settings-DZJeXoRV.js} +0 -0
- /package/client/dist/assets/{settings-C2_QJA8f2.js → settings-TNga5gIF2.js} +0 -0
- /package/client/dist/assets/{settings-BJ6fj67y2.js → settings-lFoaYT-s2.js} +0 -0
- /package/client/dist/assets/{shell-Csnb9Yqd.js → shell-YOaE4udl.js} +0 -0
- /package/client/dist/assets/{solidity-Dbw5-0QP.js → solidity-l3jSyVLu.js} +0 -0
- /package/client/dist/assets/{sophia-ZQ3saZQx.js → sophia-BhSGTaQJ.js} +0 -0
- /package/client/dist/assets/{sparql-BEtOel8u.js → sparql-qhk6QD9w.js} +0 -0
- /package/client/dist/assets/{sql-DGPDbzB7.js → sql-DoO3y21-.js} +0 -0
- /package/client/dist/assets/{st-GeW2MOgh.js → st-ChZAY8oG.js} +0 -0
- /package/client/dist/assets/{swift-BVYTN8jq.js → swift-D290Tr7_.js} +0 -0
- /package/client/dist/assets/{systemverilog-Deg2a8Lr.js → systemverilog-DsxzgJ-o.js} +0 -0
- /package/client/dist/assets/{tcl-6DnLmROF.js → tcl-BKDUHAAR.js} +0 -0
- /package/client/dist/assets/{terminal-CDiOAmBd2.js → terminal-BRm03iFA2.js} +0 -0
- /package/client/dist/assets/{terminal-CJN-mQMc.js → terminal-De2Brd23.js} +0 -0
- /package/client/dist/assets/{terminal-CYB4TiAd.js → terminal-DxQWCqSD2.js} +0 -0
- /package/client/dist/assets/{terminal-DsaDTq5N2.js → terminal-WSAvHXoU.js} +0 -0
- /package/client/dist/assets/{terminal-DTQ_dPqi2.js → terminal-Z7KsDM_n.js} +0 -0
- /package/client/dist/assets/{terminal-58ReNaya.js → terminal-cqfd3EDV.js} +0 -0
- /package/client/dist/assets/{terminal-DawP8xNL.js → terminal-xGbCZJHg.js} +0 -0
- /package/client/dist/assets/{tickets-DoRTUYRT.js → tickets-B7zT4IRf.js} +0 -0
- /package/client/dist/assets/{tickets-DBfFePwk2.js → tickets-BoXom7l8.js} +0 -0
- /package/client/dist/assets/{tickets-DvohTziT2.js → tickets-C3b8cHhd2.js} +0 -0
- /package/client/dist/assets/{tickets-Da15iaRw.js → tickets-CFXnJsYF.js} +0 -0
- /package/client/dist/assets/{tickets-CujsZvkf.js → tickets-CWYFvx1W2.js} +0 -0
- /package/client/dist/assets/{tickets-Df6pee-O2.js → tickets-DTHo9c3C.js} +0 -0
- /package/client/dist/assets/{tickets-CNvIilmP.js → tickets-SuX_HkK4.js} +0 -0
- /package/client/dist/assets/{twig-XbbXW9Yz.js → twig-UpZQaM8G.js} +0 -0
- /package/client/dist/assets/{typespec-CRlV8GhI.js → typespec-DzaKvN8i.js} +0 -0
- /package/client/dist/assets/{vb-BHE2izPH.js → vb-CZpbb7tk.js} +0 -0
- /package/client/dist/assets/{wgsl-Bf5vkfmY.js → wgsl-CNt3OIvl.js} +0 -0
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.PR_DECISION_ACTIONS = void 0;
|
|
37
|
+
exports.isPrDecisionAction = isPrDecisionAction;
|
|
38
|
+
exports.executePrDecision = executePrDecision;
|
|
39
|
+
/**
|
|
40
|
+
* Execute a user's ask-first PR decision (safe-pr-review-flow) against its
|
|
41
|
+
* authoritative `rail_pr_deliveries` row: the FOUR actions both decision
|
|
42
|
+
* surfaces (the dashboard rail row and the launching agent-chat card) POST to
|
|
43
|
+
* `/rails/pr-decision`.
|
|
44
|
+
*
|
|
45
|
+
* create-pr → deferred deliverRailAsPr, reconstructed from the row's durable
|
|
46
|
+
* columns (nothing survives in memory after build-settle). The
|
|
47
|
+
* PR title/body are composed HERE (canonical OSS style — see
|
|
48
|
+
* pr-naming/pr-body) from the ticket store + jira_links + the
|
|
49
|
+
* branch diffs, all failure-tolerant.
|
|
50
|
+
* publish → `gh pr ready` opens the draft for team review.
|
|
51
|
+
* discard → close the PR, sweep the launch's worktrees + branches, revert
|
|
52
|
+
* the on_review tickets to todo.
|
|
53
|
+
* poll-merge → `gh pr view` — MERGED promotes the tickets to done.
|
|
54
|
+
* merge-local→ the REMOTE-LESS acceptance path: merge the delivered branches
|
|
55
|
+
* into the integration branch directly in the user's checkout
|
|
56
|
+
* (guarded: correct branch checked out + clean tree, abort on
|
|
57
|
+
* conflict). Without it, a repo with no GitHub remote wedges
|
|
58
|
+
* forever in retry(local-only)/discard — no way to ACCEPT work.
|
|
59
|
+
*
|
|
60
|
+
* Every mutation rides the compare-and-set `transitionDecision` (a raced
|
|
61
|
+
* concurrent decision loses with a 409) and re-broadcasts the durable
|
|
62
|
+
* `rail.pr_state` snapshot so both surfaces converge; agent-chat-originated
|
|
63
|
+
* rows also update their inline decision card in place. Deps are injected
|
|
64
|
+
* (db/git/exec/broadcast/jira/agent-chat) so the whole matrix is unit-testable
|
|
65
|
+
* without git/gh/net — the route in rails-router validates and delegates here.
|
|
66
|
+
*/
|
|
67
|
+
const path = __importStar(require("path"));
|
|
68
|
+
const artifact_registry_1 = require("./artifact-registry");
|
|
69
|
+
const worktree_manager_1 = require("./worktree-manager");
|
|
70
|
+
const rail_pr_delivery_1 = require("./rail-pr-delivery");
|
|
71
|
+
const pr_naming_1 = require("./pr-naming");
|
|
72
|
+
const pr_body_1 = require("./pr-body");
|
|
73
|
+
const jira_db_1 = require("./jira/jira-db");
|
|
74
|
+
const rail_pr_store_1 = require("./rail-pr-store");
|
|
75
|
+
const rail_worktrees_store_1 = require("./rail-worktrees-store");
|
|
76
|
+
const ticket_store_1 = require("./ticket-store");
|
|
77
|
+
const workspace_resolution_1 = require("./workspace-resolution");
|
|
78
|
+
const agent_chat_registry_1 = require("./agent-chat-registry");
|
|
79
|
+
exports.PR_DECISION_ACTIONS = ['create-pr', 'publish', 'discard', 'poll-merge', 'merge-local'];
|
|
80
|
+
function isPrDecisionAction(v) {
|
|
81
|
+
return typeof v === 'string' && exports.PR_DECISION_ACTIONS.includes(v);
|
|
82
|
+
}
|
|
83
|
+
function staleDecision(current) {
|
|
84
|
+
return { status: 409, body: { error: 'stale_decision', current } };
|
|
85
|
+
}
|
|
86
|
+
function illegalAction(current) {
|
|
87
|
+
return { status: 409, body: { error: 'stale_decision', current, reason: 'illegal_action' } };
|
|
88
|
+
}
|
|
89
|
+
function ghFailed(r) {
|
|
90
|
+
const detail = (r.stderr.trim() || r.stdout.trim()).split('\n')[0] || `exit ${r.code}`;
|
|
91
|
+
return { status: 502, body: { error: 'gh_failed', detail } };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The D3 state machine's action legality. `create-pr` is also the RETRY path:
|
|
95
|
+
* from a retryable pr_failed, or from a pr_draft whose delivery degraded before
|
|
96
|
+
* a PR existed (pushed/local-only → pr_url null). Publish/poll require a real
|
|
97
|
+
* PR URL — a degraded draft only offers retry or discard.
|
|
98
|
+
*/
|
|
99
|
+
function actionAllowed(action, row) {
|
|
100
|
+
switch (action) {
|
|
101
|
+
case 'create-pr':
|
|
102
|
+
return row.decision === 'on_review' || row.decision === 'pr_failed' ||
|
|
103
|
+
(row.decision === 'pr_draft' && row.pr_url === null);
|
|
104
|
+
case 'publish':
|
|
105
|
+
return row.decision === 'pr_draft' && row.pr_url !== null;
|
|
106
|
+
case 'discard':
|
|
107
|
+
return row.decision === 'on_review' || row.decision === 'pr_draft' ||
|
|
108
|
+
row.decision === 'pr_ready' || row.decision === 'pr_failed';
|
|
109
|
+
case 'poll-merge':
|
|
110
|
+
return (row.decision === 'pr_draft' || row.decision === 'pr_ready') && row.pr_url !== null;
|
|
111
|
+
case 'merge-local':
|
|
112
|
+
// Remote-less acceptance ONLY: once a real PR exists (pr_url), GitHub is
|
|
113
|
+
// the merge authority — merging under an open PR would leave it dangling.
|
|
114
|
+
return row.pr_url === null &&
|
|
115
|
+
(row.decision === 'on_review' || row.decision === 'pr_failed' || row.decision === 'pr_draft');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function executePrDecision(deps, input) {
|
|
119
|
+
const row = (0, rail_pr_store_1.getPrDelivery)(deps.db, input.prDeliveryId);
|
|
120
|
+
if (!row)
|
|
121
|
+
return { status: 404, body: { error: 'Unknown prDeliveryId' } };
|
|
122
|
+
// Compare-and-set pre-check: the caller decided against a snapshot — if the
|
|
123
|
+
// row moved on (the other surface answered first), it must reconcile, not act.
|
|
124
|
+
if (row.decision !== input.expectedDecision)
|
|
125
|
+
return staleDecision(row.decision);
|
|
126
|
+
if (!actionAllowed(input.action, row))
|
|
127
|
+
return illegalAction(row.decision);
|
|
128
|
+
switch (input.action) {
|
|
129
|
+
case 'create-pr': return runCreatePr(deps, row);
|
|
130
|
+
case 'publish': return runPublish(deps, row);
|
|
131
|
+
case 'discard': return runDiscard(deps, row);
|
|
132
|
+
case 'poll-merge': return runPollMerge(deps, row);
|
|
133
|
+
case 'merge-local': return runMergeLocal(deps, row);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Atomic CAS transition; a `false` return means a concurrent mutation raced us
|
|
138
|
+
* between the pre-check and here — surface the same 409 with the fresh state.
|
|
139
|
+
*/
|
|
140
|
+
function casTransition(deps, row, next, patch = {}) {
|
|
141
|
+
if ((0, rail_pr_store_1.transitionDecision)(deps.db, row.id, row.decision, next, patch))
|
|
142
|
+
return null;
|
|
143
|
+
const current = (0, rail_pr_store_1.getPrDelivery)(deps.db, row.id);
|
|
144
|
+
return staleDecision(current?.decision ?? row.decision);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Post-transition fan-out: re-broadcast the durable rail.pr_state snapshot
|
|
148
|
+
* (both surfaces converge on it) and, for agent-chat-originated launches,
|
|
149
|
+
* update the persisted inline card in place.
|
|
150
|
+
*/
|
|
151
|
+
function finalizeTransition(deps, id) {
|
|
152
|
+
const row = (0, rail_pr_store_1.getPrDelivery)(deps.db, id);
|
|
153
|
+
if (!row)
|
|
154
|
+
return undefined;
|
|
155
|
+
const snap = (0, rail_pr_store_1.toPrDeliverySnapshot)(row);
|
|
156
|
+
deps.broadcast((0, rail_pr_store_1.toRailPrStateMessage)(deps.project.id, snap));
|
|
157
|
+
if (row.origin_conversation_id) {
|
|
158
|
+
const agent = (deps.agentChat ?? agent_chat_registry_1.getAgentChatManager)();
|
|
159
|
+
// Shared mapper (rail-pr-store.toPrDecisionCardEnvelope) — the SAME shape
|
|
160
|
+
// rail-isolated-launch's origin-card sync posts, so the two card-writing
|
|
161
|
+
// sites (incl. the runIds chip data) can never drift.
|
|
162
|
+
agent?.updatePrDecisionCard(row.origin_conversation_id, (0, rail_pr_store_1.toPrDecisionCardEnvelope)(deps.project.id, snap));
|
|
163
|
+
}
|
|
164
|
+
return snap;
|
|
165
|
+
}
|
|
166
|
+
function parsePrNumber(prUrl) {
|
|
167
|
+
const m = /\/pull\/(\d+)/.exec(prUrl);
|
|
168
|
+
return m ? parseInt(m[1], 10) : null;
|
|
169
|
+
}
|
|
170
|
+
function batchWorktreeRoot(slug) {
|
|
171
|
+
// Mirrors rail-isolated-launch's worktreesRoot — derivable, never stored.
|
|
172
|
+
return path.join((0, artifact_registry_1.resolveHome)(), '.specrails', 'projects', slug, 'worktrees');
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Load the PR's ticket data (title/labels/description) from the ticket store,
|
|
176
|
+
* with the Jira key resolved PER TICKET: the authoritative `jira_links` row
|
|
177
|
+
* prevails over the ticket's `jira_key` field (JIRA ALWAYS PREVAILS), no HTTP.
|
|
178
|
+
* Tolerant of a missing/corrupt store or link table — degrades to bare local
|
|
179
|
+
* ids, never throws, never blocks PR creation.
|
|
180
|
+
*/
|
|
181
|
+
function loadPrTicketData(deps, ticketIds) {
|
|
182
|
+
let tickets = {};
|
|
183
|
+
try {
|
|
184
|
+
tickets = (0, ticket_store_1.readStore)(resolveTicketFile(deps)).tickets;
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
/* tolerated — the PR falls back to bare ticket refs */
|
|
188
|
+
}
|
|
189
|
+
return ticketIds.map((id) => {
|
|
190
|
+
const t = tickets[String(id)];
|
|
191
|
+
let jiraKey = t?.jira_key ?? null;
|
|
192
|
+
try {
|
|
193
|
+
const link = (0, jira_db_1.getLinkByLocalId)(deps.db, id);
|
|
194
|
+
if (link && !link.tombstoned && link.jiraKey)
|
|
195
|
+
jiraKey = link.jiraKey;
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
/* tolerated — fall back to the ticket field */
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
ticketId: id,
|
|
202
|
+
title: t?.title ?? null,
|
|
203
|
+
labels: t?.labels ?? null,
|
|
204
|
+
description: t?.description ?? null,
|
|
205
|
+
jiraKey,
|
|
206
|
+
};
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/** True when the branch exists as a local ref in the base repo. */
|
|
210
|
+
async function branchExists(deps, branch) {
|
|
211
|
+
const r = await deps.git.run(['rev-parse', '--verify', '--quiet', `refs/heads/${branch}`], deps.project.path);
|
|
212
|
+
return r.code === 0;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Recovery for a recorded unit branch that no longer exists (the wedged
|
|
216
|
+
* local-only retry: the settled record drifted from the branch that really
|
|
217
|
+
* carries the commits, or the branch was deleted externally). Scan the ticket's
|
|
218
|
+
* rail_worktrees ledger (newest first) for ANY other branch a rail allocated
|
|
219
|
+
* for the same ticket that still exists AND has commits ahead of the base —
|
|
220
|
+
* that branch is the real carrier of the work. Null when nothing recoverable.
|
|
221
|
+
*/
|
|
222
|
+
async function findRecoverableBranch(deps, unit, baseBranch) {
|
|
223
|
+
let candidates = [];
|
|
224
|
+
try {
|
|
225
|
+
candidates = (0, rail_worktrees_store_1.listRailWorktreesForTicket)(deps.db, unit.ticketId);
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
for (const wt of candidates) {
|
|
231
|
+
if (!wt.branch || wt.branch === unit.branch || wt.branch === baseBranch)
|
|
232
|
+
continue;
|
|
233
|
+
if (!(await branchExists(deps, wt.branch)))
|
|
234
|
+
continue;
|
|
235
|
+
const ahead = await deps.git.run(['rev-list', '--count', `${baseBranch}..${wt.branch}`], deps.project.path);
|
|
236
|
+
const n = ahead.code === 0 ? parseInt(ahead.stdout.trim(), 10) : NaN;
|
|
237
|
+
if (Number.isFinite(n) && n > 0)
|
|
238
|
+
return wt.branch;
|
|
239
|
+
}
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
async function runCreatePr(deps, row) {
|
|
243
|
+
const snap = (0, rail_pr_store_1.toPrDeliverySnapshot)(row);
|
|
244
|
+
// Pre-flight: every succeeded unit branch must actually exist before we push
|
|
245
|
+
// it — a missing ref can only degrade to local-only again, so a retry on a
|
|
246
|
+
// wedged row would loop forever. When a recorded branch is gone, recover the
|
|
247
|
+
// REAL branch from the ticket's worktree ledger (see findRecoverableBranch)
|
|
248
|
+
// and persist the substitution on the row; unrecoverable → honest pr_failed.
|
|
249
|
+
let effectiveBranches = snap.branches;
|
|
250
|
+
let branchesRecovered = false;
|
|
251
|
+
for (const unit of snap.branches) {
|
|
252
|
+
if (!unit.succeeded)
|
|
253
|
+
continue;
|
|
254
|
+
if (await branchExists(deps, unit.branch))
|
|
255
|
+
continue;
|
|
256
|
+
const real = await findRecoverableBranch(deps, unit, row.base_branch);
|
|
257
|
+
if (!real) {
|
|
258
|
+
const detail = `branch '${unit.branch}' (ticket #${unit.ticketId}) no longer exists locally and no other rail branch for the ticket holds commits — nothing to deliver`;
|
|
259
|
+
const conflict = casTransition(deps, row, 'pr_failed');
|
|
260
|
+
if (conflict)
|
|
261
|
+
return conflict;
|
|
262
|
+
finalizeTransition(deps, row.id);
|
|
263
|
+
return { status: 200, body: { ok: true, decision: 'pr_failed', detail } };
|
|
264
|
+
}
|
|
265
|
+
console.warn(`[rail-pr-decision] recorded branch '${unit.branch}' missing — recovered '${real}' from the ticket ${unit.ticketId} worktree ledger`);
|
|
266
|
+
effectiveBranches = effectiveBranches.map((b) => (b === unit ? { ...b, branch: real } : b));
|
|
267
|
+
branchesRecovered = true;
|
|
268
|
+
}
|
|
269
|
+
// Succeeded COVERED tickets for the PR title/body: a single unit covers every
|
|
270
|
+
// launch ticket (scope='all'), per-ticket units cover exactly their own.
|
|
271
|
+
const succeededUnits = effectiveBranches.filter((b) => b.succeeded);
|
|
272
|
+
const succeededTicketIds = effectiveBranches.length === 1 && succeededUnits.length === 1
|
|
273
|
+
? snap.ticketIds
|
|
274
|
+
: succeededUnits.map((b) => b.ticketId);
|
|
275
|
+
const ticketData = loadPrTicketData(deps, succeededTicketIds);
|
|
276
|
+
// The batch name is derived ONLY for multi-unit deliveries — the single-ticket
|
|
277
|
+
// path delivers straight from its unit branch and must never even compute one.
|
|
278
|
+
const batchPreferred = succeededUnits.length > 1 ? (0, pr_naming_1.batchBranchNameFor)(ticketData) : null;
|
|
279
|
+
// Retry hazard: deliverRailAsPr assembles with `worktree add -b` (no -B) and a
|
|
280
|
+
// prior degraded delivery KEEPS the batch branch — so a retry would die on
|
|
281
|
+
// "branch already exists". Defensively drop the stale batch branch first
|
|
282
|
+
// (batch deliveries only). HARD GUARDS: NEVER a branch present in the row's
|
|
283
|
+
// unit records (deleting one would destroy the commits about to be delivered)
|
|
284
|
+
// and NEVER the integration branch; a missing branch is tolerated.
|
|
285
|
+
const unitBranches = new Set(effectiveBranches.map((b) => b.branch));
|
|
286
|
+
if (batchPreferred && batchPreferred !== row.base_branch && !unitBranches.has(batchPreferred)) {
|
|
287
|
+
await deps.git.run(['branch', '-D', batchPreferred], deps.project.path).catch(() => { });
|
|
288
|
+
}
|
|
289
|
+
// Per-ticket covering branch for the body's honest Tests digest: per-ticket
|
|
290
|
+
// units map 1:1; a single 'all'-scope unit covers every launch ticket.
|
|
291
|
+
const branchFor = (ticketId) => {
|
|
292
|
+
const unit = succeededUnits.find((b) => b.ticketId === ticketId);
|
|
293
|
+
if (unit)
|
|
294
|
+
return unit.branch;
|
|
295
|
+
return succeededUnits.length === 1 ? succeededUnits[0].branch : null;
|
|
296
|
+
};
|
|
297
|
+
// Diffstats are best-effort: a git failure degrades the body (section
|
|
298
|
+
// omitted / "diff unavailable" note), never blocks the PR.
|
|
299
|
+
let changes = null;
|
|
300
|
+
try {
|
|
301
|
+
changes = await (0, pr_body_1.collectBranchChanges)(deps.git, deps.project.path, row.base_branch, succeededUnits.map((b) => b.branch));
|
|
302
|
+
}
|
|
303
|
+
catch {
|
|
304
|
+
changes = null;
|
|
305
|
+
}
|
|
306
|
+
const title = (0, pr_naming_1.buildPrTitle)(ticketData, { loopName: row.loop_name });
|
|
307
|
+
const body = (0, pr_body_1.buildCanonicalPrBody)({
|
|
308
|
+
loopName: row.loop_name,
|
|
309
|
+
baseBranch: row.base_branch,
|
|
310
|
+
tickets: ticketData.map((t) => ({ ...t, branch: branchFor(t.ticketId) })),
|
|
311
|
+
changes,
|
|
312
|
+
});
|
|
313
|
+
let next;
|
|
314
|
+
// Underlying git/gh failure detail for a degraded or failed delivery —
|
|
315
|
+
// relayed on the response body so the decision surfaces can say WHY instead
|
|
316
|
+
// of a bare "retry". Never persisted (the durable columns stay state-only).
|
|
317
|
+
let detail = null;
|
|
318
|
+
const patch = {};
|
|
319
|
+
// Persist any pre-flight substitution so the row records the branch that
|
|
320
|
+
// actually carries the commits — the next retry/discard works from reality.
|
|
321
|
+
if (branchesRecovered)
|
|
322
|
+
patch.branches = effectiveBranches;
|
|
323
|
+
try {
|
|
324
|
+
const result = await (0, rail_pr_delivery_1.deliverRailAsPr)(deps.git, deps.exec, {
|
|
325
|
+
baseRepo: deps.project.path,
|
|
326
|
+
integrationBranch: row.base_branch,
|
|
327
|
+
railKey: row.rail_key,
|
|
328
|
+
batchBranch: batchPreferred ?? undefined,
|
|
329
|
+
batchWorktreeRoot: batchWorktreeRoot(deps.project.slug),
|
|
330
|
+
branches: effectiveBranches,
|
|
331
|
+
title,
|
|
332
|
+
body,
|
|
333
|
+
});
|
|
334
|
+
if (result.state === 'delivered') {
|
|
335
|
+
next = 'pr_draft';
|
|
336
|
+
patch.branch = result.branch;
|
|
337
|
+
patch.prState = result.pr.state;
|
|
338
|
+
if (result.pr.state === 'pr-created' && result.pr.prUrl) {
|
|
339
|
+
patch.prUrl = result.pr.prUrl;
|
|
340
|
+
patch.prNumber = parsePrNumber(result.pr.prUrl);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
// Degraded (pushed / local-only): no PR exists — only retry or discard.
|
|
344
|
+
patch.prUrl = null;
|
|
345
|
+
patch.prNumber = null;
|
|
346
|
+
detail = result.pr.reason ?? null;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
// 'assembly-failed' (or an unexpected 'no-op' — settle guarantees ≥1
|
|
351
|
+
// succeeded unit, but a wedged row must not 500) → retryable failure.
|
|
352
|
+
next = 'pr_failed';
|
|
353
|
+
detail = result.reason;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
catch (err) {
|
|
357
|
+
// publishDraftPr can propagate GitGuardrailError — a guardrail violation is
|
|
358
|
+
// a retryable delivery failure, never a crash.
|
|
359
|
+
console.error('[rail-pr-decision] create-pr delivery failed:', err);
|
|
360
|
+
next = 'pr_failed';
|
|
361
|
+
detail = err instanceof Error ? err.message : String(err);
|
|
362
|
+
}
|
|
363
|
+
const conflict = casTransition(deps, row, next, patch);
|
|
364
|
+
if (conflict)
|
|
365
|
+
return conflict;
|
|
366
|
+
const after = finalizeTransition(deps, row.id);
|
|
367
|
+
// Tickets stay on_review — a draft PR is still awaiting the engineer's merge.
|
|
368
|
+
return {
|
|
369
|
+
status: 200,
|
|
370
|
+
body: {
|
|
371
|
+
ok: true,
|
|
372
|
+
decision: next,
|
|
373
|
+
prUrl: after?.prUrl ?? null,
|
|
374
|
+
prState: after?.prState ?? row.pr_state,
|
|
375
|
+
...(detail ? { detail } : {}),
|
|
376
|
+
},
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
async function runPublish(deps, row) {
|
|
380
|
+
const r = await deps.exec.run('gh', ['pr', 'ready', row.pr_url], deps.project.path);
|
|
381
|
+
if (r.code !== 0)
|
|
382
|
+
return ghFailed(r); // no transition — the draft is still a draft
|
|
383
|
+
const conflict = casTransition(deps, row, 'pr_ready');
|
|
384
|
+
if (conflict)
|
|
385
|
+
return conflict;
|
|
386
|
+
finalizeTransition(deps, row.id);
|
|
387
|
+
return { status: 200, body: { ok: true, decision: 'pr_ready', prUrl: row.pr_url } };
|
|
388
|
+
}
|
|
389
|
+
async function runDiscard(deps, row) {
|
|
390
|
+
const snap = (0, rail_pr_store_1.toPrDeliverySnapshot)(row);
|
|
391
|
+
// 1. Close the PR (drops its head branch) when one exists. Best-effort — a
|
|
392
|
+
// gh failure must never leave the discard half-done.
|
|
393
|
+
if (row.pr_url) {
|
|
394
|
+
try {
|
|
395
|
+
const r = await deps.exec.run('gh', ['pr', 'close', row.pr_url, '--delete-branch'], deps.project.path);
|
|
396
|
+
if (r.code !== 0) {
|
|
397
|
+
console.warn(`[rail-pr-decision] gh pr close failed (continuing discard): ${(r.stderr.trim() || r.stdout.trim()).split('\n')[0]}`);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
catch (err) {
|
|
401
|
+
console.warn('[rail-pr-decision] gh pr close threw (continuing discard):', err);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
// 2. Remove the launch's worktrees (still on disk unless a restart already
|
|
405
|
+
// swept them) and close their ledger rows — the reconcile-style removal,
|
|
406
|
+
// branch deletion deferred to step 3 (a checked-out branch can't be -D'd).
|
|
407
|
+
const branchSet = new Set(snap.branches.map((b) => b.branch));
|
|
408
|
+
for (const wtId of snap.worktreeIds) {
|
|
409
|
+
const wt = (0, rail_worktrees_store_1.getRailWorktree)(deps.db, wtId);
|
|
410
|
+
if (!wt)
|
|
411
|
+
continue;
|
|
412
|
+
branchSet.add(wt.branch);
|
|
413
|
+
await (0, worktree_manager_1.removeWorktree)(deps.git, {
|
|
414
|
+
repoDir: deps.project.path, worktreePath: wt.worktree_path, branch: wt.branch, deleteBranch: false,
|
|
415
|
+
}).catch(() => { });
|
|
416
|
+
if (!(0, rail_worktrees_store_1.isTerminalMergeState)(wt.merge_state))
|
|
417
|
+
(0, rail_worktrees_store_1.updateRailWorktreeState)(deps.db, wt.id, 'failed');
|
|
418
|
+
}
|
|
419
|
+
// 3. Delete every branch the delivery references: per-unit source branches,
|
|
420
|
+
// the assembled head and the (possibly stale) batch branch — recomputed
|
|
421
|
+
// best-effort from the same ticket data the create-pr path names it from
|
|
422
|
+
// (the delivered head is already covered by row.branch). Missing branches
|
|
423
|
+
// are tolerated; the integration branch is NEVER deleted.
|
|
424
|
+
if (row.branch)
|
|
425
|
+
branchSet.add(row.branch);
|
|
426
|
+
const succeededUnits = snap.branches.filter((b) => b.succeeded);
|
|
427
|
+
if (succeededUnits.length > 1) {
|
|
428
|
+
try {
|
|
429
|
+
branchSet.add((0, pr_naming_1.batchBranchNameFor)(loadPrTicketData(deps, succeededUnits.map((b) => b.ticketId))));
|
|
430
|
+
}
|
|
431
|
+
catch {
|
|
432
|
+
/* best-effort defense-in-depth only */
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
for (const branch of branchSet) {
|
|
436
|
+
if (!branch || branch === row.base_branch)
|
|
437
|
+
continue;
|
|
438
|
+
await deps.git.run(['branch', '-D', branch], deps.project.path).catch(() => { });
|
|
439
|
+
}
|
|
440
|
+
const conflict = casTransition(deps, row, 'discarded');
|
|
441
|
+
if (conflict)
|
|
442
|
+
return conflict;
|
|
443
|
+
finalizeTransition(deps, row.id);
|
|
444
|
+
// 4. Revert the parked tickets to the backlog + mirror to Jira (outbox-only;
|
|
445
|
+
// the local write above is ours).
|
|
446
|
+
const changed = applyTicketTransition(deps, snap.ticketIds, 'todo');
|
|
447
|
+
try {
|
|
448
|
+
deps.jiraSyncManager?.onRailDiscard(changed, row.id);
|
|
449
|
+
}
|
|
450
|
+
catch (err) {
|
|
451
|
+
console.error('[rail-pr-decision] jira onRailDiscard failed:', err);
|
|
452
|
+
}
|
|
453
|
+
return { status: 200, body: { ok: true, decision: 'discarded' } };
|
|
454
|
+
}
|
|
455
|
+
async function runPollMerge(deps, row) {
|
|
456
|
+
const r = await deps.exec.run('gh', ['pr', 'view', row.pr_url, '--json', 'state,mergedAt'], deps.project.path);
|
|
457
|
+
if (r.code !== 0)
|
|
458
|
+
return ghFailed(r); // no transition
|
|
459
|
+
let state;
|
|
460
|
+
try {
|
|
461
|
+
state = JSON.parse(r.stdout).state;
|
|
462
|
+
}
|
|
463
|
+
catch {
|
|
464
|
+
return { status: 502, body: { error: 'gh_failed', detail: 'unparseable gh pr view output' } };
|
|
465
|
+
}
|
|
466
|
+
if (state !== 'MERGED') {
|
|
467
|
+
// Not merged (OPEN/CLOSED/unknown) → observation only, nothing changes.
|
|
468
|
+
return { status: 200, body: { ok: true, decision: row.decision, merged: false } };
|
|
469
|
+
}
|
|
470
|
+
const conflict = casTransition(deps, row, 'merged');
|
|
471
|
+
if (conflict)
|
|
472
|
+
return conflict;
|
|
473
|
+
finalizeTransition(deps, row.id);
|
|
474
|
+
const snap = (0, rail_pr_store_1.toPrDeliverySnapshot)(row);
|
|
475
|
+
const changed = applyTicketTransition(deps, snap.ticketIds, 'done');
|
|
476
|
+
try {
|
|
477
|
+
deps.jiraSyncManager?.onRailMerged(changed, row.id, row.pr_url);
|
|
478
|
+
}
|
|
479
|
+
catch (err) {
|
|
480
|
+
console.error('[rail-pr-decision] jira onRailMerged failed:', err);
|
|
481
|
+
}
|
|
482
|
+
return { status: 200, body: { ok: true, decision: 'merged', merged: true, prUrl: row.pr_url } };
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Remote-less acceptance: merge the delivery's branches into the integration
|
|
486
|
+
* branch DIRECTLY in the user's checkout. This is the one decision that touches
|
|
487
|
+
* the user's working tree, so it is triple-guarded and transactional-ish:
|
|
488
|
+
*
|
|
489
|
+
* - The checkout must have the integration branch checked out (a branch can
|
|
490
|
+
* only be checked out in one worktree — merging via a temp worktree is
|
|
491
|
+
* impossible while the user holds it) → 409 `merge_local_blocked` otherwise.
|
|
492
|
+
* - The working tree must be CLEAN → 409 `merge_local_blocked` otherwise.
|
|
493
|
+
* - Merge = the assembled head when one exists (row.branch), else each
|
|
494
|
+
* succeeded unit branch sequentially, `--no-ff --no-edit`. Any conflict →
|
|
495
|
+
* `merge --abort` + 502 `merge_failed`, NO transition (retry or discard).
|
|
496
|
+
*
|
|
497
|
+
* Success mirrors poll-merge's MERGED arm: decision → merged (prUrl stays
|
|
498
|
+
* null), worktrees/branches swept, tickets → done, Jira onRailMerged(null).
|
|
499
|
+
*/
|
|
500
|
+
async function runMergeLocal(deps, row) {
|
|
501
|
+
const snap = (0, rail_pr_store_1.toPrDeliverySnapshot)(row);
|
|
502
|
+
// Guards on the user's checkout.
|
|
503
|
+
const head = await deps.git.run(['rev-parse', '--abbrev-ref', 'HEAD'], deps.project.path);
|
|
504
|
+
const currentBranch = head.code === 0 ? head.stdout.trim() : '';
|
|
505
|
+
if (currentBranch !== row.base_branch) {
|
|
506
|
+
return {
|
|
507
|
+
status: 409,
|
|
508
|
+
body: { error: 'merge_local_blocked', reason: 'wrong_branch', current: currentBranch || null, base: row.base_branch },
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
const status = await deps.git.run(['status', '--porcelain'], deps.project.path);
|
|
512
|
+
if (status.code !== 0 || status.stdout.trim() !== '') {
|
|
513
|
+
return { status: 409, body: { error: 'merge_local_blocked', reason: 'dirty', base: row.base_branch } };
|
|
514
|
+
}
|
|
515
|
+
// What to merge: the assembled head carries every unit already; without one
|
|
516
|
+
// (straight from on_review) merge each succeeded unit branch in order.
|
|
517
|
+
let toMerge;
|
|
518
|
+
if (row.branch && (await branchExists(deps, row.branch))) {
|
|
519
|
+
toMerge = [row.branch];
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
toMerge = [];
|
|
523
|
+
for (const unit of snap.branches.filter((b) => b.succeeded)) {
|
|
524
|
+
let branch = unit.branch;
|
|
525
|
+
if (!(await branchExists(deps, branch)))
|
|
526
|
+
branch = await findRecoverableBranch(deps, unit, row.base_branch);
|
|
527
|
+
if (!branch) {
|
|
528
|
+
return {
|
|
529
|
+
status: 502,
|
|
530
|
+
body: { error: 'merge_failed', detail: `branch '${unit.branch}' (ticket #${unit.ticketId}) no longer exists locally — nothing to merge` },
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
toMerge.push(branch);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
if (toMerge.length === 0) {
|
|
537
|
+
return { status: 502, body: { error: 'merge_failed', detail: 'no succeeded branch to merge' } };
|
|
538
|
+
}
|
|
539
|
+
for (const branch of toMerge) {
|
|
540
|
+
const r = await deps.git.run(['merge', '--no-ff', '--no-edit', branch], deps.project.path);
|
|
541
|
+
if (r.code !== 0) {
|
|
542
|
+
await deps.git.run(['merge', '--abort'], deps.project.path).catch(() => { });
|
|
543
|
+
const detail = (r.stderr.trim() || r.stdout.trim()).split('\n')[0] || `exit ${r.code}`;
|
|
544
|
+
return { status: 502, body: { error: 'merge_failed', detail: `merging '${branch}': ${detail}` } };
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
// Post-merge sweep (same shape as discard steps 2-3): the work now lives on
|
|
548
|
+
// the integration branch, so the launch's worktrees + branches are spent.
|
|
549
|
+
const branchSet = new Set(toMerge);
|
|
550
|
+
for (const b of snap.branches)
|
|
551
|
+
branchSet.add(b.branch);
|
|
552
|
+
if (row.branch)
|
|
553
|
+
branchSet.add(row.branch);
|
|
554
|
+
for (const wtId of snap.worktreeIds) {
|
|
555
|
+
const wt = (0, rail_worktrees_store_1.getRailWorktree)(deps.db, wtId);
|
|
556
|
+
if (!wt)
|
|
557
|
+
continue;
|
|
558
|
+
branchSet.add(wt.branch);
|
|
559
|
+
await (0, worktree_manager_1.removeWorktree)(deps.git, {
|
|
560
|
+
repoDir: deps.project.path, worktreePath: wt.worktree_path, branch: wt.branch, deleteBranch: false,
|
|
561
|
+
}).catch(() => { });
|
|
562
|
+
if (!(0, rail_worktrees_store_1.isTerminalMergeState)(wt.merge_state))
|
|
563
|
+
(0, rail_worktrees_store_1.updateRailWorktreeState)(deps.db, wt.id, 'merged');
|
|
564
|
+
}
|
|
565
|
+
for (const branch of branchSet) {
|
|
566
|
+
if (!branch || branch === row.base_branch)
|
|
567
|
+
continue;
|
|
568
|
+
await deps.git.run(['branch', '-D', branch], deps.project.path).catch(() => { });
|
|
569
|
+
}
|
|
570
|
+
const conflict = casTransition(deps, row, 'merged');
|
|
571
|
+
if (conflict)
|
|
572
|
+
return conflict;
|
|
573
|
+
finalizeTransition(deps, row.id);
|
|
574
|
+
const changed = applyTicketTransition(deps, snap.ticketIds, 'done');
|
|
575
|
+
try {
|
|
576
|
+
deps.jiraSyncManager?.onRailMerged(changed, row.id, null);
|
|
577
|
+
}
|
|
578
|
+
catch (err) {
|
|
579
|
+
console.error('[rail-pr-decision] jira onRailMerged (local) failed:', err);
|
|
580
|
+
}
|
|
581
|
+
return { status: 200, body: { ok: true, decision: 'merged', merged: true, local: true } };
|
|
582
|
+
}
|
|
583
|
+
function resolveTicketFile(deps) {
|
|
584
|
+
if (deps.ticketFile)
|
|
585
|
+
return deps.ticketFile;
|
|
586
|
+
const exec = (0, workspace_resolution_1.resolveProjectExecution)({ slug: deps.project.slug, path: deps.project.path });
|
|
587
|
+
return exec.relocated ? exec.ticketsPath : (0, ticket_store_1.resolveTicketStoragePath)(deps.project.path);
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Move the launch's on_review tickets to `todo` (discard) or `done` (merged),
|
|
591
|
+
* broadcasting ticket_updated per changed spec — mirroring onLoopRunFinished's
|
|
592
|
+
* revert style in project-registry. ONLY tickets still parked at on_review move
|
|
593
|
+
* (a manually re-triaged spec is respected). Best-effort: a ticket-store
|
|
594
|
+
* failure is logged, never fatal (the decision row already transitioned).
|
|
595
|
+
*/
|
|
596
|
+
function applyTicketTransition(deps, ticketIds, to) {
|
|
597
|
+
const changed = [];
|
|
598
|
+
if (ticketIds.length === 0)
|
|
599
|
+
return changed;
|
|
600
|
+
try {
|
|
601
|
+
const ticketFile = resolveTicketFile(deps);
|
|
602
|
+
const now = new Date().toISOString();
|
|
603
|
+
const store = (0, ticket_store_1.mutateStore)(ticketFile, (s) => {
|
|
604
|
+
for (const tid of ticketIds) {
|
|
605
|
+
const ticket = s.tickets[String(tid)];
|
|
606
|
+
if (!ticket || ticket.status !== 'on_review')
|
|
607
|
+
continue;
|
|
608
|
+
ticket.status = to;
|
|
609
|
+
ticket.updated_at = now;
|
|
610
|
+
changed.push(tid);
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
for (const tid of changed) {
|
|
614
|
+
const ticket = store.tickets[String(tid)];
|
|
615
|
+
if (!ticket)
|
|
616
|
+
continue;
|
|
617
|
+
deps.broadcast({
|
|
618
|
+
type: 'ticket_updated',
|
|
619
|
+
ticket: ticket,
|
|
620
|
+
projectId: deps.project.id,
|
|
621
|
+
timestamp: ticket.updated_at,
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
catch (err) {
|
|
626
|
+
console.error('[rail-pr-decision] failed to apply ticket transition:', err);
|
|
627
|
+
}
|
|
628
|
+
return changed;
|
|
629
|
+
}
|