specrails-desktop 2.21.0 → 2.22.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-roDyKGuv.js} +1 -1
- package/client/dist/assets/AgentBrowserCapture-BsXnWa4j.js +1 -0
- package/client/dist/assets/{AgentModeCodePane-DhVkOSdv.js → AgentModeCodePane-o97EJvbJ.js} +2 -2
- package/client/dist/assets/AgentModeJobsPane-CLtpPxPM.js +1 -0
- package/client/dist/assets/AgentsPage-eNSo_ZcC.js +86 -0
- package/client/dist/assets/AnalyticsPage-cAJ60_Ex.js +1 -0
- package/client/dist/assets/{BarChart-9_p1-qtv.js → BarChart-NLtK7xAY.js} +1 -1
- package/client/dist/assets/CodePage-B5rum8ZB.js +2 -0
- package/client/dist/assets/DesktopAnalyticsPage-DSuvG6Tq.js +1 -0
- package/client/dist/assets/DocsDialog-Bo38G3Yc.js +11 -0
- package/client/dist/assets/DocsPage-BNkiBBrC.js +11 -0
- package/client/dist/assets/{ExportDropdown-Clt8DyCs.js → ExportDropdown-DCV8PN4-.js} +1 -1
- package/client/dist/assets/IntegrationsPage-BMJOzpPz.js +3 -0
- package/client/dist/assets/InteractiveJobComposer-aLduNs5R.js +19 -0
- package/client/dist/assets/JobDetailModal-kpkUWJIS.js +1 -0
- package/client/dist/assets/JobDetailPage-CFeqlrPU.js +1 -0
- package/client/dist/assets/JobsPage-fuwhXy2I.js +1 -0
- package/client/dist/assets/LoopBuilderPage-DP66322C.js +7 -0
- package/client/dist/assets/LoopPreviewModal-CpmBhE31.js +1 -0
- package/client/dist/assets/LoopsPage-CvQ18VUx.js +1 -0
- package/client/dist/assets/ProjectSettingsDialog-Deq4pwvq.js +1 -0
- package/client/dist/assets/TemplatePreviewModal-DziOj2Ct.js +1 -0
- package/client/dist/assets/agent-Csh4kP2S.js +1 -0
- package/client/dist/assets/agent-Cz_jgQX32.js +1 -0
- package/client/dist/assets/agent-D3vcIvaz2.js +1 -0
- package/client/dist/assets/agent-Dnbt0V4e.js +1 -0
- package/client/dist/assets/agent-HolR7QrZ.js +1 -0
- package/client/dist/assets/agent-Ka0rRWJy.js +1 -0
- package/client/dist/assets/agent-Te3yysMd.js +1 -0
- package/client/dist/assets/agent-vM4_iLDk2.js +1 -0
- package/client/dist/assets/{upload-DPRq2dC-.js → brain-kFJuEDNH.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-BaStj_a_.js +1 -0
- package/client/dist/assets/dashboard-Bi6ugu5Q.js +1 -0
- package/client/dist/assets/dashboard-BmqTn3L02.js +1 -0
- package/client/dist/assets/dashboard-CvT8lOCT.js +1 -0
- package/client/dist/assets/dashboard-D7Pmeavq2.js +1 -0
- package/client/dist/assets/dashboard-DAnWdAac2.js +1 -0
- package/client/dist/assets/dashboard-JnYy2WLg.js +1 -0
- package/client/dist/assets/dashboard-L47YsFS_.js +1 -0
- package/client/dist/assets/{dist-js-4mmVovCB.js → dist-js-BZSiJDbG.js} +1 -1
- package/client/dist/assets/{dist-js-wMFtEMAw.js → dist-js-DKpmIJlQ.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-DM6heiGa.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-B2nCKzmA.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-CLAzW1mS.js +1 -0
- package/client/dist/assets/{value-DJMRojPA.js → value-DSwzyyWR.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 +367 -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 +149 -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 +519 -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 +224 -37
- 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
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAX_RAILS = exports.BASE_RAIL_COUNT = void 0;
|
|
4
|
+
exports.ensureRailMeta = ensureRailMeta;
|
|
5
|
+
exports.listRailIndices = listRailIndices;
|
|
6
|
+
exports.railCount = railCount;
|
|
7
|
+
exports.railExists = railExists;
|
|
3
8
|
exports.getRails = getRails;
|
|
4
9
|
exports.getRail = getRail;
|
|
5
10
|
exports.setRailTickets = setRailTickets;
|
|
6
11
|
exports.setRailProfile = setRailProfile;
|
|
7
12
|
exports.setRailEngine = setRailEngine;
|
|
13
|
+
exports.createRail = createRail;
|
|
14
|
+
exports.deleteRail = deleteRail;
|
|
8
15
|
exports.setRailName = setRailName;
|
|
16
|
+
/** The three rails every project starts with (indices 0-2, never auto-removed). */
|
|
17
|
+
exports.BASE_RAIL_COUNT = 3;
|
|
18
|
+
/** Hard cap on rails per project — keeps railIndex-keyed maps (metrics,
|
|
19
|
+
* pr-deliveries, worktree progress) bounded and the board renderable. */
|
|
20
|
+
exports.MAX_RAILS = 12;
|
|
9
21
|
/** Read the per-rail display names from rail_meta into a lookup map. */
|
|
10
22
|
function railNames(db) {
|
|
11
23
|
const rows = db.prepare('SELECT rail_index, name FROM rail_meta').all();
|
|
@@ -14,6 +26,32 @@ function railNames(db) {
|
|
|
14
26
|
map.set(r.rail_index, r.name);
|
|
15
27
|
return map;
|
|
16
28
|
}
|
|
29
|
+
/** Materialize a rail's identity row (idempotent). rail_meta is the existence
|
|
30
|
+
* authority for rails: a rail exists iff it has a rail_meta row (the base
|
|
31
|
+
* three are seeded by db migration 39; created rails insert theirs) or any
|
|
32
|
+
* leftover ticket rows. Called by every mutation that "touches" a rail so a
|
|
33
|
+
* rail the client only knew locally (legacy localStorage rail-4+) becomes
|
|
34
|
+
* server-backed the first time it is named / assigned tickets. */
|
|
35
|
+
function ensureRailMeta(db, railIndex) {
|
|
36
|
+
db.prepare('INSERT OR IGNORE INTO rail_meta (rail_index, name) VALUES (?, NULL)').run(railIndex);
|
|
37
|
+
}
|
|
38
|
+
/** Every existing rail index, ascending: the union of rail_meta identity rows
|
|
39
|
+
* and any index that still holds ticket rows (defensive — covers rows written
|
|
40
|
+
* before rail_meta materialization existed). */
|
|
41
|
+
function listRailIndices(db) {
|
|
42
|
+
const rows = db
|
|
43
|
+
.prepare('SELECT rail_index FROM rail_meta UNION SELECT rail_index FROM rails ORDER BY rail_index')
|
|
44
|
+
.all();
|
|
45
|
+
return rows.map((r) => r.rail_index);
|
|
46
|
+
}
|
|
47
|
+
/** How many rails currently exist (>= BASE_RAIL_COUNT unless deleted below it). */
|
|
48
|
+
function railCount(db) {
|
|
49
|
+
return listRailIndices(db).length;
|
|
50
|
+
}
|
|
51
|
+
/** Whether a rail exists (base rails always do; dynamic rails via rail_meta/rows). */
|
|
52
|
+
function railExists(db, railIndex) {
|
|
53
|
+
return listRailIndices(db).includes(railIndex);
|
|
54
|
+
}
|
|
17
55
|
// ─── Queries ─────────────────────────────────────────────────────────────────
|
|
18
56
|
function getRails(db) {
|
|
19
57
|
const rows = db
|
|
@@ -32,7 +70,10 @@ function getRails(db) {
|
|
|
32
70
|
map.get(row.rail_index).ticketIds.push(row.ticket_id);
|
|
33
71
|
}
|
|
34
72
|
const names = railNames(db);
|
|
35
|
-
|
|
73
|
+
// DYNAMIC rail count: every rail with an identity row (rail_meta) or ticket
|
|
74
|
+
// rows is listed — the base three are seeded, created rails append, deleted
|
|
75
|
+
// dynamic rails disappear (indices may be sparse after a middle deletion).
|
|
76
|
+
return listRailIndices(db).map((railIndex) => {
|
|
36
77
|
const rail = map.get(railIndex);
|
|
37
78
|
return {
|
|
38
79
|
railIndex,
|
|
@@ -67,6 +108,10 @@ function setRailTickets(db, railIndex, ticketIds, mode, profileName, aiEngine) {
|
|
|
67
108
|
// undefined → preserve existing engine across re-orders; null → explicit clear.
|
|
68
109
|
const resolvedEngine = aiEngine === undefined ? (getRail(db, railIndex).aiEngine ?? null) : aiEngine;
|
|
69
110
|
db.transaction(() => {
|
|
111
|
+
// Materialize the rail's identity so a rail first touched by a ticket sync
|
|
112
|
+
// (e.g. a legacy client-local rail-4+ at launch time) persists server-side
|
|
113
|
+
// even after its tickets are released.
|
|
114
|
+
ensureRailMeta(db, railIndex);
|
|
70
115
|
deleteStmt.run(railIndex);
|
|
71
116
|
for (let i = 0; i < ticketIds.length; i++) {
|
|
72
117
|
insertStmt.run(railIndex, ticketIds[i], i, resolvedMode, resolvedProfile, resolvedEngine);
|
|
@@ -102,6 +147,38 @@ function setRailEngine(db, railIndex, aiEngine) {
|
|
|
102
147
|
db.prepare('UPDATE rails SET ai_engine = ? WHERE rail_index = ?').run(aiEngine, railIndex);
|
|
103
148
|
return { ...current, aiEngine };
|
|
104
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Create the next rail (index = highest existing + 1) with an optional display
|
|
152
|
+
* name. The caller (rails-router / MCP create_rail) enforces the MAX_RAILS cap
|
|
153
|
+
* — the store itself stays mechanism-only. Returns the new rail's state.
|
|
154
|
+
*/
|
|
155
|
+
function createRail(db, name) {
|
|
156
|
+
// Lowest free index (not max+1): re-filling a deleted middle rail's slot keeps
|
|
157
|
+
// indices bounded below MAX_RAILS whenever the COUNT is below the cap. Reuse
|
|
158
|
+
// is safe — the delete guards ensure a deleted index left no active run or
|
|
159
|
+
// undecided PR delivery behind.
|
|
160
|
+
const taken = new Set(listRailIndices(db));
|
|
161
|
+
let railIndex = 0;
|
|
162
|
+
while (taken.has(railIndex))
|
|
163
|
+
railIndex++;
|
|
164
|
+
const trimmed = typeof name === 'string' ? name.trim() : null;
|
|
165
|
+
const value = trimmed && trimmed.length > 0 ? trimmed : null;
|
|
166
|
+
db.prepare('INSERT OR IGNORE INTO rail_meta (rail_index, name) VALUES (?, ?)').run(railIndex, value);
|
|
167
|
+
return { railIndex, ticketIds: [], mode: 'implement', profileName: null, aiEngine: null, name: value };
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Delete a rail's identity + ticket rows. Pure mechanism — the router enforces
|
|
171
|
+
* the guards (rail exists, empty, idle, no pending PR decision, not the last
|
|
172
|
+
* rail). Deleting a middle rail leaves a sparse index gap on purpose: indices
|
|
173
|
+
* are IDENTITY (metrics / pr-deliveries / worktree maps key by railIndex), so
|
|
174
|
+
* they are never compacted/re-numbered.
|
|
175
|
+
*/
|
|
176
|
+
function deleteRail(db, railIndex) {
|
|
177
|
+
db.transaction(() => {
|
|
178
|
+
db.prepare('DELETE FROM rail_meta WHERE rail_index = ?').run(railIndex);
|
|
179
|
+
db.prepare('DELETE FROM rails WHERE rail_index = ?').run(railIndex);
|
|
180
|
+
})();
|
|
181
|
+
}
|
|
105
182
|
/**
|
|
106
183
|
* Set a rail's display name (the "Rail "-suffix the user types). Stored in
|
|
107
184
|
* rail_meta (ticket-independent) so even an empty rail keeps its name. Pass
|
|
@@ -137,6 +137,7 @@ function getBundledToolCandidates(runtimesBase, tool) {
|
|
|
137
137
|
npm: [path_1.default.join(runtimesBase, 'node', 'npm.cmd')],
|
|
138
138
|
npx: [path_1.default.join(runtimesBase, 'node', 'npx.cmd')],
|
|
139
139
|
git: [path_1.default.join(runtimesBase, 'git', 'cmd', 'git.exe'), path_1.default.join(runtimesBase, 'git', 'bin', 'git.exe')],
|
|
140
|
+
gh: [path_1.default.join(runtimesBase, 'gh', 'bin', 'gh.exe')],
|
|
140
141
|
};
|
|
141
142
|
return map[tool];
|
|
142
143
|
}
|
|
@@ -145,6 +146,7 @@ function getBundledToolCandidates(runtimesBase, tool) {
|
|
|
145
146
|
npm: [path_1.default.join(runtimesBase, 'node', 'bin', 'npm')],
|
|
146
147
|
npx: [path_1.default.join(runtimesBase, 'node', 'bin', 'npx')],
|
|
147
148
|
git: [path_1.default.join(runtimesBase, 'git', 'bin', 'git')],
|
|
149
|
+
gh: [path_1.default.join(runtimesBase, 'gh', 'bin', 'gh')],
|
|
148
150
|
};
|
|
149
151
|
return map[tool];
|
|
150
152
|
}
|
|
@@ -272,6 +274,23 @@ function computeSetupPrerequisitesStatus(options = {}) {
|
|
|
272
274
|
? 'Install Git for Windows and enable the option that adds Git to PATH, then restart Specrails.'
|
|
273
275
|
: 'Install Git and restart Specrails if PATH changed.',
|
|
274
276
|
},
|
|
277
|
+
{
|
|
278
|
+
key: 'gh',
|
|
279
|
+
kind: 'tool',
|
|
280
|
+
label: 'GitHub CLI',
|
|
281
|
+
command: 'gh',
|
|
282
|
+
// Optional: the app degrades gracefully without gh (the PR-delivery flow
|
|
283
|
+
// reports local-only/pushed instead of creating the PR) — never blocks
|
|
284
|
+
// Add Project. Desktop builds bundle a fallback gh; the system one wins
|
|
285
|
+
// when installed (it carries the user's auth/hosts config).
|
|
286
|
+
required: false,
|
|
287
|
+
installUrl: 'https://cli.github.com',
|
|
288
|
+
installHint: process.platform === 'win32'
|
|
289
|
+
? 'Install GitHub CLI via winget (`winget install GitHub.cli`), run `gh auth login`, then restart Specrails.'
|
|
290
|
+
: process.platform === 'darwin'
|
|
291
|
+
? 'Install GitHub CLI via Homebrew (`brew install gh`), run `gh auth login`, then restart Specrails.'
|
|
292
|
+
: 'Install GitHub CLI (https://cli.github.com), run `gh auth login`, then restart Specrails.',
|
|
293
|
+
},
|
|
275
294
|
];
|
|
276
295
|
// Provider CLIs (one entry per registered adapter). Individually `required:
|
|
277
296
|
// false` — the "at least one provider" rule is enforced at the bottom of
|
|
@@ -305,6 +324,11 @@ function computeSetupPrerequisitesStatus(options = {}) {
|
|
|
305
324
|
});
|
|
306
325
|
}
|
|
307
326
|
const prerequisites = definitions.map((definition) => {
|
|
327
|
+
// gh is SYSTEM-FIRST with a bundled fallback (the inverse of node/git):
|
|
328
|
+
// the user's own gh must win because it carries their auth/hosts config.
|
|
329
|
+
if (definition.key === 'gh') {
|
|
330
|
+
return probeGhPrerequisite(definition, isDesktop, runtimesBase);
|
|
331
|
+
}
|
|
308
332
|
// Desktop mode: probe bundled absolute paths for node/npm/npx/git.
|
|
309
333
|
// Provider CLIs (claude, codex) are always probed via system PATH regardless of mode.
|
|
310
334
|
if (isDesktop && definition.kind === 'tool' && isBundledTool(definition.key)) {
|
|
@@ -402,6 +426,87 @@ function computeSetupPrerequisitesStatus(options = {}) {
|
|
|
402
426
|
missingRequired,
|
|
403
427
|
};
|
|
404
428
|
}
|
|
429
|
+
/** Offline auth check: `gh auth token` exits 0 iff a credential exists for the
|
|
430
|
+
* default host. No network (unlike `gh auth status`, which validates the token
|
|
431
|
+
* against the API and would misreport "not signed in" offline). The token
|
|
432
|
+
* value is intentionally never read. */
|
|
433
|
+
function probeGhAuthenticated(ghBin) {
|
|
434
|
+
const result = runVersionSpawn(ghBin, ['auth', 'token'], VERSION_PROBE_TIMEOUT_MS);
|
|
435
|
+
return !result.error && (result.status ?? 1) === 0;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* gh probe order — the INVERSE of node/git:
|
|
439
|
+
* 1. System PATH (`which gh`) — the user's install always wins (their
|
|
440
|
+
* auth/hosts config, GHES setups, aliases live there).
|
|
441
|
+
* 2. Desktop bundled fallback (`runtimes/gh/bin/gh[.exe]`) — only when no
|
|
442
|
+
* system gh resolves. File exists but fails its probe → corrupted-bundle
|
|
443
|
+
* (same semantics as node/git).
|
|
444
|
+
* Either way, an executable gh also reports `authenticated` (bundling removes
|
|
445
|
+
* the INSTALL step, not the `gh auth login` step — the config at ~/.config/gh
|
|
446
|
+
* is shared by any gh binary, so a system login carries over to the bundled
|
|
447
|
+
* one automatically).
|
|
448
|
+
*/
|
|
449
|
+
function probeGhPrerequisite(definition, isDesktop, runtimesBase) {
|
|
450
|
+
// 1. System probe.
|
|
451
|
+
const lookup = locateCommand(definition.command);
|
|
452
|
+
if (lookup.found) {
|
|
453
|
+
const probe = probeVersion(definition.command, lookup.resolvedPath);
|
|
454
|
+
const executable = probe.executed;
|
|
455
|
+
return {
|
|
456
|
+
...definition,
|
|
457
|
+
installed: true,
|
|
458
|
+
executable,
|
|
459
|
+
version: probe.version,
|
|
460
|
+
resolvedPath: lookup.resolvedPath,
|
|
461
|
+
executionError: probe.error,
|
|
462
|
+
meetsMinimum: executable && meetsMinimumVersion(probe.version, definition.minVersion),
|
|
463
|
+
installHint: executable
|
|
464
|
+
? definition.installHint
|
|
465
|
+
: brokenSymlinkHint(definition.label, definition.command, lookup.resolvedPath),
|
|
466
|
+
...(executable && lookup.resolvedPath
|
|
467
|
+
? { authenticated: probeGhAuthenticated(lookup.resolvedPath) }
|
|
468
|
+
: {}),
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
// 2. Bundled fallback (desktop mode only, existence-gated).
|
|
472
|
+
if (isDesktop && runtimesBase) {
|
|
473
|
+
const bundledPath = getBundledToolCandidates(runtimesBase, 'gh').find(fileExists);
|
|
474
|
+
if (bundledPath) {
|
|
475
|
+
const probe = probeVersion('gh', bundledPath);
|
|
476
|
+
if (!probe.executed) {
|
|
477
|
+
return {
|
|
478
|
+
...definition,
|
|
479
|
+
installed: true,
|
|
480
|
+
executable: false,
|
|
481
|
+
bundled: true,
|
|
482
|
+
error: 'corrupted-bundle',
|
|
483
|
+
resolvedPath: bundledPath,
|
|
484
|
+
executionError: probe.error,
|
|
485
|
+
meetsMinimum: false,
|
|
486
|
+
installHint: 'Bundle corrupted — reinstall the Specrails app.',
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
return {
|
|
490
|
+
...definition,
|
|
491
|
+
installed: true,
|
|
492
|
+
executable: true,
|
|
493
|
+
bundled: true,
|
|
494
|
+
version: probe.version,
|
|
495
|
+
resolvedPath: bundledPath,
|
|
496
|
+
meetsMinimum: meetsMinimumVersion(probe.version, definition.minVersion),
|
|
497
|
+
installHint: '',
|
|
498
|
+
authenticated: probeGhAuthenticated(bundledPath),
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
// Neither system nor bundled gh present.
|
|
503
|
+
return {
|
|
504
|
+
...definition,
|
|
505
|
+
installed: false,
|
|
506
|
+
executable: false,
|
|
507
|
+
meetsMinimum: false,
|
|
508
|
+
};
|
|
509
|
+
}
|
|
405
510
|
// ─── Provider install hints ────────────────────────────────────────────────
|
|
406
511
|
function providerInstallUrl(id) {
|
|
407
512
|
switch (id) {
|
|
@@ -353,7 +353,9 @@ function applySmashUndo(filePath, epicId, smashedAt, nowIso) {
|
|
|
353
353
|
// Restore the pre-SMASH status from metadata if available.
|
|
354
354
|
// B61: 'done' was missing from this whitelist, so undoing a SMASH on a ticket
|
|
355
355
|
// that was 'done' before silently demoted it to 'todo'. Include every valid
|
|
356
|
-
// non-epic status.
|
|
356
|
+
// non-epic status. 'on_review' is DELIBERATELY excluded: it is a transient
|
|
357
|
+
// rail-settle state owned by the PR-decision flow — an undo cannot resurrect
|
|
358
|
+
// the delivery it belonged to, so it falls back to 'todo' (pinned by test).
|
|
357
359
|
const md = (target.metadata ?? {});
|
|
358
360
|
if (md.pre_smash_status === 'todo' || md.pre_smash_status === 'in_progress'
|
|
359
361
|
|| md.pre_smash_status === 'cancelled' || md.pre_smash_status === 'draft'
|
|
@@ -19,7 +19,7 @@ exports.isValidPriority = isValidPriority;
|
|
|
19
19
|
exports.validatePriorityForStatus = validatePriorityForStatus;
|
|
20
20
|
const fs_1 = __importDefault(require("fs"));
|
|
21
21
|
const path_1 = __importDefault(require("path"));
|
|
22
|
-
const VALID_STATUSES = new Set(['draft', 'todo', 'in_progress', 'done', 'cancelled']);
|
|
22
|
+
const VALID_STATUSES = new Set(['draft', 'todo', 'in_progress', 'on_review', 'done', 'cancelled']);
|
|
23
23
|
const VALID_PRIORITIES = new Set(['critical', 'high', 'medium', 'low']);
|
|
24
24
|
exports.CURRENT_SCHEMA_VERSION = '1.3';
|
|
25
25
|
exports.SHORT_SUMMARY_MAX_LEN = 240;
|
|
@@ -327,12 +327,16 @@ function writeStore(filePath, store) {
|
|
|
327
327
|
*
|
|
328
328
|
* - `completed`: promote `todo`/`in_progress` â `done` (never resurrect a `draft`
|
|
329
329
|
* or a `cancelled` spec into Done); clear any stale `needs_review` flag.
|
|
330
|
+
* When `opts.completedStatus` is `'on_review'` (the ask-first PR-delivery
|
|
331
|
+
* path), the same promotable set moves to `on_review` instead of `done` —
|
|
332
|
+
* the spec only reaches Done once the delivered PR merges. The default
|
|
333
|
+
* `'done'` is byte-identical to the legacy behaviour.
|
|
330
334
|
* - `failed`/`canceled`/`zombie_terminated`: revert an `in_progress` spec â `todo`
|
|
331
335
|
* (back to the Specs column). If the agent had already marked it `done` (its
|
|
332
336
|
* Ship phase ran, then the process died), keep it `done` but set `needs_review`
|
|
333
337
|
* so the board flags it for review.
|
|
334
338
|
*/
|
|
335
|
-
function applyJobOutcomeToTickets(store, ticketIds, outcome, now) {
|
|
339
|
+
function applyJobOutcomeToTickets(store, ticketIds, outcome, now, opts) {
|
|
336
340
|
const changed = [];
|
|
337
341
|
for (const tid of ticketIds) {
|
|
338
342
|
const ticket = store.tickets[String(tid)];
|
|
@@ -344,7 +348,7 @@ function applyJobOutcomeToTickets(store, ticketIds, outcome, now) {
|
|
|
344
348
|
if (!promotable && !clearWarning)
|
|
345
349
|
continue;
|
|
346
350
|
if (promotable)
|
|
347
|
-
ticket.status = 'done';
|
|
351
|
+
ticket.status = opts?.completedStatus ?? 'done';
|
|
348
352
|
if (clearWarning)
|
|
349
353
|
delete ticket.needs_review;
|
|
350
354
|
ticket.updated_at = now;
|
|
@@ -36,6 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
37
|
exports.isWorkspacePopulated = isWorkspacePopulated;
|
|
38
38
|
exports.resolveProjectExecution = resolveProjectExecution;
|
|
39
|
+
exports.resolveLoopBaseEnv = resolveLoopBaseEnv;
|
|
39
40
|
const fs_1 = __importDefault(require("fs"));
|
|
40
41
|
const path_1 = __importDefault(require("path"));
|
|
41
42
|
const artifact_registry_1 = require("./artifact-registry");
|
|
@@ -127,6 +128,32 @@ function resolveProjectExecution(project, home) {
|
|
|
127
128
|
env,
|
|
128
129
|
};
|
|
129
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Base spawn env for a project's LOOP executors (rails / custom loops).
|
|
133
|
+
*
|
|
134
|
+
* Relocated projects need core's env-first artifact indirection
|
|
135
|
+
* (`SPECRAILS_TICKETS_PATH` / `SPECRAILS_BACKLOG_CONFIG_PATH` /
|
|
136
|
+
* `SPECRAILS_PROFILES_DIR` / `SPECRAILS_STATE_DIR` / `SPECRAILS_WORKSPACE_DIR`
|
|
137
|
+
* → the workspace) even when the spawn cwd is NOT the workspace: an ISOLATED
|
|
138
|
+
* rail spawns from its git WORKTREE, where the cwd-relative `${ENV:-legacy}`
|
|
139
|
+
* defaults would resolve to nothing (`git worktree add` materializes only
|
|
140
|
+
* tracked files). In particular `SPECRAILS_BACKLOG_CONFIG_PATH` MUST reach core
|
|
141
|
+
* so it never falls through to its default `write_access:true` branch.
|
|
142
|
+
*
|
|
143
|
+
* `SPECRAILS_REPO_DIR` is intentionally OMITTED: it is PER-RUN (the worktree
|
|
144
|
+
* for isolated runs — writes/git must land there — vs the repo for shared
|
|
145
|
+
* runs) and is injected by the executors from each run's `repoDir`. Leaving it
|
|
146
|
+
* here would leak the LIVE repo path into isolated shell steps.
|
|
147
|
+
*
|
|
148
|
+
* Legacy projects return `process.env` untouched — byte-identical behaviour.
|
|
149
|
+
*/
|
|
150
|
+
function resolveLoopBaseEnv(project, home) {
|
|
151
|
+
const exec = resolveProjectExecution(project, home);
|
|
152
|
+
if (!exec.relocated)
|
|
153
|
+
return process.env;
|
|
154
|
+
const { SPECRAILS_REPO_DIR: _perRun, ...projectEnv } = exec.env;
|
|
155
|
+
return { ...process.env, ...projectEnv };
|
|
156
|
+
}
|
|
130
157
|
/** Build the legacy (in-repo, byte-identical-to-today) execution. */
|
|
131
158
|
function legacyExecution(repoDir) {
|
|
132
159
|
const specrailsDir = path_1.default.join(repoDir, '.specrails');
|
|
@@ -41,12 +41,15 @@ exports.worktreePath = worktreePath;
|
|
|
41
41
|
exports.createWorktree = createWorktree;
|
|
42
42
|
exports.commitWorktree = commitWorktree;
|
|
43
43
|
exports.removeWorktree = removeWorktree;
|
|
44
|
+
exports.listLocalBranches = listLocalBranches;
|
|
44
45
|
exports.listWorktrees = listWorktrees;
|
|
45
46
|
/**
|
|
46
47
|
* Git worktree lifecycle for parallel-rail isolation. Each isolated ticket run
|
|
47
|
-
* gets its own worktree on branch
|
|
48
|
+
* gets its own worktree on its own branch off the integration base, so
|
|
48
49
|
* concurrent AI CLIs never collide on a shared working tree; the merge-manager
|
|
49
|
-
* later integrates the branches back.
|
|
50
|
+
* later integrates the branches back. The caller passes the conventional
|
|
51
|
+
* branch name (`<type>/<ref>-<kebab-title>`, see pr-naming.ts); when absent
|
|
52
|
+
* the legacy `sr/<slug>/ticket-<id>` fallback is used.
|
|
50
53
|
*
|
|
51
54
|
* All git I/O goes through an injectable `GitRunner` so the logic is unit-tested
|
|
52
55
|
* without a real repository. Worktrees live under `$HOME` (never in the repo) and
|
|
@@ -86,7 +89,8 @@ async function repoIsolationStatus(git, dir) {
|
|
|
86
89
|
const head = await git.run(['rev-parse', '--verify', '--quiet', 'HEAD'], dir);
|
|
87
90
|
return head.code === 0 ? 'ok' : 'no-commits';
|
|
88
91
|
}
|
|
89
|
-
/**
|
|
92
|
+
/** Legacy fallback branch name for a ticket's isolated run (used only when the
|
|
93
|
+
* caller does not pass a conventional preferred name — see pr-naming.ts). */
|
|
90
94
|
function worktreeBranch(slug, ticketId) {
|
|
91
95
|
return `sr/${slug}/ticket-${ticketId}`;
|
|
92
96
|
}
|
|
@@ -100,7 +104,7 @@ function worktreePath(worktreesRoot, ticketId) {
|
|
|
100
104
|
* fall back to the shared-cwd path for that ticket.
|
|
101
105
|
*/
|
|
102
106
|
async function createWorktree(git, input) {
|
|
103
|
-
const branch = worktreeBranch(input.slug, input.ticketId);
|
|
107
|
+
const branch = input.branch ?? worktreeBranch(input.slug, input.ticketId);
|
|
104
108
|
const wt = worktreePath(input.worktreesRoot, input.ticketId);
|
|
105
109
|
const base = input.baseRef ?? 'HEAD';
|
|
106
110
|
// RESUME-AWARE (idempotency): a re-launched rail must pick up the partial work
|
|
@@ -111,7 +115,16 @@ async function createWorktree(git, input) {
|
|
|
111
115
|
// 3. neither → create a fresh branch off base.
|
|
112
116
|
const existing = await listWorktrees(git, input.repoDir);
|
|
113
117
|
if (existing.some((p) => path.resolve(p) === path.resolve(wt))) {
|
|
114
|
-
|
|
118
|
+
// The still-mounted worktree may be checked out on a DIFFERENT branch than
|
|
119
|
+
// the caller's preferred name (the path is keyed by ticketId only, so a
|
|
120
|
+
// stale mount from a prior run of the same ticket collides here). The
|
|
121
|
+
// handle MUST report the branch that will actually carry the run's commits
|
|
122
|
+
// — reporting the caller's preferred name recorded a branch that never
|
|
123
|
+
// existed, so the later `git push` had no ref and the PR delivery wedged
|
|
124
|
+
// at local-only. Detached HEAD / a git failure falls back to the input.
|
|
125
|
+
const head = await git.run(['rev-parse', '--abbrev-ref', 'HEAD'], wt);
|
|
126
|
+
const actual = head.code === 0 ? head.stdout.trim() : '';
|
|
127
|
+
return { branch: actual && actual !== 'HEAD' ? actual : branch, worktreePath: wt };
|
|
115
128
|
}
|
|
116
129
|
const hasBranch = (await git.run(['rev-parse', '--verify', '--quiet', `refs/heads/${branch}`], input.repoDir)).code === 0;
|
|
117
130
|
const args = hasBranch
|
|
@@ -128,9 +141,19 @@ async function createWorktree(git, input) {
|
|
|
128
141
|
* git — it survives worktree removal, is mergeable by the merge-back, and lets a
|
|
129
142
|
* re-launched rail resume from it. No-op (the commit just exits non-zero) when
|
|
130
143
|
* there is nothing to commit. Best-effort: never throws.
|
|
144
|
+
*
|
|
145
|
+
* `excludePaths` (worktree-relative, POSIX separators) are skipped via
|
|
146
|
+
* `:(exclude)` pathspecs — the per-run overlay (worktree-overlay.ts) threads its
|
|
147
|
+
* app-owned scaffolding (framework symlinks, `.mcp.json` copy, manifest) here so
|
|
148
|
+
* it NEVER lands on the ticket branch / PR. All excluded paths are untracked by
|
|
149
|
+
* construction (the overlay only creates entries the checkout lacked), so
|
|
150
|
+
* excluding them can never drop real work.
|
|
131
151
|
*/
|
|
132
|
-
async function commitWorktree(git, worktreePath, message) {
|
|
133
|
-
|
|
152
|
+
async function commitWorktree(git, worktreePath, message, excludePaths = []) {
|
|
153
|
+
const addArgs = excludePaths.length > 0
|
|
154
|
+
? ['add', '-A', '--', '.', ...excludePaths.map((p) => `:(exclude)${p}`)]
|
|
155
|
+
: ['add', '-A'];
|
|
156
|
+
await git.run(addArgs, worktreePath).catch(() => { });
|
|
134
157
|
await git.run(['commit', '-m', message], worktreePath).catch(() => { });
|
|
135
158
|
}
|
|
136
159
|
/** Remove a worktree (force) and optionally delete its branch. Best-effort — a
|
|
@@ -141,6 +164,18 @@ async function removeWorktree(git, input) {
|
|
|
141
164
|
await git.run(['branch', '-D', input.branch], input.repoDir);
|
|
142
165
|
}
|
|
143
166
|
}
|
|
167
|
+
/** Every local branch name (`git for-each-ref refs/heads/`) — the collision
|
|
168
|
+
* input for conventional branch naming. A git failure returns an empty set
|
|
169
|
+
* (the caller then trusts the preferred names; worktree add still guards). */
|
|
170
|
+
async function listLocalBranches(git, repoDir) {
|
|
171
|
+
const res = await git.run(['for-each-ref', '--format=%(refname:short)', 'refs/heads/'], repoDir);
|
|
172
|
+
if (res.code !== 0)
|
|
173
|
+
return new Set();
|
|
174
|
+
return new Set(res.stdout
|
|
175
|
+
.split('\n')
|
|
176
|
+
.map((s) => s.trim())
|
|
177
|
+
.filter(Boolean));
|
|
178
|
+
}
|
|
144
179
|
/** Parse `git worktree list --porcelain` into the worktree paths it reports
|
|
145
180
|
* (excluding the main working tree, which is `repoDir` itself). */
|
|
146
181
|
async function listWorktrees(git, repoDir) {
|