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
|
@@ -3,20 +3,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.specsTools = specsTools;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const types_1 = require("./types");
|
|
6
|
+
const agent_spec_framing_1 = require("../../agent-spec-framing");
|
|
6
7
|
// Per-action danger classification for the specs (tickets) facade.
|
|
7
8
|
const DESTRUCTIVE_ACTIONS = new Set(['delete', 'smash_undo', 'delete_epic_children']);
|
|
8
9
|
// `create` routes through Quick Add Spec (generate-spec) so MCP-created specs
|
|
9
10
|
// match the app's "Add Spec → Quick" flow — hence ai-spawn, not write.
|
|
10
11
|
const AI_SPAWN_ACTIONS = new Set(['create', 'generate', 'ai_edit', 'contract_refine', 'smash']);
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// scope; agent-authored inserts by the facade's default-ON `contractRefine` —
|
|
14
|
-
// opt out per call with `contractRefine: false`), but the call itself is a
|
|
15
|
-
// synchronous store mutation (a write), so it is classified as `write`.
|
|
12
|
+
// A post-commit background AI pass still incurs cost. Classify commit_draft
|
|
13
|
+
// using its actual side effects, not the synchronous HTTP response alone.
|
|
16
14
|
const WRITE_ACTIONS = new Set([
|
|
17
15
|
'update', 'from_prompt', 'save_draft', 'commit_draft', 'cancel_ai_edit',
|
|
18
16
|
]);
|
|
19
|
-
function resolveSpecsTier(action) {
|
|
17
|
+
function resolveSpecsTier(action, args) {
|
|
18
|
+
if (action === 'commit_draft') {
|
|
19
|
+
// Explore's stored scope governs refinement; its route does not accept an
|
|
20
|
+
// opt-out override here. A standalone draft flip does not launch AI.
|
|
21
|
+
if (args.conversationId)
|
|
22
|
+
return 'ai-spawn';
|
|
23
|
+
return args.draftTicketId != null || args.contractRefine === false ? 'write' : 'ai-spawn';
|
|
24
|
+
}
|
|
20
25
|
if (DESTRUCTIVE_ACTIONS.has(action))
|
|
21
26
|
return 'destructive';
|
|
22
27
|
if (AI_SPAWN_ACTIONS.has(action))
|
|
@@ -45,7 +50,7 @@ function specsTools() {
|
|
|
45
50
|
'from_prompt (verbatim insert, no AI — use ONLY when you already have a complete finished spec to store as-is; ' +
|
|
46
51
|
'cannot set acceptanceCriteria or shortSummary — prefer commit_draft for structured specs), ' +
|
|
47
52
|
'save_draft (persist an Explore conversation as a draft), ' +
|
|
48
|
-
'commit_draft (write — TWO uses: (a) flip an Explore draft to a real spec, passing conversationId from ' +
|
|
53
|
+
'commit_draft (ai-spawn when refinement may run; write for standalone draft flips or new inserts with contractRefine:false — TWO uses: (a) flip an Explore draft to a real spec, passing conversationId from ' +
|
|
49
54
|
'specrails_chat and/or draftTicketId; (b) with NO conversationId/draftTicketId, insert a COMPLETE spec you ' +
|
|
50
55
|
'authored in ONE call: title (required), description, acceptanceCriteria, priority, labels, shortSummary, ' +
|
|
51
56
|
'assignee, prerequisites, metadata. THE canonical way to persist a spec refined in conversation — do NOT route ' +
|
|
@@ -62,7 +67,7 @@ function specsTools() {
|
|
|
62
67
|
'list_attachments, get_attachment. The generate/ai_edit/contract_refine/smash actions are async (HTTP 202) — ' +
|
|
63
68
|
'results arrive over the WebSocket, not the HTTP response.',
|
|
64
69
|
hintTier: 'read',
|
|
65
|
-
tier: (args) => resolveSpecsTier(args.action),
|
|
70
|
+
tier: (args) => resolveSpecsTier(args.action, args),
|
|
66
71
|
inputSchema: {
|
|
67
72
|
action: zod_1.z
|
|
68
73
|
.enum([
|
|
@@ -88,6 +93,8 @@ function specsTools() {
|
|
|
88
93
|
])
|
|
89
94
|
.describe('Operation to perform'),
|
|
90
95
|
projectId: zod_1.z.string().optional().describe('Project id (defaults to the active project)'),
|
|
96
|
+
repositoryIds: zod_1.z.array(zod_1.z.string().min(1)).min(1).max(50).optional().describe('Affected repositories for this shared spec. Nonempty unique membership IDs from this project. Omission preserves existing scope; historical specs default to primary only.'),
|
|
97
|
+
repositoryId: zod_1.z.string().min(1).optional().describe('files_touched only: repository to inspect; required for multi-repository projects.'),
|
|
91
98
|
// ── Ticket identity ──────────────────────────────────────────────
|
|
92
99
|
id: zod_1.z
|
|
93
100
|
.number()
|
|
@@ -101,6 +108,8 @@ function specsTools() {
|
|
|
101
108
|
.describe('list: CSV status filter (draft|todo|in_progress|on_review|done|cancelled). update: set ticket status — note job outcomes set in_progress/on_review/done automatically (on_review = implemented, awaiting PR review); do not fight the pipeline.'),
|
|
102
109
|
label: zod_1.z.string().optional().describe('list: filter by label (CSV)'),
|
|
103
110
|
q: zod_1.z.string().optional().describe('list: free-text search over title + description'),
|
|
111
|
+
limit: zod_1.z.number().int().positive().max(100).optional().describe('list: compact results per page (default 50, maximum 100)'),
|
|
112
|
+
offset: zod_1.z.number().int().nonnegative().optional().describe('list: zero-based offset for the next compact page'),
|
|
104
113
|
// ── create / update / from_prompt / commit_draft fields ──────────
|
|
105
114
|
title: zod_1.z.string().optional().describe('Ticket title (required for create / commit_draft)'),
|
|
106
115
|
description: zod_1.z
|
|
@@ -113,7 +122,7 @@ function specsTools() {
|
|
|
113
122
|
.optional()
|
|
114
123
|
.describe('update/from_prompt/commit_draft: ticket priority. update: null allowed only for drafts'),
|
|
115
124
|
labels: zod_1.z.array(zod_1.z.string()).optional().describe('update/from_prompt/save_draft/commit_draft: labels array'),
|
|
116
|
-
assignee: zod_1.z.string().optional().describe('update/commit_draft: assignee'),
|
|
125
|
+
assignee: zod_1.z.string().nullable().optional().describe('update/commit_draft: assignee; null clears'),
|
|
117
126
|
prerequisites: zod_1.z.array(zod_1.z.number().int()).optional().describe('update/commit_draft: prerequisite ticket ids'),
|
|
118
127
|
metadata: zod_1.z.record(zod_1.z.unknown()).optional().describe('update/commit_draft: free-form metadata object (update merges keys)'),
|
|
119
128
|
acceptanceCriteria: zod_1.z
|
|
@@ -121,7 +130,7 @@ function specsTools() {
|
|
|
121
130
|
.optional()
|
|
122
131
|
.describe('update/commit_draft: acceptance-criteria bullets folded into the description'),
|
|
123
132
|
shortSummary: zod_1.z.string().optional().describe('commit_draft: explicit short summary (camelCase key)'),
|
|
124
|
-
short_summary: zod_1.z.string().optional().describe('update: explicit short summary (snake_case key; null clears)'),
|
|
133
|
+
short_summary: zod_1.z.string().nullable().optional().describe('update: explicit short summary (snake_case key; null clears)'),
|
|
125
134
|
structured: zod_1.z.boolean().optional().describe('from_prompt: lightly structure the verbatim prompt'),
|
|
126
135
|
createLocal: zod_1.z.boolean().optional().describe('create/generate/commit_draft: keep the spec local (skip Jira promote)'),
|
|
127
136
|
// ── draft linkage ────────────────────────────────────────────────
|
|
@@ -192,6 +201,7 @@ function specsTools() {
|
|
|
192
201
|
attachmentIds: args.attachmentIds,
|
|
193
202
|
pendingSpecId: args.pendingSpecId,
|
|
194
203
|
createLocal: args.createLocal,
|
|
204
|
+
...(args.repositoryIds === undefined ? {} : { repositoryIds: args.repositoryIds }),
|
|
195
205
|
});
|
|
196
206
|
switch (action) {
|
|
197
207
|
// ── reads ──────────────────────────────────────────────────────
|
|
@@ -204,14 +214,40 @@ function specsTools() {
|
|
|
204
214
|
if (typeof args.q === 'string')
|
|
205
215
|
qs.set('q', args.q);
|
|
206
216
|
const suffix = qs.toString() ? `?${qs.toString()}` : '';
|
|
207
|
-
|
|
217
|
+
const result = await (0, types_1.apiCall)(ctx, 'GET', `${base}/tickets${suffix}`);
|
|
218
|
+
const tickets = Array.isArray(result.tickets) ? result.tickets : [];
|
|
219
|
+
const offset = typeof args.offset === 'number' ? args.offset : 0;
|
|
220
|
+
const limit = typeof args.limit === 'number' ? args.limit : 50;
|
|
221
|
+
const page = tickets.slice(offset, offset + limit).map((ticket) => ({
|
|
222
|
+
id: ticket.id,
|
|
223
|
+
title: ticket.title,
|
|
224
|
+
status: ticket.status,
|
|
225
|
+
priority: ticket.priority,
|
|
226
|
+
labels: ticket.labels,
|
|
227
|
+
...(ticket.repositoryIds === undefined ? {} : { repositoryIds: ticket.repositoryIds }),
|
|
228
|
+
shortSummary: ticket.short_summary ?? ticket.shortSummary ?? null,
|
|
229
|
+
updatedAt: ticket.updated_at ?? ticket.updatedAt,
|
|
230
|
+
}));
|
|
231
|
+
const nextOffset = offset + page.length < tickets.length ? offset + page.length : null;
|
|
232
|
+
return {
|
|
233
|
+
tickets: page,
|
|
234
|
+
revision: result.revision,
|
|
235
|
+
total: result.total ?? tickets.length,
|
|
236
|
+
matched: tickets.length,
|
|
237
|
+
offset,
|
|
238
|
+
limit,
|
|
239
|
+
nextOffset,
|
|
240
|
+
hint: nextOffset == null
|
|
241
|
+
? 'List complete. Use get(id) for the full description and acceptance criteria.'
|
|
242
|
+
: `More specs are available. Call list with offset=${nextOffset}; use get(id) for full details.`,
|
|
243
|
+
};
|
|
208
244
|
}
|
|
209
245
|
case 'get':
|
|
210
246
|
return (0, types_1.apiCall)(ctx, 'GET', `${base}/tickets/${requireId()}`);
|
|
211
247
|
case 'spending_summary':
|
|
212
248
|
return (0, types_1.apiCall)(ctx, 'GET', `${base}/tickets/${requireId()}/spending-summary`);
|
|
213
249
|
case 'files_touched':
|
|
214
|
-
return (0, types_1.apiCall)(ctx, 'GET', `${
|
|
250
|
+
return (0, types_1.apiCall)(ctx, 'GET', `${(0, types_1.repositoryPath)(ctx, args.projectId, args.repositoryId)}/code/provenance?ticketId=${requireId()}`);
|
|
215
251
|
case 'list_attachments': {
|
|
216
252
|
const ticketId = args.ticketId;
|
|
217
253
|
if (!ticketId)
|
|
@@ -225,7 +261,17 @@ function specsTools() {
|
|
|
225
261
|
throw new Error('get_attachment requires a "ticketId".');
|
|
226
262
|
if (!attachmentId)
|
|
227
263
|
throw new Error('get_attachment requires an "attachmentId".');
|
|
228
|
-
|
|
264
|
+
// The download endpoint streams binary files; decoding those as
|
|
265
|
+
// text corrupts their content and can exhaust the model context.
|
|
266
|
+
const list = await (0, types_1.apiCall)(ctx, 'GET', `${base}/tickets/${encodeURIComponent(ticketId)}/attachments`);
|
|
267
|
+
const attachment = list.attachments?.find((entry) => entry.id === attachmentId);
|
|
268
|
+
if (!attachment)
|
|
269
|
+
throw new Error('Attachment not found. Use list_attachments to read current attachment ids.');
|
|
270
|
+
return {
|
|
271
|
+
attachment,
|
|
272
|
+
path: `${base}/tickets/${encodeURIComponent(ticketId)}/attachments/${encodeURIComponent(attachmentId)}`,
|
|
273
|
+
hint: 'Attachment metadata and download path; binary content is not inlined. Fetch the authenticated REST download or open the attachment in the app.',
|
|
274
|
+
};
|
|
229
275
|
}
|
|
230
276
|
// ── writes (synchronous store mutations) ────────────────────────
|
|
231
277
|
case 'create': {
|
|
@@ -264,6 +310,7 @@ function specsTools() {
|
|
|
264
310
|
metadata: args.metadata,
|
|
265
311
|
acceptanceCriteria: args.acceptanceCriteria,
|
|
266
312
|
short_summary: args.short_summary,
|
|
313
|
+
...(args.repositoryIds === undefined ? {} : { repositoryIds: args.repositoryIds }),
|
|
267
314
|
});
|
|
268
315
|
case 'from_prompt':
|
|
269
316
|
return (0, types_1.apiCall)(ctx, 'POST', `${base}/tickets/from-prompt`, {
|
|
@@ -272,6 +319,7 @@ function specsTools() {
|
|
|
272
319
|
labels: args.labels,
|
|
273
320
|
priority: args.priority,
|
|
274
321
|
structured: args.structured,
|
|
322
|
+
...(args.repositoryIds === undefined ? {} : { repositoryIds: args.repositoryIds }),
|
|
275
323
|
pendingSpecId: args.pendingSpecId,
|
|
276
324
|
});
|
|
277
325
|
case 'save_draft': {
|
|
@@ -283,6 +331,7 @@ function specsTools() {
|
|
|
283
331
|
description: args.description,
|
|
284
332
|
labels: args.labels,
|
|
285
333
|
editTicketId: args.editTicketId,
|
|
334
|
+
...(args.repositoryIds === undefined ? {} : { repositoryIds: args.repositoryIds }),
|
|
286
335
|
});
|
|
287
336
|
}
|
|
288
337
|
case 'commit_draft': {
|
|
@@ -299,7 +348,22 @@ function specsTools() {
|
|
|
299
348
|
: agentAuthored
|
|
300
349
|
? true
|
|
301
350
|
: undefined;
|
|
302
|
-
|
|
351
|
+
// The framing gate (critical-spec-framing): a spec the in-app agent
|
|
352
|
+
// authored may not be persisted until the conversation holds a
|
|
353
|
+
// problem frame the user has answered, and one frame authorises ONE
|
|
354
|
+
// spec. Applied ONLY to first-party calls carrying a conversation —
|
|
355
|
+
// an external MCP client cannot render the framing card and holds no
|
|
356
|
+
// conversation here, so its behaviour is byte-identical to before.
|
|
357
|
+
// Throwing lands in registerTieredTool's catch, producing the same
|
|
358
|
+
// errorResult shape a tier refusal does.
|
|
359
|
+
const framedConversationId = ctx.firstPartyAgent ? ctx.originConversationId : null;
|
|
360
|
+
const agentProvider = framedConversationId ? (0, types_1.originConversationDefaults)(ctx).provider : undefined;
|
|
361
|
+
if (framedConversationId) {
|
|
362
|
+
const refusal = (0, agent_spec_framing_1.checkSpecFraming)(ctx.desktopDb, framedConversationId);
|
|
363
|
+
if (refusal)
|
|
364
|
+
throw new Error(refusal);
|
|
365
|
+
}
|
|
366
|
+
const committed = await (0, types_1.apiCall)(ctx, 'POST', `${base}/tickets/from-draft`, {
|
|
303
367
|
title: args.title,
|
|
304
368
|
description: args.description,
|
|
305
369
|
draftTicketId: args.draftTicketId,
|
|
@@ -313,8 +377,16 @@ function specsTools() {
|
|
|
313
377
|
prerequisites: args.prerequisites,
|
|
314
378
|
metadata: args.metadata,
|
|
315
379
|
createLocal: args.createLocal,
|
|
380
|
+
...(args.repositoryIds === undefined ? {} : { repositoryIds: args.repositoryIds }),
|
|
316
381
|
contractRefine,
|
|
382
|
+
agentProvider,
|
|
317
383
|
});
|
|
384
|
+
// Spend the frame only on a spec that actually landed: a refusal or
|
|
385
|
+
// a failed write above throws before reaching here, so nothing is
|
|
386
|
+
// consumed by an attempt.
|
|
387
|
+
if (framedConversationId)
|
|
388
|
+
(0, agent_spec_framing_1.recordSpecCommitted)(ctx.desktopDb, framedConversationId);
|
|
389
|
+
return committed;
|
|
318
390
|
}
|
|
319
391
|
case 'cancel_ai_edit': {
|
|
320
392
|
if (!args.requestId)
|
|
@@ -150,7 +150,7 @@ function inferTopic(question) {
|
|
|
150
150
|
return 'general_usage';
|
|
151
151
|
}
|
|
152
152
|
async function collectDiagnostics(ctx, projectId, topic) {
|
|
153
|
-
const projects = ctx.registry.
|
|
153
|
+
const projects = ctx.registry.listProjects().map((p) => ({ ...(0, projects_1.serializeProject)(p), available: !!ctx.registry.getContext(p.id) }));
|
|
154
154
|
const selectedProjectId = projectId ?? (0, types_1.getActiveProject)(ctx) ?? undefined;
|
|
155
155
|
const out = {
|
|
156
156
|
mcp: {
|
|
@@ -1,17 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.McpApiError = void 0;
|
|
3
4
|
exports.apiCall = apiCall;
|
|
4
5
|
exports.projectPath = projectPath;
|
|
6
|
+
exports.requireRepository = requireRepository;
|
|
7
|
+
exports.repositoryPath = repositoryPath;
|
|
5
8
|
exports.originConversationDefaults = originConversationDefaults;
|
|
6
9
|
exports.requireProject = requireProject;
|
|
7
10
|
exports.setActiveProject = setActiveProject;
|
|
8
11
|
exports.getActiveProject = getActiveProject;
|
|
12
|
+
exports.toolTierAllowed = toolTierAllowed;
|
|
9
13
|
exports.registerTieredTool = registerTieredTool;
|
|
10
14
|
const mcp_tiers_1 = require("../mcp-tiers");
|
|
11
|
-
const
|
|
15
|
+
const internal_api_1 = require("../../internal-api");
|
|
12
16
|
const agent_tier_1 = require("../../agent-tier");
|
|
13
17
|
const agent_store_1 = require("../../agent-store");
|
|
14
18
|
const agent_capability_1 = require("../agent-capability");
|
|
19
|
+
const project_repositories_1 = require("../../project-repositories");
|
|
20
|
+
const agent_steering_1 = require("../../agent-steering");
|
|
21
|
+
class McpApiError extends Error {
|
|
22
|
+
status;
|
|
23
|
+
data;
|
|
24
|
+
code;
|
|
25
|
+
constructor(message, status, data) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.status = status;
|
|
28
|
+
this.data = data;
|
|
29
|
+
this.name = 'McpApiError';
|
|
30
|
+
const error = data?.error;
|
|
31
|
+
if (typeof error === 'string')
|
|
32
|
+
this.code = error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.McpApiError = McpApiError;
|
|
15
36
|
/**
|
|
16
37
|
* Calls the app's own REST API over loopback using the MASTER token (held
|
|
17
38
|
* server-side, never exposed to the MCP client). This reuses every router's
|
|
@@ -20,33 +41,45 @@ const agent_capability_1 = require("../agent-capability");
|
|
|
20
41
|
* after `/api` (e.g. `/projects/<id>/tickets`).
|
|
21
42
|
*/
|
|
22
43
|
async function apiCall(ctx, method, path, body) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
data = text ? JSON.parse(text) : null;
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
data = text;
|
|
39
|
-
}
|
|
44
|
+
// Shared loopback client (server/internal-api.ts) — also drives the milestone
|
|
45
|
+
// launch chain's chunk launches, so both stay byte-identical to a dashboard call.
|
|
46
|
+
// MCP calls additionally retain their request cancellation and bounded wait;
|
|
47
|
+
// those lifetimes belong to this call, not to the durable milestone chain.
|
|
48
|
+
const signal = ctx.signal
|
|
49
|
+
? AbortSignal.any([ctx.signal, AbortSignal.timeout(120_000)])
|
|
50
|
+
: AbortSignal.timeout(120_000);
|
|
51
|
+
const res = await (0, internal_api_1.createInternalApi)({
|
|
52
|
+
port: ctx.desktopPort,
|
|
53
|
+
fetchImpl: (input, init) => fetch(input, { ...init, signal }),
|
|
54
|
+
}).call(method, path, body);
|
|
40
55
|
if (!res.ok) {
|
|
56
|
+
const data = res.body;
|
|
41
57
|
const detail = typeof data === 'object' && data !== null ? JSON.stringify(data) : String(data);
|
|
42
|
-
throw new
|
|
58
|
+
throw new McpApiError(`API ${method} ${path} → ${res.status}: ${detail}`, res.status, data);
|
|
43
59
|
}
|
|
44
|
-
return
|
|
60
|
+
return res.body;
|
|
45
61
|
}
|
|
46
62
|
/** Convenience: build the `/projects/<id>` path prefix for a resolved project. */
|
|
47
63
|
function projectPath(ctx, projectId) {
|
|
48
64
|
return `/projects/${requireProject(ctx, projectId).project.id}`;
|
|
49
65
|
}
|
|
66
|
+
/** Repository identity is relative to the resolved project, never a free path
|
|
67
|
+
* or another project's membership. MCP requires a choice where a file/Git
|
|
68
|
+
* operation could otherwise silently target the primary. */
|
|
69
|
+
function requireRepository(ctx, projectId, repositoryId) {
|
|
70
|
+
const { project } = requireProject(ctx, projectId);
|
|
71
|
+
const repositories = (0, project_repositories_1.getProjectRepositories)(project);
|
|
72
|
+
if (repositoryId === undefined && repositories.length > 1) {
|
|
73
|
+
const data = { error: 'repository_required', projectId: project.id, repositories };
|
|
74
|
+
throw new McpApiError(`Provide repositoryId for this multi-repository project: ${JSON.stringify(data)}`, 400, data);
|
|
75
|
+
}
|
|
76
|
+
return (0, project_repositories_1.resolveProjectRepository)(project, repositoryId);
|
|
77
|
+
}
|
|
78
|
+
function repositoryPath(ctx, projectId, repositoryId) {
|
|
79
|
+
const repository = requireRepository(ctx, projectId, repositoryId);
|
|
80
|
+
const base = `/projects/${encodeURIComponent(repository.projectId)}`;
|
|
81
|
+
return repositoryId === undefined ? base : `${base}/repositories/${encodeURIComponent(repository.id)}`;
|
|
82
|
+
}
|
|
50
83
|
/**
|
|
51
84
|
* Launch defaults derived from the LAUNCHING agent-chat conversation (the
|
|
52
85
|
* authenticated origin carried on `ctx.originConversationId`). When the in-app agent
|
|
@@ -69,6 +102,7 @@ function originConversationDefaults(ctx) {
|
|
|
69
102
|
return {};
|
|
70
103
|
return {
|
|
71
104
|
...(conv.provider ? { provider: conv.provider } : {}),
|
|
105
|
+
...(conv.model ? { model: conv.model } : {}),
|
|
72
106
|
...(conv.reasoning_effort ? { reasoningEffort: conv.reasoning_effort } : {}),
|
|
73
107
|
};
|
|
74
108
|
}
|
|
@@ -83,8 +117,12 @@ function requireProject(ctx, projectId) {
|
|
|
83
117
|
throw new Error('No project specified and no active project selected. Call specrails_select_project or pass projectId.');
|
|
84
118
|
}
|
|
85
119
|
const pc = ctx.registry.getContext(id);
|
|
86
|
-
if (!pc)
|
|
120
|
+
if (!pc) {
|
|
121
|
+
if (ctx.registry.getProjectRow?.(id)) {
|
|
122
|
+
throw new Error(`Project "${id}" is registered but its database is temporarily unavailable. Retry after recovery; do not register a duplicate project.`);
|
|
123
|
+
}
|
|
87
124
|
throw new Error(`Unknown projectId "${id}". Use specrails_projects(list) to see valid ids.`);
|
|
125
|
+
}
|
|
88
126
|
return pc;
|
|
89
127
|
}
|
|
90
128
|
// ── Active-project stickiness (per server process) ────────────────────────────
|
|
@@ -93,11 +131,25 @@ function requireProject(ctx, projectId) {
|
|
|
93
131
|
// wins over the process-wide selection. `setActiveProject` remains for
|
|
94
132
|
// `specrails_select_project`; request context must never mutate this global.
|
|
95
133
|
let _activeProjectId = null;
|
|
96
|
-
function setActiveProject(id) {
|
|
97
|
-
|
|
134
|
+
function setActiveProject(ctxOrId, id) {
|
|
135
|
+
if (typeof ctxOrId === 'object' && ctxOrId !== null) {
|
|
136
|
+
ctxOrId.sessionState ??= { activeProjectId: null };
|
|
137
|
+
ctxOrId.sessionState.activeProjectId = id ?? null;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// Compatibility for direct legacy unit callers. Live transports always
|
|
141
|
+
// provide sessionState and never consult or change this fallback.
|
|
142
|
+
_activeProjectId = ctxOrId;
|
|
143
|
+
}
|
|
98
144
|
}
|
|
99
145
|
function getActiveProject(ctx) {
|
|
100
|
-
return ctx.requestProjectId !== undefined ? ctx.requestProjectId
|
|
146
|
+
return ctx.requestProjectId !== undefined ? ctx.requestProjectId
|
|
147
|
+
: ctx.sessionState ? ctx.sessionState.activeProjectId : _activeProjectId;
|
|
148
|
+
}
|
|
149
|
+
function toolTierAllowed(ctx, tier) {
|
|
150
|
+
return ctx.firstPartyAgent && ctx.agentTierLevel !== undefined
|
|
151
|
+
? (0, agent_tier_1.levelAllowsTier)(ctx.agentTierLevel, tier)
|
|
152
|
+
: (0, mcp_tiers_1.isTierEnabled)(ctx.desktopDb, tier);
|
|
101
153
|
}
|
|
102
154
|
function tierAnnotations(tier) {
|
|
103
155
|
switch (tier) {
|
|
@@ -112,7 +164,7 @@ function tierAnnotations(tier) {
|
|
|
112
164
|
}
|
|
113
165
|
}
|
|
114
166
|
function toResult(data) {
|
|
115
|
-
const text = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
|
|
167
|
+
const text = typeof data === 'string' ? data : JSON.stringify(data ?? null, null, 2);
|
|
116
168
|
return { content: [{ type: 'text', text }] };
|
|
117
169
|
}
|
|
118
170
|
function errorResult(message) {
|
|
@@ -151,42 +203,64 @@ function emitMcpActivity(ctx, spec, args, tier) {
|
|
|
151
203
|
* the tier check because it lives here, not in the handler.
|
|
152
204
|
*/
|
|
153
205
|
function registerTieredTool(server, ctx, spec) {
|
|
154
|
-
|
|
206
|
+
// An action facade may read, write, launch AI and delete data through ONE
|
|
207
|
+
// protocol tool. Advertising the common read action as readOnlyHint:true
|
|
208
|
+
// misleads clients that use annotations when approving mutations.
|
|
209
|
+
const annotations = typeof spec.tier === 'function'
|
|
210
|
+
? { readOnlyHint: false, destructiveHint: true, openWorldHint: true }
|
|
211
|
+
: tierAnnotations(spec.tier);
|
|
155
212
|
server.registerTool(spec.name, {
|
|
156
213
|
title: spec.title,
|
|
157
214
|
description: spec.description,
|
|
158
215
|
inputSchema: spec.inputSchema,
|
|
159
|
-
annotations
|
|
216
|
+
annotations,
|
|
160
217
|
}, async (args, extra) => {
|
|
218
|
+
if (extra?.signal?.aborted)
|
|
219
|
+
return errorResult('MCP request was cancelled before execution.');
|
|
161
220
|
// Loopback identifies a machine, not a trusted caller. All first-party
|
|
162
221
|
// authority and context come from this unguessable, server-minted bearer;
|
|
163
222
|
// legacy tier/project/conversation headers are deliberately ignored.
|
|
164
|
-
const
|
|
223
|
+
const suppliedCapability = extra?.requestInfo?.headers?.[agent_tier_1.AGENT_CAPABILITY_HEADER];
|
|
224
|
+
const capability = (0, agent_capability_1.verifyAgentCapability)(suppliedCapability);
|
|
225
|
+
if (suppliedCapability !== undefined && !capability) {
|
|
226
|
+
return errorResult('Agent capability expired or was revoked. Start a new mission turn to reconnect.');
|
|
227
|
+
}
|
|
165
228
|
const callCtx = capability
|
|
166
229
|
? {
|
|
167
230
|
...ctx,
|
|
168
231
|
requestProjectId: capability.projectId,
|
|
169
232
|
originConversationId: capability.conversationId,
|
|
170
233
|
firstPartyAgent: true,
|
|
234
|
+
agentTierLevel: capability.tierLevel,
|
|
171
235
|
}
|
|
172
|
-
: ctx;
|
|
236
|
+
: { ...ctx };
|
|
237
|
+
callCtx.signal = extra?.signal;
|
|
173
238
|
const tier = typeof spec.tier === 'function' ? spec.tier(args ?? {}) : spec.tier;
|
|
174
|
-
if (
|
|
175
|
-
if (!(0, agent_tier_1.levelAllowsTier)(capability.tierLevel, tier)) {
|
|
176
|
-
return errorResult((0, mcp_tiers_1.tierRefusalMessage)(tier));
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
else if (!(0, mcp_tiers_1.isTierEnabled)(ctx.desktopDb, tier)) {
|
|
239
|
+
if (!toolTierAllowed(callCtx, tier)) {
|
|
180
240
|
return errorResult((0, mcp_tiers_1.tierRefusalMessage)(tier));
|
|
181
241
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
242
|
+
const operation = async () => {
|
|
243
|
+
try {
|
|
244
|
+
const data = await spec.handler(callCtx, args ?? {});
|
|
245
|
+
if (tier !== 'read')
|
|
246
|
+
emitMcpActivity(callCtx, spec, args ?? {}, tier);
|
|
247
|
+
return toResult(data);
|
|
248
|
+
}
|
|
249
|
+
catch (err) {
|
|
250
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
if (capability && typeof suppliedCapability === 'string') {
|
|
254
|
+
callCtx.acknowledgeAgentUpdates = revision => (0, agent_steering_1.acknowledgeAgentSteering)(ctx.desktopDb, suppliedCapability, revision);
|
|
255
|
+
callCtx.acknowledgeAgentInputsRead = inputIds => (0, agent_steering_1.acknowledgeAgentInputsRead)(ctx.desktopDb, suppliedCapability, inputIds);
|
|
256
|
+
callCtx.onMissionInput = listener => (0, agent_steering_1.onAgentSteering)(ctx.desktopDb, suppliedCapability, listener);
|
|
257
|
+
return (0, agent_steering_1.runWithAgentSteering)(ctx.desktopDb, suppliedCapability, extra?.signal, operation, {
|
|
258
|
+
acknowledgement: spec.name === 'specrails_mission' && args?.action === 'acknowledge_updates',
|
|
259
|
+
});
|
|
190
260
|
}
|
|
261
|
+
callCtx.acknowledgeAgentUpdates = undefined;
|
|
262
|
+
callCtx.acknowledgeAgentInputsRead = undefined;
|
|
263
|
+
callCtx.onMissionInput = undefined;
|
|
264
|
+
return operation();
|
|
191
265
|
});
|
|
192
266
|
}
|