specrails-desktop 2.20.1 → 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 -2
- package/client/dist/assets/{ActivityFeedPage-3WSqRYVx.js → ActivityFeedPage-roDyKGuv.js} +1 -1
- package/client/dist/assets/AgentBrowserCapture-BsXnWa4j.js +1 -0
- package/client/dist/assets/{AgentModeCodePane-Cnsea6eZ.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-C6If656N.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-CezTK0EX.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-CRtTj4Co.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-BQn4yxaw.js → dist-js-BZSiJDbG.js} +1 -1
- package/client/dist/assets/{dist-js-BAWSqVtr.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-C-g8QbZl.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/{settings-BPq9nCJm.js → settings-BOHOmHkb.js} +1 -1
- package/client/dist/assets/{settings-r8Qq2Gzp2.js → settings-BlEA_7h02.js} +1 -1
- package/client/dist/assets/{settings-C-m3yEZ2.js → settings-BsJMsWGc.js} +1 -1
- package/client/dist/assets/{settings-zZr7NzuB.js → settings-D6qY9_UI.js} +1 -1
- package/client/dist/assets/{settings-VgCsjaYf.js → settings-DZJeXoRV.js} +1 -1
- package/client/dist/assets/settings-Mr7MnJbf.js +1 -0
- package/client/dist/assets/{settings-BWHGtmU12.js → settings-TNga5gIF2.js} +1 -1
- package/client/dist/assets/{settings-DZj7Uqy32.js → settings-lFoaYT-s2.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-D9aLbxw-.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 +14 -14
- 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 +9 -5
- 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 +10 -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 +9 -5
- 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 +9 -5
- 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 +10 -6
- 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 +9 -5
- 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 +9 -5
- 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 +10 -6
- 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 +6 -2
- 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 +102 -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/git-guardrails.js +62 -0
- package/server/dist/index.js +5 -0
- package/server/dist/integration-branch.js +63 -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-effect.js +12 -0
- package/server/dist/loop-executors.js +92 -22
- 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/pr-publisher.js +68 -0
- package/server/dist/project-registry.js +77 -17
- package/server/dist/project-router-jobs.js +53 -13
- package/server/dist/project-router-settings.js +33 -0
- 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 +268 -83
- package/server/dist/rail-isolated-launch.js +324 -34
- package/server/dist/rail-isolation.js +32 -5
- package/server/dist/rail-pr-decision.js +519 -0
- package/server/dist/rail-pr-delivery.js +75 -0
- package/server/dist/rail-pr-store.js +175 -0
- package/server/dist/rail-worktrees-store.js +18 -0
- package/server/dist/rails-router.js +241 -17
- 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-BlGDZahz.js +0 -1
- package/client/dist/assets/AgentModeJobsPane-CyNR-9BO.js +0 -1
- package/client/dist/assets/AgentsPage-dNsEsY_x.js +0 -86
- package/client/dist/assets/AnalyticsPage-BAxmR0HQ.js +0 -1
- package/client/dist/assets/CodePage-Crc4BBQN.js +0 -2
- package/client/dist/assets/DesktopAnalyticsPage-IXSnbCce.js +0 -1
- package/client/dist/assets/DocsDialog-Bc4hx7oW.js +0 -11
- package/client/dist/assets/DocsPage-bEU4t9c6.js +0 -11
- package/client/dist/assets/IntegrationsPage-wq2CezEL.js +0 -3
- package/client/dist/assets/JobDetailPage-BBcPk3j8.js +0 -1
- package/client/dist/assets/JobsPage-DXrSPlwa.js +0 -1
- package/client/dist/assets/LogViewer-BoYbwvbU.js +0 -16
- package/client/dist/assets/LoopBuilderPage-CiUMAuWz.js +0 -7
- package/client/dist/assets/LoopsPage-Xrp6W5XW.js +0 -1
- package/client/dist/assets/ProjectSettingsDialog-BU98L5JD.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-B8032psZ.js +0 -1
- package/client/dist/assets/dashboard-BHGKtxty2.js +0 -1
- package/client/dist/assets/dashboard-CXnoUgN22.js +0 -1
- package/client/dist/assets/dashboard-Ccyxqy7d.js +0 -1
- package/client/dist/assets/dashboard-CoED_41r.js +0 -1
- package/client/dist/assets/dashboard-Dc5ZAgMN.js +0 -1
- package/client/dist/assets/dashboard-JMY8ueD3.js +0 -1
- package/client/dist/assets/dashboard-tkWr1aHD2.js +0 -1
- package/client/dist/assets/index-BHPbzyg6.css +0 -2
- package/client/dist/assets/index-n2PmJGF6.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/settings-CY8udi0e.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/{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,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isTestFilePath = isTestFilePath;
|
|
4
|
+
exports.collectBranchChanges = collectBranchChanges;
|
|
5
|
+
exports.parseShortstat = parseShortstat;
|
|
6
|
+
exports.parseNameStatus = parseNameStatus;
|
|
7
|
+
exports.buildCanonicalPrBody = buildCanonicalPrBody;
|
|
8
|
+
exports.extractSpecNarrative = extractSpecNarrative;
|
|
9
|
+
const explore_contract_refine_1 = require("./explore-contract-refine");
|
|
10
|
+
const pr_naming_1 = require("./pr-naming");
|
|
11
|
+
const TEST_FILE_RE = /(\.test\.[jt]sx?|\.spec\.[jt]sx?)$/;
|
|
12
|
+
const PROBLEM_MAX = 600;
|
|
13
|
+
const SOLUTION_MAX = 900;
|
|
14
|
+
const OVERFLOW_MAX = 3000;
|
|
15
|
+
const MAX_TEST_FILES_LISTED = 20;
|
|
16
|
+
function isTestFilePath(p) {
|
|
17
|
+
return TEST_FILE_RE.test(p) || p.includes('__tests__/');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Per-branch diffstat + touched test files via `git diff` against the base
|
|
21
|
+
* (three-dot: what the branch adds over the merge-base). Failures are recorded
|
|
22
|
+
* per branch (`failed: true`) — never thrown.
|
|
23
|
+
*/
|
|
24
|
+
async function collectBranchChanges(git, repoDir, baseBranch, branches) {
|
|
25
|
+
const out = new Map();
|
|
26
|
+
for (const branch of [...new Set(branches)]) {
|
|
27
|
+
const entry = { branch, filesChanged: 0, insertions: 0, deletions: 0, testFiles: [], failed: false };
|
|
28
|
+
try {
|
|
29
|
+
const stat = await git.run(['diff', '--shortstat', `${baseBranch}...${branch}`], repoDir);
|
|
30
|
+
const names = await git.run(['diff', '--name-status', `${baseBranch}...${branch}`], repoDir);
|
|
31
|
+
if (stat.code !== 0 || names.code !== 0) {
|
|
32
|
+
entry.failed = true;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
const parsed = parseShortstat(stat.stdout);
|
|
36
|
+
entry.filesChanged = parsed.filesChanged;
|
|
37
|
+
entry.insertions = parsed.insertions;
|
|
38
|
+
entry.deletions = parsed.deletions;
|
|
39
|
+
entry.testFiles = parseNameStatus(names.stdout).filter(isTestFilePath);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
entry.failed = true;
|
|
44
|
+
}
|
|
45
|
+
out.set(branch, entry);
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
/** Parse `N files changed, X insertions(+), Y deletions(-)` (any part may be absent). */
|
|
50
|
+
function parseShortstat(stdout) {
|
|
51
|
+
const files = /(\d+) files? changed/.exec(stdout);
|
|
52
|
+
const ins = /(\d+) insertions?\(\+\)/.exec(stdout);
|
|
53
|
+
const del = /(\d+) deletions?\(-\)/.exec(stdout);
|
|
54
|
+
return {
|
|
55
|
+
filesChanged: files ? parseInt(files[1], 10) : 0,
|
|
56
|
+
insertions: ins ? parseInt(ins[1], 10) : 0,
|
|
57
|
+
deletions: del ? parseInt(del[1], 10) : 0,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Parse `git diff --name-status` output into touched paths (rename → new path). */
|
|
61
|
+
function parseNameStatus(stdout) {
|
|
62
|
+
const paths = [];
|
|
63
|
+
for (const line of stdout.split('\n')) {
|
|
64
|
+
const trimmed = line.trim();
|
|
65
|
+
if (!trimmed)
|
|
66
|
+
continue;
|
|
67
|
+
const parts = trimmed.split('\t');
|
|
68
|
+
if (parts.length < 2)
|
|
69
|
+
continue;
|
|
70
|
+
paths.push(parts[parts.length - 1]);
|
|
71
|
+
}
|
|
72
|
+
return paths;
|
|
73
|
+
}
|
|
74
|
+
function buildCanonicalPrBody(input) {
|
|
75
|
+
const parts = [summaryParagraph(input)];
|
|
76
|
+
for (const t of input.tickets) {
|
|
77
|
+
parts.push(ticketSection(t, input.changes ?? null));
|
|
78
|
+
}
|
|
79
|
+
const changesSection = buildChangesSection(input.changes ?? null);
|
|
80
|
+
if (changesSection)
|
|
81
|
+
parts.push(changesSection);
|
|
82
|
+
return parts.join('\n\n');
|
|
83
|
+
}
|
|
84
|
+
function summaryParagraph(input) {
|
|
85
|
+
const n = input.tickets.length;
|
|
86
|
+
const refs = input.tickets.map((t) => displayRef(t)).join(', ');
|
|
87
|
+
const noun = n === 1 ? 'ticket' : 'tickets';
|
|
88
|
+
return (`This pull request delivers ${n} ${noun} (${refs}) implemented by the ` +
|
|
89
|
+
`**${input.loopName}** run against \`${input.baseBranch}\`. Each ticket below ` +
|
|
90
|
+
`describes the problem it addresses, the approach taken, and the test files ` +
|
|
91
|
+
`touched by its diff.`);
|
|
92
|
+
}
|
|
93
|
+
/** Body-facing ref: Jira key verbatim when linked, `#<id>` for local tickets. */
|
|
94
|
+
function displayRef(t) {
|
|
95
|
+
return t.jiraKey?.trim() ? (0, pr_naming_1.ticketRef)(t) : `#${t.ticketId}`;
|
|
96
|
+
}
|
|
97
|
+
function ticketSection(t, changes) {
|
|
98
|
+
const title = cleanInline(t.title);
|
|
99
|
+
const heading = title ? `## ${displayRef(t)} — ${title}` : `## ${displayRef(t)}`;
|
|
100
|
+
const chunks = [heading];
|
|
101
|
+
const narrative = extractSpecNarrative(t.description);
|
|
102
|
+
if (narrative.problem) {
|
|
103
|
+
chunks.push('**Problem**', clampText(narrative.problem, PROBLEM_MAX));
|
|
104
|
+
}
|
|
105
|
+
if (narrative.solution) {
|
|
106
|
+
chunks.push('**Solution**', clampText(narrative.solution, SOLUTION_MAX));
|
|
107
|
+
if (narrative.overflow) {
|
|
108
|
+
chunks.push(`<details>\n<summary>Full spec digest</summary>\n\n${clampText(narrative.overflow, OVERFLOW_MAX)}\n\n</details>`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
chunks.push('**Tests**', testsLine(t, changes));
|
|
112
|
+
return chunks.join('\n\n');
|
|
113
|
+
}
|
|
114
|
+
function testsLine(t, changes) {
|
|
115
|
+
const entry = t.branch ? changes?.get(t.branch) : undefined;
|
|
116
|
+
if (!entry || entry.failed) {
|
|
117
|
+
return '_Diff unavailable — test changes could not be derived._';
|
|
118
|
+
}
|
|
119
|
+
if (entry.testFiles.length === 0) {
|
|
120
|
+
return 'No test files changed in this diff.';
|
|
121
|
+
}
|
|
122
|
+
const listed = entry.testFiles.slice(0, MAX_TEST_FILES_LISTED);
|
|
123
|
+
const lines = listed.map((f) => `- \`${f}\``);
|
|
124
|
+
const more = entry.testFiles.length - listed.length;
|
|
125
|
+
if (more > 0)
|
|
126
|
+
lines.push(`- … and ${more} more`);
|
|
127
|
+
return lines.join('\n');
|
|
128
|
+
}
|
|
129
|
+
function buildChangesSection(changes) {
|
|
130
|
+
if (!changes)
|
|
131
|
+
return null;
|
|
132
|
+
const ok = [...changes.values()].filter((c) => !c.failed);
|
|
133
|
+
if (ok.length === 0)
|
|
134
|
+
return null;
|
|
135
|
+
const lines = ok.map((c) => {
|
|
136
|
+
const stat = c.filesChanged > 0
|
|
137
|
+
? `${c.filesChanged} file${c.filesChanged === 1 ? '' : 's'} changed, +${c.insertions} −${c.deletions}`
|
|
138
|
+
: 'no file changes detected';
|
|
139
|
+
return `- \`${c.branch}\` — ${stat}`;
|
|
140
|
+
});
|
|
141
|
+
return ['## Changes', lines.join('\n')].join('\n\n');
|
|
142
|
+
}
|
|
143
|
+
const PROBLEM_HEADING_RE = /\b(problem|context|background|motivation|why)\b/i;
|
|
144
|
+
const SOLUTION_HEADING_RE = /\b(solution|approach|design|implementation|proposal|how|what)\b/i;
|
|
145
|
+
/**
|
|
146
|
+
* Split a spec description into Problem/Solution digests:
|
|
147
|
+
* - a heading matching problem/context/background wins the Problem slot,
|
|
148
|
+
* else the leading narrative before the first heading;
|
|
149
|
+
* - headings matching solution/approach/design/implementation feed the
|
|
150
|
+
* Solution slot, else everything that is not the Problem;
|
|
151
|
+
* - the Contract Layer appendix (app machinery) is stripped first.
|
|
152
|
+
* Tolerates missing/empty descriptions (both slots null → headings omitted).
|
|
153
|
+
*/
|
|
154
|
+
function extractSpecNarrative(description) {
|
|
155
|
+
if (typeof description !== 'string' || !description.trim()) {
|
|
156
|
+
return { problem: null, solution: null, overflow: null };
|
|
157
|
+
}
|
|
158
|
+
const { user } = (0, explore_contract_refine_1.splitDescriptionAtContractLayer)(description);
|
|
159
|
+
const text = user.replace(/\r\n/g, '\n').trim();
|
|
160
|
+
if (!text)
|
|
161
|
+
return { problem: null, solution: null, overflow: null };
|
|
162
|
+
const sections = splitSections(text);
|
|
163
|
+
const preamble = sections.find((s) => s.title === null)?.content?.trim() ?? '';
|
|
164
|
+
const headed = sections.filter((s) => s.title !== null);
|
|
165
|
+
let problem = null;
|
|
166
|
+
const problemSection = headed.find((s) => PROBLEM_HEADING_RE.test(s.title));
|
|
167
|
+
if (problemSection?.content.trim()) {
|
|
168
|
+
problem = problemSection.content.trim();
|
|
169
|
+
}
|
|
170
|
+
else if (preamble) {
|
|
171
|
+
problem = preamble;
|
|
172
|
+
}
|
|
173
|
+
const solutionParts = [];
|
|
174
|
+
const solutionSections = headed.filter((s) => s !== problemSection && SOLUTION_HEADING_RE.test(s.title));
|
|
175
|
+
if (solutionSections.length > 0) {
|
|
176
|
+
for (const s of solutionSections) {
|
|
177
|
+
if (s.content.trim())
|
|
178
|
+
solutionParts.push(`**${s.title.trim()}** — ${s.content.trim()}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// No explicit solution headings: use the remaining content (everything
|
|
183
|
+
// after what we used as the problem).
|
|
184
|
+
const rest = headed.filter((s) => s !== problemSection && s.content.trim());
|
|
185
|
+
if (rest.length > 0) {
|
|
186
|
+
for (const s of rest)
|
|
187
|
+
solutionParts.push(`**${s.title.trim()}** — ${s.content.trim()}`);
|
|
188
|
+
}
|
|
189
|
+
else if (!problemSection && preamble && problem === preamble) {
|
|
190
|
+
// Heading-less description: first paragraph = problem, remainder = solution.
|
|
191
|
+
const paras = preamble.split(/\n{2,}/);
|
|
192
|
+
if (paras.length > 1) {
|
|
193
|
+
problem = paras[0].trim();
|
|
194
|
+
solutionParts.push(paras.slice(1).join('\n\n').trim());
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const solutionFull = solutionParts.join('\n\n').trim() || null;
|
|
199
|
+
if (!solutionFull)
|
|
200
|
+
return { problem, solution: null, overflow: null };
|
|
201
|
+
if (solutionFull.length <= SOLUTION_MAX)
|
|
202
|
+
return { problem, solution: solutionFull, overflow: null };
|
|
203
|
+
return {
|
|
204
|
+
problem,
|
|
205
|
+
solution: clampText(solutionFull, SOLUTION_MAX),
|
|
206
|
+
overflow: solutionFull,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/** Split markdown into sections at `#`-headings and standalone `**Bold**` label lines. */
|
|
210
|
+
function splitSections(text) {
|
|
211
|
+
const lines = text.split('\n');
|
|
212
|
+
const sections = [];
|
|
213
|
+
let current = { title: null, content: '' };
|
|
214
|
+
for (const line of lines) {
|
|
215
|
+
const heading = /^#{1,6}\s+(.+?)\s*$/.exec(line) ?? /^\*\*([^*]+)\*\*:?\s*$/.exec(line);
|
|
216
|
+
if (heading) {
|
|
217
|
+
sections.push(current);
|
|
218
|
+
current = { title: heading[1], content: '' };
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
current.content += (current.content ? '\n' : '') + line;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
sections.push(current);
|
|
225
|
+
return sections;
|
|
226
|
+
}
|
|
227
|
+
function cleanInline(raw) {
|
|
228
|
+
if (typeof raw !== 'string')
|
|
229
|
+
return '';
|
|
230
|
+
// eslint-disable-next-line no-control-regex
|
|
231
|
+
return raw.replace(/[\x00-\x1F\x7F]/g, ' ').replace(/\s+/g, ' ').trim();
|
|
232
|
+
}
|
|
233
|
+
function clampText(s, max) {
|
|
234
|
+
const trimmed = s.trim();
|
|
235
|
+
if (trimmed.length <= max)
|
|
236
|
+
return trimmed;
|
|
237
|
+
const cut = trimmed.slice(0, max);
|
|
238
|
+
const lastSpace = cut.lastIndexOf(' ');
|
|
239
|
+
return `${cut.slice(0, lastSpace > max / 2 ? lastSpace : max).trimEnd()} …`;
|
|
240
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.classifyChangeType = classifyChangeType;
|
|
4
|
+
exports.batchChangeType = batchChangeType;
|
|
5
|
+
exports.ticketRef = ticketRef;
|
|
6
|
+
exports.kebabTitle = kebabTitle;
|
|
7
|
+
exports.ticketBranchName = ticketBranchName;
|
|
8
|
+
exports.batchBranchNameFor = batchBranchNameFor;
|
|
9
|
+
exports.resolveCollisionFreeName = resolveCollisionFreeName;
|
|
10
|
+
exports.titleChangeSummary = titleChangeSummary;
|
|
11
|
+
exports.buildPrTitle = buildPrTitle;
|
|
12
|
+
/**
|
|
13
|
+
* Conventional naming for the safe-pr-review-flow's user-facing git surface:
|
|
14
|
+
* branch names and PR titles. Pure string logic (no git/db IO) so the whole
|
|
15
|
+
* matrix is unit-testable; callers thread ticket data (title/labels/jira key)
|
|
16
|
+
* in and run the collision predicate against their own branch listing.
|
|
17
|
+
*
|
|
18
|
+
* Branch conventions:
|
|
19
|
+
* per-unit → `<type>/<ref>-<kebab-title>` e.g. feat/SKILLS-101-add-dark-mode
|
|
20
|
+
* batch → `<type>/<primary-ref>-batch-<n>-tickets`
|
|
21
|
+
*
|
|
22
|
+
* PR title conventions:
|
|
23
|
+
* single → `[<ref>]<type> - <change>` e.g. [SKILLS-101]feat - darkmode added
|
|
24
|
+
* batch → `[<ref> +<n-1>]<type> - <loop-level summary>`
|
|
25
|
+
*
|
|
26
|
+
* `<ref>` is the ticket's Jira key when Jira-linked (JIRA ALWAYS PREVAILS —
|
|
27
|
+
* resolved by the caller from the authoritative `jira_links` row first, the
|
|
28
|
+
* ticket's `jira_key` field second), else the local ticket number.
|
|
29
|
+
*
|
|
30
|
+
* `<type>` heuristic (labels checked before the title; first match wins):
|
|
31
|
+
* bug | bugfix | fix | hotfix → fix
|
|
32
|
+
* chore | refactor | cleanup | clean-up → chore
|
|
33
|
+
* docs | doc | documentation → docs
|
|
34
|
+
* anything else → feat
|
|
35
|
+
*/
|
|
36
|
+
const integration_branch_1 = require("./integration-branch");
|
|
37
|
+
const TYPE_PATTERNS = [
|
|
38
|
+
{ type: 'fix', re: /(^|[^a-z0-9])(bug|bugfix|fix|fixes|fixed|hotfix)([^a-z0-9]|$)/i },
|
|
39
|
+
{ type: 'chore', re: /(^|[^a-z0-9])(chore|refactor|refactoring|cleanup|clean-up|maintenance)([^a-z0-9]|$)/i },
|
|
40
|
+
{ type: 'docs', re: /(^|[^a-z0-9])(docs|doc|documentation)([^a-z0-9]|$)/i },
|
|
41
|
+
];
|
|
42
|
+
/** The documented `<type>` heuristic: labels take precedence over the title. */
|
|
43
|
+
function classifyChangeType(t) {
|
|
44
|
+
const labels = (t.labels ?? []).filter((l) => typeof l === 'string');
|
|
45
|
+
for (const { type, re } of TYPE_PATTERNS) {
|
|
46
|
+
if (labels.some((l) => re.test(l)))
|
|
47
|
+
return type;
|
|
48
|
+
}
|
|
49
|
+
const title = typeof t.title === 'string' ? t.title : '';
|
|
50
|
+
for (const { type, re } of TYPE_PATTERNS) {
|
|
51
|
+
if (re.test(title))
|
|
52
|
+
return type;
|
|
53
|
+
}
|
|
54
|
+
return 'feat';
|
|
55
|
+
}
|
|
56
|
+
/** Batch type: `feat` unless EVERY ticket maps to the same other type. */
|
|
57
|
+
function batchChangeType(tickets) {
|
|
58
|
+
if (tickets.length === 0)
|
|
59
|
+
return 'feat';
|
|
60
|
+
const types = new Set(tickets.map(classifyChangeType));
|
|
61
|
+
if (types.size === 1) {
|
|
62
|
+
const only = [...types][0];
|
|
63
|
+
return only;
|
|
64
|
+
}
|
|
65
|
+
return 'feat';
|
|
66
|
+
}
|
|
67
|
+
/** Display ref: the Jira key when linked (Jira always prevails), else the local id. */
|
|
68
|
+
function ticketRef(t) {
|
|
69
|
+
const key = t.jiraKey?.trim();
|
|
70
|
+
return key ? key : String(t.ticketId);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Branch-safe form of the ref. Jira keys (`PROJ-123`) are already ref-safe;
|
|
74
|
+
* anything unusual is folded to the safe subset, and an unusable key falls
|
|
75
|
+
* back to the local ticket number.
|
|
76
|
+
*/
|
|
77
|
+
function refSlug(t) {
|
|
78
|
+
const key = t.jiraKey?.trim();
|
|
79
|
+
if (key) {
|
|
80
|
+
const safe = key
|
|
81
|
+
.replace(/[^A-Za-z0-9._-]+/g, '-')
|
|
82
|
+
.replace(/\.{2,}/g, '.')
|
|
83
|
+
.replace(/^[-.]+|[-.]+$/g, '');
|
|
84
|
+
if (safe && !/\.lock$/i.test(safe))
|
|
85
|
+
return safe;
|
|
86
|
+
}
|
|
87
|
+
return String(t.ticketId);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* ASCII-folded kebab of a ticket title: NFKD fold + strip diacritics, lowercase,
|
|
91
|
+
* everything outside [a-z0-9] collapsed to single dashes, ~40 char cap, never a
|
|
92
|
+
* leading/trailing dash. Emoji/symbol-only titles fold to '' (caller omits).
|
|
93
|
+
*/
|
|
94
|
+
function kebabTitle(raw, maxLen = 40) {
|
|
95
|
+
if (typeof raw !== 'string' || !raw)
|
|
96
|
+
return '';
|
|
97
|
+
const folded = raw
|
|
98
|
+
.replace(/\u00df/g, 'ss') // no NFKD decomposition \u2014 fold explicitly
|
|
99
|
+
.normalize('NFKD')
|
|
100
|
+
.replace(/[\u0300-\u036f]/g, '');
|
|
101
|
+
let kebab = folded
|
|
102
|
+
.toLowerCase()
|
|
103
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
104
|
+
.replace(/^-+|-+$/g, '');
|
|
105
|
+
if (kebab.length > maxLen) {
|
|
106
|
+
kebab = kebab.slice(0, maxLen);
|
|
107
|
+
// Prefer cutting at a word boundary when one exists in the tail.
|
|
108
|
+
const lastDash = kebab.lastIndexOf('-');
|
|
109
|
+
if (lastDash > maxLen / 2)
|
|
110
|
+
kebab = kebab.slice(0, lastDash);
|
|
111
|
+
kebab = kebab.replace(/-+$/g, '');
|
|
112
|
+
}
|
|
113
|
+
return kebab;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Conventional per-unit branch name: `<type>/<ref>-<kebab-title>` (the kebab is
|
|
117
|
+
* omitted when the title folds to nothing). Guaranteed to pass
|
|
118
|
+
* `isValidBranchName` — a pathological input degrades to `<type>/<ticketId>`.
|
|
119
|
+
*/
|
|
120
|
+
function ticketBranchName(t) {
|
|
121
|
+
const type = classifyChangeType(t);
|
|
122
|
+
const ref = refSlug(t);
|
|
123
|
+
const kebab = kebabTitle(t.title);
|
|
124
|
+
const name = kebab ? `${type}/${ref}-${kebab}` : `${type}/${ref}`;
|
|
125
|
+
return (0, integration_branch_1.isValidBranchName)(name) ? name : `${type}/${t.ticketId}`;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Conventional batch branch name (N>1 assembled delivery):
|
|
129
|
+
* `<type>/<primary-ref>-batch-<n>-tickets`.
|
|
130
|
+
*/
|
|
131
|
+
function batchBranchNameFor(tickets) {
|
|
132
|
+
const type = batchChangeType(tickets);
|
|
133
|
+
const primary = tickets[0];
|
|
134
|
+
const ref = primary ? refSlug(primary) : '0';
|
|
135
|
+
const name = `${type}/${ref}-batch-${tickets.length}-tickets`;
|
|
136
|
+
return (0, integration_branch_1.isValidBranchName)(name) ? name : `${type}/batch-${tickets.length}-tickets`;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Bounded collision resolution: the preferred name, else `-2`, `-3`, … up to
|
|
140
|
+
* `maxAttempts`. Reserved names (the integration branch) are NEVER returned.
|
|
141
|
+
* `null` when exhausted — the caller picks its own fallback.
|
|
142
|
+
*/
|
|
143
|
+
function resolveCollisionFreeName(preferred, opts) {
|
|
144
|
+
const reserved = new Set(opts.reserved ?? []);
|
|
145
|
+
const max = Math.max(1, opts.maxAttempts ?? 20);
|
|
146
|
+
for (let i = 1; i <= max; i++) {
|
|
147
|
+
const name = i === 1 ? preferred : `${preferred}-${i}`;
|
|
148
|
+
if (reserved.has(name))
|
|
149
|
+
continue;
|
|
150
|
+
if (!opts.taken(name))
|
|
151
|
+
return name;
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
const TITLE_CHANGE_MAX = 72;
|
|
156
|
+
const TITLE_MAX = 100;
|
|
157
|
+
/**
|
|
158
|
+
* One short sentence derived from the ticket title: control chars stripped,
|
|
159
|
+
* whitespace collapsed, trailing periods dropped, first letter lowercased
|
|
160
|
+
* unless the leading word reads as an acronym / proper CamelCase identifier.
|
|
161
|
+
*/
|
|
162
|
+
function titleChangeSummary(raw) {
|
|
163
|
+
if (typeof raw !== 'string')
|
|
164
|
+
return '';
|
|
165
|
+
// eslint-disable-next-line no-control-regex
|
|
166
|
+
let s = raw.replace(/[\x00-\x1F\x7F]/g, ' ').replace(/\s+/g, ' ').trim();
|
|
167
|
+
s = s.replace(/[.\s]+$/g, '');
|
|
168
|
+
if (!s)
|
|
169
|
+
return '';
|
|
170
|
+
s = decapitalizeFirst(s);
|
|
171
|
+
if (s.length > TITLE_CHANGE_MAX)
|
|
172
|
+
s = `${s.slice(0, TITLE_CHANGE_MAX - 1).trimEnd()}…`;
|
|
173
|
+
return s;
|
|
174
|
+
}
|
|
175
|
+
function decapitalizeFirst(s) {
|
|
176
|
+
const m = /^[A-Za-z][A-Za-z0-9']*/.exec(s);
|
|
177
|
+
if (!m)
|
|
178
|
+
return s;
|
|
179
|
+
const word = m[0];
|
|
180
|
+
// All-caps acronym (MCP, OTEL) or CamelCase identifier (JobDetailPage) → keep.
|
|
181
|
+
if (word.length > 1 && /[A-Z]/.test(word.slice(1)))
|
|
182
|
+
return s;
|
|
183
|
+
return s[0].toLowerCase() + s.slice(1);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Conventional PR title.
|
|
187
|
+
* 1 ticket → `[<ref>]<type> - <change>`
|
|
188
|
+
* N tickets → `[<primary-ref> +<n-1>]<type> - <loop-level summary>`
|
|
189
|
+
* The per-ticket `<type>` uses the SAME heuristic as the branch name, so the
|
|
190
|
+
* two stay consistent for a given ticket.
|
|
191
|
+
*/
|
|
192
|
+
function buildPrTitle(tickets, opts = {}) {
|
|
193
|
+
if (tickets.length === 0) {
|
|
194
|
+
// Defensive — deliveries always carry ≥1 succeeded ticket.
|
|
195
|
+
return truncateTitle(titleChangeSummary(opts.loopName) || 'specrails delivery');
|
|
196
|
+
}
|
|
197
|
+
if (tickets.length === 1) {
|
|
198
|
+
const t = tickets[0];
|
|
199
|
+
const change = titleChangeSummary(t.title) || `implement ${ticketRef(t)}`;
|
|
200
|
+
return truncateTitle(`[${ticketRef(t)}]${classifyChangeType(t)} - ${change}`);
|
|
201
|
+
}
|
|
202
|
+
const primary = tickets[0];
|
|
203
|
+
const type = batchChangeType(tickets);
|
|
204
|
+
const loop = titleChangeSummary(opts.loopName);
|
|
205
|
+
const summary = loop ? `${loop} batch of ${tickets.length} tickets` : `batch of ${tickets.length} tickets`;
|
|
206
|
+
return truncateTitle(`[${ticketRef(primary)} +${tickets.length - 1}]${type} - ${summary}`);
|
|
207
|
+
}
|
|
208
|
+
function truncateTitle(s) {
|
|
209
|
+
return s.length > TITLE_MAX ? `${s.slice(0, TITLE_MAX - 1).trimEnd()}…` : s;
|
|
210
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultExec = void 0;
|
|
4
|
+
exports.parsePrUrl = parsePrUrl;
|
|
5
|
+
exports.publishDraftPr = publishDraftPr;
|
|
6
|
+
/**
|
|
7
|
+
* App-owned "deliver a mutating loop's result as a DRAFT PR" primitive.
|
|
8
|
+
*
|
|
9
|
+
* This is the single sanctioned path for a loop's work to leave the machine:
|
|
10
|
+
* push the (already-committed) ticket/integration branch and open a **draft**
|
|
11
|
+
* pull request against the designated integration branch. specrails never
|
|
12
|
+
* merges and never opens a non-draft PR — the human owns the merge.
|
|
13
|
+
*
|
|
14
|
+
* Degradation ladder (a loop must NEVER fail because a PR could not be opened):
|
|
15
|
+
* pr-created → branch pushed AND `gh pr create --draft` succeeded.
|
|
16
|
+
* pushed → branch pushed but the PR could not be created (no `gh`, not
|
|
17
|
+
* authenticated, insufficient remote perms). The user can open
|
|
18
|
+
* the PR by hand from the pushed branch.
|
|
19
|
+
* local-only → the branch could not be pushed (no remote / no network /
|
|
20
|
+
* auth). The work is still safe as a local branch.
|
|
21
|
+
*
|
|
22
|
+
* Pure over an injectable `Exec` so it is unit-tested without git/gh or a network.
|
|
23
|
+
*/
|
|
24
|
+
const child_process_1 = require("child_process");
|
|
25
|
+
const git_guardrails_1 = require("./git-guardrails");
|
|
26
|
+
exports.defaultExec = {
|
|
27
|
+
run(cmd, args, cwd) {
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
(0, child_process_1.execFile)(cmd, args, { cwd, maxBuffer: 16 * 1024 * 1024 }, (err, stdout, stderr) => {
|
|
30
|
+
const code = err && typeof err.code === 'number' ? err.code : err ? 1 : 0;
|
|
31
|
+
resolve({ code, stdout: stdout?.toString() ?? '', stderr: stderr?.toString() ?? '' });
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
/** Extract the first PR URL gh prints (e.g. https://github.com/o/r/pull/12). */
|
|
37
|
+
function parsePrUrl(stdout) {
|
|
38
|
+
const m = stdout.match(/https?:\/\/\S+\/pull\/\d+/);
|
|
39
|
+
return m ? m[0] : undefined;
|
|
40
|
+
}
|
|
41
|
+
async function publishDraftPr(exec, input) {
|
|
42
|
+
const remote = input.remote ?? 'origin';
|
|
43
|
+
const { repoDir, branch, baseBranch } = input;
|
|
44
|
+
// 1. Push the branch (set upstream). Failure → local-only, never throw.
|
|
45
|
+
// Guardrail: never force-push, never push the integration branch itself.
|
|
46
|
+
const pushArgs = ['push', '-u', remote, branch];
|
|
47
|
+
(0, git_guardrails_1.assertGitAllowed)('git', pushArgs, { protectedBranch: baseBranch });
|
|
48
|
+
const push = await exec.run('git', pushArgs, repoDir);
|
|
49
|
+
if (push.code !== 0) {
|
|
50
|
+
return { state: 'local-only', branch, reason: reasonFrom(push) };
|
|
51
|
+
}
|
|
52
|
+
// 2. Open a DRAFT PR. Failure (no gh / not authed / perms) → pushed, never throw.
|
|
53
|
+
const pr = await exec.run('gh', ['pr', 'create', '--draft', '--base', baseBranch, '--head', branch, '--title', input.title, '--body', input.body], repoDir);
|
|
54
|
+
if (pr.code !== 0) {
|
|
55
|
+
return { state: 'pushed', branch, reason: reasonFrom(pr) };
|
|
56
|
+
}
|
|
57
|
+
const prUrl = parsePrUrl(pr.stdout);
|
|
58
|
+
if (!prUrl) {
|
|
59
|
+
// gh exited 0 but we couldn't find a URL — treat as pushed (the PR likely
|
|
60
|
+
// exists) rather than claiming a URL we don't have.
|
|
61
|
+
return { state: 'pushed', branch, reason: 'pr-created-no-url' };
|
|
62
|
+
}
|
|
63
|
+
return { state: 'pr-created', branch, prUrl };
|
|
64
|
+
}
|
|
65
|
+
function reasonFrom(r) {
|
|
66
|
+
const msg = (r.stderr.trim() || r.stdout.trim()).split('\n')[0];
|
|
67
|
+
return msg || `exit ${r.code}`;
|
|
68
|
+
}
|