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
|
@@ -26,7 +26,7 @@ const ai_invocations_1 = require("./ai-invocations");
|
|
|
26
26
|
const crypto_1 = require("crypto");
|
|
27
27
|
const artifact_registry_1 = require("./artifact-registry");
|
|
28
28
|
const install_config_path_1 = require("./install-config-path");
|
|
29
|
-
const
|
|
29
|
+
const core_runtime_1 = require("./core-runtime");
|
|
30
30
|
const path_resolver_1 = require("./path-resolver");
|
|
31
31
|
const offline_assemble_1 = require("./offline-assemble");
|
|
32
32
|
const framework_manager_1 = require("./framework-manager");
|
|
@@ -627,9 +627,10 @@ async function validateCoreContract() {
|
|
|
627
627
|
return;
|
|
628
628
|
}
|
|
629
629
|
if (contract.checkpoints) {
|
|
630
|
-
const
|
|
631
|
-
const
|
|
632
|
-
|
|
630
|
+
const keys = Array.isArray(contract.checkpoints) ? contract.checkpoints : Object.keys(contract.checkpoints);
|
|
631
|
+
const missingCheckpoints = keys.filter((c) => !exports.CHECKPOINTS.some((cp) => cp.key === c));
|
|
632
|
+
const extraCheckpoints = Number(contract.schemaVersion?.split('.')[0] ?? 0) >= 4 ? [] : exports.CHECKPOINTS
|
|
633
|
+
.filter((cp) => !keys.includes(cp.key))
|
|
633
634
|
.map((cp) => cp.key);
|
|
634
635
|
if (missingCheckpoints.length > 0 || extraCheckpoints.length > 0) {
|
|
635
636
|
console.warn('[Specrails] ⚠️ specrails-core contract checkpoint mismatch:');
|
|
@@ -771,7 +772,13 @@ class SetupManager {
|
|
|
771
772
|
providers: list,
|
|
772
773
|
continueOnError: true,
|
|
773
774
|
onProviderStart: (p) => emit(p, 'running'),
|
|
774
|
-
onProviderResult: (r) =>
|
|
775
|
+
onProviderResult: (r) => {
|
|
776
|
+
// The WS event carries the reason to the app; the server log must too,
|
|
777
|
+
// or a packaged-app failure (installer smoke, support bundle) is blind.
|
|
778
|
+
if (!r.ok)
|
|
779
|
+
console.warn(`[SetupManager] silent assemble: ${r.provider} failed for ${projectId}: ${r.error ?? 'unknown error'}`);
|
|
780
|
+
emit(r.provider, r.ok ? 'done' : 'failed', r.error);
|
|
781
|
+
},
|
|
775
782
|
})
|
|
776
783
|
.then((results) => {
|
|
777
784
|
const failed = results.filter((r) => !r.ok).map((r) => r.provider);
|
|
@@ -874,7 +881,12 @@ class SetupManager {
|
|
|
874
881
|
// assemble by symlink; openspec init is the only remaining network step) —
|
|
875
882
|
// NO `npx specrails-core` round-trip. When NO bundled core is present we fall
|
|
876
883
|
// through to the legacy npx probe + spawn, byte-identical to today.
|
|
877
|
-
const
|
|
884
|
+
const selectedCore = (0, core_runtime_1.getCoreRuntimeStatus)();
|
|
885
|
+
if (selectedCore.error) {
|
|
886
|
+
this._broadcast({ type: 'setup_error', projectId, error: selectedCore.error });
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
const useBundledCore = selectedCore.runtime !== null;
|
|
878
890
|
if (useBundledCore) {
|
|
879
891
|
// Materialize the framework for the selected provider (idempotent). The
|
|
880
892
|
// subsequent bundled `init` finds it already present (ensureFramework
|
|
@@ -886,7 +898,7 @@ class SetupManager {
|
|
|
886
898
|
const fm = new framework_manager_1.FrameworkManager({
|
|
887
899
|
broadcast: (msg) => this._broadcast(msg),
|
|
888
900
|
});
|
|
889
|
-
const mat = fm.materialize(
|
|
901
|
+
const mat = fm.materialize(undefined, [provider]);
|
|
890
902
|
if (mat.ran && mat.errors.length > 0) {
|
|
891
903
|
console.warn(`[SetupManager] framework materialize had errors: ${mat.errors.map((e) => `${e.provider}: ${e.message}`).join('; ')}`);
|
|
892
904
|
}
|
|
@@ -935,7 +947,7 @@ class SetupManager {
|
|
|
935
947
|
// entry realpath) is diagnosable without server-console access.
|
|
936
948
|
const diagHeader = [];
|
|
937
949
|
if (useBundledCore) {
|
|
938
|
-
diagHeader.push(`[diag] node=${(0, path_resolver_1.resolveBundledNodeExe)() ?? process.execPath}`, `[diag] cli=${
|
|
950
|
+
diagHeader.push(`[diag] node=${(0, path_resolver_1.resolveBundledNodeExe)() ?? process.execPath}`, `[diag] cli=${selectedCore.runtime?.cli ?? '<none>'}`, `[diag] cwd=${projectPath}`, `[diag] args=${initArgs.join(' ')}`, `[diag] SPECRAILS_BUNDLED_RUNTIMES_PATH=${process.env.SPECRAILS_BUNDLED_RUNTIMES_PATH ?? '<unset>'}`, `[diag] SPECRAILS_BUNDLED_CORE_PATH=${process.env.SPECRAILS_BUNDLED_CORE_PATH ?? '<unset>'}`);
|
|
939
951
|
}
|
|
940
952
|
// Bundled core (offline, node <cli> init) when available, else legacy npx.
|
|
941
953
|
const child = useBundledCore
|
|
@@ -1041,8 +1053,38 @@ class SetupManager {
|
|
|
1041
1053
|
}
|
|
1042
1054
|
});
|
|
1043
1055
|
}
|
|
1056
|
+
_completeDeterministicSetup(projectId, projectPath, provider) {
|
|
1057
|
+
const root = this._artifactRoot(projectId, projectPath);
|
|
1058
|
+
let installedVersion = null;
|
|
1059
|
+
try {
|
|
1060
|
+
const marker = (0, path_1.join)(root, '.specrails', 'specrails-version');
|
|
1061
|
+
if ((0, fs_1.existsSync)(marker))
|
|
1062
|
+
installedVersion = (0, fs_1.readFileSync)(marker, 'utf8').trim();
|
|
1063
|
+
}
|
|
1064
|
+
catch { /* not installed */ }
|
|
1065
|
+
const runtime = (0, core_runtime_1.getCoreRuntimeStatus)().runtime;
|
|
1066
|
+
if (!(Number((installedVersion ?? runtime?.version ?? '0').split('.')[0]) >= 5))
|
|
1067
|
+
return false;
|
|
1068
|
+
const validation = validateInstalledCore(root);
|
|
1069
|
+
const selectedProvider = provider ?? this._projectProviders.get(projectId) ?? 'claude';
|
|
1070
|
+
const summary = computeSummary(root, 'quick', selectedProvider);
|
|
1071
|
+
if (!validation.ok || !installedVersion || summary.agents < 3 || summary.specrailsCommands < 1) {
|
|
1072
|
+
this._broadcast({ type: 'setup_error', projectId, error: 'Core 5 uses deterministic installation. Run project installation to repair its framework; enrichment is no longer supported.' });
|
|
1073
|
+
return true;
|
|
1074
|
+
}
|
|
1075
|
+
if (provider)
|
|
1076
|
+
this._projectProviders.set(projectId, provider);
|
|
1077
|
+
this._projectTiers.set(projectId, 'quick');
|
|
1078
|
+
this._initCheckpoints(projectId);
|
|
1079
|
+
this._syncFilesystemCheckpoints(projectId, projectPath);
|
|
1080
|
+
this._broadcast({ type: 'setup_complete', projectId, summary });
|
|
1081
|
+
this._onSetupDone?.(projectId);
|
|
1082
|
+
return true;
|
|
1083
|
+
}
|
|
1044
1084
|
// ─── Enrich: claude -p "/specrails:enrich --from-config" ────────────────────
|
|
1045
1085
|
startEnrich(projectId, projectPath, provider, projectName) {
|
|
1086
|
+
if (this._completeDeterministicSetup(projectId, projectPath, provider))
|
|
1087
|
+
return;
|
|
1046
1088
|
this._abortedProjects.delete(projectId); // fresh run — clear any prior abort flag
|
|
1047
1089
|
if (this._setupProcesses.has(projectId)) {
|
|
1048
1090
|
console.warn(`[SetupManager] enrich already running for ${projectId}`);
|
|
@@ -1092,6 +1134,8 @@ class SetupManager {
|
|
|
1092
1134
|
return this.startEnrich(projectId, projectPath, provider);
|
|
1093
1135
|
}
|
|
1094
1136
|
resumeEnrich(projectId, projectPath, sessionId, userMessage, provider) {
|
|
1137
|
+
if (this._completeDeterministicSetup(projectId, projectPath, provider))
|
|
1138
|
+
return;
|
|
1095
1139
|
if (this._setupProcesses.has(projectId)) {
|
|
1096
1140
|
console.warn(`[SetupManager] enrich already running for ${projectId}`);
|
|
1097
1141
|
return;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Specrails — bash shell-integration shim
|
|
2
|
+
# Loaded via --rcfile when the user spawns a terminal in the app.
|
|
3
|
+
# Sources the user's real ~/.bashrc, then layers OSC 133 / OSC 1337 hooks on top.
|
|
4
|
+
|
|
5
|
+
export SPECRAILS_SHELL_INTEGRATION_LOADED=1
|
|
6
|
+
|
|
7
|
+
if [[ -r "$HOME/.bashrc" ]]; then
|
|
8
|
+
# shellcheck disable=SC1091
|
|
9
|
+
source "$HOME/.bashrc"
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
# OSC helpers (\a = BEL terminator)
|
|
13
|
+
__sr_osc_prompt_start() { printf '\e]133;A\a'; }
|
|
14
|
+
__sr_osc_prompt_end() { printf '\e]133;B\a'; }
|
|
15
|
+
__sr_osc_pre_exec() { printf '\e]133;C\a'; }
|
|
16
|
+
__sr_osc_post_exec() { printf '\e]133;D;%d\a' "${1:-0}"; }
|
|
17
|
+
__sr_osc_cwd() { printf '\e]1337;CurrentDir=%s\a' "$PWD"; }
|
|
18
|
+
|
|
19
|
+
# DEBUG trap fires before each simple command.
|
|
20
|
+
# Skip when inside the prompt itself (BASH_COMMAND == PROMPT_COMMAND) to avoid
|
|
21
|
+
# treating the prompt as a user command.
|
|
22
|
+
__sr_in_prompt=0
|
|
23
|
+
__sr_debug_trap() {
|
|
24
|
+
if [[ "$__sr_in_prompt" == "1" ]]; then return; fi
|
|
25
|
+
__sr_osc_prompt_end
|
|
26
|
+
__sr_osc_pre_exec
|
|
27
|
+
}
|
|
28
|
+
trap '__sr_debug_trap' DEBUG
|
|
29
|
+
|
|
30
|
+
# PROMPT_COMMAND wraps the user's existing PROMPT_COMMAND.
|
|
31
|
+
__sr_prompt_command() {
|
|
32
|
+
local exit=$?
|
|
33
|
+
__sr_in_prompt=1
|
|
34
|
+
__sr_osc_post_exec "$exit"
|
|
35
|
+
__sr_osc_cwd
|
|
36
|
+
__sr_osc_prompt_start
|
|
37
|
+
__sr_in_prompt=0
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if [[ -n "$PROMPT_COMMAND" ]]; then
|
|
41
|
+
PROMPT_COMMAND="__sr_prompt_command; $PROMPT_COMMAND"
|
|
42
|
+
else
|
|
43
|
+
PROMPT_COMMAND="__sr_prompt_command"
|
|
44
|
+
fi
|
|
45
|
+
export PROMPT_COMMAND
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Specrails — fish shell-integration shim
|
|
2
|
+
# Sourced via `fish -C "source <this-file>"`, which runs after the user's
|
|
3
|
+
# config.fish / conf.d, so the user's real fish config is preserved.
|
|
4
|
+
|
|
5
|
+
set -gx SPECRAILS_SHELL_INTEGRATION_LOADED 1
|
|
6
|
+
|
|
7
|
+
function __sr_osc_prompt_start
|
|
8
|
+
printf '\e]133;A\a'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
function __sr_osc_prompt_end
|
|
12
|
+
printf '\e]133;B\a'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
function __sr_osc_pre_exec
|
|
16
|
+
printf '\e]133;C\a'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
function __sr_osc_post_exec
|
|
20
|
+
printf '\e]133;D;%d\a' $argv[1]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
function __sr_osc_cwd
|
|
24
|
+
printf '\e]1337;CurrentDir=%s\a' (pwd)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
function __sr_preexec --on-event fish_preexec
|
|
28
|
+
__sr_osc_prompt_end
|
|
29
|
+
__sr_osc_pre_exec
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
function __sr_postexec --on-event fish_postexec
|
|
33
|
+
__sr_osc_post_exec $status
|
|
34
|
+
__sr_osc_cwd
|
|
35
|
+
__sr_osc_prompt_start
|
|
36
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Specrails — PowerShell shell-integration shim
|
|
2
|
+
# Loaded via -NoLogo -NoExit -File <shim.ps1>. Dot-sources the user's real
|
|
3
|
+
# $PROFILE if it exists, then wraps the prompt function with OSC 133 marks.
|
|
4
|
+
|
|
5
|
+
$env:SPECRAILS_SHELL_INTEGRATION_LOADED = '1'
|
|
6
|
+
|
|
7
|
+
# Dot-source the user's real profile so their environment, aliases, modules load.
|
|
8
|
+
$__srUserProfile = $PROFILE.CurrentUserAllHosts
|
|
9
|
+
if (Test-Path -LiteralPath $__srUserProfile) {
|
|
10
|
+
. $__srUserProfile
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
# Capture the user's existing prompt function so we can chain to it.
|
|
14
|
+
$__srOriginalPrompt = $function:prompt
|
|
15
|
+
|
|
16
|
+
function global:__sr-OscEmit([string]$seq) {
|
|
17
|
+
[Console]::Write($seq)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
# Override prompt with our wrapper.
|
|
21
|
+
function global:prompt {
|
|
22
|
+
$exit = if ($global:LASTEXITCODE) { [int]$global:LASTEXITCODE } else { 0 }
|
|
23
|
+
|
|
24
|
+
# post-exec for the *previous* command, then cwd, then prompt-start.
|
|
25
|
+
__sr-OscEmit ("`e]133;D;{0}`a" -f $exit)
|
|
26
|
+
__sr-OscEmit ("`e]1337;CurrentDir={0}`a" -f (Get-Location).Path)
|
|
27
|
+
__sr-OscEmit "`e]133;A`a"
|
|
28
|
+
|
|
29
|
+
if ($__srOriginalPrompt) {
|
|
30
|
+
& $__srOriginalPrompt
|
|
31
|
+
} else {
|
|
32
|
+
"PS $((Get-Location).Path)> "
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
__sr-OscEmit "`e]133;B`a"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Trace pre-exec via PSReadLine if available.
|
|
39
|
+
if (Get-Module -Name PSReadLine -ListAvailable) {
|
|
40
|
+
try {
|
|
41
|
+
Set-PSReadLineKeyHandler -Key Enter -ScriptBlock {
|
|
42
|
+
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
|
|
43
|
+
__sr-OscEmit "`e]133;C`a"
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
# PSReadLine version may not support custom handlers; ignore.
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Specrails — zsh shell-integration shim
|
|
2
|
+
# Loaded via ZDOTDIR override when the user spawns a terminal in the app.
|
|
3
|
+
# Sources the user's real login files, then layers OSC 133 / OSC 1337 hooks on top.
|
|
4
|
+
|
|
5
|
+
# Sentinel so the server can detect bootstrap success.
|
|
6
|
+
export SPECRAILS_SHELL_INTEGRATION_LOADED=1
|
|
7
|
+
|
|
8
|
+
# The ZDOTDIR override makes zsh read its startup files from the shim dir, so the
|
|
9
|
+
# user's own ~/.zshenv/.zprofile/.zshrc/.zlogin are skipped — losing PATH,
|
|
10
|
+
# Homebrew, nvm/fnm/asdf, etc. Source them ourselves from the user's real ZDOTDIR
|
|
11
|
+
# (default $HOME), in zsh's normal login order, before installing our hooks so we
|
|
12
|
+
# don't stomp on the user's precmd/preexec arrays.
|
|
13
|
+
__sr_uz="${SPECRAILS_REAL_ZDOTDIR:-$HOME}"
|
|
14
|
+
[[ -r "$__sr_uz/.zshenv" ]] && source "$__sr_uz/.zshenv"
|
|
15
|
+
[[ -r "$__sr_uz/.zprofile" ]] && source "$__sr_uz/.zprofile"
|
|
16
|
+
[[ -r "$__sr_uz/.zshrc" ]] && source "$__sr_uz/.zshrc"
|
|
17
|
+
[[ -r "$__sr_uz/.zlogin" ]] && source "$__sr_uz/.zlogin"
|
|
18
|
+
unset __sr_uz
|
|
19
|
+
|
|
20
|
+
# Helper: print OSC 133 sequences. \a is the BEL (ST) terminator.
|
|
21
|
+
__sr_osc_prompt_start() { print -n -- $'\e]133;A\a' }
|
|
22
|
+
__sr_osc_prompt_end() { print -n -- $'\e]133;B\a' }
|
|
23
|
+
__sr_osc_pre_exec() { print -n -- $'\e]133;C\a' }
|
|
24
|
+
__sr_osc_post_exec() { print -n -- $'\e]133;D;'"${1:-0}"$'\a' }
|
|
25
|
+
__sr_osc_cwd() { print -n -- $'\e]1337;CurrentDir='"$PWD"$'\a' }
|
|
26
|
+
|
|
27
|
+
# Track exit code of the last command for OSC 133;D.
|
|
28
|
+
__sr_last_exit=0
|
|
29
|
+
|
|
30
|
+
# precmd: runs before every prompt. Emits prompt-start and CWD.
|
|
31
|
+
__sr_precmd() {
|
|
32
|
+
__sr_last_exit=$?
|
|
33
|
+
__sr_osc_post_exec "$__sr_last_exit"
|
|
34
|
+
__sr_osc_cwd
|
|
35
|
+
__sr_osc_prompt_start
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# preexec: runs just before a command executes. Emits pre-exec and prompt-end.
|
|
39
|
+
__sr_preexec() {
|
|
40
|
+
__sr_osc_prompt_end
|
|
41
|
+
__sr_osc_pre_exec
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Append (do not overwrite) so user-defined hooks are preserved.
|
|
45
|
+
typeset -ga precmd_functions preexec_functions
|
|
46
|
+
precmd_functions+=("__sr_precmd")
|
|
47
|
+
preexec_functions+=("__sr_preexec")
|
|
@@ -301,6 +301,7 @@ function applySmashToStore(filePath, epicId, children, nowIso, createdBy) {
|
|
|
301
301
|
const id = s.next_id++;
|
|
302
302
|
const description = composeChildDescription(child);
|
|
303
303
|
const ticket = {
|
|
304
|
+
...(target.repositoryIds ? { repositoryIds: [...target.repositoryIds] } : {}),
|
|
304
305
|
id,
|
|
305
306
|
title: child.title,
|
|
306
307
|
description,
|
|
@@ -11,13 +11,10 @@
|
|
|
11
11
|
// manages crash-respawn / idle-kill) stay with the caller via hooks + the
|
|
12
12
|
// returned result. Adopting it is behaviour-preserving: the caller keeps every
|
|
13
13
|
// post-close decision it had, just without re-implementing the plumbing.
|
|
14
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
-
};
|
|
17
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
15
|
exports.runAiCliInvocation = runAiCliInvocation;
|
|
19
16
|
const node_readline_1 = require("node:readline");
|
|
20
|
-
const
|
|
17
|
+
const win_spawn_1 = require("./util/win-spawn");
|
|
21
18
|
const cli_prompt_1 = require("./util/cli-prompt");
|
|
22
19
|
const runtime_1 = require("./providers/runtime");
|
|
23
20
|
const STDERR_TAIL_CAP = 64 * 1024;
|
|
@@ -42,6 +39,40 @@ function runAiCliInvocation(hooks) {
|
|
|
42
39
|
return new Promise((resolve) => {
|
|
43
40
|
let settled = false;
|
|
44
41
|
let timer = null;
|
|
42
|
+
let inactivityTimer = null;
|
|
43
|
+
let child;
|
|
44
|
+
const terminateForTimeout = () => {
|
|
45
|
+
if (child.pid) {
|
|
46
|
+
(0, win_spawn_1.treeKillSafe)(child.pid, 'SIGTERM');
|
|
47
|
+
const pid = child.pid;
|
|
48
|
+
const killTimer = setTimeout(() => {
|
|
49
|
+
try {
|
|
50
|
+
(0, win_spawn_1.treeKillSafe)(pid, 'SIGKILL', () => { });
|
|
51
|
+
}
|
|
52
|
+
catch { /* gone */ }
|
|
53
|
+
}, 2000);
|
|
54
|
+
killTimer.unref?.();
|
|
55
|
+
child.once('close', () => clearTimeout(killTimer));
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
try {
|
|
59
|
+
child.kill('SIGTERM');
|
|
60
|
+
}
|
|
61
|
+
catch { /* already gone */ }
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const armInactivityTimer = () => {
|
|
65
|
+
if (hooks.inactivityTimeoutMs == null || hooks.inactivityTimeoutMs <= 0 || settled)
|
|
66
|
+
return;
|
|
67
|
+
if (inactivityTimer)
|
|
68
|
+
clearTimeout(inactivityTimer);
|
|
69
|
+
inactivityTimer = setTimeout(() => {
|
|
70
|
+
hooks.onInactivityTimeout?.();
|
|
71
|
+
terminateForTimeout();
|
|
72
|
+
settle({ code: null, timedOut: true, spawnFailed: false, child });
|
|
73
|
+
}, hooks.inactivityTimeoutMs);
|
|
74
|
+
inactivityTimer.unref?.();
|
|
75
|
+
};
|
|
45
76
|
const settle = (partial) => {
|
|
46
77
|
if (settled)
|
|
47
78
|
return;
|
|
@@ -50,9 +81,12 @@ function runAiCliInvocation(hooks) {
|
|
|
50
81
|
clearTimeout(timer);
|
|
51
82
|
timer = null;
|
|
52
83
|
}
|
|
84
|
+
if (inactivityTimer) {
|
|
85
|
+
clearTimeout(inactivityTimer);
|
|
86
|
+
inactivityTimer = null;
|
|
87
|
+
}
|
|
53
88
|
resolve({ ...partial, events, lastResultEvent, sessionId, stderrTail });
|
|
54
89
|
};
|
|
55
|
-
let child;
|
|
56
90
|
try {
|
|
57
91
|
child = spawn(binary, args, {
|
|
58
92
|
env,
|
|
@@ -66,6 +100,7 @@ function runAiCliInvocation(hooks) {
|
|
|
66
100
|
return;
|
|
67
101
|
}
|
|
68
102
|
hooks.onSpawn?.(child);
|
|
103
|
+
armInactivityTimer();
|
|
69
104
|
if (hooks.timeoutMs != null && hooks.timeoutMs > 0) {
|
|
70
105
|
timer = setTimeout(() => {
|
|
71
106
|
hooks.onTimeout?.();
|
|
@@ -73,31 +108,13 @@ function runAiCliInvocation(hooks) {
|
|
|
73
108
|
// then escalate to SIGKILL after a grace window if the child ignores
|
|
74
109
|
// SIGTERM — otherwise a hung, signal-swallowing CLI is orphaned for the
|
|
75
110
|
// host's lifetime. (Mirrors QueueManager._kill.)
|
|
76
|
-
|
|
77
|
-
(0, tree_kill_1.default)(child.pid, 'SIGTERM');
|
|
78
|
-
const pid = child.pid;
|
|
79
|
-
const killTimer = setTimeout(() => {
|
|
80
|
-
try {
|
|
81
|
-
(0, tree_kill_1.default)(pid, 'SIGKILL', () => { });
|
|
82
|
-
}
|
|
83
|
-
catch { /* gone */ }
|
|
84
|
-
}, 2000);
|
|
85
|
-
killTimer.unref?.();
|
|
86
|
-
child.once('close', () => clearTimeout(killTimer));
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
try {
|
|
90
|
-
child.kill('SIGTERM');
|
|
91
|
-
}
|
|
92
|
-
catch { /* already gone */ }
|
|
93
|
-
}
|
|
111
|
+
terminateForTimeout();
|
|
94
112
|
settle({ code: null, timedOut: true, spawnFailed: false, child });
|
|
95
113
|
}, hooks.timeoutMs);
|
|
96
114
|
}
|
|
97
115
|
if (child.stdout) {
|
|
98
116
|
const reader = (0, node_readline_1.createInterface)({ input: child.stdout, crlfDelay: Infinity });
|
|
99
|
-
|
|
100
|
-
child.stdout.on('data', () => hooks.onData('stdout'));
|
|
117
|
+
child.stdout.on('data', () => { armInactivityTimer(); hooks.onData?.('stdout'); });
|
|
101
118
|
reader.on('line', (line) => {
|
|
102
119
|
// A malformed line or a buggy adapter parser must NEVER crash the whole
|
|
103
120
|
// server process — a throw in this readline handler is otherwise an
|
|
@@ -127,12 +144,12 @@ function runAiCliInvocation(hooks) {
|
|
|
127
144
|
if (child.stderr) {
|
|
128
145
|
if (hooks.onStderrLine) {
|
|
129
146
|
const errReader = (0, node_readline_1.createInterface)({ input: child.stderr, crlfDelay: Infinity });
|
|
130
|
-
|
|
131
|
-
child.stderr.on('data', () => hooks.onData('stderr'));
|
|
147
|
+
child.stderr.on('data', () => { armInactivityTimer(); hooks.onData?.('stderr'); });
|
|
132
148
|
errReader.on('line', (line) => hooks.onStderrLine(line));
|
|
133
149
|
}
|
|
134
150
|
else {
|
|
135
151
|
child.stderr.on('data', (chunk) => {
|
|
152
|
+
armInactivityTimer();
|
|
136
153
|
if (hooks.onData)
|
|
137
154
|
hooks.onData('stderr');
|
|
138
155
|
if (stderrTail.length < STDERR_TAIL_CAP)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─── The ONE premium spec contract (premium-milestone-progress D6) ─────────
|
|
3
|
+
//
|
|
4
|
+
// Every AI author of detailed specs derives its spec-content instructions
|
|
5
|
+
// from here: the day-0 Project Builder (blueprint-operator-prompt.ts), M2+
|
|
6
|
+
// milestone generation (chat-manager.ts _buildMilestoneSystemPrompt) and the
|
|
7
|
+
// agent's super-spec mode (agent-operator-prompt.ts). The DEPTH bar is shared;
|
|
8
|
+
// only the grounding rule differs per author (`day0` = everything introduced
|
|
9
|
+
// is labelled *planned*, nothing existing may be claimed; `verified` = only
|
|
10
|
+
// paths/identifiers actually read may be named).
|
|
11
|
+
//
|
|
12
|
+
// BYTE-STABILITY: every export is a static string / object (no timestamps,
|
|
13
|
+
// no live data) so provider prompt caching keeps working across turns.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.PREMIUM_SCAFFOLD_EXAMPLE = exports.SPEC_DEPTH_FLOORS = void 0;
|
|
16
|
+
exports.premiumSpecContract = premiumSpecContract;
|
|
17
|
+
exports.premiumSpecContractCompact = premiumSpecContractCompact;
|
|
18
|
+
/** Deterministic floors the quality gate enforces (server + client mirror). */
|
|
19
|
+
exports.SPEC_DEPTH_FLOORS = {
|
|
20
|
+
problemMinChars: 200,
|
|
21
|
+
solutionMinChars: 500,
|
|
22
|
+
outOfScopeMinBullets: 3,
|
|
23
|
+
technicalMinBullets: 5,
|
|
24
|
+
criteriaMin: 6,
|
|
25
|
+
criteriaMax: 10,
|
|
26
|
+
criterionMinChars: 20,
|
|
27
|
+
};
|
|
28
|
+
const GROUNDING = {
|
|
29
|
+
day0: {
|
|
30
|
+
intro: 'No repository exists yet. Ground every technical detail in the selected stack, the planned components, the intended contracts and data shapes, the known risks and the dependencies between specs.',
|
|
31
|
+
modules: 'name the modules, components, routes, tables and files this spec will CREATE, each explicitly marked as planned (for example "src/features/pantry/PantryList.tsx (planned)") with one line of responsibility — never claim that any of them already exists',
|
|
32
|
+
technical: 'anchor bullets on the planned artifacts above and on the selected stack; never invent or imply an existing repository path, module, function, migration or test file',
|
|
33
|
+
},
|
|
34
|
+
verified: {
|
|
35
|
+
intro: 'Ground every technical detail in the real codebase you read during this conversation, never in plausible-sounding memory.',
|
|
36
|
+
modules: 'name the REAL modules, components, routes, tables and files the change builds on or extends — only ones you actually opened — plus the new ones it will create, each marked as planned',
|
|
37
|
+
technical: 'anchor bullets on EXACT file paths and identifiers you verified; if you did not read it, do not name it',
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* The full contract, as a markdown section body (no leading heading) — for
|
|
42
|
+
* instruction files and prompt bodies.
|
|
43
|
+
*/
|
|
44
|
+
function premiumSpecContract(mode) {
|
|
45
|
+
const g = GROUNDING[mode];
|
|
46
|
+
const f = exports.SPEC_DEPTH_FLOORS;
|
|
47
|
+
return `${g.intro} Write every spec as if a senior engineer who has never spoken to the user must implement it unattended and a non-technical reviewer must understand what they are approving: no section is a restated title, every section carries decisions.
|
|
48
|
+
|
|
49
|
+
Every detailed spec MUST satisfy all of these rules:
|
|
50
|
+
|
|
51
|
+
- \`kind\` is exactly \`scaffold\`, \`feature\`, or \`verification\`.
|
|
52
|
+
- \`title\` is concise, imperative, unique in the batch, and in English.
|
|
53
|
+
- \`shortSummary\` is one useful English sentence, no more than 240 characters.
|
|
54
|
+
- \`description\` is English markdown with exactly these five \`##\` headings, once each and in this order (sub-blocks use \`###\`, never \`##\`):
|
|
55
|
+
1. \`## Problem Statement\` — 3–5 sentences (at least ${f.problemMinChars} characters): the persona, the moment the pain happens, what hurts today and why, why this belongs in THIS milestone, and what a good outcome looks like. A narrative, not a restated title.
|
|
56
|
+
2. \`## Proposed Solution\` — at least ${f.solutionMinChars} characters. Open with a numbered user journey (what the user does and sees, step by step), then these \`###\` sub-blocks:
|
|
57
|
+
- \`### User experience\` — the screens/commands involved and their states: empty, loading, error, success; copy tone; what is remembered between visits.
|
|
58
|
+
- \`### Data model\` — the entities with their fields, types, constraints and relationships (as planned).
|
|
59
|
+
- \`### Interfaces & contracts\` — routes/commands/events with request and response shapes, validation rules and error responses.
|
|
60
|
+
- \`### Planned modules\` — ${g.modules}.
|
|
61
|
+
- \`### Key decisions\` — 2–3 decisions with the alternative considered and why it was rejected.
|
|
62
|
+
3. \`## Out of Scope\` — at least ${f.outOfScopeMinBullets} bullets; each names what is deferred, why, and where it lands (a later spec or milestone by title).
|
|
63
|
+
4. \`## Technical Considerations\` — at least ${f.technicalMinBullets} labelled bullets chosen from: **Architecture**, **Data & contracts**, **Failure handling & edge cases**, **Security & privacy**, **Performance & limits**, **Observability**, **Testing strategy** (unit / integration / end-to-end with named scenarios), **Dependencies** (earlier specs by title), **Risks & mitigations**; ${g.technical}.
|
|
64
|
+
5. \`## Estimated Complexity\` — Low, Medium, High, or Very High, then 1–2 sentences on what drives the estimate and the main uncertainty.
|
|
65
|
+
- Do NOT put an \`## Acceptance Criteria\` heading in \`description\`. Criteria live only in the separate \`acceptanceCriteria\` array; the app folds them into the ticket deterministically at commit time.
|
|
66
|
+
- \`acceptanceCriteria\` contains ${f.criteriaMin}–${f.criteriaMax} independent, testable outcomes (each at least ${f.criterionMinChars} characters), written as observable behaviour — "Given … when … then …" or "When X, the system Y" — never implementation steps. Across the set cover: the happy path, at least one failure or edge case (invalid input, empty state, permission denied, offline, timeout), at least one automated verification (the unit/integration/e2e test that proves it), and for user-facing specs an empty-state or accessibility outcome.
|
|
67
|
+
- \`priority\` is exactly \`low\`, \`medium\`, \`high\`, or \`critical\` and reflects delivery urgency/risk rather than implementation complexity.
|
|
68
|
+
- \`labels\` includes the milestone label plus at least one concise domain label such as \`frontend\`, \`api\`, \`data\`, \`auth\`, \`testing\`, or \`infra\`.`;
|
|
69
|
+
}
|
|
70
|
+
/** One-paragraph form for \`--system-prompt\` channels (same rules, no markdown). */
|
|
71
|
+
function premiumSpecContractCompact(mode) {
|
|
72
|
+
const g = GROUNDING[mode];
|
|
73
|
+
const f = exports.SPEC_DEPTH_FLOORS;
|
|
74
|
+
return `Spec depth bar (premium): ${g.intro} Each spec has kind (scaffold|feature|verification), a unique imperative English title, a one-sentence shortSummary <=240 characters, and a description with exactly these ## headings once and in order: ## Problem Statement (3-5 sentences, >=${f.problemMinChars} chars: persona, trigger, pain, why this milestone, what good looks like), ## Proposed Solution (>=${f.solutionMinChars} chars: a numbered user journey, then ### User experience with empty/loading/error/success states, ### Data model with fields and types, ### Interfaces & contracts with request/response shapes and errors, ### Planned modules — ${g.modules} — and ### Key decisions with the rejected alternative), ## Out of Scope (>=${f.outOfScopeMinBullets} bullets: what, why deferred, where it lands), ## Technical Considerations (>=${f.technicalMinBullets} labelled bullets from Architecture, Data & contracts, Failure handling & edge cases, Security & privacy, Performance & limits, Observability, Testing strategy with named scenarios, Dependencies by spec title, Risks & mitigations; ${g.technical}), ## Estimated Complexity (level plus 1-2 sentences and the main uncertainty). Never an ## Acceptance Criteria section in description. A separate acceptanceCriteria array of ${f.criteriaMin}-${f.criteriaMax} observable outcomes (>=${f.criterionMinChars} chars each, Given/When/Then style) covering the happy path, at least one failure/edge case, at least one automated verification and an empty-state/accessibility outcome for user-facing specs. priority low|medium|high|critical by urgency/risk; labels include the milestone label plus a domain label.`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A complete premium example (the mandatory M1 scaffold) — rendered into the
|
|
78
|
+
* Builder prompt so the model mirrors the DEPTH, not just the shape.
|
|
79
|
+
*/
|
|
80
|
+
exports.PREMIUM_SCAFFOLD_EXAMPLE = {
|
|
81
|
+
kind: 'scaffold',
|
|
82
|
+
title: 'Scaffold the runnable project foundation',
|
|
83
|
+
shortSummary: 'Turn the README-only repository into an installable, runnable, testable application shell with CI, so every later slice lands on a verified foundation.',
|
|
84
|
+
description: [
|
|
85
|
+
'## Problem Statement',
|
|
86
|
+
'A contributor who clones the repository today finds a README and nothing else: there is no dependency manifest, no command that starts the app, no test to prove anything works and no CI to catch a broken change. Every Milestone-1 slice would otherwise begin by improvising its own setup, producing three incompatible foundations by week one. The walking skeleton needs this first because each later spec is defined as "runs on top of the scaffold". A good outcome is a clean checkout that installs, starts, tests and passes CI with documented commands, with zero product behaviour beyond a visible placeholder.',
|
|
87
|
+
'',
|
|
88
|
+
'## Proposed Solution',
|
|
89
|
+
'1. The contributor runs the documented install command and gets a reproducible dependency tree.',
|
|
90
|
+
'2. They run the development command and see the placeholder home screen respond on the documented port.',
|
|
91
|
+
'3. They run the test command and one smoke test passes.',
|
|
92
|
+
'4. They open a pull request and CI runs the same install, lint, build and test steps.',
|
|
93
|
+
'',
|
|
94
|
+
'### User experience',
|
|
95
|
+
'A single placeholder route/screen showing the product name and a short "foundation ready" message; no other UI. States: success (page renders), error (the process exits with a clear message when the port is taken or a dependency is missing). Nothing is remembered between visits.',
|
|
96
|
+
'',
|
|
97
|
+
'### Data model',
|
|
98
|
+
'None yet. The persistence layer is initialised (connection/config only) so later specs add entities without re-scaffolding.',
|
|
99
|
+
'',
|
|
100
|
+
'### Interfaces & contracts',
|
|
101
|
+
'`GET /health` → `{ "status": "ok", "version": "<package version>" }` (200). Development, build and test commands documented in the README with their exit-code semantics.',
|
|
102
|
+
'',
|
|
103
|
+
'### Planned modules',
|
|
104
|
+
'- `package manifest + lockfile (planned)` — pinned runtime and dependency versions.',
|
|
105
|
+
'- `src/app entry (planned)` — process bootstrap, port/config loading, the placeholder route.',
|
|
106
|
+
'- `src/config (planned)` — typed environment loading with defaults.',
|
|
107
|
+
'- `tests/smoke (planned)` — one end-to-end smoke test hitting `/health`.',
|
|
108
|
+
'- `CI workflow (planned)` — install → lint → build → test on every push and pull request.',
|
|
109
|
+
'',
|
|
110
|
+
'### Key decisions',
|
|
111
|
+
'- Keep the placeholder minimal instead of seeding a real feature: a feature here would blur the boundary later specs build on. Rejected: scaffolding the first product screen now.',
|
|
112
|
+
'- Pin exact dependency versions from day one; floating ranges were rejected because the first CI break would be a dependency drift, not a product bug.',
|
|
113
|
+
'',
|
|
114
|
+
'## Out of Scope',
|
|
115
|
+
'- Any product feature beyond the placeholder — every slice of the core flow lands in the later Milestone-1 specs.',
|
|
116
|
+
'- Production deployment, hosting and environment provisioning — deferred to a later milestone once the skeleton runs end to end.',
|
|
117
|
+
'- Authentication, authorization and user accounts — a dedicated Milestone-1 or Milestone-2 spec owns them.',
|
|
118
|
+
'',
|
|
119
|
+
'## Technical Considerations',
|
|
120
|
+
'- **Architecture**: one process, one entry module, configuration read once at boot; later specs add modules under the planned layout rather than reshaping it.',
|
|
121
|
+
'- **Data & contracts**: `/health` is the only contract; its response shape is frozen so CI and later monitoring can rely on it.',
|
|
122
|
+
'- **Failure handling & edge cases**: a missing runtime or an occupied port fails fast with an actionable message; the smoke test fails when `/health` is not 200.',
|
|
123
|
+
'- **Security & privacy**: no secrets committed; `.env.example` documents variables; the health endpoint exposes no internal detail beyond the version.',
|
|
124
|
+
'- **Performance & limits**: cold start under a few seconds on a laptop; no performance work beyond that.',
|
|
125
|
+
'- **Observability**: structured startup log line with port and version; CI logs are the audit trail.',
|
|
126
|
+
'- **Testing strategy**: unit — config loading with and without overrides; e2e — the smoke test starts the app and asserts `/health`; CI runs both on every change.',
|
|
127
|
+
'- **Dependencies**: none (first spec); every later Milestone-1 spec depends on this one.',
|
|
128
|
+
'- **Risks & mitigations**: toolchain drift between contributors — mitigated by the pinned lockfile and CI running from a clean checkout.',
|
|
129
|
+
'',
|
|
130
|
+
'## Estimated Complexity',
|
|
131
|
+
'Medium — the foundation must align local development, automated tests and CI without implementing product behaviour; the main uncertainty is CI runtime setup for the chosen stack.',
|
|
132
|
+
].join('\n'),
|
|
133
|
+
acceptanceCriteria: [
|
|
134
|
+
'Given a clean checkout, when the contributor runs the documented install command, then it completes without errors and produces the pinned dependency tree.',
|
|
135
|
+
'When the development command runs, the placeholder screen renders and GET /health returns 200 with { status: "ok", version } within a few seconds.',
|
|
136
|
+
'When the test command runs from a clean checkout, the smoke test passes and the process exits with code 0.',
|
|
137
|
+
'When the configured port is already in use, the process exits non-zero with a message naming the port instead of hanging.',
|
|
138
|
+
'When a pull request is opened, CI runs install, lint, build and test and reports a red status on any failure.',
|
|
139
|
+
'The README documents the install, run and test commands and a contributor can follow them without asking anyone.',
|
|
140
|
+
],
|
|
141
|
+
priority: 'high',
|
|
142
|
+
labels: ['M1', 'foundation', 'infra'],
|
|
143
|
+
};
|
|
@@ -29,6 +29,9 @@ function validateBlock(parsed) {
|
|
|
29
29
|
partial.title = obj.title;
|
|
30
30
|
if (typeof obj.description === 'string')
|
|
31
31
|
partial.description = obj.description;
|
|
32
|
+
if (Array.isArray(obj.repositoryIds) && obj.repositoryIds.length > 0 && obj.repositoryIds.every((id) => typeof id === 'string' && id.trim()) && new Set(obj.repositoryIds).size === obj.repositoryIds.length) {
|
|
33
|
+
partial.repositoryIds = [...obj.repositoryIds];
|
|
34
|
+
}
|
|
32
35
|
const labels = coerceStringArray(obj.labels);
|
|
33
36
|
if (labels)
|
|
34
37
|
partial.labels = labels;
|
|
@@ -87,6 +90,8 @@ function mergeDraft(prev, next) {
|
|
|
87
90
|
out.title = next.title;
|
|
88
91
|
if (typeof next.description === 'string' && next.description !== '')
|
|
89
92
|
out.description = next.description;
|
|
93
|
+
if (Array.isArray(next.repositoryIds) && next.repositoryIds.length > 0 && next.repositoryIds.every((id) => typeof id === 'string' && id.trim()) && new Set(next.repositoryIds).size === next.repositoryIds.length)
|
|
94
|
+
out.repositoryIds = next.repositoryIds.slice();
|
|
90
95
|
if (Array.isArray(next.labels))
|
|
91
96
|
out.labels = next.labels.slice();
|
|
92
97
|
if (Array.isArray(next.acceptanceCriteria))
|
|
@@ -108,7 +113,7 @@ function applyBlocks(prev, blocks) {
|
|
|
108
113
|
for (const block of blocks) {
|
|
109
114
|
const before = nextDraft;
|
|
110
115
|
nextDraft = mergeDraft(before, block.partial);
|
|
111
|
-
for (const key of ['title', 'description', 'labels', 'priority', 'acceptanceCriteria']) {
|
|
116
|
+
for (const key of ['title', 'description', 'labels', 'priority', 'acceptanceCriteria', 'repositoryIds']) {
|
|
112
117
|
if (!shallowEqual(before[key], nextDraft[key]))
|
|
113
118
|
changed.add(key);
|
|
114
119
|
}
|
|
@@ -12,6 +12,7 @@ exports.CLAUDE_MODELS = [
|
|
|
12
12
|
{ value: 'haiku', label: 'Claude Haiku' },
|
|
13
13
|
];
|
|
14
14
|
exports.CODEX_MODELS = [
|
|
15
|
+
{ value: 'gpt-6-astra', label: 'GPT-6 Astra' },
|
|
15
16
|
{ value: 'gpt-5.6-sol', label: 'GPT-5.6 Sol' },
|
|
16
17
|
{ value: 'gpt-5.6-terra', label: 'GPT-5.6 Terra' },
|
|
17
18
|
{ value: 'gpt-5.6-luna', label: 'GPT-5.6 Luna' },
|