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
|
@@ -7,6 +7,7 @@ const auth_1 = require("../auth");
|
|
|
7
7
|
const mobile_redact_1 = require("./mobile-redact");
|
|
8
8
|
const mobile_auth_1 = require("./mobile-auth");
|
|
9
9
|
const mobile_devices_1 = require("./mobile-devices");
|
|
10
|
+
const mobile_missions_1 = require("./mobile-missions");
|
|
10
11
|
// The gateway's authenticated REST surface: the `/v1/*` allow-list. Each route
|
|
11
12
|
// forwards, in-process, via a REAL loopback HTTP request to
|
|
12
13
|
// http://127.0.0.1:<desktopPort> with the master token injected server-side as
|
|
@@ -34,7 +35,7 @@ function createMobileRouter(deps) {
|
|
|
34
35
|
// any `:pid`-scoped route is gated against the device's granted project set.
|
|
35
36
|
// An unrestricted device (null grant ⇒ all projects, legacy default) passes
|
|
36
37
|
// through; a scoped device gets 403 for any project it wasn't granted. The
|
|
37
|
-
// bare `GET /v1/projects` list
|
|
38
|
+
// bare `GET /v1/projects` list applies the same grant when shaping its response.
|
|
38
39
|
v1.use('/projects/:pid', (req, res, next) => {
|
|
39
40
|
const pid = seg(req.params.pid);
|
|
40
41
|
if (!PID_RE.test(pid)) {
|
|
@@ -56,11 +57,12 @@ function createMobileRouter(deps) {
|
|
|
56
57
|
});
|
|
57
58
|
/** Forward to the internal desktop API with the master token injected; redact
|
|
58
59
|
* the JSON response. `internalPath` is built from validated params only. */
|
|
59
|
-
async function forward(res, method, internalPath, query, body) {
|
|
60
|
+
async function forward(res, method, internalPath, query, body, transform) {
|
|
60
61
|
const url = internalBase + internalPath + (query ? `?${query}` : '');
|
|
61
62
|
try {
|
|
62
63
|
const init = {
|
|
63
64
|
method,
|
|
65
|
+
signal: AbortSignal.timeout(30_000),
|
|
64
66
|
headers: {
|
|
65
67
|
'x-desktop-token': (0, auth_1.loadOrGenerateToken)(),
|
|
66
68
|
...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),
|
|
@@ -79,7 +81,7 @@ function createMobileRouter(deps) {
|
|
|
79
81
|
res.status(502).json({ error: 'Bad upstream response' });
|
|
80
82
|
return;
|
|
81
83
|
}
|
|
82
|
-
res.status(upstream.status).json((0, mobile_redact_1.redact)(json));
|
|
84
|
+
res.status(upstream.status).json((0, mobile_redact_1.redact)(upstream.ok && transform ? transform(json) : json));
|
|
83
85
|
}
|
|
84
86
|
catch {
|
|
85
87
|
res.status(502).json({ error: 'Server unreachable' });
|
|
@@ -102,7 +104,13 @@ function createMobileRouter(deps) {
|
|
|
102
104
|
// —— Reads ——
|
|
103
105
|
v1.get('/projects', (req, res) => {
|
|
104
106
|
// Exact GET /api/projects is served by the desktop router (mounted at /api).
|
|
105
|
-
|
|
107
|
+
const allowed = (0, mobile_devices_1.getAllowedProjects)(deps.db, req.mobileDevice.id);
|
|
108
|
+
void forward(res, 'GET', '/api/projects', '', undefined, json => {
|
|
109
|
+
if (allowed === null || !json || typeof json !== 'object')
|
|
110
|
+
return json;
|
|
111
|
+
const value = json;
|
|
112
|
+
return { ...value, projects: value.projects?.filter(project => project.id && allowed.has(project.id)) ?? [] };
|
|
113
|
+
});
|
|
106
114
|
});
|
|
107
115
|
const projectReads = [
|
|
108
116
|
['/projects/:pid/tickets', '/tickets'],
|
|
@@ -164,6 +172,13 @@ function createMobileRouter(deps) {
|
|
|
164
172
|
narrowed.priority = b.priority;
|
|
165
173
|
if (typeof b.title === 'string')
|
|
166
174
|
narrowed.title = b.title;
|
|
175
|
+
if (b.repositoryIds !== undefined) {
|
|
176
|
+
if (!Array.isArray(b.repositoryIds) || !b.repositoryIds.length || b.repositoryIds.length > 30 || b.repositoryIds.some(id => typeof id !== 'string' || !PID_RE.test(id))) {
|
|
177
|
+
res.status(400).json({ error: 'Invalid repository selection' });
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
narrowed.repositoryIds = b.repositoryIds;
|
|
181
|
+
}
|
|
167
182
|
void forward(res, 'PATCH', `/api/projects/${encodeURIComponent(pid)}/tickets/${encodeURIComponent(tid)}`, '', narrowed);
|
|
168
183
|
});
|
|
169
184
|
v1.delete('/projects/:pid/tickets/:tid', (req, res) => {
|
|
@@ -206,6 +221,13 @@ function createMobileRouter(deps) {
|
|
|
206
221
|
}
|
|
207
222
|
if (typeof b.interactive === 'boolean')
|
|
208
223
|
narrowed.interactive = b.interactive;
|
|
224
|
+
if (b.repositoryIds !== undefined) {
|
|
225
|
+
if (!Array.isArray(b.repositoryIds) || !b.repositoryIds.length || b.repositoryIds.length > 30 || b.repositoryIds.some(id => typeof id !== 'string' || !PID_RE.test(id))) {
|
|
226
|
+
res.status(400).json({ error: 'Invalid repository selection' });
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
narrowed.repositoryIds = b.repositoryIds;
|
|
230
|
+
}
|
|
209
231
|
void forward(res, 'POST', `/api/projects/${encodeURIComponent(pid)}/rails/${encodeURIComponent(i)}/launch`, '', narrowed);
|
|
210
232
|
});
|
|
211
233
|
v1.put('/projects/:pid/rails/:i/engine', (req, res) => {
|
|
@@ -382,6 +404,12 @@ function createMobileRouter(deps) {
|
|
|
382
404
|
narrowed.acceptanceCriteria = b.acceptanceCriteria.filter((x) => typeof x === 'string');
|
|
383
405
|
void forward(res, 'POST', `/api/projects/${encodeURIComponent(pid)}/tickets/from-draft`, '', narrowed);
|
|
384
406
|
});
|
|
407
|
+
v1.use((0, mobile_missions_1.createMobileMissionsRouter)({ db: deps.db, upstream: async (method, path, body) => {
|
|
408
|
+
const response = await fetch(internalBase + path, { method, signal: AbortSignal.timeout(30_000),
|
|
409
|
+
headers: { 'x-desktop-token': (0, auth_1.loadOrGenerateToken)(), ...(body !== undefined ? { 'Content-Type': 'application/json' } : {}) },
|
|
410
|
+
...(body !== undefined ? { body: JSON.stringify(body) } : {}) });
|
|
411
|
+
return { status: response.status, json: await response.json() };
|
|
412
|
+
} }));
|
|
385
413
|
router.use('/v1', v1);
|
|
386
414
|
// Any unmatched gateway path → 404 JSON (NEVER falls through to a SPA handler;
|
|
387
415
|
// the gateway serves JSON/WS only, no static client).
|
|
@@ -393,6 +421,20 @@ function createMobileRouter(deps) {
|
|
|
393
421
|
/** The allow-list, exported for the CI drift test (asserts each entry resolves
|
|
394
422
|
* against a real internal route, and that no traversal param is accepted). */
|
|
395
423
|
exports.MOBILE_ALLOWLIST = [
|
|
424
|
+
{ method: 'GET', path: '/v1/capabilities' },
|
|
425
|
+
{ method: 'GET', path: '/v1/mission-models' },
|
|
426
|
+
{ method: 'GET', path: '/v1/projects/:pid/repositories' },
|
|
427
|
+
{ method: 'GET', path: '/v1/projects/:pid/missions' },
|
|
428
|
+
{ method: 'POST', path: '/v1/projects/:pid/missions' },
|
|
429
|
+
{ method: 'GET', path: '/v1/projects/:pid/missions/:cid' },
|
|
430
|
+
{ method: 'POST', path: '/v1/projects/:pid/missions/:cid/send' },
|
|
431
|
+
{ method: 'POST', path: '/v1/projects/:pid/missions/:cid/abort' },
|
|
432
|
+
{ method: 'PATCH', path: '/v1/projects/:pid/missions/:cid/queue/:queueId' },
|
|
433
|
+
{ method: 'DELETE', path: '/v1/projects/:pid/missions/:cid/queue/:queueId' },
|
|
434
|
+
{ method: 'POST', path: '/v1/projects/:pid/missions/:cid/queue/:queueId/steer' },
|
|
435
|
+
{ method: 'GET', path: '/v1/projects/:pid/missions/:cid/processes' },
|
|
436
|
+
{ method: 'GET', path: '/v1/projects/:pid/missions/:cid/processes/:processId/logs' },
|
|
437
|
+
{ method: 'DELETE', path: '/v1/projects/:pid/missions/:cid/processes/:processId' },
|
|
396
438
|
{ method: 'GET', path: '/v1/projects' },
|
|
397
439
|
{ method: 'GET', path: '/v1/projects/:pid/tickets' },
|
|
398
440
|
{ method: 'GET', path: '/v1/projects/:pid/tickets/:tid' },
|
|
@@ -16,6 +16,24 @@ const LOG_LINE_MAX = 2048;
|
|
|
16
16
|
const LOG_BATCH_MAX = 60;
|
|
17
17
|
function topicFor(type) {
|
|
18
18
|
switch (type) {
|
|
19
|
+
case 'agent_stream':
|
|
20
|
+
case 'agent_done':
|
|
21
|
+
case 'agent_partial':
|
|
22
|
+
case 'agent_error':
|
|
23
|
+
case 'agent_title':
|
|
24
|
+
case 'agent_tool':
|
|
25
|
+
case 'agent_tool_result':
|
|
26
|
+
case 'agent_queued':
|
|
27
|
+
case 'agent_dequeued':
|
|
28
|
+
case 'agent_steered':
|
|
29
|
+
case 'agent_queue_edited':
|
|
30
|
+
case 'agent_queue_removed':
|
|
31
|
+
case 'agent_queue_cleared':
|
|
32
|
+
case 'agent_input_receipt':
|
|
33
|
+
case 'agent_pr_decision':
|
|
34
|
+
case 'background_process.started':
|
|
35
|
+
case 'background_process.updated':
|
|
36
|
+
case 'background_process.exited': return 'missions';
|
|
19
37
|
case 'queue': return 'queue';
|
|
20
38
|
case 'phase': return 'phase';
|
|
21
39
|
case 'ticket_created':
|
|
@@ -107,9 +125,11 @@ class MobileWsBridge {
|
|
|
107
125
|
// it so a companion can only subscribe to projects it was granted. Default
|
|
108
126
|
// resolver (undefined) keeps every device unrestricted — byte-identical legacy.
|
|
109
127
|
_allowedProjectsFor;
|
|
128
|
+
_missionProjectFor;
|
|
110
129
|
constructor(opts = {}) {
|
|
111
130
|
this._clock = opts.clock ?? (() => Date.now());
|
|
112
131
|
this._allowedProjectsFor = opts.allowedProjectsFor ?? (() => null);
|
|
132
|
+
this._missionProjectFor = opts.missionProjectFor ?? (() => null);
|
|
113
133
|
}
|
|
114
134
|
start() {
|
|
115
135
|
if (this._unsub)
|
|
@@ -227,10 +247,34 @@ class MobileWsBridge {
|
|
|
227
247
|
if (!topic)
|
|
228
248
|
return;
|
|
229
249
|
for (const s of this._socks) {
|
|
250
|
+
const allowed = this._allowedProjectsFor(s.deviceId);
|
|
251
|
+
if (topic === 'missions') {
|
|
252
|
+
if (allowed !== null || !s.topics.has('missions'))
|
|
253
|
+
continue;
|
|
254
|
+
const value = msg;
|
|
255
|
+
const process = value.process;
|
|
256
|
+
const cid = typeof value.conversationId === 'string' ? value.conversationId : process?.chatId;
|
|
257
|
+
const projectId = cid ? this._missionProjectFor(cid) : null;
|
|
258
|
+
if (!projectId || !s.projects.has(projectId))
|
|
259
|
+
continue;
|
|
260
|
+
// The snapshot is authoritative. Events are bounded invalidation hints;
|
|
261
|
+
// never stream tool inputs/results or arbitrary provider payloads.
|
|
262
|
+
this.send(s, (0, mobile_redact_1.redact)({ type: 'mission.updated', projectId, conversationId: cid, event: msg.type, timestamp: value.timestamp,
|
|
263
|
+
...(msg.type === 'agent_stream' ? { delta: String(value.delta ?? '').slice(0, 16_000) } : {}),
|
|
264
|
+
...(msg.type === 'agent_tool' ? { tool: String(value.tool ?? '').slice(0, 100) } : {}) }));
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
230
267
|
if (topic === 'hub') {
|
|
231
268
|
// App-level (project registry): always forward, but translate to the
|
|
232
269
|
// legacy mobile wire types and redact (the projects payload carries `path`).
|
|
233
|
-
|
|
270
|
+
if (msg.type === 'desktop.projects')
|
|
271
|
+
this.send(s, (0, mobile_redact_1.redact)(toMobileWire({ ...msg, projects: allowed === null ? msg.projects : msg.projects.filter(project => allowed.has(project.id)) })));
|
|
272
|
+
else if (msg.type === 'desktop.project_added') {
|
|
273
|
+
if (allowed === null || allowed.has(msg.project.id))
|
|
274
|
+
this.send(s, (0, mobile_redact_1.redact)(toMobileWire(msg)));
|
|
275
|
+
}
|
|
276
|
+
else if (msg.type === 'desktop.project_removed' && (allowed === null || allowed.has(msg.projectId)))
|
|
277
|
+
this.send(s, (0, mobile_redact_1.redact)(toMobileWire(msg)));
|
|
234
278
|
continue;
|
|
235
279
|
}
|
|
236
280
|
// App-level desktop budget alert: deliver to subscribers holding the
|
|
@@ -239,12 +283,12 @@ class MobileWsBridge {
|
|
|
239
283
|
// topic gate like every other delivery — a device that never subscribed to
|
|
240
284
|
// `alerts` (topics init empty) must NOT receive these frames (BUG-MOBILE-05).
|
|
241
285
|
if (topic === 'alerts' && msg.type === 'desktop_daily_budget_exceeded') {
|
|
242
|
-
if (s.topics.has('alerts'))
|
|
286
|
+
if (allowed === null && s.topics.has('alerts'))
|
|
243
287
|
this.send(s, (0, mobile_redact_1.redact)(toMobileWire(msg)));
|
|
244
288
|
continue;
|
|
245
289
|
}
|
|
246
290
|
const projectId = msg.projectId;
|
|
247
|
-
if (!projectId || !s.projects.has(projectId))
|
|
291
|
+
if (!projectId || !s.projects.has(projectId) || (allowed !== null && !allowed.has(projectId)))
|
|
248
292
|
continue;
|
|
249
293
|
if (topic === 'jobtail') {
|
|
250
294
|
if (!s.watchedJob || s.watchedJob.projectId !== projectId)
|
|
@@ -278,7 +322,8 @@ class MobileWsBridge {
|
|
|
278
322
|
flushLogs() {
|
|
279
323
|
for (const s of this._socks) {
|
|
280
324
|
for (const [jobId, lines] of s.logBuf) {
|
|
281
|
-
|
|
325
|
+
const allowed = this._allowedProjectsFor(s.deviceId);
|
|
326
|
+
if (lines.length === 0 || !s.watchedJob || s.watchedJob.jobId !== jobId || (allowed !== null && !allowed.has(s.watchedJob.projectId)))
|
|
282
327
|
continue;
|
|
283
328
|
const dropped = s.logDropped.get(jobId) ?? 0;
|
|
284
329
|
this.send(s, { type: 'log_batch', jobId, lines, dropped });
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveRepositoryDeliveryBases = resolveRepositoryDeliveryBases;
|
|
4
|
+
const rail_pr_store_1 = require("./rail-pr-store");
|
|
5
|
+
const project_repositories_1 = require("./project-repositories");
|
|
6
|
+
/** Resolve the latest delivered head per member from durable milestone history.
|
|
7
|
+
* The request names deliveries, never invents a repository/branch/SHA binding. */
|
|
8
|
+
async function resolveRepositoryDeliveryBases(db, project, selectedIds, value, git) {
|
|
9
|
+
const repositoryBaseBranches = {};
|
|
10
|
+
const repositoryBaseShas = {};
|
|
11
|
+
if (value === undefined)
|
|
12
|
+
return { repositoryBaseBranches, repositoryBaseShas };
|
|
13
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > 100 || value.some((id) => typeof id !== 'string' || id.length === 0 || id.length > 200)) {
|
|
14
|
+
throw new Error('baseDeliveryIds must be a nonempty list of at most 100 delivery IDs');
|
|
15
|
+
}
|
|
16
|
+
const primary = (0, project_repositories_1.resolveProjectRepository)(project);
|
|
17
|
+
const bases = new Map();
|
|
18
|
+
for (const id of value) {
|
|
19
|
+
const row = (0, rail_pr_store_1.getPrDelivery)(db, id);
|
|
20
|
+
if (!row || row.parent_delivery_id)
|
|
21
|
+
throw new Error(`Unknown base delivery: ${id}`);
|
|
22
|
+
const snapshot = (0, rail_pr_store_1.toPrDeliverySnapshot)(row);
|
|
23
|
+
if (!['on_review', 'no_changes', 'pr_draft', 'pr_ready', 'completed', 'merged'].includes(snapshot.decision))
|
|
24
|
+
throw new Error(`Base delivery ${id} is not ready`);
|
|
25
|
+
const entries = snapshot.repositoryDeliveries?.length ? snapshot.repositoryDeliveries : [{
|
|
26
|
+
repositoryId: primary.id, decision: snapshot.decision, baseBranch: snapshot.baseBranch,
|
|
27
|
+
branch: snapshot.branch ?? (snapshot.branches.length === 1 ? snapshot.branches[0].branch : null),
|
|
28
|
+
deliverySha: snapshot.deliverySha ?? (snapshot.branches.length === 1 ? snapshot.branches[0].finalSha : null),
|
|
29
|
+
}];
|
|
30
|
+
for (const entry of entries) {
|
|
31
|
+
if (!selectedIds.includes(entry.repositoryId) || ['no_changes', 'completed'].includes(entry.decision))
|
|
32
|
+
continue;
|
|
33
|
+
const branch = entry.decision === 'merged' ? (('integrationBranch' in entry && entry.integrationBranch) || entry.baseBranch) : entry.branch;
|
|
34
|
+
if (!branch || !entry.deliverySha)
|
|
35
|
+
throw new Error(`Base delivery ${id} has no verified head for repository ${entry.repositoryId}`);
|
|
36
|
+
bases.set(entry.repositoryId, { branch, sha: entry.deliverySha, merged: entry.decision === 'merged' });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
for (const [id, base] of bases) {
|
|
40
|
+
const repository = (0, project_repositories_1.resolveProjectRepository)(project, id);
|
|
41
|
+
const result = await git.run(['rev-parse', '--verify', `refs/heads/${base.branch}`], repository.path);
|
|
42
|
+
const head = result.stdout.trim();
|
|
43
|
+
if (result.code !== 0 || !/^[a-f0-9]{40,64}$/i.test(head))
|
|
44
|
+
throw new Error(`Missing base branch ${base.branch} in ${repository.name}`);
|
|
45
|
+
if (base.merged) {
|
|
46
|
+
const contains = await git.run(['merge-base', '--is-ancestor', base.sha, head], repository.path);
|
|
47
|
+
if (contains.code !== 0)
|
|
48
|
+
throw new Error(`Integrated base no longer contains the delivered commit in ${repository.name}`);
|
|
49
|
+
}
|
|
50
|
+
else if (head !== base.sha)
|
|
51
|
+
throw new Error(`Delivered base branch changed in ${repository.name}`);
|
|
52
|
+
repositoryBaseBranches[id] = base.branch;
|
|
53
|
+
repositoryBaseShas[id] = head;
|
|
54
|
+
}
|
|
55
|
+
return { repositoryBaseBranches, repositoryBaseShas };
|
|
56
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.repositoryDeliveryCheckoutTarget = repositoryDeliveryCheckoutTarget;
|
|
4
|
+
exports.checkoutRepositoryDelivery = checkoutRepositoryDelivery;
|
|
5
|
+
const ids_1 = require("./ids");
|
|
6
|
+
const repo_lock_1 = require("./repo-lock");
|
|
7
|
+
const project_git_1 = require("./project-git");
|
|
8
|
+
const rail_pr_store_1 = require("./rail-pr-store");
|
|
9
|
+
const rail_worktree_release_1 = require("./rail-worktree-release");
|
|
10
|
+
const multi_repo_execution_1 = require("./multi-repo-execution");
|
|
11
|
+
const agent_chat_registry_1 = require("./agent-chat-registry");
|
|
12
|
+
function repositoryDeliveryCheckoutTarget(delivery) {
|
|
13
|
+
if (delivery.branch && delivery.deliverySha)
|
|
14
|
+
return { branch: delivery.branch, sha: delivery.deliverySha };
|
|
15
|
+
const units = delivery.branches;
|
|
16
|
+
if (!delivery.branch && !delivery.deliverySha && units.length === 1 && units[0].succeeded && units[0].finalSha &&
|
|
17
|
+
units[0].deliveryOutcome !== 'blocked' && units[0].deliveryOutcome !== 'no_changes' &&
|
|
18
|
+
units[0].implementationOutcome !== 'failed' && units[0].changed !== false) {
|
|
19
|
+
return { branch: units[0].branch, sha: units[0].finalSha };
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
function checkoutBlock(delivery) {
|
|
24
|
+
if ((0, rail_pr_store_1.isTerminalPrDecision)(delivery.decision) || ['building', 'implementation_failed', 'no_changes'].includes(delivery.decision))
|
|
25
|
+
return 'delivery is not awaiting implementation review';
|
|
26
|
+
if (delivery.deliveryOutcome === 'blocked')
|
|
27
|
+
return 'delivery is blocked and has no safely checkoutable result';
|
|
28
|
+
const target = repositoryDeliveryCheckoutTarget(delivery);
|
|
29
|
+
return target && /^[0-9a-f]{40,64}$/i.test(target.sha) ? null : 'delivery has no verified commit available for checkout';
|
|
30
|
+
}
|
|
31
|
+
/** Checkout changes one physical checkout; it never accepts a shared spec. */
|
|
32
|
+
async function checkoutRepositoryDelivery(deps, input) {
|
|
33
|
+
const parent = (0, rail_pr_store_1.getPrDelivery)(deps.db, input.prDeliveryId);
|
|
34
|
+
if (!parent || parent.parent_delivery_id || !parent.execution_manifest)
|
|
35
|
+
return { status: 404, body: { error: 'Unknown repository delivery group' } };
|
|
36
|
+
const children = (0, multi_repo_execution_1.listRepositoryDeliveries)(deps.db, parent.id);
|
|
37
|
+
if (!input.repositoryId && children.length !== 1)
|
|
38
|
+
return { status: 400, body: { error: 'repositoryId_required', detail: 'Choose the repository checkout to move.' } };
|
|
39
|
+
const child = input.repositoryId ? children.find((row) => row.repository_id === input.repositoryId) : children[0];
|
|
40
|
+
if (!child?.repository_path)
|
|
41
|
+
return { status: 404, body: { error: 'Unknown repository in this delivery' } };
|
|
42
|
+
return (0, repo_lock_1.withRepoLock)(child.repository_path, async () => {
|
|
43
|
+
deps.assertAdmission?.();
|
|
44
|
+
const active = (0, rail_pr_store_1.getActivePrDeliveryByRail)(deps.db, parent.rail_index);
|
|
45
|
+
if (active?.id !== parent.id)
|
|
46
|
+
return { status: 409, body: { error: 'stale_decision', currentPrDeliveryId: active?.id ?? null } };
|
|
47
|
+
if (active.operation_token)
|
|
48
|
+
return { status: 409, body: { error: 'operation_in_progress' } };
|
|
49
|
+
const token = (0, ids_1.newId)();
|
|
50
|
+
if (!(0, rail_pr_store_1.claimPrDeliveryOperation)(deps.db, parent.id, active.decision, 'checkout', token))
|
|
51
|
+
return { status: 409, body: { error: 'operation_in_progress' } };
|
|
52
|
+
const perform = async () => {
|
|
53
|
+
const current = (0, rail_pr_store_1.getPrDelivery)(deps.db, child.id);
|
|
54
|
+
const snap = (0, rail_pr_store_1.toPrDeliverySnapshot)(current);
|
|
55
|
+
const block = checkoutBlock(snap);
|
|
56
|
+
if (block)
|
|
57
|
+
return { status: 409, body: { error: 'checkout_not_deliverable', detail: block } };
|
|
58
|
+
const target = repositoryDeliveryCheckoutTarget(snap);
|
|
59
|
+
const cleanliness = await (0, project_git_1.inspectProjectCheckoutCleanliness)(child.repository_path);
|
|
60
|
+
if (!cleanliness.ok)
|
|
61
|
+
return { status: 409, body: { error: 'checkout_safety_unknown', detail: cleanliness.detail } };
|
|
62
|
+
const git = await (0, project_git_1.getProjectGitInfo)(child.repository_path);
|
|
63
|
+
if (!git.git)
|
|
64
|
+
return { status: 409, body: { error: 'checkout_unavailable', detail: 'repository is not a Git checkout' } };
|
|
65
|
+
const cleanupWarnings = await (0, rail_worktree_release_1.releaseRailWorktrees)({
|
|
66
|
+
db: deps.db, git: deps.git, repoDir: child.repository_path, worktreeIds: snap.worktreeIds,
|
|
67
|
+
expectedHeadByBranch: (0, rail_worktree_release_1.durableBranchHeads)(snap.branches), overlayEvidenceByBranch: (0, rail_worktree_release_1.durableOverlayCleanupEvidence)(snap.branches),
|
|
68
|
+
settlementIgnoredByBranch: (0, rail_worktree_release_1.durableSettlementIgnoredPaths)(snap.branches),
|
|
69
|
+
onSafetyArchive: (archive) => {
|
|
70
|
+
if (!(0, rail_pr_store_1.appendPrDeliverySafetyArchive)(deps.db, child.id, archive))
|
|
71
|
+
throw new Error(`delivery ${child.id} disappeared while recording safety archive`);
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
(0, rail_pr_store_1.transitionDecision)(deps.db, child.id, current.decision, current.decision, {
|
|
75
|
+
cleanupWarnings,
|
|
76
|
+
...(cleanupWarnings.length ? { statusCode: 'cleanup_incomplete' } : snap.statusCode === 'cleanup_incomplete' ? { statusCode: null } : {}),
|
|
77
|
+
});
|
|
78
|
+
const stillActive = (0, rail_pr_store_1.getActivePrDeliveryByRail)(deps.db, parent.rail_index);
|
|
79
|
+
const outcome = stillActive?.id === parent.id
|
|
80
|
+
? await (0, project_git_1.checkoutProjectReviewBranch)(child.repository_path, target.branch, target.sha)
|
|
81
|
+
: { ok: false, error: 'The delivery generation changed before checkout.' };
|
|
82
|
+
if (!outcome.ok)
|
|
83
|
+
return { status: 409, body: { error: 'checkout_failed', detail: [outcome.error, ...cleanupWarnings].join('\n') } };
|
|
84
|
+
return { status: 200, body: { ok: true, repositoryId: child.repository_id, branch: target.branch,
|
|
85
|
+
git: await (0, project_git_1.getProjectGitInfo)(child.repository_path), cleanupWarnings } };
|
|
86
|
+
};
|
|
87
|
+
let result;
|
|
88
|
+
try {
|
|
89
|
+
result = await perform();
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
(0, rail_pr_store_1.releasePrDeliveryOperation)(deps.db, parent.id, token);
|
|
93
|
+
}
|
|
94
|
+
const updated = (0, multi_repo_execution_1.refreshRepositoryDeliveryGroup)(deps.db, parent.id);
|
|
95
|
+
const parentSnap = (0, rail_pr_store_1.toPrDeliverySnapshot)(updated);
|
|
96
|
+
deps.broadcast((0, rail_pr_store_1.toRailPrStateMessage)(deps.project.id, parentSnap));
|
|
97
|
+
if (updated.origin_conversation_id)
|
|
98
|
+
(deps.agentChat ?? agent_chat_registry_1.getAgentChatManager)()?.updatePrDecisionCard(updated.origin_conversation_id, (0, rail_pr_store_1.toPrDecisionCardEnvelope)(deps.project.id, parentSnap));
|
|
99
|
+
return { status: result.status, body: { ...result.body, snapshot: parentSnap } };
|
|
100
|
+
});
|
|
101
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeRepositoryGroupDecision = executeRepositoryGroupDecision;
|
|
4
|
+
const ids_1 = require("./ids");
|
|
5
|
+
const repo_lock_1 = require("./repo-lock");
|
|
6
|
+
const workspace_resolution_1 = require("./workspace-resolution");
|
|
7
|
+
const agent_chat_registry_1 = require("./agent-chat-registry");
|
|
8
|
+
const rail_pr_decision_1 = require("./rail-pr-decision");
|
|
9
|
+
const rail_pr_store_1 = require("./rail-pr-store");
|
|
10
|
+
const rail_pr_ticket_effects_1 = require("./rail-pr-ticket-effects");
|
|
11
|
+
const multi_repo_execution_1 = require("./multi-repo-execution");
|
|
12
|
+
const multi_repo_execution_store_1 = require("./multi-repo-execution-store");
|
|
13
|
+
function completed(row) {
|
|
14
|
+
return row.decision === 'merged' || row.decision === 'completed';
|
|
15
|
+
}
|
|
16
|
+
/** A parent operation has one lease; each child keeps its own existing safe Git
|
|
17
|
+
* decision and immutable SHA. A retry never reintegrates accepted repositories. */
|
|
18
|
+
async function executeRepositoryGroupDecision(deps, input) {
|
|
19
|
+
const parent = (0, rail_pr_store_1.getPrDelivery)(deps.db, input.prDeliveryId);
|
|
20
|
+
if (!parent || !(0, multi_repo_execution_store_1.readExecutionManifest)(parent.execution_manifest))
|
|
21
|
+
return { status: 404, body: { error: 'Unknown repository delivery group' } };
|
|
22
|
+
if (parent.decision !== input.expectedDecision)
|
|
23
|
+
return { status: 409, body: { error: 'stale_decision', current: parent.decision } };
|
|
24
|
+
if (['building', 'merged', 'completed', 'discarded', 'superseded'].includes(parent.decision)) {
|
|
25
|
+
return { status: 409, body: { error: 'stale_decision', current: parent.decision, reason: 'illegal_action' } };
|
|
26
|
+
}
|
|
27
|
+
const children = (0, multi_repo_execution_1.listRepositoryDeliveries)(deps.db, parent.id);
|
|
28
|
+
const selected = input.repositoryId ? children.filter((row) => row.repository_id === input.repositoryId) : children;
|
|
29
|
+
if (selected.length === 0)
|
|
30
|
+
return { status: 404, body: { error: 'Unknown repository in this delivery' } };
|
|
31
|
+
if ((input.action === 'discard' || input.action === 'dismiss') && children.some(completed)) {
|
|
32
|
+
return { status: 409, body: { error: 'partial_delivery_already_integrated', detail: 'Complete the remaining repository deliveries; already accepted commits cannot be discarded.' } };
|
|
33
|
+
}
|
|
34
|
+
const steps = selected.flatMap((row) => {
|
|
35
|
+
if (completed(row) || row.decision === 'discarded' || row.decision === 'superseded')
|
|
36
|
+
return [];
|
|
37
|
+
const action = row.decision === 'no_changes' &&
|
|
38
|
+
['merge-local', 'poll-merge', 'acknowledge-no-changes'].includes(input.action)
|
|
39
|
+
? 'acknowledge-no-changes' : input.action;
|
|
40
|
+
return (0, rail_pr_decision_1.actionAllowed)(action, row) ? [{ row, action }] : [];
|
|
41
|
+
});
|
|
42
|
+
if (steps.length === 0)
|
|
43
|
+
return { status: 409, body: { error: 'stale_decision', current: parent.decision, reason: 'illegal_action' } };
|
|
44
|
+
const token = (0, ids_1.newId)();
|
|
45
|
+
if (!(0, rail_pr_store_1.claimPrDeliveryOperation)(deps.db, parent.id, parent.decision, input.action, token)) {
|
|
46
|
+
return { status: 409, body: { error: 'operation_in_progress', current: (0, rail_pr_store_1.getPrDelivery)(deps.db, parent.id)?.decision } };
|
|
47
|
+
}
|
|
48
|
+
const outcomes = [];
|
|
49
|
+
try {
|
|
50
|
+
deps.assertAdmission?.();
|
|
51
|
+
const ticketFile = deps.ticketFile ?? (0, workspace_resolution_1.resolveProjectExecution)(deps.project).ticketsPath;
|
|
52
|
+
for (const { row, action } of steps) {
|
|
53
|
+
const current = (0, rail_pr_store_1.getPrDelivery)(deps.db, row.id);
|
|
54
|
+
if (!current || current.parent_delivery_id !== parent.id || current.repository_path !== row.repository_path) {
|
|
55
|
+
outcomes.push({ repositoryId: row.repository_id, status: 409, body: { error: 'repository_delivery_changed' } });
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const childDeps = {
|
|
59
|
+
...deps, project: { ...deps.project, path: row.repository_path }, ticketFile,
|
|
60
|
+
repositoryChildOf: parent.id, repositoryIntegrationBranch: (0, multi_repo_execution_store_1.readExecutionManifest)(row.execution_manifest)?.repositories.find((repo) => repo.repositoryId === row.repository_id)?.integrationBranch, jiraSyncManager: undefined, broadcast: () => { }, agentChat: () => null,
|
|
61
|
+
};
|
|
62
|
+
try {
|
|
63
|
+
const perform = () => (0, rail_pr_decision_1.executePrDecision)(childDeps, { prDeliveryId: row.id, action, expectedDecision: current.decision });
|
|
64
|
+
// merge-local already locks around its checkout resolution and merge.
|
|
65
|
+
const result = action === 'merge-local' ? await perform() : await (0, repo_lock_1.withRepoLock)(row.repository_path, perform);
|
|
66
|
+
outcomes.push({ repositoryId: row.repository_id, ...result });
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
outcomes.push({ repositoryId: row.repository_id, status: 500, body: { error: 'repository_delivery_failed', detail: error instanceof Error ? error.message : String(error) } });
|
|
70
|
+
}
|
|
71
|
+
(0, multi_repo_execution_1.refreshRepositoryDeliveryGroup)(deps.db, parent.id);
|
|
72
|
+
}
|
|
73
|
+
const aggregate = (0, multi_repo_execution_1.refreshRepositoryDeliveryGroup)(deps.db, parent.id);
|
|
74
|
+
if (aggregate.decision === 'merged' || aggregate.decision === 'completed' || aggregate.decision === 'discarded') {
|
|
75
|
+
const effect = (0, rail_pr_ticket_effects_1.applyRailPrTicketEffect)(deps, aggregate.id);
|
|
76
|
+
if (!effect.ok)
|
|
77
|
+
(0, rail_pr_store_1.transitionClaimedDecision)(deps.db, aggregate.id, aggregate.decision, aggregate.decision, token, {
|
|
78
|
+
statusCode: 'cleanup_incomplete', cleanupWarnings: [`Shared ticket update pending: ${effect.error ?? 'unknown error'}`],
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
const failure = outcomes.find((outcome) => outcome.status >= 400);
|
|
82
|
+
return {
|
|
83
|
+
status: failure?.status ?? 200,
|
|
84
|
+
body: { ok: !failure, ...(failure ? { error: 'repository_delivery_incomplete', detail: outcomes.filter((outcome) => outcome.status >= 400).map((outcome) => `${outcome.repositoryId}: ${outcome.body.detail ?? outcome.body.error ?? 'delivery failed'}`).join('; ') } : {}), repositories: outcomes,
|
|
85
|
+
decision: aggregate.decision, prState: aggregate.pr_state, statusCode: aggregate.status_code, statusDetail: aggregate.status_detail,
|
|
86
|
+
snapshot: (0, rail_pr_store_1.toPrDeliverySnapshot)((0, rail_pr_store_1.getPrDelivery)(deps.db, parent.id)), delivery: (0, rail_pr_store_1.toPrDeliverySnapshot)((0, rail_pr_store_1.getPrDelivery)(deps.db, parent.id)) },
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
(0, rail_pr_store_1.releasePrDeliveryOperation)(deps.db, parent.id, token);
|
|
91
|
+
const current = (0, rail_pr_store_1.getPrDelivery)(deps.db, parent.id);
|
|
92
|
+
if (current) {
|
|
93
|
+
const snap = (0, rail_pr_store_1.toPrDeliverySnapshot)(current);
|
|
94
|
+
deps.broadcast((0, rail_pr_store_1.toRailPrStateMessage)(deps.project.id, snap));
|
|
95
|
+
if (current.origin_conversation_id) {
|
|
96
|
+
(deps.agentChat ?? agent_chat_registry_1.getAgentChatManager)()?.updatePrDecisionCard(current.origin_conversation_id, (0, rail_pr_store_1.toPrDecisionCardEnvelope)(deps.project.id, snap));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.migrateMultiRepoExecution = migrateMultiRepoExecution;
|
|
4
|
+
exports.readExecutionManifest = readExecutionManifest;
|
|
5
|
+
exports.getRepositoryExecutionReferences = getRepositoryExecutionReferences;
|
|
6
|
+
exports.executionManifestPrompt = executionManifestPrompt;
|
|
7
|
+
/** Project DB migration 59. Desktop membership is migrated separately. */
|
|
8
|
+
function migrateMultiRepoExecution(db) {
|
|
9
|
+
db.exec(`
|
|
10
|
+
ALTER TABLE rail_pr_deliveries ADD COLUMN parent_delivery_id TEXT REFERENCES rail_pr_deliveries(id);
|
|
11
|
+
ALTER TABLE rail_pr_deliveries ADD COLUMN repository_id TEXT;
|
|
12
|
+
ALTER TABLE rail_pr_deliveries ADD COLUMN repository_path TEXT;
|
|
13
|
+
ALTER TABLE rail_pr_deliveries ADD COLUMN execution_manifest TEXT;
|
|
14
|
+
ALTER TABLE rail_pr_deliveries ADD COLUMN repository_deliveries TEXT NOT NULL DEFAULT '[]';
|
|
15
|
+
ALTER TABLE rail_worktrees ADD COLUMN repository_id TEXT;
|
|
16
|
+
ALTER TABLE rail_worktrees ADD COLUMN repository_path TEXT;
|
|
17
|
+
ALTER TABLE loop_runs ADD COLUMN execution_manifest TEXT;
|
|
18
|
+
CREATE INDEX idx_rail_pr_delivery_parent ON rail_pr_deliveries(parent_delivery_id);
|
|
19
|
+
CREATE INDEX idx_rail_worktree_repository ON rail_worktrees(repository_id);
|
|
20
|
+
DROP INDEX IF EXISTS idx_rail_pr_deliveries_one_active_per_rail;
|
|
21
|
+
CREATE UNIQUE INDEX idx_rail_pr_deliveries_one_active_per_rail
|
|
22
|
+
ON rail_pr_deliveries(rail_index)
|
|
23
|
+
WHERE parent_delivery_id IS NULL AND decision NOT IN ('completed','merged','discarded','superseded');
|
|
24
|
+
`);
|
|
25
|
+
}
|
|
26
|
+
function readExecutionManifest(raw) {
|
|
27
|
+
if (!raw)
|
|
28
|
+
return null;
|
|
29
|
+
try {
|
|
30
|
+
const value = JSON.parse(raw);
|
|
31
|
+
if (value.version !== 1 || !Array.isArray(value.repositories) || !Array.isArray(value.selectedRepositoryIds))
|
|
32
|
+
return null;
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function getRepositoryExecutionReferences(db, repositoryId) {
|
|
40
|
+
const deliveries = db.prepare(`SELECT id, parent_delivery_id, run_ids FROM rail_pr_deliveries
|
|
41
|
+
WHERE repository_id = ? AND decision NOT IN ('completed','merged','discarded','superseded')`).all(repositoryId);
|
|
42
|
+
const worktrees = db.prepare(`SELECT run_id FROM rail_worktrees WHERE repository_id = ?
|
|
43
|
+
AND merge_state NOT IN ('merged','failed','released')`).all(repositoryId);
|
|
44
|
+
const runs = db.prepare("SELECT id, execution_manifest FROM loop_runs WHERE status <> 'completed' AND execution_manifest IS NOT NULL").all();
|
|
45
|
+
const manifestRunIds = runs.filter((row) => readExecutionManifest(row.execution_manifest)?.selectedRepositoryIds.includes(repositoryId)).map((row) => row.id);
|
|
46
|
+
return {
|
|
47
|
+
runIds: [...new Set([...worktrees.flatMap((row) => row.run_id ? [row.run_id] : []), ...manifestRunIds])],
|
|
48
|
+
deliveryIds: [...new Set(deliveries.map((row) => row.parent_delivery_id ?? row.id))],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function executionManifestPrompt(manifest) {
|
|
52
|
+
if (!manifest)
|
|
53
|
+
return '';
|
|
54
|
+
return [
|
|
55
|
+
'Specrails repository execution scope (immutable for this run):',
|
|
56
|
+
JSON.stringify({
|
|
57
|
+
projectId: manifest.projectId,
|
|
58
|
+
artifactRepositoryId: manifest.artifactRepositoryId,
|
|
59
|
+
repositories: manifest.repositories.map((repo) => ({ repositoryId: repo.repositoryId, name: repo.name, path: repo.worktreePath, branch: repo.branch, base: repo.baseSha })),
|
|
60
|
+
}),
|
|
61
|
+
'This is ONE shared spec and ONE coordinated implementation. Complete and verify every required repository and their shared contracts before reporting success.',
|
|
62
|
+
'Edit only the listed worktree paths. The original checkouts are not implementation targets. Keep the shared backlog in the project artifact workspace; keep OpenSpec changes in its designated artifact repository.',
|
|
63
|
+
'Specrails owns Git delivery: do not merge, push, delete branches or open pull requests yourself.',
|
|
64
|
+
].join('\n');
|
|
65
|
+
}
|