specrails-desktop 2.36.0 → 2.42.2
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 +94 -247
- package/client/dist/assets/ActivityFeedPage-DoEMumQS.js +1 -0
- package/client/dist/assets/AgentBrowserCapture-DIh4K0gh.js +1 -0
- package/client/dist/assets/AgentModeAnalyticsPane-mbq4WEoO.js +2 -0
- package/client/dist/assets/AgentModeCodePane-CKh7zuA4.js +2 -0
- package/client/dist/assets/AgentModeJobsPane-BDokPiLJ.js +1 -0
- package/client/dist/assets/AgentsPage-BFVAZbBj.js +87 -0
- package/client/dist/assets/AnalyticsPage-3Y9LuWwz.js +1 -0
- package/client/dist/assets/CodePage-C9KyuV_C.js +3 -0
- package/client/dist/assets/DesktopAnalyticsPage-Bhi54bXQ.js +1 -0
- package/client/dist/assets/{DocsDialog-C76VdBJC.js → DocsDialog-Dj6mt4ga.js} +2 -2
- package/client/dist/assets/{DocsPage-ziMlj6B6.js → DocsPage-24yWglNI.js} +1 -1
- package/client/dist/assets/ExportDropdown-ophapHrT.js +1 -0
- package/client/dist/assets/InteractiveJobComposer-C1ucmxQh.js +19 -0
- package/client/dist/assets/JobDetailModal-DNWmgVHD.js +1 -0
- package/client/dist/assets/JobDetailPage-BcajZyuu.js +1 -0
- package/client/dist/assets/JobsPage-B9nTZw6e.js +1 -0
- package/client/dist/assets/LoopBuilderPage-Oc48iOFW.js +7 -0
- package/client/dist/assets/LoopPreviewModal-ae0Fr6SU.js +1 -0
- package/client/dist/assets/LoopsPage-CUEqzUBI.js +1 -0
- package/client/dist/assets/MinimizedChatsContext-Deg39peL.js +1 -0
- package/client/dist/assets/PluginsPage-C1xtARIx.js +2 -0
- package/client/dist/assets/ProjectSettingsDialog-JZzrXFBN.js +1 -0
- package/client/dist/assets/RepositoryDeliveries-CSDsiVUz.js +5 -0
- package/client/dist/assets/RepositoryScopeSelector-D-RCaknl.js +1 -0
- package/client/dist/assets/ReviewPacketPage-x5EfGTiL.js +1 -0
- package/client/dist/assets/TemplatePreviewModal-BSyuZxGq.js +1 -0
- package/client/dist/assets/TicketDetailModalContext-DqyF0so-.js +14 -0
- package/client/dist/assets/Trans-SnMX4MhW.js +1 -0
- package/client/dist/assets/agent-BdT0SB1D.js +1 -0
- package/client/dist/assets/agent-Bh9K7iEt.js +1 -0
- package/client/dist/assets/agent-C4ibdFk9.js +1 -0
- package/client/dist/assets/agent-CSFY22Zo.js +1 -0
- package/client/dist/assets/agent-DAnqxUn8.js +1 -0
- package/client/dist/assets/agent-DTQiu0Mi.js +1 -0
- package/client/dist/assets/agent-T54WuR_Y.js +1 -0
- package/client/dist/assets/agent-i75WDZOA.js +1 -0
- package/client/dist/assets/browser-05vRDg_y.js +1 -0
- package/client/dist/assets/browser-Bulb-cB1.js +1 -0
- package/client/dist/assets/browser-C7f-Jsg1.js +1 -0
- package/client/dist/assets/browser-CG0PE1j_.js +1 -0
- package/client/dist/assets/browser-CMzaqAjo.js +1 -0
- package/client/dist/assets/browser-DMajYdNX.js +1 -0
- package/client/dist/assets/browser-DxcOHrdP.js +1 -0
- package/client/dist/assets/browser-ObE7xVo3.js +1 -0
- package/client/dist/assets/builder-765NeYTp.js +1 -0
- package/client/dist/assets/builder-8MG3V6ea.js +1 -0
- package/client/dist/assets/builder-B-1UBs5K.js +1 -0
- package/client/dist/assets/builder-BTiGnPT0.js +1 -0
- package/client/dist/assets/builder-Cx9Rz-7u.js +1 -0
- package/client/dist/assets/builder-DKFMELBl.js +1 -0
- package/client/dist/assets/builder-OcmKrC0h.js +1 -0
- package/client/dist/assets/builder-P9qVBXFZ.js +1 -0
- package/client/dist/assets/{button-CJqFnUOL.js → button-DCBqEaZl.js} +1 -1
- package/client/dist/assets/{code-CkUuW4m9.js → code-B37GRg9C.js} +1 -1
- package/client/dist/assets/{code-B0O8-p8k.js → code-BBOEZbf9.js} +1 -1
- package/client/dist/assets/{code-B1VLZDhS.js → code-BRm-jcyx.js} +1 -1
- package/client/dist/assets/{code-Bpj4Ddml.js → code-CF7w62CR.js} +1 -1
- package/client/dist/assets/{code-BykBZ5-e.js → code-CLuvJt2r.js} +1 -1
- package/client/dist/assets/{code-B86IMAfz.js → code-D0RCm59f.js} +1 -1
- package/client/dist/assets/code-DaZ-ZwCT.js +1 -0
- package/client/dist/assets/{code-cAqaqMTx.js → code-iIHkGaCL.js} +1 -1
- package/client/dist/assets/commands-0XjAftla.js +1 -0
- package/client/dist/assets/commands-BAWSYHjQ.js +1 -0
- package/client/dist/assets/commands-BBwowgiE.js +1 -0
- package/client/dist/assets/commands-BacjIZLN.js +1 -0
- package/client/dist/assets/commands-Bs62IAZ3.js +1 -0
- package/client/dist/assets/commands-CLPdh-Hh.js +1 -0
- package/client/dist/assets/commands-DlbFzgrp.js +1 -0
- package/client/dist/assets/commands-LjPSsi5F.js +1 -0
- package/client/dist/assets/common-B5AZNYMH.js +1 -0
- package/client/dist/assets/common-BFZ0c_vN.js +1 -0
- package/client/dist/assets/common-BrlwEnL7.js +1 -0
- package/client/dist/assets/common-BttQx3z4.js +1 -0
- package/client/dist/assets/common-CM65k_-e.js +1 -0
- package/client/dist/assets/common-D4mvFFlu.js +1 -0
- package/client/dist/assets/common-TZ9Ny96S.js +1 -0
- package/client/dist/assets/common-nFpSF4GC.js +1 -0
- package/client/dist/assets/dashboard-B14uYXkG.js +1 -0
- package/client/dist/assets/dashboard-BK_mez-z.js +1 -0
- package/client/dist/assets/dashboard-BfBir_6o.js +1 -0
- package/client/dist/assets/dashboard-Bt0cCzeG.js +1 -0
- package/client/dist/assets/dashboard-BwkjxI6H.js +1 -0
- package/client/dist/assets/{dashboard-C8WOEiPu.js → dashboard-C3bDKf7s.js} +1 -1
- package/client/dist/assets/dashboard-CdvjGfog.js +1 -0
- package/client/dist/assets/dashboard-fRrP0Kv0.js +1 -0
- package/client/dist/assets/dialog-SRw01_QU.js +45 -0
- package/client/dist/assets/dist-js-CJ_2XX1Y.js +1 -0
- package/client/dist/assets/formatDistanceToNow-DSj5DprF.js +1 -0
- package/client/dist/assets/getTimezoneOffsetInMilliseconds-YhD8rIEs.js +1 -0
- package/client/dist/assets/index-DwAmL7m5.css +2 -0
- package/client/dist/assets/index-EzrkUb8B.js +76 -0
- package/client/dist/assets/{jira-api-B1-MUehg.js → jira-api-CSCqGr-Q.js} +1 -1
- package/client/dist/assets/{jobs-CN_zv4Gr.js → jobs-B8rrzfyZ.js} +1 -1
- package/client/dist/assets/{jobs-DUlWSYq2.js → jobs-BS6RTurf.js} +1 -1
- package/client/dist/assets/{jobs-Bpks6doU.js → jobs-BTT0Bsks.js} +1 -1
- package/client/dist/assets/{jobs-Bgq-PZkC.js → jobs-CezU69AE.js} +1 -1
- package/client/dist/assets/{jobs-SwYS2M-B.js → jobs-ClFJae0s.js} +1 -1
- package/client/dist/assets/{jobs-BAls3bWq.js → jobs-DJSFIFVy.js} +1 -1
- package/client/dist/assets/{jobs-DhxKgWFq.js → jobs-DhgGr8vm.js} +1 -1
- package/client/dist/assets/{jobs-B_TeSQxb.js → jobs-DzMjUcaN.js} +1 -1
- package/client/dist/assets/mcp-6rMoZfEO.js +1 -0
- package/client/dist/assets/mcp-BD8sL5mP.js +1 -0
- package/client/dist/assets/mcp-BkcA3I5s.js +1 -0
- package/client/dist/assets/mcp-CCpSelOh.js +1 -0
- package/client/dist/assets/mcp-CUAN6ORK.js +1 -0
- package/client/dist/assets/mcp-CqbRxRTE.js +1 -0
- package/client/dist/assets/mcp-DP2YfVhO.js +1 -0
- package/client/dist/assets/mcp-DUVQamDz.js +1 -0
- package/client/dist/assets/narration-B-ynWTpn.js +1 -0
- package/client/dist/assets/narration-Bj_laZwg.js +1 -0
- package/client/dist/assets/narration-BxHpmMv_.js +1 -0
- package/client/dist/assets/narration-C1Px0-0j.js +1 -0
- package/client/dist/assets/narration-CAXhGbzM.js +1 -0
- package/client/dist/assets/narration-DQ1l_Kq6.js +1 -0
- package/client/dist/assets/narration-XISXwqZd.js +1 -0
- package/client/dist/assets/narration-kwzfglQo.js +1 -0
- package/client/dist/assets/nav-1-Hh2kOz.js +1 -0
- package/client/dist/assets/nav-B34QkESm.js +1 -0
- package/client/dist/assets/nav-Bap_UXAq.js +1 -0
- package/client/dist/assets/{nav-pYuXq7sf.js → nav-BwxXIB24.js} +1 -1
- package/client/dist/assets/nav-Ch-zHBG5.js +1 -0
- package/client/dist/assets/nav-CygC_WN-.js +1 -0
- package/client/dist/assets/{nav-iwjCg5FR.js → nav-KnnLQtOQ.js} +1 -1
- package/client/dist/assets/nav-m00uxYUG.js +1 -0
- package/client/dist/assets/packet-BQ2tXfJI.js +1 -0
- package/client/dist/assets/packet-BdpOJ1Cy.js +1 -0
- package/client/dist/assets/packet-C3Ievb9R.js +1 -0
- package/client/dist/assets/packet-C4zJIG0Y.js +1 -0
- package/client/dist/assets/packet-Cx-zRuWn.js +1 -0
- package/client/dist/assets/packet-DUTGX52M.js +1 -0
- package/client/dist/assets/packet-DhsKtUPB.js +1 -0
- package/client/dist/assets/packet-z3LJ8Zyy.js +1 -0
- package/client/dist/assets/project-repositories-DYhTvwQ1.js +1 -0
- package/client/dist/assets/provider-capabilities-B-wOHfLP.js +1 -0
- package/client/dist/assets/settings-BBt2xtDQ.js +1 -0
- package/client/dist/assets/settings-BJB9RKJj.js +1 -0
- package/client/dist/assets/settings-CHwQR2rB.js +1 -0
- package/client/dist/assets/settings-CrMi3kSi.js +1 -0
- package/client/dist/assets/settings-DKyhDGD1.js +1 -0
- package/client/dist/assets/settings-Deupji9c.js +1 -0
- package/client/dist/assets/settings-DqRMmwAM.js +1 -0
- package/client/dist/assets/settings-J4rj6vo-.js +1 -0
- package/client/dist/assets/setup-2xGgu4Sk.js +1 -0
- package/client/dist/assets/setup-Ba11l2JA.js +1 -0
- package/client/dist/assets/setup-BzW4kMok.js +1 -0
- package/client/dist/assets/setup-COzwYhkJ.js +1 -0
- package/client/dist/assets/setup-CRVULhtF.js +1 -0
- package/client/dist/assets/setup-DgvlxwpE.js +1 -0
- package/client/dist/assets/setup-Dw_wYeEY.js +1 -0
- package/client/dist/assets/setup-ZPtEeJPW.js +1 -0
- package/client/dist/assets/spending-BqbdPm_4.js +1 -0
- package/client/dist/assets/square-Ci-PFcFe.js +1 -0
- package/client/dist/assets/{terminal-BFRZnMPP.js → terminal-BAzpHtpY.js} +1 -1
- package/client/dist/assets/{terminal-IahE4LW9.js → terminal-C7dHeR3x.js} +1 -1
- package/client/dist/assets/{terminal-tITa81iz.js → terminal-CMla5Qsz.js} +1 -1
- package/client/dist/assets/{terminal-BZiIu3rf.js → terminal-CdNXH-n9.js} +1 -1
- package/client/dist/assets/{terminal-ScjyXNxQ.js → terminal-Cw5bZsmV.js} +1 -1
- package/client/dist/assets/{terminal-C2NAd7BW.js → terminal-DFUP4eNv.js} +1 -1
- package/client/dist/assets/{terminal-d7GadXbN.js → terminal-DGqljeK_.js} +1 -1
- package/client/dist/assets/{terminal-QpXZU2Bn.js → terminal-cU70NodO.js} +1 -1
- package/client/dist/assets/useDesktop-RSMTyy7V.js +1 -0
- package/client/dist/assets/useSharedWebSocket-BOdS5_Iz.js +2 -0
- package/client/dist/index.html +34 -35
- package/docs/README.md +3 -0
- package/docs/agent-live-steering.md +57 -0
- package/docs/ci-cd.md +57 -0
- package/docs/code-explorer.md +48 -0
- package/docs/codex.md +12 -1
- package/docs/features/detachable-mission-windows.md +59 -0
- package/docs/guide/de/integrations/5-mcp-server.md +13 -9
- package/docs/guide/de/integrations/6-agent-chat.md +1 -0
- package/docs/guide/en/integrations/5-mcp-server.md +13 -9
- package/docs/guide/en/integrations/6-agent-chat.md +1 -0
- package/docs/guide/es/integrations/5-mcp-server.md +13 -9
- package/docs/guide/es/integrations/6-agent-chat.md +1 -0
- package/docs/guide/fr/integrations/5-mcp-server.md +13 -9
- package/docs/guide/fr/integrations/6-agent-chat.md +1 -0
- package/docs/guide/it/integrations/5-mcp-server.md +13 -9
- package/docs/guide/it/integrations/6-agent-chat.md +1 -0
- package/docs/guide/ja/integrations/5-mcp-server.md +13 -9
- package/docs/guide/ja/integrations/6-agent-chat.md +1 -0
- package/docs/guide/pt/integrations/5-mcp-server.md +13 -9
- package/docs/guide/pt/integrations/6-agent-chat.md +1 -0
- package/docs/guide/zh/integrations/5-mcp-server.md +13 -9
- package/docs/guide/zh/integrations/6-agent-chat.md +1 -0
- package/docs/internals/README.md +1 -0
- package/docs/internals/browser-capture-performance.md +55 -3
- package/docs/internals/browser-login-popups.md +45 -0
- package/docs/internals/browser-native-retina-audit.md +39 -0
- package/docs/internals/ci-cd-audit.md +39 -0
- package/docs/internals/core-runtime-updates.md +68 -0
- package/docs/internals/embedded-browser-native-webview-evaluation.md +2 -0
- package/docs/internals/implementation-reliability-audit.md +93 -0
- package/docs/internals/interactive-jobs.md +110 -6
- package/docs/internals/mcp-mission-audit.md +76 -0
- package/docs/internals/project-builder.md +404 -42
- package/docs/internals/safe-pr-review-flow.md +52 -10
- package/docs/internals/startup-recovery-audit.md +58 -0
- package/docs/mcp.md +74 -41
- package/docs/mission-processes.md +59 -0
- package/docs/multi-repo-projects.md +51 -0
- package/docs/platforms/windows-parity.md +70 -0
- package/docs/platforms/windows.md +13 -11
- package/docs/running-pipelines.md +14 -0
- package/mcp-bridge/dist/specrails-mcp.js +7186 -0
- package/package.json +9 -4
- package/server/dist/agent-chat-manager.js +537 -68
- package/server/dist/agent-chat-router.js +87 -6
- package/server/dist/agent-context-resolver.js +129 -25
- package/server/dist/agent-defaults.js +19 -11
- package/server/dist/agent-input-store.js +206 -0
- package/server/dist/agent-mcp-config.js +54 -15
- package/server/dist/agent-operator-prompt.js +255 -65
- package/server/dist/agent-spec-framing.js +202 -0
- package/server/dist/agent-steering.js +218 -0
- package/server/dist/agent-store.js +153 -0
- package/server/dist/api-not-found.js +8 -0
- package/server/dist/background-process-control.js +164 -0
- package/server/dist/background-process-service.js +61 -0
- package/server/dist/background-process-store.js +242 -0
- package/server/dist/background-windows-bootstrap.js +238 -0
- package/server/dist/blueprint-chat-manager.js +476 -62
- package/server/dist/blueprint-commit.js +21 -1
- package/server/dist/blueprint-draft-parser.js +122 -17
- package/server/dist/blueprint-generation.js +238 -0
- package/server/dist/blueprint-operator-prompt.js +91 -63
- package/server/dist/blueprint-router.js +55 -3
- package/server/dist/blueprint-spec-fixtures.js +85 -0
- package/server/dist/blueprint-spec-quality.js +57 -16
- package/server/dist/blueprint-store.js +92 -1
- package/server/dist/browser-capture-manager.js +86 -30
- package/server/dist/browser-playwright.js +168 -45
- package/server/dist/browser-viewport.js +26 -0
- package/server/dist/chat-manager.js +23 -15
- package/server/dist/chromium-archive.cjs +83 -0
- package/server/dist/chromium-resolver.js +72 -64
- package/server/dist/code-activity.js +145 -0
- package/server/dist/code-explorer-router.js +714 -114
- package/server/dist/core-compat.js +28 -1
- package/server/dist/core-execution.js +111 -0
- package/server/dist/core-package.js +4 -16
- package/server/dist/core-runtime.js +202 -0
- package/server/dist/core-update-manager.js +161 -60
- package/server/dist/core-update-state.js +29 -0
- package/server/dist/db.js +66 -35
- package/server/dist/delivery-evidence.js +142 -39
- package/server/dist/desktop-db.js +239 -43
- package/server/dist/desktop-router.js +109 -9
- package/server/dist/dev-ports.js +8 -3
- package/server/dist/file-provenance.js +34 -22
- package/server/dist/file-story-manager.js +62 -64
- package/server/dist/file-story.js +118 -35
- package/server/dist/file-summary-generator.js +46 -5
- package/server/dist/file-summary-manager.js +355 -106
- package/server/dist/framework-manager.js +98 -110
- package/server/dist/framework-reseed.js +76 -10
- package/server/dist/git-diagnostics.js +2 -2
- package/server/dist/headroom-manager.js +38 -3
- package/server/dist/host-control.js +52 -0
- package/server/dist/index.js +43 -2
- package/server/dist/interactive-job-session.js +149 -16
- package/server/dist/internal-api.js +48 -0
- package/server/dist/jira/jira-materializer.js +1 -0
- package/server/dist/json-tolerant.js +174 -0
- package/server/dist/legacy-migration.js +4 -2
- package/server/dist/loop-command-catalog.js +83 -21
- package/server/dist/loop-constants.js +6 -1
- package/server/dist/loop-decider.js +11 -1
- package/server/dist/loop-executors.js +194 -45
- package/server/dist/loop-factory.js +11 -4
- package/server/dist/loop-graph.js +90 -4
- package/server/dist/loop-run-manager.js +301 -69
- package/server/dist/loop-shell-invocation.js +21 -0
- package/server/dist/loop-step-idle.js +55 -0
- package/server/dist/loop-templates.js +31 -7
- package/server/dist/mcp/agent-capability.js +37 -4
- package/server/dist/mcp/guide.js +149 -36
- package/server/dist/mcp/mcp-admin-router.js +20 -4
- package/server/dist/mcp/mcp-server.js +89 -43
- package/server/dist/mcp/mcp-tiers.js +6 -5
- package/server/dist/mcp/mcp-token.js +3 -1
- package/server/dist/mcp/resources.js +5 -4
- package/server/dist/mcp/tools/catalog.js +4 -0
- package/server/dist/mcp/tools/code.js +125 -14
- package/server/dist/mcp/tools/context.js +153 -0
- package/server/dist/mcp/tools/git.js +15 -5
- package/server/dist/mcp/tools/jobs.js +84 -71
- package/server/dist/mcp/tools/loops.js +17 -6
- package/server/dist/mcp/tools/meta.js +74 -27
- package/server/dist/mcp/tools/mission.js +29 -0
- package/server/dist/mcp/tools/projects.js +22 -6
- package/server/dist/mcp/tools/rails.js +48 -11
- package/server/dist/mcp/tools/specs.js +86 -14
- package/server/dist/mcp/tools/support.js +1 -1
- package/server/dist/mcp/tools/types.js +117 -43
- package/server/dist/mcp/tools/watch.js +144 -51
- package/server/dist/milestone-chain-store.js +164 -0
- package/server/dist/milestone-chain.js +487 -0
- package/server/dist/milestone-progress.js +348 -0
- package/server/dist/mobile/mobile-devices.js +10 -7
- package/server/dist/mobile/mobile-gateway.js +2 -0
- package/server/dist/mobile/mobile-missions.js +214 -0
- package/server/dist/mobile/mobile-redact.js +17 -3
- package/server/dist/mobile/mobile-router.js +46 -4
- package/server/dist/mobile/mobile-ws.js +49 -4
- package/server/dist/multi-repo-bases.js +56 -0
- package/server/dist/multi-repo-checkout.js +101 -0
- package/server/dist/multi-repo-delivery.js +100 -0
- package/server/dist/multi-repo-execution-store.js +65 -0
- package/server/dist/multi-repo-execution.js +453 -0
- package/server/dist/offline-assemble.js +10 -8
- package/server/dist/openspec-runtime-plugin-commands.json +18 -0
- package/server/dist/openspec-runtime-plugin.js +120 -0
- package/server/dist/plugins/codex-spawn.js +49 -0
- package/server/dist/plugins/serena/manifest.js +2 -2
- package/server/dist/plugins/serena/templates/instructions.md +16 -0
- package/server/dist/pr-publisher.js +1 -1
- package/server/dist/profiles-router.js +3 -18
- package/server/dist/project-code-discovery.js +142 -0
- package/server/dist/project-git.js +19 -21
- package/server/dist/project-registry.js +272 -20
- package/server/dist/project-repositories.js +157 -0
- package/server/dist/project-repository-provenance.js +31 -0
- package/server/dist/project-router-background-processes.js +105 -0
- package/server/dist/project-router-git.js +75 -16
- package/server/dist/project-router-jobs.js +2 -126
- package/server/dist/project-router-loop-runs.js +72 -2
- package/server/dist/project-router-tickets.js +53 -8
- package/server/dist/project-router.js +239 -38
- package/server/dist/provider-detection.js +18 -6
- package/server/dist/provider-limit.js +64 -0
- package/server/dist/providers/claude-adapter.js +26 -1
- package/server/dist/providers/claude-background-tasks.js +18 -0
- package/server/dist/providers/claude-live-session.js +383 -0
- package/server/dist/providers/codex-adapter.js +19 -0
- package/server/dist/providers/codex-live-session.js +545 -0
- package/server/dist/providers/gemini-adapter.js +1 -0
- package/server/dist/providers/live-session-types.js +12 -0
- package/server/dist/providers/live-session.js +13 -0
- package/server/dist/providers/terminal-result.js +24 -0
- package/server/dist/queue-manager.js +2 -0
- package/server/dist/rail-isolated-launch.js +141 -16
- package/server/dist/rail-pr-decision.js +364 -99
- package/server/dist/rail-pr-store.js +24 -10
- package/server/dist/rail-worktree-release.js +34 -2
- package/server/dist/rail-worktrees-store.js +4 -4
- package/server/dist/rails-router.js +249 -55
- package/server/dist/repo-lock.js +92 -17
- package/server/dist/review-packet.js +23 -13
- package/server/dist/schemas/file-summary.v1.json +59 -59
- package/server/dist/schemas/profile.v1.json +137 -137
- package/server/dist/setup-manager.js +52 -8
- package/server/dist/shell-integration/bash-shim.bash +45 -0
- package/server/dist/shell-integration/fish-shim.fish +36 -0
- package/server/dist/shell-integration/powershell-shim.ps1 +48 -0
- package/server/dist/shell-integration/zsh-shim.zsh +47 -0
- package/server/dist/smash-runner.js +1 -0
- package/server/dist/spawn-lifecycle.js +44 -27
- package/server/dist/spec-contract-prompt.js +143 -0
- package/server/dist/spec-draft-parser.js +6 -1
- package/server/dist/spec-models.js +1 -0
- package/server/dist/stuck-run-detector.js +1 -0
- package/server/dist/terminal-manager.js +21 -1
- package/server/dist/terminal-shell-integration.js +4 -1
- package/server/dist/transient-children.js +619 -230
- package/server/dist/util/cli-prompt.js +78 -5
- package/server/dist/util/sqlite-migrations.js +20 -0
- package/server/dist/util/win-spawn.js +18 -3
- package/server/dist/util/windows-provider-shell.js +29 -0
- package/server/dist/verification-sentinel.js +14 -0
- package/server/dist/vitest-setup.js +2 -0
- package/server/dist/windows-job-supervisor.js +133 -0
- package/server/dist/workspace-manager.js +9 -30
- package/server/dist/worktree-manager.js +17 -2
- package/server/dist/worktree-overlay.js +3 -1
- package/client/dist/assets/ActivityFeedPage-tAQcWs1R.js +0 -1
- package/client/dist/assets/AgentBrowserCapture-BX8BNae5.js +0 -1
- package/client/dist/assets/AgentModeAnalyticsPane-BVAqCL0K.js +0 -2
- package/client/dist/assets/AgentModeCodePane-9XfqQc9c.js +0 -2
- package/client/dist/assets/AgentModeJobsPane-BCjLsPhc.js +0 -1
- package/client/dist/assets/AgentsPage-C8J_42sm.js +0 -87
- package/client/dist/assets/AnalyticsPage-BtQuyfJm.js +0 -1
- package/client/dist/assets/CodePage-BZ2MwdCu.js +0 -2
- package/client/dist/assets/DesktopAnalyticsPage-Bh_29V4g.js +0 -1
- package/client/dist/assets/ExportDropdown-BrtfWzEG.js +0 -1
- package/client/dist/assets/InteractiveJobComposer-BCZiSfzc.js +0 -19
- package/client/dist/assets/JobDetailModal-NAJmuYIT.js +0 -1
- package/client/dist/assets/JobDetailPage-fE0ZycUX.js +0 -1
- package/client/dist/assets/JobsPage-z5M_HVJG.js +0 -1
- package/client/dist/assets/LoopBuilderPage-j1FQS47c.js +0 -7
- package/client/dist/assets/LoopPreviewModal-DhDJjdCe.js +0 -1
- package/client/dist/assets/LoopsPage-Ll7zORZb.js +0 -1
- package/client/dist/assets/MinimizedChatsContext-Bd3OqR_S.js +0 -1
- package/client/dist/assets/PluginsPage-DN4kGvJt.js +0 -2
- package/client/dist/assets/ProjectSettingsDialog-OgsgxjzF.js +0 -1
- package/client/dist/assets/ReviewPacketPage-DFog4sXn.js +0 -1
- package/client/dist/assets/TemplatePreviewModal-L2XxqiOD.js +0 -1
- package/client/dist/assets/TicketDetailModal-CsF-AWZX.js +0 -14
- package/client/dist/assets/Trans-Bsz9_gyq.js +0 -1
- package/client/dist/assets/agent-BQgKv_2F.js +0 -1
- package/client/dist/assets/agent-C1NRDJqL.js +0 -1
- package/client/dist/assets/agent-CLNleiy6.js +0 -1
- package/client/dist/assets/agent-CmceArkQ.js +0 -1
- package/client/dist/assets/agent-D3UxQ3SR.js +0 -1
- package/client/dist/assets/agent-DB1JeE64.js +0 -1
- package/client/dist/assets/agent-DXkHcQ-D.js +0 -1
- package/client/dist/assets/agent-DjJJJ2M8.js +0 -1
- package/client/dist/assets/auth-D_5bQv5W.js +0 -1
- package/client/dist/assets/ban-E4EaZe3a.js +0 -1
- package/client/dist/assets/bot-DzuuuC5R.js +0 -1
- package/client/dist/assets/browser-BgqHDMXP.js +0 -1
- package/client/dist/assets/browser-CsKJtrpv.js +0 -1
- package/client/dist/assets/browser-Cu58EpZU.js +0 -1
- package/client/dist/assets/browser-CvXOJm-j.js +0 -1
- package/client/dist/assets/browser-DOrFh1c7.js +0 -1
- package/client/dist/assets/browser-DQv_Jo7x.js +0 -1
- package/client/dist/assets/browser-LPgxvJu2.js +0 -1
- package/client/dist/assets/browser-eL-3MIEI.js +0 -1
- package/client/dist/assets/builder-0IWtosUm.js +0 -1
- package/client/dist/assets/builder-Bf2N6XWn.js +0 -1
- package/client/dist/assets/builder-BnqaaBkT.js +0 -1
- package/client/dist/assets/builder-BxxfGgAO.js +0 -1
- package/client/dist/assets/builder-C5IIgWsq.js +0 -1
- package/client/dist/assets/builder-CHuahItu.js +0 -1
- package/client/dist/assets/builder-CjWosXL_.js +0 -1
- package/client/dist/assets/builder-CpCIOoKj.js +0 -1
- package/client/dist/assets/code-CHPkOkDS.js +0 -1
- package/client/dist/assets/commands-6tYQih5m.js +0 -1
- package/client/dist/assets/commands-BK2QinXN.js +0 -1
- package/client/dist/assets/commands-C2Nca76h.js +0 -1
- package/client/dist/assets/commands-CKdLihNX.js +0 -1
- package/client/dist/assets/commands-CYIBTAlc.js +0 -1
- package/client/dist/assets/commands-CjUtYJIM.js +0 -1
- package/client/dist/assets/commands-Cq_u_8y9.js +0 -1
- package/client/dist/assets/commands-D_ZHYQug.js +0 -1
- package/client/dist/assets/common-6MLbD-jM.js +0 -1
- package/client/dist/assets/common-BKGEu4rm.js +0 -1
- package/client/dist/assets/common-BNbnv8cE.js +0 -1
- package/client/dist/assets/common-BqGWtDbt.js +0 -1
- package/client/dist/assets/common-DBtTzeYm.js +0 -1
- package/client/dist/assets/common-DEW3Nr8n.js +0 -1
- package/client/dist/assets/common-DHsv9N5d.js +0 -1
- package/client/dist/assets/common-mkrEcW-Y.js +0 -1
- package/client/dist/assets/dashboard-B9GhC5ku.js +0 -1
- package/client/dist/assets/dashboard-CBnv6zOI.js +0 -1
- package/client/dist/assets/dashboard-CaP0fU87.js +0 -1
- package/client/dist/assets/dashboard-D4ZZ4x84.js +0 -1
- package/client/dist/assets/dashboard-DmuTQBX8.js +0 -1
- package/client/dist/assets/dashboard-DynLYj3d.js +0 -1
- package/client/dist/assets/dashboard-zj4gGFJ1.js +0 -1
- package/client/dist/assets/dialog-CdWCb02j.js +0 -45
- package/client/dist/assets/dist-bVqfYmby.js +0 -1
- package/client/dist/assets/dist-js-CWeUdf5Z.js +0 -1
- package/client/dist/assets/formatDistanceToNow-DQCvMgUc.js +0 -1
- package/client/dist/assets/getTimezoneOffsetInMilliseconds-C16cxSe1.js +0 -1
- package/client/dist/assets/git-refresh-wTW0rO0Z.js +0 -1
- package/client/dist/assets/i18n-hnX2DPmo.js +0 -2
- package/client/dist/assets/index-DIhMEAVw.js +0 -66
- package/client/dist/assets/index-DwygcU7s.css +0 -2
- package/client/dist/assets/mcp-B8X8wBLu.js +0 -1
- package/client/dist/assets/mcp-C2AojZZN.js +0 -1
- package/client/dist/assets/mcp-D8BT78_L.js +0 -1
- package/client/dist/assets/mcp-Df5RWBNk.js +0 -1
- package/client/dist/assets/mcp-Dj7BgMQW.js +0 -1
- package/client/dist/assets/mcp-Q7iT7rcz.js +0 -1
- package/client/dist/assets/mcp-YlvNvJbW.js +0 -1
- package/client/dist/assets/mcp-mKFpTSRb.js +0 -1
- package/client/dist/assets/narration-4Z2VUhZw.js +0 -1
- package/client/dist/assets/narration-BGuiEDj3.js +0 -1
- package/client/dist/assets/narration-BuSoqRmv.js +0 -1
- package/client/dist/assets/narration-CB9t29fy.js +0 -1
- package/client/dist/assets/narration-CU3x8FHD.js +0 -1
- package/client/dist/assets/narration-CWeXhfP5.js +0 -1
- package/client/dist/assets/narration-DRaDnhT5.js +0 -1
- package/client/dist/assets/narration-DtEbQgCw.js +0 -1
- package/client/dist/assets/nav-ApJVg3xu.js +0 -1
- package/client/dist/assets/nav-BKNky1Bg.js +0 -1
- package/client/dist/assets/nav-C6vWWKYx.js +0 -1
- package/client/dist/assets/nav-CXJ6Aw89.js +0 -1
- package/client/dist/assets/nav-CsmFBIDf.js +0 -1
- package/client/dist/assets/nav-DjkmQJjd.js +0 -1
- package/client/dist/assets/packet-B1IxaL5f.js +0 -1
- package/client/dist/assets/packet-Bh5kkbiB.js +0 -1
- package/client/dist/assets/packet-By8fqYxW.js +0 -1
- package/client/dist/assets/packet-CZdvA44E.js +0 -1
- package/client/dist/assets/packet-CrjHRQCP.js +0 -1
- package/client/dist/assets/packet-Dwi2pTtx.js +0 -1
- package/client/dist/assets/packet-_-ZIa0IR.js +0 -1
- package/client/dist/assets/packet-n0W6E1Hn.js +0 -1
- package/client/dist/assets/play-DNlrawbS.js +0 -1
- package/client/dist/assets/provider-capabilities-Doej9lfa.js +0 -1
- package/client/dist/assets/settings-Bd0x4TBa.js +0 -1
- package/client/dist/assets/settings-C1-7cXzC.js +0 -1
- package/client/dist/assets/settings-CAFaT38b.js +0 -1
- package/client/dist/assets/settings-Ct3v1nW2.js +0 -1
- package/client/dist/assets/settings-DHh7_IF5.js +0 -1
- package/client/dist/assets/settings-DQXAmdcv.js +0 -1
- package/client/dist/assets/settings-guzlhpup.js +0 -1
- package/client/dist/assets/settings-sZfTPMEH.js +0 -1
- package/client/dist/assets/setup-3jWaoVUO.js +0 -1
- package/client/dist/assets/setup-BjgRneb2.js +0 -1
- package/client/dist/assets/setup-BzFIjv-f.js +0 -1
- package/client/dist/assets/setup-C4VfQsxE.js +0 -1
- package/client/dist/assets/setup-DfUkpDbN.js +0 -1
- package/client/dist/assets/setup-ECe90Pmu.js +0 -1
- package/client/dist/assets/setup-dlqC4Jmm.js +0 -1
- package/client/dist/assets/setup-jwfLMiM2.js +0 -1
- package/client/dist/assets/spending-EC9xqio-.js +0 -1
- package/client/dist/assets/useDesktop-BQVt8lFd.js +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.registerLoopRunRoutes = registerLoopRunRoutes;
|
|
4
|
+
const loop_graph_1 = require("./loop-graph");
|
|
4
5
|
const feature_flags_1 = require("./feature-flags");
|
|
5
6
|
const loops_store_1 = require("./loops-store");
|
|
6
7
|
const loop_runs_store_1 = require("./loop-runs-store");
|
|
@@ -14,6 +15,12 @@ const spec_models_1 = require("./spec-models");
|
|
|
14
15
|
const workspace_resolution_1 = require("./workspace-resolution");
|
|
15
16
|
const loop_command_catalog_1 = require("./loop-command-catalog");
|
|
16
17
|
const ids_1 = require("./ids");
|
|
18
|
+
const project_repositories_1 = require("./project-repositories");
|
|
19
|
+
const multi_repo_execution_1 = require("./multi-repo-execution");
|
|
20
|
+
const rails_store_1 = require("./rails-store");
|
|
21
|
+
const rail_pr_store_1 = require("./rail-pr-store");
|
|
22
|
+
const rail_isolation_1 = require("./rail-isolation");
|
|
23
|
+
const process_admission_1 = require("./process-admission");
|
|
17
24
|
function registerLoopRunRoutes(deps) {
|
|
18
25
|
const { router, ctx } = deps;
|
|
19
26
|
// GET a single loop run's live/terminal state. Backs the companion's running
|
|
@@ -59,7 +66,7 @@ function registerLoopRunRoutes(deps) {
|
|
|
59
66
|
: (0, run_duration_stats_1.getJobCommandDurationRange)(c.db, (0, run_duration_stats_1.jobCommandShape)(command));
|
|
60
67
|
res.json({ range, minSamples: run_duration_stats_1.MIN_DURATION_SAMPLES });
|
|
61
68
|
});
|
|
62
|
-
router.post('/:projectId/loop-runs', (req, res) => {
|
|
69
|
+
router.post('/:projectId/loop-runs', async (req, res) => {
|
|
63
70
|
if (!(0, feature_flags_1.isLoopsEnabled)()) {
|
|
64
71
|
res.status(404).json({ error: 'Not Found' });
|
|
65
72
|
return;
|
|
@@ -80,6 +87,11 @@ function registerLoopRunRoutes(deps) {
|
|
|
80
87
|
res.status(400).json({ error: 'Loop must be published before it can run' });
|
|
81
88
|
return;
|
|
82
89
|
}
|
|
90
|
+
const validation = (0, loop_graph_1.validateLoopGraph)(loop.graph);
|
|
91
|
+
if (!validation.valid) {
|
|
92
|
+
res.status(422).json({ error: 'Loop graph is invalid', errors: validation.errors });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
83
95
|
const check = (0, provider_selection_1.validateRequestedProvider)(c.project, aiEngine ?? providerAlias);
|
|
84
96
|
if (!check.ok) {
|
|
85
97
|
res.status(400).json({ error: check.error });
|
|
@@ -139,6 +151,63 @@ function registerLoopRunRoutes(deps) {
|
|
|
139
151
|
&& (0, runtime_1.isReasoningEffortValidForModel)(adapter, model, globalAgentDefaults.pipelineEffort)) {
|
|
140
152
|
effort = globalAgentDefaults.pipelineEffort;
|
|
141
153
|
}
|
|
154
|
+
let repositoryIds;
|
|
155
|
+
const primary = (0, project_repositories_1.getProjectRepositories)(c.project).find((repository) => repository.isPrimary);
|
|
156
|
+
try {
|
|
157
|
+
repositoryIds = (0, project_repositories_1.validateTicketRepositoryIds)(c.project, body.repositoryIds) ?? [primary.id];
|
|
158
|
+
(0, loop_graph_1.assertLoopShellRepositoryScope)(loop.graph, repositoryIds);
|
|
159
|
+
(0, process_admission_1.assertProcessAdmission)(c.project.id);
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
res.status(error instanceof project_repositories_1.RepositoryValidationError ? error.status : error instanceof process_admission_1.ProcessAdmissionClosedError ? 409 : 400).json({ error: error instanceof Error ? error.message : 'Invalid repository scope' });
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (repositoryIds.length !== 1 || repositoryIds[0] !== primary.id) {
|
|
166
|
+
if (!(0, rail_isolation_1.isolationApplies)({ loopsEnabled: true, scope: 'all', ticketCount: 1, readOnly: false })) {
|
|
167
|
+
res.status(409).json({ error: 'repository_isolation_required' });
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
// A real empty rail makes the grouped delivery reviewable from the board
|
|
171
|
+
// without manufacturing a spec for a ticket-less loop.
|
|
172
|
+
const rails = (0, rails_store_1.getRails)(c.db);
|
|
173
|
+
const used = new Set([...c.railJobs.values(), ...c.railLoopRuns.values()].map((run) => run.railIndex));
|
|
174
|
+
let rail = rails.find((candidate) => candidate.ticketIds.length === 0 && !used.has(candidate.railIndex) && !(0, rail_pr_store_1.getActivePrDeliveryByRail)(c.db, candidate.railIndex));
|
|
175
|
+
let created = false;
|
|
176
|
+
if (!rail) {
|
|
177
|
+
if (rails.length >= rails_store_1.MAX_RAILS) {
|
|
178
|
+
res.status(409).json({ error: 'no_available_rail', detail: 'Finish a pending rail delivery before launching another isolated loop.' });
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
rail = (0, rails_store_1.createRail)(c.db, loop.name);
|
|
182
|
+
created = true;
|
|
183
|
+
}
|
|
184
|
+
const reservationId = `preparing-${(0, ids_1.newId)()}`;
|
|
185
|
+
c.railLoopRuns.set(reservationId, { railIndex: rail.railIndex, ticketIds: [], requiresTerminalIntent: true });
|
|
186
|
+
try {
|
|
187
|
+
let prDeliveryId;
|
|
188
|
+
const ids = await (0, multi_repo_execution_1.launchMultiRepositoryRail)({
|
|
189
|
+
ctx: c, railIndex: rail.railIndex, ticketIds: [], repositoryIds, scope: 'all',
|
|
190
|
+
loopId, loopName: loop.name, loopGraph: loop.graph, provider, model, effort,
|
|
191
|
+
onPrDeliveryCreated: (id) => { prDeliveryId = id; },
|
|
192
|
+
});
|
|
193
|
+
res.status(202).json({ loopRunId: ids[0], railIndex: rail.railIndex, prDeliveryId, isolated: true });
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
if (created && !(0, rail_pr_store_1.getActivePrDeliveryByRail)(c.db, rail.railIndex))
|
|
197
|
+
(0, rails_store_1.deleteRail)(c.db, rail.railIndex);
|
|
198
|
+
res.status(409).json({ error: 'repository_launch_failed', detail: error instanceof Error ? error.message : String(error) });
|
|
199
|
+
}
|
|
200
|
+
finally {
|
|
201
|
+
c.railLoopRuns.delete(reservationId);
|
|
202
|
+
if (created && (0, rails_store_1.getRails)(c.db).some((candidate) => candidate.railIndex === rail.railIndex)) {
|
|
203
|
+
const current = (0, rails_store_1.getRail)(c.db, rail.railIndex);
|
|
204
|
+
c.broadcast({ type: 'rail.updated', projectId: c.project.id, railIndex: current.railIndex,
|
|
205
|
+
changed: 'name', ticketIds: current.ticketIds, name: current.name ?? null,
|
|
206
|
+
mode: current.mode, profileName: current.profileName ?? null, aiEngine: current.aiEngine ?? null });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
142
211
|
const exec = (0, workspace_resolution_1.resolveProjectExecution)({ slug: c.project.slug, path: c.project.path });
|
|
143
212
|
const runId = (0, ids_1.newId)();
|
|
144
213
|
c.loopRunManager
|
|
@@ -148,6 +217,7 @@ function registerLoopRunRoutes(deps) {
|
|
|
148
217
|
loopName: loop.name,
|
|
149
218
|
graph: loop.graph,
|
|
150
219
|
projectId: c.project.id,
|
|
220
|
+
repositoryId: primary.id,
|
|
151
221
|
cwd: exec.cwd,
|
|
152
222
|
repoDir: exec.relocated ? exec.repoDir : undefined,
|
|
153
223
|
railIndex: null,
|
|
@@ -158,7 +228,7 @@ function registerLoopRunRoutes(deps) {
|
|
|
158
228
|
model,
|
|
159
229
|
effort,
|
|
160
230
|
})
|
|
161
|
-
.then((r) => c.onLoopRunFinished(r.runId, r.outcome))
|
|
231
|
+
.then((r) => c.onLoopRunFinished(r.runId, r.outcome, r.stallReason ? { stallReason: r.stallReason } : undefined))
|
|
162
232
|
.catch((err) => {
|
|
163
233
|
console.error('[loop-runs] standalone run failed:', err);
|
|
164
234
|
c.onLoopRunFinished(runId, 'failed');
|
|
@@ -40,6 +40,7 @@ exports.registerTicketsRoutes = registerTicketsRoutes;
|
|
|
40
40
|
// Domain routes extracted from project-router.ts (tickets).
|
|
41
41
|
// Registered on the shared router by createProjectRouter — behaviour-preserving.
|
|
42
42
|
const fs_1 = __importDefault(require("fs"));
|
|
43
|
+
const project_repositories_1 = require("./project-repositories");
|
|
43
44
|
const ids_1 = require("./ids");
|
|
44
45
|
const db_1 = require("./db");
|
|
45
46
|
const providers_1 = require("./providers");
|
|
@@ -130,6 +131,26 @@ async function maybePromoteSpecToJira(c, ticketId, createLocal, broadcast) {
|
|
|
130
131
|
}
|
|
131
132
|
function registerTicketsRoutes(deps) {
|
|
132
133
|
const { router, registry, ctx, ticketPath } = deps;
|
|
134
|
+
// Validate scope at every authoring boundary before writes, uploads or AI.
|
|
135
|
+
const validateRepositoryScope = (req, res, next) => {
|
|
136
|
+
try {
|
|
137
|
+
res.locals.repositoryIds = (0, project_repositories_1.validateTicketRepositoryIds)(ctx(req).project, req.body?.repositoryIds);
|
|
138
|
+
next();
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
if (err instanceof project_repositories_1.RepositoryValidationError)
|
|
142
|
+
res.status(err.status).json({ error: err.message, code: err.code });
|
|
143
|
+
else
|
|
144
|
+
next(err);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
router.post(['/:projectId/tickets', '/:projectId/tickets/generate-spec', '/:projectId/tickets/save-as-draft', '/:projectId/tickets/from-draft', '/:projectId/tickets/from-prompt'], validateRepositoryScope);
|
|
148
|
+
router.patch('/:projectId/tickets/:id', validateRepositoryScope);
|
|
149
|
+
const repositoryScope = (req, res) => {
|
|
150
|
+
// Generation can outlive a membership change; validate again when saving.
|
|
151
|
+
const ids = (0, project_repositories_1.validateTicketRepositoryIds)(ctx(req).project, res.locals.repositoryIds);
|
|
152
|
+
return ids === undefined ? {} : { repositoryIds: ids };
|
|
153
|
+
};
|
|
133
154
|
// ─── Tickets ──────────────────────────────────────────────────────────────────
|
|
134
155
|
/** Resolve the ticket storage file path for a project */
|
|
135
156
|
// GET /:projectId/tickets — List all tickets with optional filters
|
|
@@ -326,6 +347,10 @@ function registerTicketsRoutes(deps) {
|
|
|
326
347
|
`## Short Summary\n[One or two plain-language sentences, max 120 characters total, that capture the essence of this spec for a dashboard postit. No markdown, no bullets, no headings.]`;
|
|
327
348
|
if (hasAttachments)
|
|
328
349
|
baseSystemPrompt = `${baseSystemPrompt}\n\n${attachment_manager_1.USER_ATTACHMENT_SYSTEM_NOTE}`;
|
|
350
|
+
const selectedIds = res.locals.repositoryIds;
|
|
351
|
+
if ((0, project_repositories_1.getProjectRepositories)(project).length > 1) {
|
|
352
|
+
baseSystemPrompt += `\n\nThis logical project has one shared backlog across these repositories: ${JSON.stringify((0, project_repositories_1.getProjectRepositories)(project).map(({ id, name, path, isPrimary, kind }) => ({ id, name, path, isPrimary, kind })))}.\nThis spec targets repository IDs: ${JSON.stringify(selectedIds ?? [(0, project_repositories_1.getProjectRepositories)(project).find((repo) => repo.isPrimary).id])}. Describe cross-repository contracts when selected; do not create separate tickets per repository.`;
|
|
353
|
+
}
|
|
329
354
|
const systemPrompt = baseSystemPrompt;
|
|
330
355
|
const userPrompt = baseUserPrompt;
|
|
331
356
|
// Generate-spec spawn args are adapter-driven. For Claude the `--tools`
|
|
@@ -512,6 +537,7 @@ function registerTicketsRoutes(deps) {
|
|
|
512
537
|
const store = (0, ticket_store_1.mutateStore)(filePath, (s) => {
|
|
513
538
|
const id = s.next_id++;
|
|
514
539
|
const ticket = {
|
|
540
|
+
...repositoryScope(req, res),
|
|
515
541
|
id,
|
|
516
542
|
title: specTitle,
|
|
517
543
|
description,
|
|
@@ -703,6 +729,7 @@ function registerTicketsRoutes(deps) {
|
|
|
703
729
|
return;
|
|
704
730
|
}
|
|
705
731
|
const title = providedTitle || target.title || (0, explore_draft_title_1.generateAutoTitle)(messages.map((m) => ({ role: m.role, content: m.content ?? '' })));
|
|
732
|
+
Object.assign(target, repositoryScope(req, res));
|
|
706
733
|
target.title = title;
|
|
707
734
|
if (description)
|
|
708
735
|
target.description = description;
|
|
@@ -730,6 +757,7 @@ function registerTicketsRoutes(deps) {
|
|
|
730
757
|
const existing = anyExisting && anyExisting.status === 'draft' ? anyExisting : undefined;
|
|
731
758
|
const title = providedTitle || existing?.title || (0, explore_draft_title_1.generateAutoTitle)(messages.map((m) => ({ role: m.role, content: m.content ?? '' })));
|
|
732
759
|
if (existing) {
|
|
760
|
+
Object.assign(existing, repositoryScope(req, res));
|
|
733
761
|
existing.title = title;
|
|
734
762
|
if (description)
|
|
735
763
|
existing.description = description;
|
|
@@ -741,6 +769,7 @@ function registerTicketsRoutes(deps) {
|
|
|
741
769
|
}
|
|
742
770
|
const id = s.next_id++;
|
|
743
771
|
const ticket = {
|
|
772
|
+
...repositoryScope(req, res),
|
|
744
773
|
id,
|
|
745
774
|
title,
|
|
746
775
|
description,
|
|
@@ -904,6 +933,7 @@ function registerTicketsRoutes(deps) {
|
|
|
904
933
|
flipTarget.labels = labels;
|
|
905
934
|
// PATCH-route semantics: apply only when the field was supplied;
|
|
906
935
|
// metadata merges keys instead of replacing the object.
|
|
936
|
+
Object.assign(flipTarget, repositoryScope(req, res));
|
|
907
937
|
if (hasAssignee)
|
|
908
938
|
flipTarget.assignee = assignee;
|
|
909
939
|
if (hasPrerequisites)
|
|
@@ -937,6 +967,7 @@ function registerTicketsRoutes(deps) {
|
|
|
937
967
|
// Legacy: insert new ticket
|
|
938
968
|
const id = s.next_id++;
|
|
939
969
|
const ticket = {
|
|
970
|
+
...repositoryScope(req, res),
|
|
940
971
|
id,
|
|
941
972
|
title: rawTitle,
|
|
942
973
|
description: descriptionForStore,
|
|
@@ -1057,13 +1088,12 @@ function registerTicketsRoutes(deps) {
|
|
|
1057
1088
|
// --resume; seeded with the just-inserted spec body). Default OFF at
|
|
1058
1089
|
// this layer so Explore-client payloads stay byte-identical — the MCP
|
|
1059
1090
|
// specs facade defaults it ON for agent-authored commit_drafts. The
|
|
1060
|
-
//
|
|
1061
|
-
//
|
|
1062
|
-
const
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
if (refineProvider) {
|
|
1091
|
+
// The originating agent provider is forwarded by the authenticated MCP
|
|
1092
|
+
// facade. Never borrow another installed provider (and its quota).
|
|
1093
|
+
const requestedAgentProvider = typeof body.agentProvider === 'string' ? body.agentProvider : null;
|
|
1094
|
+
const providerCheck = (0, provider_selection_1.validateRequestedProvider)(project, requestedAgentProvider);
|
|
1095
|
+
const refineProvider = providerCheck.ok ? providerCheck.provider : null;
|
|
1096
|
+
if (refineProvider && (0, providers_1.getAdapter)(refineProvider).capabilities.structuredActions === true) {
|
|
1067
1097
|
const refineTicketId = created.id;
|
|
1068
1098
|
const refineTitle = created.title;
|
|
1069
1099
|
const refineDescription = created.description;
|
|
@@ -1083,7 +1113,19 @@ function registerTicketsRoutes(deps) {
|
|
|
1083
1113
|
});
|
|
1084
1114
|
}
|
|
1085
1115
|
else {
|
|
1086
|
-
console.
|
|
1116
|
+
console.info('[project-router] agent-authored contract refine skipped', JSON.stringify({
|
|
1117
|
+
ticketId: created.id,
|
|
1118
|
+
provider: refineProvider ?? requestedAgentProvider,
|
|
1119
|
+
reason: 'provider-unsupported',
|
|
1120
|
+
}));
|
|
1121
|
+
broadcast({
|
|
1122
|
+
type: 'explore.contract_refine_failed',
|
|
1123
|
+
projectId: project.id,
|
|
1124
|
+
provider: refineProvider ?? requestedAgentProvider ?? 'unknown',
|
|
1125
|
+
ticketId: created.id,
|
|
1126
|
+
reason: 'provider-unsupported',
|
|
1127
|
+
timestamp: new Date().toISOString(),
|
|
1128
|
+
});
|
|
1087
1129
|
}
|
|
1088
1130
|
}
|
|
1089
1131
|
}
|
|
@@ -1134,6 +1176,7 @@ function registerTicketsRoutes(deps) {
|
|
|
1134
1176
|
const store = (0, ticket_store_1.mutateStore)(filePath, (s) => {
|
|
1135
1177
|
const id = s.next_id++;
|
|
1136
1178
|
const ticket = {
|
|
1179
|
+
...repositoryScope(req, res),
|
|
1137
1180
|
id,
|
|
1138
1181
|
title,
|
|
1139
1182
|
description,
|
|
@@ -1457,6 +1500,7 @@ function registerTicketsRoutes(deps) {
|
|
|
1457
1500
|
const store = (0, ticket_store_1.mutateStore)(filePath, (s) => {
|
|
1458
1501
|
const id = s.next_id++;
|
|
1459
1502
|
const ticket = {
|
|
1503
|
+
...repositoryScope(req, res),
|
|
1460
1504
|
id,
|
|
1461
1505
|
title: title.trim(),
|
|
1462
1506
|
description: typeof description === 'string' ? description : '',
|
|
@@ -1532,6 +1576,7 @@ function registerTicketsRoutes(deps) {
|
|
|
1532
1576
|
validationError = err;
|
|
1533
1577
|
return;
|
|
1534
1578
|
}
|
|
1579
|
+
Object.assign(ticket, repositoryScope(req, res));
|
|
1535
1580
|
if (title !== undefined)
|
|
1536
1581
|
ticket.title = title.trim();
|
|
1537
1582
|
if (description !== undefined)
|
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.resolveDefaultSpecModel = exports.formatDescriptionWithCriteria = exports.lightlyStructurePrompt = exports.deriveFallbackShortSummary = exports.extractShortSummary = exports.stripSpecMetadataSections = void 0;
|
|
4
7
|
exports.createProjectRouter = createProjectRouter;
|
|
5
8
|
const express_1 = require("express");
|
|
9
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
|
+
const project_repositories_1 = require("./project-repositories");
|
|
11
|
+
const file_summary_manager_1 = require("./file-summary-manager");
|
|
12
|
+
const project_code_discovery_1 = require("./project-code-discovery");
|
|
13
|
+
const feature_flags_1 = require("./feature-flags");
|
|
6
14
|
const hooks_1 = require("./hooks");
|
|
7
15
|
const rails_router_1 = require("./rails-router");
|
|
8
16
|
const profiles_router_1 = require("./profiles-router");
|
|
9
17
|
const plugins_router_1 = require("./plugins-router");
|
|
10
18
|
const code_explorer_router_1 = require("./code-explorer-router");
|
|
19
|
+
const code_activity_1 = require("./code-activity");
|
|
11
20
|
const jira_router_1 = require("./jira-router");
|
|
12
21
|
const ticket_store_1 = require("./ticket-store");
|
|
13
22
|
const workspace_resolution_1 = require("./workspace-resolution");
|
|
14
23
|
const workspace_manager_1 = require("./workspace-manager");
|
|
15
24
|
const blueprint_render_1 = require("./blueprint-render");
|
|
25
|
+
const milestone_progress_1 = require("./milestone-progress");
|
|
16
26
|
const blueprint_draft_parser_1 = require("./blueprint-draft-parser");
|
|
17
27
|
const blueprint_spec_quality_1 = require("./blueprint-spec-quality");
|
|
18
28
|
const file_story_manager_1 = require("./file-story-manager");
|
|
@@ -45,6 +55,16 @@ function createProjectRouter(registry) {
|
|
|
45
55
|
const projectId = req.params.projectId;
|
|
46
56
|
const ctx = registry.getContext(projectId);
|
|
47
57
|
if (!ctx) {
|
|
58
|
+
if (registry.getProjectRow(projectId)) {
|
|
59
|
+
const failure = registry.listFailedProjects().find((entry) => entry.project.id === projectId);
|
|
60
|
+
res.setHeader('Retry-After', '2');
|
|
61
|
+
res.status(503).json({
|
|
62
|
+
error: 'project_unavailable',
|
|
63
|
+
projectId,
|
|
64
|
+
detail: failure?.error ?? 'Project is registered but its database is not available yet.',
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
48
68
|
res.status(404).json({ error: 'Project not found' });
|
|
49
69
|
return;
|
|
50
70
|
}
|
|
@@ -91,45 +111,115 @@ function createProjectRouter(registry) {
|
|
|
91
111
|
const jiraRouter = (0, jira_router_1.createJiraRouter)();
|
|
92
112
|
router.use('/:projectId/jira', jiraRouter);
|
|
93
113
|
// Mount Code-Explorer router. FileSummaryManager comes from ProjectContext.
|
|
114
|
+
router.get('/:projectId/code/discover', async (req, res) => {
|
|
115
|
+
if (!(0, feature_flags_1.isCodeExplorerEnabled)()) {
|
|
116
|
+
res.status(404).json({ error: 'code_explorer_disabled' });
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
res.json(await (0, project_code_discovery_1.discoverProjectCode)(ctx(req).project, {
|
|
121
|
+
kind: String(req.query.kind ?? 'find'),
|
|
122
|
+
query: String(req.query.q ?? ''),
|
|
123
|
+
...(req.query.limit === undefined ? {} : { limit: Number(req.query.limit) }),
|
|
124
|
+
...(req.query.path === undefined ? {} : { path: String(req.query.path) }),
|
|
125
|
+
caseSensitive: req.query.caseSensitive === 'true',
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
res.status(400).json({ error: err.message });
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
// Activity reads recorded evidence across memberships; unlike source reads it
|
|
133
|
+
// can report unavailable roots explicitly without hiding the rest of a project.
|
|
134
|
+
router.get(['/:projectId/code/activity', '/:projectId/repositories/:repositoryId/code/activity'], async (req, res) => {
|
|
135
|
+
if (!(0, feature_flags_1.isCodeExplorerEnabled)()) {
|
|
136
|
+
res.status(404).json({ error: 'code_explorer_disabled' });
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
const context = ctx(req);
|
|
141
|
+
res.json(await (0, code_activity_1.listCodeActivity)(context.db, context.project, (0, code_activity_1.parseCodeActivityQuery)(req.query, req.params.repositoryId), code_explorer_router_1.filterCodeExplorerActivityPaths));
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
res.status(err instanceof code_activity_1.CodeActivityQueryError ? err.status : 500).json({ error: err instanceof code_activity_1.CodeActivityQueryError ? err.message : 'activity_unavailable' });
|
|
145
|
+
}
|
|
146
|
+
});
|
|
94
147
|
const codeRouterByCtx = new WeakMap();
|
|
95
|
-
|
|
148
|
+
const storyManagerByCtx = new WeakMap();
|
|
149
|
+
router.use(['/:projectId/repositories/:repositoryId/code', '/:projectId/code'], (req, res, next) => {
|
|
96
150
|
const projectCtx = ctx(req);
|
|
97
|
-
|
|
151
|
+
let repository;
|
|
152
|
+
try {
|
|
153
|
+
repository = (0, project_repositories_1.resolveProjectRepository)(projectCtx.project, req.params.repositoryId);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
res.status(404).json({ error: 'repository_not_found', detail: err.message });
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
if (!node_fs_1.default.statSync(repository.path).isDirectory())
|
|
161
|
+
throw new Error('not a directory');
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
res.status(503).json({ error: 'repository_unavailable', repositoryId: repository.id });
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
let cache = codeRouterByCtx.get(projectCtx);
|
|
168
|
+
if (!cache) {
|
|
169
|
+
cache = new Map();
|
|
170
|
+
codeRouterByCtx.set(projectCtx, cache);
|
|
171
|
+
}
|
|
172
|
+
const members = (0, project_repositories_1.getProjectRepositories)(projectCtx.project);
|
|
173
|
+
for (const [id, cached] of cache) {
|
|
174
|
+
if (!members.some(member => member.id === id && member.path === cached.path)) {
|
|
175
|
+
cache.delete(id);
|
|
176
|
+
projectCtx.fileSummaryManager.detachWatcher(projectCtx.project.id, id);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
let codeRouter = cache.get(repository.id)?.router;
|
|
180
|
+
if (!codeRouter) {
|
|
98
181
|
// Construction-story contribution generator — per-ctx (memoized with the
|
|
99
182
|
// router). Reuses the file-summary spawn skeleton with the story prompt,
|
|
100
183
|
// and the SAME monthly budget setting + ai_invocations surface, so the
|
|
101
184
|
// whole Code-section AI spend rides one budget (see file-story-manager).
|
|
102
185
|
const storyAdapter = (0, providers_1.getAdapter)(projectCtx.project.provider ?? 'claude');
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
186
|
+
let fileStoryManager = storyManagerByCtx.get(projectCtx);
|
|
187
|
+
if (!fileStoryManager)
|
|
188
|
+
fileStoryManager = new file_story_manager_1.FileStoryManager({
|
|
189
|
+
db: projectCtx.db,
|
|
190
|
+
broadcast: projectCtx.broadcast,
|
|
191
|
+
scheduler: projectCtx.fileSummaryManager,
|
|
192
|
+
generate: (0, file_summary_generator_1.createFileSummaryGenerator)({
|
|
193
|
+
adapter: storyAdapter,
|
|
194
|
+
cwd: projectCtx.project.path,
|
|
195
|
+
systemPrompt: file_story_manager_1.buildStorySystemPrompt,
|
|
196
|
+
}),
|
|
197
|
+
monthToDateSpend: (projectId) => {
|
|
198
|
+
const row = projectCtx.db.prepare(`SELECT COALESCE(SUM(total_cost_usd), 0) AS total FROM ai_invocations
|
|
113
199
|
WHERE project_id = ? AND surface = 'file-summary'
|
|
114
200
|
AND started_at >= strftime('%Y-%m-01', 'now')`).get(projectId);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
201
|
+
return row?.total ?? 0;
|
|
202
|
+
},
|
|
203
|
+
monthlyBudgetUsd: () => {
|
|
204
|
+
const raw = (0, desktop_db_1.getDesktopSetting)(projectCtx.desktopDb, 'summary_monthly_budget_usd');
|
|
205
|
+
const n = parseFloat(raw ?? '5.00');
|
|
206
|
+
return isNaN(n) ? 5.0 : n;
|
|
207
|
+
},
|
|
208
|
+
language: () => {
|
|
209
|
+
const raw = (0, desktop_db_1.getDesktopSetting)(projectCtx.desktopDb, 'summary_language');
|
|
210
|
+
return raw === 'es' ? 'es' : 'en';
|
|
211
|
+
},
|
|
212
|
+
providerId: () => storyAdapter.id,
|
|
213
|
+
getTicketSpec: projectCtx.getTicketSpec,
|
|
214
|
+
});
|
|
215
|
+
storyManagerByCtx.set(projectCtx, fileStoryManager);
|
|
216
|
+
codeRouter = (0, code_explorer_router_1.createCodeExplorerRouter)({
|
|
130
217
|
db: projectCtx.db,
|
|
131
|
-
projectPath:
|
|
218
|
+
projectPath: repository.path,
|
|
132
219
|
projectId: projectCtx.project.id,
|
|
220
|
+
repositoryId: repository.id,
|
|
221
|
+
repositoryName: repository.name,
|
|
222
|
+
includeLegacyProvenance: repository.isPrimary,
|
|
133
223
|
broadcast: projectCtx.broadcast,
|
|
134
224
|
fileSummaryManager: projectCtx.fileSummaryManager,
|
|
135
225
|
getTicketSpec: projectCtx.getTicketSpec,
|
|
@@ -139,27 +229,123 @@ function createProjectRouter(registry) {
|
|
|
139
229
|
// relocated (source tree still read from project.path). Resolved per-call.
|
|
140
230
|
resolveSummaryRoot: () => {
|
|
141
231
|
const exec = (0, workspace_resolution_1.resolveProjectExecution)({ slug: projectCtx.project.slug, path: projectCtx.project.path });
|
|
142
|
-
|
|
232
|
+
const artifactRoot = exec.relocated && exec.workspaceDir ? exec.workspaceDir : projectCtx.project.path;
|
|
233
|
+
return (0, file_summary_manager_1.repositorySummaryRoot)(artifactRoot, repository);
|
|
143
234
|
},
|
|
144
235
|
});
|
|
145
|
-
|
|
236
|
+
cache.set(repository.id, { path: repository.path, router: codeRouter });
|
|
237
|
+
}
|
|
146
238
|
codeRouter(req, res, next);
|
|
147
239
|
});
|
|
148
240
|
// Project Builder sidebar re-entry (add-project-builder D5): read the
|
|
149
241
|
// workspace-resident blueprint pair's source of truth. 404 when the project
|
|
150
242
|
// has no blueprint (every non-Builder project) — the sidebar entry hides.
|
|
151
243
|
router.get('/:projectId/blueprint', (req, res) => {
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
|
|
244
|
+
const projectCtx = ctx(req);
|
|
245
|
+
const project = projectCtx.project;
|
|
246
|
+
// `progress` is the server-derived live milestone model (premium-milestone-
|
|
247
|
+
// progress): counts by spec state, rails, chain, derived state — the same
|
|
248
|
+
// payload `blueprint.milestone_progress` re-broadcasts on every mutation.
|
|
249
|
+
const snapshot = (0, milestone_progress_1.readMilestoneProgress)({
|
|
250
|
+
db: projectCtx.db,
|
|
251
|
+
projectId: project.id,
|
|
252
|
+
workspaceDir: () => (0, milestone_progress_1.resolveBlueprintWorkspace)({ slug: project.slug, path: project.path }),
|
|
253
|
+
ticketsPath: () => ticketPath(req),
|
|
254
|
+
railJobs: projectCtx.railJobs,
|
|
255
|
+
railLoopRuns: projectCtx.railLoopRuns,
|
|
256
|
+
chains: projectCtx.milestoneChains ? () => projectCtx.milestoneChains.listActive() : undefined,
|
|
257
|
+
});
|
|
258
|
+
if (!snapshot) {
|
|
159
259
|
res.status(404).json({ error: 'no blueprint for this project' });
|
|
160
260
|
return;
|
|
161
261
|
}
|
|
162
|
-
res.json({ blueprint });
|
|
262
|
+
res.json({ blueprint: snapshot.blueprint, progress: snapshot.progress });
|
|
263
|
+
});
|
|
264
|
+
// Milestone launch chain (premium-milestone-progress D3): "Launch Milestone
|
|
265
|
+
// N" is server-owned — chunked into ≤3-spec rails, launched through the
|
|
266
|
+
// ordinary rails launch route, and (sequential) chained on each chunk's
|
|
267
|
+
// delivered branch. The client keeps NO plan in browser storage.
|
|
268
|
+
router.post('/:projectId/blueprint/milestones/:n/launch', async (req, res) => {
|
|
269
|
+
const projectCtx = ctx(req);
|
|
270
|
+
const n = Number.parseInt(String(req.params.n), 10);
|
|
271
|
+
if (!Number.isInteger(n) || n < 1 || n > 999) {
|
|
272
|
+
res.status(400).json({ error: 'invalid_milestone' });
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const rawMode = (req.body ?? {}).mode;
|
|
276
|
+
if (rawMode !== undefined && rawMode !== 'sequential' && rawMode !== 'parallel') {
|
|
277
|
+
res.status(400).json({ error: "mode must be 'sequential' or 'parallel'" });
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
const rawAuto = (req.body ?? {}).autoAdvance;
|
|
281
|
+
if (rawAuto !== undefined && typeof rawAuto !== 'boolean') {
|
|
282
|
+
res.status(400).json({ error: 'autoAdvance must be a boolean' });
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const chains = projectCtx.milestoneChains;
|
|
286
|
+
if (!chains) {
|
|
287
|
+
res.status(503).json({ error: 'milestone_chain_unavailable' });
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
try {
|
|
291
|
+
const result = await chains.start(n, rawMode ?? 'sequential', { autoAdvance: rawAuto });
|
|
292
|
+
if (result.ok) {
|
|
293
|
+
res.status(202).json({ chainId: result.chainId, launched: result.launched, pending: result.pending });
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
res.status(result.status).json({ error: result.error, ...(result.detail ? { detail: result.detail } : {}), ...(result.chainId ? { chainId: result.chainId } : {}) });
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
console.error('[project-router] milestone launch error:', err);
|
|
301
|
+
res.status(500).json({ error: 'Failed to launch the milestone' });
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
router.post('/:projectId/blueprint/chains/:id/resume', async (req, res) => {
|
|
305
|
+
const chains = ctx(req).milestoneChains;
|
|
306
|
+
if (!chains) {
|
|
307
|
+
res.status(503).json({ error: 'milestone_chain_unavailable' });
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
const result = await chains.resume(String(req.params.id));
|
|
312
|
+
res.status(result.status).json(result.ok ? { chain: result.chain } : { error: result.error, ...(result.detail ? { detail: result.detail } : {}) });
|
|
313
|
+
}
|
|
314
|
+
catch (err) {
|
|
315
|
+
console.error('[project-router] chain resume error:', err);
|
|
316
|
+
res.status(500).json({ error: 'Failed to resume the chain' });
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
// Wave checkpoints (D9): flip auto-advance on a live chain; turning it on
|
|
320
|
+
// at a checkpoint launches the next chunk right away.
|
|
321
|
+
router.patch('/:projectId/blueprint/chains/:id', async (req, res) => {
|
|
322
|
+
const chains = ctx(req).milestoneChains;
|
|
323
|
+
if (!chains) {
|
|
324
|
+
res.status(503).json({ error: 'milestone_chain_unavailable' });
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const autoAdvance = (req.body ?? {}).autoAdvance;
|
|
328
|
+
if (typeof autoAdvance !== 'boolean') {
|
|
329
|
+
res.status(400).json({ error: 'autoAdvance must be a boolean' });
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
try {
|
|
333
|
+
const result = await chains.setAutoAdvance(String(req.params.id), autoAdvance);
|
|
334
|
+
res.status(result.status).json(result.ok ? { chain: result.chain } : { error: result.error, ...(result.detail ? { detail: result.detail } : {}) });
|
|
335
|
+
}
|
|
336
|
+
catch (err) {
|
|
337
|
+
console.error('[project-router] chain patch error:', err);
|
|
338
|
+
res.status(500).json({ error: 'Failed to update the chain' });
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
router.post('/:projectId/blueprint/chains/:id/cancel', (req, res) => {
|
|
342
|
+
const chains = ctx(req).milestoneChains;
|
|
343
|
+
if (!chains) {
|
|
344
|
+
res.status(503).json({ error: 'milestone_chain_unavailable' });
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
const result = chains.cancel(String(req.params.id));
|
|
348
|
+
res.status(result.status).json(result.ok ? { chain: result.chain } : { error: result.error, ...(result.detail ? { detail: result.detail } : {}) });
|
|
163
349
|
});
|
|
164
350
|
// Relocate-artifacts gate (single chokepoint for ALL project-router ticket
|
|
165
351
|
// I/O): relocated ⇒ the registry entry's ticketsPath (workspace); legacy ⇒
|
|
@@ -190,6 +376,17 @@ function createProjectRouter(registry) {
|
|
|
190
376
|
res.status(400).json({ error: 'specs must contain at least one titled spec' });
|
|
191
377
|
return;
|
|
192
378
|
}
|
|
379
|
+
let repositoryScopes;
|
|
380
|
+
try {
|
|
381
|
+
repositoryScopes = rawSpecs.map((spec) => (0, project_repositories_1.validateTicketRepositoryIds)(project, spec && typeof spec === 'object' ? spec.repositoryIds : undefined));
|
|
382
|
+
}
|
|
383
|
+
catch (err) {
|
|
384
|
+
if (err instanceof project_repositories_1.RepositoryValidationError) {
|
|
385
|
+
res.status(err.status).json({ error: err.message, code: err.code });
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
throw err;
|
|
389
|
+
}
|
|
193
390
|
const exec = (0, workspace_resolution_1.resolveProjectExecution)({ slug: project.slug, path: project.path });
|
|
194
391
|
const workspace = exec.relocated && exec.workspaceDir
|
|
195
392
|
? exec.workspaceDir
|
|
@@ -230,6 +427,7 @@ function createProjectRouter(registry) {
|
|
|
230
427
|
? [indexToId.get(prerequisite)]
|
|
231
428
|
: [];
|
|
232
429
|
const ticket = {
|
|
430
|
+
...(repositoryScopes[index] ? { repositoryIds: repositoryScopes[index] } : {}),
|
|
233
431
|
id,
|
|
234
432
|
title: spec.title,
|
|
235
433
|
description: (0, project_router_helpers_1.formatDescriptionWithCriteria)(spec.description, spec.acceptanceCriteria),
|
|
@@ -257,6 +455,9 @@ function createProjectRouter(registry) {
|
|
|
257
455
|
milestone.status = 'committed';
|
|
258
456
|
milestone.ticketIds = created.map((t) => t.id);
|
|
259
457
|
(0, blueprint_render_1.writeBlueprintPair)(workspace, blueprint);
|
|
458
|
+
// A blueprint now exists for sure — forget any "absent" memo so the
|
|
459
|
+
// ticket_created broadcasts below re-derive the milestone progress.
|
|
460
|
+
projectCtx.milestoneProgress?.invalidate();
|
|
260
461
|
for (const ticket of created) {
|
|
261
462
|
projectCtx.broadcast({
|
|
262
463
|
type: 'ticket_created',
|