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
|
@@ -12,6 +12,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
12
12
|
const crypto_1 = require("crypto");
|
|
13
13
|
const win_spawn_1 = require("./util/win-spawn");
|
|
14
14
|
const desktop_db_1 = require("./desktop-db");
|
|
15
|
+
const blueprint_store_1 = require("./blueprint-store");
|
|
15
16
|
const providers_1 = require("./providers");
|
|
16
17
|
const blueprint_draft_parser_1 = require("./blueprint-draft-parser");
|
|
17
18
|
const blueprint_types_1 = require("./blueprint-types");
|
|
@@ -104,6 +105,10 @@ function createBlueprintCommitRunner(deps) {
|
|
|
104
105
|
assemble: deps.io?.assemble ?? (async (opts) => { await (0, offline_assemble_1.assembleProjectOffline)(opts); }),
|
|
105
106
|
writePair: deps.io?.writePair ?? blueprint_render_1.writeBlueprintPair,
|
|
106
107
|
mutateTickets: deps.io?.mutateTickets ?? ((filePath, fn) => { (0, ticket_store_1.mutateStore)(filePath, fn); }),
|
|
108
|
+
markCommitted: deps.io?.markCommitted ??
|
|
109
|
+
((conversationId, projectId) => {
|
|
110
|
+
(0, blueprint_store_1.markBlueprintCommitted)(deps.registry.desktopDb, conversationId, projectId);
|
|
111
|
+
}),
|
|
107
112
|
registerProject: deps.io?.registerProject ??
|
|
108
113
|
((opts) => {
|
|
109
114
|
const ctx = deps.registry.addProject({
|
|
@@ -148,6 +153,9 @@ function createBlueprintCommitRunner(deps) {
|
|
|
148
153
|
return { ok: false, error: 'm1_specs_over_cap', detail: `max ${blueprint_types_1.M1_SPECS_MAX}` };
|
|
149
154
|
}
|
|
150
155
|
const rawBlueprint = input.blueprint;
|
|
156
|
+
if (Array.isArray(rawBlueprint.m1Specs) && rawBlueprint.m1Specs.some((spec) => spec && typeof spec === 'object' && Object.prototype.hasOwnProperty.call(spec, 'repositoryIds'))) {
|
|
157
|
+
return { ok: false, error: 'invalid_repository_ids', detail: 'A new Builder project uses its primary repository. Add repository scope after the project and its repository IDs exist.' };
|
|
158
|
+
}
|
|
151
159
|
const quality = (0, blueprint_spec_quality_1.analyzeBuilderSpecBatch)({
|
|
152
160
|
specsComplete: rawBlueprint.specsComplete,
|
|
153
161
|
specs: Array.isArray(rawBlueprint.m1Specs) ? rawBlueprint.m1Specs : [],
|
|
@@ -174,7 +182,11 @@ function createBlueprintCommitRunner(deps) {
|
|
|
174
182
|
catch {
|
|
175
183
|
/* unreadable registry — never block on the projection; addProject re-mirrors */
|
|
176
184
|
}
|
|
177
|
-
|
|
185
|
+
const conversationId = typeof input.conversationId === 'string' && input.conversationId
|
|
186
|
+
&& (0, blueprint_store_1.getBlueprintConversation)(deps.registry.desktopDb, input.conversationId)
|
|
187
|
+
? input.conversationId
|
|
188
|
+
: null;
|
|
189
|
+
return { ok: true, blueprint, name, location, providers, createGithubRepo: input.createGithubRepo === true, conversationId };
|
|
178
190
|
};
|
|
179
191
|
const start = (input) => {
|
|
180
192
|
const validated = validate(input);
|
|
@@ -283,6 +295,14 @@ function createBlueprintCommitRunner(deps) {
|
|
|
283
295
|
emit(commitId, step, 'running');
|
|
284
296
|
io.registerProject({ id: projectId, slug, name, path: location, providers });
|
|
285
297
|
emit(commitId, step, 'done');
|
|
298
|
+
if (v.conversationId) {
|
|
299
|
+
try {
|
|
300
|
+
io.markCommitted(v.conversationId, projectId);
|
|
301
|
+
}
|
|
302
|
+
catch (err) {
|
|
303
|
+
console.warn(`[blueprint-commit] could not link conversation ${v.conversationId}:`, err.message);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
286
306
|
// 7. best-effort GitHub remote — never aborts. Pre-flight guards against
|
|
287
307
|
// a stale client cache sending createGithubRepo with gh absent/unauthed.
|
|
288
308
|
if (v.createGithubRepo) {
|
|
@@ -8,13 +8,69 @@
|
|
|
8
8
|
// Streaming tail cut: the fence regex only matches CLOSED fences, so an
|
|
9
9
|
// unterminated trailing block is never parsed. `cutUnterminatedBlock` lets
|
|
10
10
|
// stream renderers hide the raw open fence while it is still arriving.
|
|
11
|
+
//
|
|
12
|
+
// Nothing is dropped silently any more: every block that could not become a
|
|
13
|
+
// snapshot is reported in `rejected` (invalid JSON after the tolerant repair
|
|
14
|
+
// pass, missing `blueprintVersion`, or a block the output limit cut off before
|
|
15
|
+
// its closing fence — `truncated`). The chat manager turns those into an
|
|
16
|
+
// automatic repair turn and the UI into a precise, actionable notice.
|
|
11
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.promoteJsonBlueprintFences = promoteJsonBlueprintFences;
|
|
19
|
+
exports.countStartedSpecs = countStartedSpecs;
|
|
12
20
|
exports.coerceBlueprint = coerceBlueprint;
|
|
13
21
|
exports.parseBlueprintDraftBlocks = parseBlueprintDraftBlocks;
|
|
14
22
|
exports.cutUnterminatedBlock = cutUnterminatedBlock;
|
|
15
23
|
const blueprint_types_1 = require("./blueprint-types");
|
|
24
|
+
const json_tolerant_1 = require("./json-tolerant");
|
|
16
25
|
const FENCE_RE = /```blueprint-draft\s*\n([\s\S]*?)\n\s*```/g;
|
|
17
26
|
const OPEN_FENCE_RE = /```blueprint-draft(?![\s\S]*?\n\s*```)/;
|
|
27
|
+
// Fence tolerance: models mirror the schema example and sometimes emit the
|
|
28
|
+
// snapshot inside a ```json (or bare) fence. A closed json/bare block whose
|
|
29
|
+
// body is a `{…}` object carrying an integer `blueprintVersion` IS a snapshot
|
|
30
|
+
// — it is promoted to a blueprint-draft fence before parsing so the panel
|
|
31
|
+
// fills and the raw JSON never lands in the transcript. Never applied inside
|
|
32
|
+
// a proper blueprint-draft block (the nested-json case is handled there).
|
|
33
|
+
const JSON_BLUEPRINT_FENCE_RE = /```(?:json|JSON)?[ \t]*\r?\n(?=[ \t]*\{)([\s\S]*?)\r?\n[ \t]*```(?=[ \t]*(?:\r?\n|$))/g;
|
|
34
|
+
const OPEN_JSON_BLUEPRINT_FENCE_RE = /```(?:json|JSON)?[ \t]*\r?\n[ \t]*\{(?=[\s\S]*"blueprintVersion")(?![\s\S]*?\n[ \t]*```)/;
|
|
35
|
+
/** A lone closing fence right after a matched block — left behind when the
|
|
36
|
+
* model nested a ```json fence inside the blueprint-draft one. */
|
|
37
|
+
const ORPHAN_CLOSE_RE = /^[ \t]*\r?\n?[ \t]*```[ \t]*(?=\r?\n|$)/;
|
|
38
|
+
/** Promote json / bare fenced blueprint objects to blueprint-draft fences
|
|
39
|
+
* (outside proper blueprint-draft blocks). Exported for the client mirror
|
|
40
|
+
* tests' parity checks. */
|
|
41
|
+
function promoteJsonBlueprintFences(text) {
|
|
42
|
+
if (!text || !text.includes('"blueprintVersion"'))
|
|
43
|
+
return text ?? '';
|
|
44
|
+
const promoteGap = (gap) => {
|
|
45
|
+
if (!gap.includes('```') || !gap.includes('"blueprintVersion"'))
|
|
46
|
+
return gap;
|
|
47
|
+
JSON_BLUEPRINT_FENCE_RE.lastIndex = 0;
|
|
48
|
+
return gap.replace(JSON_BLUEPRINT_FENCE_RE, (whole, body) => {
|
|
49
|
+
if (!body.includes('"blueprintVersion"'))
|
|
50
|
+
return whole;
|
|
51
|
+
const parsed = (0, json_tolerant_1.parseJsonTolerant)(body);
|
|
52
|
+
if (!parsed.ok || !coerceBlueprint(parsed.value))
|
|
53
|
+
return whole;
|
|
54
|
+
return '```blueprint-draft\n' + body + '\n```';
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
let out = '';
|
|
58
|
+
let cursor = 0;
|
|
59
|
+
FENCE_RE.lastIndex = 0;
|
|
60
|
+
let m;
|
|
61
|
+
while ((m = FENCE_RE.exec(text)) !== null) {
|
|
62
|
+
out += promoteGap(text.slice(cursor, m.index)) + m[0];
|
|
63
|
+
cursor = m.index + m[0].length;
|
|
64
|
+
}
|
|
65
|
+
return out + promoteGap(text.slice(cursor));
|
|
66
|
+
}
|
|
67
|
+
/** Rough count of specs that had started in a (possibly truncated) block. */
|
|
68
|
+
function countStartedSpecs(blockText) {
|
|
69
|
+
const at = blockText.indexOf('"m1Specs"');
|
|
70
|
+
if (at === -1)
|
|
71
|
+
return 0;
|
|
72
|
+
return (blockText.slice(at).match(/"title"\s*:/g) ?? []).length;
|
|
73
|
+
}
|
|
18
74
|
function asString(value) {
|
|
19
75
|
return typeof value === 'string' ? value : '';
|
|
20
76
|
}
|
|
@@ -89,6 +145,9 @@ function coerceM1Specs(value) {
|
|
|
89
145
|
if (typeof obj.dependsOnIndex === 'number' && Number.isInteger(obj.dependsOnIndex) && obj.dependsOnIndex >= 0) {
|
|
90
146
|
spec.dependsOnIndex = obj.dependsOnIndex;
|
|
91
147
|
}
|
|
148
|
+
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) {
|
|
149
|
+
spec.repositoryIds = [...obj.repositoryIds];
|
|
150
|
+
}
|
|
92
151
|
out.push(spec);
|
|
93
152
|
}
|
|
94
153
|
return out;
|
|
@@ -121,36 +180,82 @@ function coerceBlueprint(parsed) {
|
|
|
121
180
|
* every block (valid or malformed) stripped, plus the LAST valid snapshot.
|
|
122
181
|
* Never throws.
|
|
123
182
|
*/
|
|
124
|
-
function parseBlueprintDraftBlocks(
|
|
125
|
-
|
|
126
|
-
|
|
183
|
+
function parseBlueprintDraftBlocks(input) {
|
|
184
|
+
const text = promoteJsonBlueprintFences(input ?? '');
|
|
185
|
+
if (!text || (!text.includes('```blueprint-draft') && !OPEN_JSON_BLUEPRINT_FENCE_RE.test(text))) {
|
|
186
|
+
return {
|
|
187
|
+
stripped: text ?? '',
|
|
188
|
+
blueprint: null,
|
|
189
|
+
rawBlueprint: null,
|
|
190
|
+
hadBlocks: false,
|
|
191
|
+
rejected: [],
|
|
192
|
+
repaired: false,
|
|
193
|
+
truncated: false,
|
|
194
|
+
};
|
|
127
195
|
}
|
|
128
196
|
let blueprint = null;
|
|
129
197
|
let rawBlueprint = null;
|
|
198
|
+
let repaired = false;
|
|
130
199
|
let hadBlocks = false;
|
|
200
|
+
const rejected = [];
|
|
131
201
|
let stripped = '';
|
|
132
202
|
let cursor = 0;
|
|
203
|
+
let index = 0;
|
|
133
204
|
FENCE_RE.lastIndex = 0;
|
|
134
205
|
let match;
|
|
135
206
|
while ((match = FENCE_RE.exec(text)) !== null) {
|
|
136
207
|
hadBlocks = true;
|
|
137
208
|
stripped += text.slice(cursor, match.index);
|
|
138
209
|
cursor = match.index + match[0].length;
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
210
|
+
const orphan = ORPHAN_CLOSE_RE.exec(text.slice(cursor));
|
|
211
|
+
if (orphan) {
|
|
212
|
+
cursor += orphan[0].length;
|
|
213
|
+
FENCE_RE.lastIndex = cursor;
|
|
142
214
|
}
|
|
143
|
-
|
|
144
|
-
|
|
215
|
+
const blockIndex = index;
|
|
216
|
+
index += 1;
|
|
217
|
+
const parsed = (0, json_tolerant_1.parseJsonTolerant)(match[1]);
|
|
218
|
+
if (!parsed.ok) {
|
|
219
|
+
const where = parsed.excerpt ? ` near: …${parsed.excerpt}…` : '';
|
|
220
|
+
rejected.push({ index: blockIndex, reason: 'invalid_json', detail: `${parsed.error}${where}` });
|
|
221
|
+
continue; // keep the previous valid snapshot
|
|
145
222
|
}
|
|
146
|
-
const candidate = coerceBlueprint(parsed);
|
|
147
|
-
if (candidate) {
|
|
148
|
-
|
|
149
|
-
|
|
223
|
+
const candidate = coerceBlueprint(parsed.value);
|
|
224
|
+
if (!candidate) {
|
|
225
|
+
rejected.push({
|
|
226
|
+
index: blockIndex,
|
|
227
|
+
reason: 'missing_version',
|
|
228
|
+
detail: 'the payload is not a blueprint object with an integer blueprintVersion',
|
|
229
|
+
});
|
|
230
|
+
continue;
|
|
150
231
|
}
|
|
232
|
+
blueprint = candidate;
|
|
233
|
+
rawBlueprint = parsed.value;
|
|
234
|
+
repaired = parsed.repaired;
|
|
151
235
|
}
|
|
152
|
-
|
|
153
|
-
|
|
236
|
+
const remainder = text.slice(cursor);
|
|
237
|
+
const open = OPEN_FENCE_RE.exec(remainder) ?? OPEN_JSON_BLUEPRINT_FENCE_RE.exec(remainder);
|
|
238
|
+
let truncated = false;
|
|
239
|
+
if (open) {
|
|
240
|
+
// The reply ended inside a block: the output limit cut it off. Never let
|
|
241
|
+
// the partial JSON reach the transcript; report how far it got instead.
|
|
242
|
+
hadBlocks = true;
|
|
243
|
+
truncated = true;
|
|
244
|
+
const partial = remainder.slice(open.index);
|
|
245
|
+
const started = countStartedSpecs(partial);
|
|
246
|
+
rejected.push({
|
|
247
|
+
index,
|
|
248
|
+
reason: 'truncated',
|
|
249
|
+
detail: started > 0
|
|
250
|
+
? `the block was cut off before its closing fence after ${started} spec title(s) had started`
|
|
251
|
+
: 'the block was cut off before its closing fence',
|
|
252
|
+
});
|
|
253
|
+
stripped += remainder.slice(0, open.index);
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
stripped += remainder;
|
|
257
|
+
}
|
|
258
|
+
return { stripped, blueprint, rawBlueprint, hadBlocks, rejected, repaired, truncated };
|
|
154
259
|
}
|
|
155
260
|
/**
|
|
156
261
|
* For live stream rendering: cut an UNTERMINATED trailing `blueprint-draft`
|
|
@@ -159,9 +264,9 @@ function parseBlueprintDraftBlocks(text) {
|
|
|
159
264
|
* parser on the settled text instead.
|
|
160
265
|
*/
|
|
161
266
|
function cutUnterminatedBlock(text) {
|
|
162
|
-
if (!text
|
|
163
|
-
return
|
|
164
|
-
const match = OPEN_FENCE_RE.exec(text);
|
|
267
|
+
if (!text)
|
|
268
|
+
return '';
|
|
269
|
+
const match = (text.includes('```blueprint-draft') ? OPEN_FENCE_RE.exec(text) : null) ?? OPEN_JSON_BLUEPRINT_FENCE_RE.exec(text);
|
|
165
270
|
if (!match)
|
|
166
271
|
return text;
|
|
167
272
|
return text.slice(0, match.index);
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// App-driven batched generation for the Project Builder (premium-milestone-
|
|
3
|
+
// progress D7). Pure helpers — the BlueprintChatManager drives the turns.
|
|
4
|
+
//
|
|
5
|
+
// Why: "emit all 5–10 specs in ONE response" capped every spec's depth by the
|
|
6
|
+
// output budget. The premium protocol splits generation:
|
|
7
|
+
// 1. OUTLINE — one full `blueprint-draft` snapshot, every spec with its
|
|
8
|
+
// kind/title/summary/priority/labels/dependency and EMPTY body.
|
|
9
|
+
// 2. DETAIL turns — the app asks for two specs at a time; the model answers
|
|
10
|
+
// with `spec-detail` fenced blocks ({ index, spec }) — small, focused
|
|
11
|
+
// payloads the app merges into the snapshot by index.
|
|
12
|
+
// 3. AUDIT turn — the model answers with one `spec-audit` block
|
|
13
|
+
// ({ specsComplete, issues[], fixes[] }); the app merges the fixes, sets
|
|
14
|
+
// specsComplete and runs the deterministic gate as before.
|
|
15
|
+
// Transcript hygiene: the generation fences are stripped exactly like
|
|
16
|
+
// blueprint-draft blocks (never shown as raw JSON).
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.MAX_GENERATION_TURNS = exports.SPECS_PER_DETAIL_TURN = void 0;
|
|
19
|
+
exports.isOutlineSnapshot = isOutlineSnapshot;
|
|
20
|
+
exports.unfilledSpecIndices = unfilledSpecIndices;
|
|
21
|
+
exports.nextDetailRange = nextDetailRange;
|
|
22
|
+
exports.projectedGenerationTurns = projectedGenerationTurns;
|
|
23
|
+
exports.specTitles = specTitles;
|
|
24
|
+
exports.buildDetailPrompt = buildDetailPrompt;
|
|
25
|
+
exports.buildAuditPrompt = buildAuditPrompt;
|
|
26
|
+
exports.buildDetailRepairPrompt = buildDetailRepairPrompt;
|
|
27
|
+
exports.buildAuditIssuesPrompt = buildAuditIssuesPrompt;
|
|
28
|
+
exports.parseGenerationBlocks = parseGenerationBlocks;
|
|
29
|
+
exports.mergeSpecDetails = mergeSpecDetails;
|
|
30
|
+
exports.withSpecsComplete = withSpecsComplete;
|
|
31
|
+
exports.rangeFilled = rangeFilled;
|
|
32
|
+
exports.cutUnterminatedGenerationBlock = cutUnterminatedGenerationBlock;
|
|
33
|
+
const json_tolerant_1 = require("./json-tolerant");
|
|
34
|
+
const blueprint_types_1 = require("./blueprint-types");
|
|
35
|
+
exports.SPECS_PER_DETAIL_TURN = 2;
|
|
36
|
+
/** Outline + detail turns + audit + one repair — 10 specs ⇒ 1 + 5 + 1 + 1. */
|
|
37
|
+
exports.MAX_GENERATION_TURNS = 8;
|
|
38
|
+
function record(value) {
|
|
39
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : null;
|
|
40
|
+
}
|
|
41
|
+
function specList(raw) {
|
|
42
|
+
const source = record(raw);
|
|
43
|
+
if (!source || !Array.isArray(source.m1Specs))
|
|
44
|
+
return null;
|
|
45
|
+
return source.m1Specs.map((s) => record(s) ?? {});
|
|
46
|
+
}
|
|
47
|
+
function specIsEmpty(spec) {
|
|
48
|
+
const description = typeof spec.description === 'string' ? spec.description.trim() : '';
|
|
49
|
+
const criteria = Array.isArray(spec.acceptanceCriteria) ? spec.acceptanceCriteria.filter((c) => typeof c === 'string' && c.trim()) : [];
|
|
50
|
+
return description === '' && criteria.length === 0;
|
|
51
|
+
}
|
|
52
|
+
/** True when the snapshot is an OUTLINE: ≥ the batch minimum of specs, none detailed. */
|
|
53
|
+
function isOutlineSnapshot(raw) {
|
|
54
|
+
const specs = specList(raw);
|
|
55
|
+
if (!specs || specs.length < blueprint_types_1.M1_SPECS_MIN)
|
|
56
|
+
return false;
|
|
57
|
+
return specs.every(specIsEmpty);
|
|
58
|
+
}
|
|
59
|
+
/** Indices (0-based) of specs still without a body. */
|
|
60
|
+
function unfilledSpecIndices(raw) {
|
|
61
|
+
const specs = specList(raw);
|
|
62
|
+
if (!specs)
|
|
63
|
+
return [];
|
|
64
|
+
return specs.flatMap((spec, index) => (specIsEmpty(spec) ? [index] : []));
|
|
65
|
+
}
|
|
66
|
+
/** Next detail range (0-based inclusive) or null when every spec is filled. */
|
|
67
|
+
function nextDetailRange(raw, perTurn = exports.SPECS_PER_DETAIL_TURN) {
|
|
68
|
+
const pending = unfilledSpecIndices(raw);
|
|
69
|
+
if (pending.length === 0)
|
|
70
|
+
return null;
|
|
71
|
+
const from = pending[0];
|
|
72
|
+
const to = Math.min(from + perTurn - 1, pending[pending.length - 1]);
|
|
73
|
+
return { from, to };
|
|
74
|
+
}
|
|
75
|
+
/** Total projected turns for an outline of `total` specs (details + audit). */
|
|
76
|
+
function projectedGenerationTurns(total, perTurn = exports.SPECS_PER_DETAIL_TURN) {
|
|
77
|
+
return 1 + Math.ceil(total / perTurn) + 1;
|
|
78
|
+
}
|
|
79
|
+
function specTitles(raw) {
|
|
80
|
+
return (specList(raw) ?? []).map((s) => (typeof s.title === 'string' ? s.title : ''));
|
|
81
|
+
}
|
|
82
|
+
// ─── Prompts (static apart from the range/titles, so the session cache holds) ─
|
|
83
|
+
function buildDetailPrompt(range, titles) {
|
|
84
|
+
const items = [];
|
|
85
|
+
for (let i = range.from; i <= range.to; i++)
|
|
86
|
+
items.push(`- index ${i}: "${titles[i] ?? ''}"`);
|
|
87
|
+
return `APP CONTINUE: write the FULL premium detail for these outline specs now — every section, every sub-block, ${items.length === 1 ? 'the spec' : 'every spec'} at the depth the contract demands:
|
|
88
|
+
${items.join('\n')}
|
|
89
|
+
|
|
90
|
+
Reply with ONE fenced \`spec-detail\` block per spec and NOTHING else — no prose, no blueprint-draft block. Each block is strictly valid JSON:
|
|
91
|
+
|
|
92
|
+
\`\`\`spec-detail
|
|
93
|
+
{ "index": <the 0-based m1Specs index above>, "spec": { "kind": "...", "title": "...", "shortSummary": "...", "description": "...", "acceptanceCriteria": ["..."], "priority": "...", "labels": ["..."], "dependsOnIndex": <optional> } }
|
|
94
|
+
\`\`\`
|
|
95
|
+
|
|
96
|
+
Keep the index, kind, title, priority, labels and dependsOnIndex the outline already fixed (refine the title only if it was wrong). Newlines inside strings escaped as \\n, inner double quotes as \\", no trailing commas, no comments, no nested fences.`;
|
|
97
|
+
}
|
|
98
|
+
function buildAuditPrompt() {
|
|
99
|
+
return `APP AUDIT: every spec now has a body. Audit the WHOLE Milestone-1 batch against the contract — five headings once and in order, the ### sub-blocks, the section depth floors, ${exports.SPECS_PER_DETAIL_TURN}-spec consistency (titles unique, dependencies strictly backward, scaffold first), 6-10 criteria each with a failure case and an automated verification, English content, priority and labels. Reply with ONE fenced \`spec-audit\` block and NOTHING else:
|
|
100
|
+
|
|
101
|
+
\`\`\`spec-audit
|
|
102
|
+
{ "specsComplete": true, "issues": [], "fixes": [ { "index": <0-based>, "spec": { ...the complete corrected spec... } } ] }
|
|
103
|
+
\`\`\`
|
|
104
|
+
|
|
105
|
+
Put every spec you had to correct in \`fixes\` (complete spec objects, same shape as spec-detail). Set \`specsComplete\` to true only when every spec passes after your fixes; otherwise false with the blocking problems listed in \`issues\`.`;
|
|
106
|
+
}
|
|
107
|
+
function buildDetailRepairPrompt(range, titles, detail) {
|
|
108
|
+
const items = [];
|
|
109
|
+
for (let i = range.from; i <= range.to; i++)
|
|
110
|
+
items.push(`- index ${i}: "${titles[i] ?? ''}"`);
|
|
111
|
+
return `APP CHECK: your last reply did not yield usable spec-detail blocks for:
|
|
112
|
+
${items.join('\n')}
|
|
113
|
+
${detail ? `\nProblem: ${detail}\n` : ''}
|
|
114
|
+
Re-emit ONE complete, strictly valid \`spec-detail\` block per spec above (index + complete spec object), and nothing else.`;
|
|
115
|
+
}
|
|
116
|
+
/** Correction turn after an audit that reported blocking problems (D7 §4). */
|
|
117
|
+
function buildAuditIssuesPrompt(issues) {
|
|
118
|
+
const list = issues.map((i) => `- ${i}`).join('\n');
|
|
119
|
+
return `APP CHECK: your audit reported blocking problems. Fix EXACTLY these — enrich, never trim — and reply with ONE fenced \`spec-detail\` block per AFFECTED spec ({ "index": <0-based m1Specs index>, "spec": { …the complete corrected spec… } }) and nothing else; untouched specs keep their content.
|
|
120
|
+
${list}`;
|
|
121
|
+
}
|
|
122
|
+
// ─── Fenced generation blocks ────────────────────────────────────────────────
|
|
123
|
+
const DETAIL_FENCE_RE = /```spec-detail\s*\n([\s\S]*?)\n\s*```/g;
|
|
124
|
+
const AUDIT_FENCE_RE = /```spec-audit\s*\n([\s\S]*?)\n\s*```/g;
|
|
125
|
+
const OPEN_GENERATION_FENCE_RE = /```spec-(?:detail|audit)(?![\s\S]*?\n\s*```)/;
|
|
126
|
+
function coerceDetail(value) {
|
|
127
|
+
const obj = record(value);
|
|
128
|
+
if (!obj)
|
|
129
|
+
return null;
|
|
130
|
+
const index = obj.index;
|
|
131
|
+
const spec = record(obj.spec);
|
|
132
|
+
if (typeof index !== 'number' || !Number.isInteger(index) || index < 0 || !spec)
|
|
133
|
+
return null;
|
|
134
|
+
return { index, spec };
|
|
135
|
+
}
|
|
136
|
+
/** Extract every closed spec-detail / spec-audit block; strip them from the text. */
|
|
137
|
+
function parseGenerationBlocks(text) {
|
|
138
|
+
const out = { stripped: text ?? '', details: [], audit: null, rejected: [], truncated: false, hadBlocks: false };
|
|
139
|
+
if (!text || !/```spec-(?:detail|audit)/.test(text))
|
|
140
|
+
return out;
|
|
141
|
+
let stripped = '';
|
|
142
|
+
let cursor = 0;
|
|
143
|
+
const matches = [];
|
|
144
|
+
DETAIL_FENCE_RE.lastIndex = 0;
|
|
145
|
+
let m;
|
|
146
|
+
while ((m = DETAIL_FENCE_RE.exec(text)) !== null)
|
|
147
|
+
matches.push({ kind: 'detail', index: m.index, length: m[0].length, body: m[1] });
|
|
148
|
+
AUDIT_FENCE_RE.lastIndex = 0;
|
|
149
|
+
while ((m = AUDIT_FENCE_RE.exec(text)) !== null)
|
|
150
|
+
matches.push({ kind: 'audit', index: m.index, length: m[0].length, body: m[1] });
|
|
151
|
+
matches.sort((a, b) => a.index - b.index);
|
|
152
|
+
for (const block of matches) {
|
|
153
|
+
if (block.index < cursor)
|
|
154
|
+
continue; // overlapping match (nested fence quirk)
|
|
155
|
+
out.hadBlocks = true;
|
|
156
|
+
stripped += text.slice(cursor, block.index);
|
|
157
|
+
cursor = block.index + block.length;
|
|
158
|
+
const parsed = (0, json_tolerant_1.parseJsonTolerant)(block.body);
|
|
159
|
+
if (!parsed.ok) {
|
|
160
|
+
out.rejected.push(`${block.kind} block: ${parsed.error}${parsed.excerpt ? ` near …${parsed.excerpt}…` : ''}`);
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (block.kind === 'detail') {
|
|
164
|
+
const detail = coerceDetail(parsed.value);
|
|
165
|
+
if (!detail) {
|
|
166
|
+
out.rejected.push('spec-detail block: expected { "index": <integer>, "spec": { … } }');
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
out.details.push(detail);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
const obj = record(parsed.value);
|
|
173
|
+
if (!obj) {
|
|
174
|
+
out.rejected.push('spec-audit block: expected an object');
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const fixes = Array.isArray(obj.fixes) ? obj.fixes.map(coerceDetail).filter((d) => d !== null) : [];
|
|
178
|
+
const issues = Array.isArray(obj.issues) ? obj.issues.filter((i) => typeof i === 'string') : [];
|
|
179
|
+
out.audit = { specsComplete: obj.specsComplete === true, issues, fixes };
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const remainder = text.slice(cursor);
|
|
183
|
+
const open = OPEN_GENERATION_FENCE_RE.exec(remainder);
|
|
184
|
+
if (open) {
|
|
185
|
+
out.hadBlocks = true;
|
|
186
|
+
out.truncated = true;
|
|
187
|
+
out.rejected.push('a generation block was cut off before its closing fence');
|
|
188
|
+
stripped += remainder.slice(0, open.index);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
stripped += remainder;
|
|
192
|
+
}
|
|
193
|
+
out.stripped = stripped;
|
|
194
|
+
return out;
|
|
195
|
+
}
|
|
196
|
+
/** Merge spec-detail blocks into a raw snapshot by index (out-of-range ignored). */
|
|
197
|
+
function mergeSpecDetails(raw, details) {
|
|
198
|
+
const source = record(raw);
|
|
199
|
+
if (!source || !Array.isArray(source.m1Specs))
|
|
200
|
+
return raw;
|
|
201
|
+
const specs = source.m1Specs.map((s) => (record(s) ? { ...s } : s));
|
|
202
|
+
for (const d of details) {
|
|
203
|
+
if (d.index >= specs.length)
|
|
204
|
+
continue;
|
|
205
|
+
const previous = record(specs[d.index]) ?? {};
|
|
206
|
+
// The outline fixed kind/title/priority/labels/dependency; a detail block
|
|
207
|
+
// may refine them but never DROP them (a missing key keeps the outline's).
|
|
208
|
+
specs[d.index] = { ...previous, ...d.spec };
|
|
209
|
+
}
|
|
210
|
+
return { ...source, m1Specs: specs };
|
|
211
|
+
}
|
|
212
|
+
function withSpecsComplete(raw, specsComplete) {
|
|
213
|
+
const source = record(raw);
|
|
214
|
+
if (!source)
|
|
215
|
+
return raw;
|
|
216
|
+
return { ...source, specsComplete };
|
|
217
|
+
}
|
|
218
|
+
/** True when every spec in `range` (0-based inclusive) now has a body. */
|
|
219
|
+
function rangeFilled(raw, range) {
|
|
220
|
+
const specs = specList(raw);
|
|
221
|
+
if (!specs)
|
|
222
|
+
return false;
|
|
223
|
+
for (let i = range.from; i <= range.to; i++) {
|
|
224
|
+
const spec = specs[i];
|
|
225
|
+
if (!spec || specIsEmpty(spec))
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
/** Live-stream helper: cut an UNTERMINATED generation fence (mirrors the client). */
|
|
231
|
+
function cutUnterminatedGenerationBlock(text) {
|
|
232
|
+
if (!text || !/```spec-(?:detail|audit)/.test(text))
|
|
233
|
+
return text ?? '';
|
|
234
|
+
const match = OPEN_GENERATION_FENCE_RE.exec(text);
|
|
235
|
+
if (!match)
|
|
236
|
+
return text;
|
|
237
|
+
return text.slice(0, match.index);
|
|
238
|
+
}
|