specrails-desktop 2.36.0 → 2.42.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -247
- package/client/dist/assets/ActivityFeedPage-DoEMumQS.js +1 -0
- package/client/dist/assets/AgentBrowserCapture-DIh4K0gh.js +1 -0
- package/client/dist/assets/AgentModeAnalyticsPane-mbq4WEoO.js +2 -0
- package/client/dist/assets/AgentModeCodePane-CKh7zuA4.js +2 -0
- package/client/dist/assets/AgentModeJobsPane-BDokPiLJ.js +1 -0
- package/client/dist/assets/AgentsPage-BFVAZbBj.js +87 -0
- package/client/dist/assets/AnalyticsPage-3Y9LuWwz.js +1 -0
- package/client/dist/assets/CodePage-C9KyuV_C.js +3 -0
- package/client/dist/assets/DesktopAnalyticsPage-Bhi54bXQ.js +1 -0
- package/client/dist/assets/{DocsDialog-C76VdBJC.js → DocsDialog-Dj6mt4ga.js} +2 -2
- package/client/dist/assets/{DocsPage-ziMlj6B6.js → DocsPage-24yWglNI.js} +1 -1
- package/client/dist/assets/ExportDropdown-ophapHrT.js +1 -0
- package/client/dist/assets/InteractiveJobComposer-C1ucmxQh.js +19 -0
- package/client/dist/assets/JobDetailModal-DNWmgVHD.js +1 -0
- package/client/dist/assets/JobDetailPage-BcajZyuu.js +1 -0
- package/client/dist/assets/JobsPage-B9nTZw6e.js +1 -0
- package/client/dist/assets/LoopBuilderPage-Oc48iOFW.js +7 -0
- package/client/dist/assets/LoopPreviewModal-ae0Fr6SU.js +1 -0
- package/client/dist/assets/LoopsPage-CUEqzUBI.js +1 -0
- package/client/dist/assets/MinimizedChatsContext-Deg39peL.js +1 -0
- package/client/dist/assets/PluginsPage-C1xtARIx.js +2 -0
- package/client/dist/assets/ProjectSettingsDialog-JZzrXFBN.js +1 -0
- package/client/dist/assets/RepositoryDeliveries-CSDsiVUz.js +5 -0
- package/client/dist/assets/RepositoryScopeSelector-D-RCaknl.js +1 -0
- package/client/dist/assets/ReviewPacketPage-x5EfGTiL.js +1 -0
- package/client/dist/assets/TemplatePreviewModal-BSyuZxGq.js +1 -0
- package/client/dist/assets/TicketDetailModalContext-DqyF0so-.js +14 -0
- package/client/dist/assets/Trans-SnMX4MhW.js +1 -0
- package/client/dist/assets/agent-BdT0SB1D.js +1 -0
- package/client/dist/assets/agent-Bh9K7iEt.js +1 -0
- package/client/dist/assets/agent-C4ibdFk9.js +1 -0
- package/client/dist/assets/agent-CSFY22Zo.js +1 -0
- package/client/dist/assets/agent-DAnqxUn8.js +1 -0
- package/client/dist/assets/agent-DTQiu0Mi.js +1 -0
- package/client/dist/assets/agent-T54WuR_Y.js +1 -0
- package/client/dist/assets/agent-i75WDZOA.js +1 -0
- package/client/dist/assets/browser-05vRDg_y.js +1 -0
- package/client/dist/assets/browser-Bulb-cB1.js +1 -0
- package/client/dist/assets/browser-C7f-Jsg1.js +1 -0
- package/client/dist/assets/browser-CG0PE1j_.js +1 -0
- package/client/dist/assets/browser-CMzaqAjo.js +1 -0
- package/client/dist/assets/browser-DMajYdNX.js +1 -0
- package/client/dist/assets/browser-DxcOHrdP.js +1 -0
- package/client/dist/assets/browser-ObE7xVo3.js +1 -0
- package/client/dist/assets/builder-765NeYTp.js +1 -0
- package/client/dist/assets/builder-8MG3V6ea.js +1 -0
- package/client/dist/assets/builder-B-1UBs5K.js +1 -0
- package/client/dist/assets/builder-BTiGnPT0.js +1 -0
- package/client/dist/assets/builder-Cx9Rz-7u.js +1 -0
- package/client/dist/assets/builder-DKFMELBl.js +1 -0
- package/client/dist/assets/builder-OcmKrC0h.js +1 -0
- package/client/dist/assets/builder-P9qVBXFZ.js +1 -0
- package/client/dist/assets/{button-CJqFnUOL.js → button-DCBqEaZl.js} +1 -1
- package/client/dist/assets/{code-CkUuW4m9.js → code-B37GRg9C.js} +1 -1
- package/client/dist/assets/{code-B0O8-p8k.js → code-BBOEZbf9.js} +1 -1
- package/client/dist/assets/{code-B1VLZDhS.js → code-BRm-jcyx.js} +1 -1
- package/client/dist/assets/{code-Bpj4Ddml.js → code-CF7w62CR.js} +1 -1
- package/client/dist/assets/{code-BykBZ5-e.js → code-CLuvJt2r.js} +1 -1
- package/client/dist/assets/{code-B86IMAfz.js → code-D0RCm59f.js} +1 -1
- package/client/dist/assets/code-DaZ-ZwCT.js +1 -0
- package/client/dist/assets/{code-cAqaqMTx.js → code-iIHkGaCL.js} +1 -1
- package/client/dist/assets/commands-0XjAftla.js +1 -0
- package/client/dist/assets/commands-BAWSYHjQ.js +1 -0
- package/client/dist/assets/commands-BBwowgiE.js +1 -0
- package/client/dist/assets/commands-BacjIZLN.js +1 -0
- package/client/dist/assets/commands-Bs62IAZ3.js +1 -0
- package/client/dist/assets/commands-CLPdh-Hh.js +1 -0
- package/client/dist/assets/commands-DlbFzgrp.js +1 -0
- package/client/dist/assets/commands-LjPSsi5F.js +1 -0
- package/client/dist/assets/common-B5AZNYMH.js +1 -0
- package/client/dist/assets/common-BFZ0c_vN.js +1 -0
- package/client/dist/assets/common-BrlwEnL7.js +1 -0
- package/client/dist/assets/common-BttQx3z4.js +1 -0
- package/client/dist/assets/common-CM65k_-e.js +1 -0
- package/client/dist/assets/common-D4mvFFlu.js +1 -0
- package/client/dist/assets/common-TZ9Ny96S.js +1 -0
- package/client/dist/assets/common-nFpSF4GC.js +1 -0
- package/client/dist/assets/dashboard-B14uYXkG.js +1 -0
- package/client/dist/assets/dashboard-BK_mez-z.js +1 -0
- package/client/dist/assets/dashboard-BfBir_6o.js +1 -0
- package/client/dist/assets/dashboard-Bt0cCzeG.js +1 -0
- package/client/dist/assets/dashboard-BwkjxI6H.js +1 -0
- package/client/dist/assets/{dashboard-C8WOEiPu.js → dashboard-C3bDKf7s.js} +1 -1
- package/client/dist/assets/dashboard-CdvjGfog.js +1 -0
- package/client/dist/assets/dashboard-fRrP0Kv0.js +1 -0
- package/client/dist/assets/dialog-SRw01_QU.js +45 -0
- package/client/dist/assets/dist-js-CJ_2XX1Y.js +1 -0
- package/client/dist/assets/formatDistanceToNow-DSj5DprF.js +1 -0
- package/client/dist/assets/getTimezoneOffsetInMilliseconds-YhD8rIEs.js +1 -0
- package/client/dist/assets/index-DwAmL7m5.css +2 -0
- package/client/dist/assets/index-EzrkUb8B.js +76 -0
- package/client/dist/assets/{jira-api-B1-MUehg.js → jira-api-CSCqGr-Q.js} +1 -1
- package/client/dist/assets/{jobs-CN_zv4Gr.js → jobs-B8rrzfyZ.js} +1 -1
- package/client/dist/assets/{jobs-DUlWSYq2.js → jobs-BS6RTurf.js} +1 -1
- package/client/dist/assets/{jobs-Bpks6doU.js → jobs-BTT0Bsks.js} +1 -1
- package/client/dist/assets/{jobs-Bgq-PZkC.js → jobs-CezU69AE.js} +1 -1
- package/client/dist/assets/{jobs-SwYS2M-B.js → jobs-ClFJae0s.js} +1 -1
- package/client/dist/assets/{jobs-BAls3bWq.js → jobs-DJSFIFVy.js} +1 -1
- package/client/dist/assets/{jobs-DhxKgWFq.js → jobs-DhgGr8vm.js} +1 -1
- package/client/dist/assets/{jobs-B_TeSQxb.js → jobs-DzMjUcaN.js} +1 -1
- package/client/dist/assets/mcp-6rMoZfEO.js +1 -0
- package/client/dist/assets/mcp-BD8sL5mP.js +1 -0
- package/client/dist/assets/mcp-BkcA3I5s.js +1 -0
- package/client/dist/assets/mcp-CCpSelOh.js +1 -0
- package/client/dist/assets/mcp-CUAN6ORK.js +1 -0
- package/client/dist/assets/mcp-CqbRxRTE.js +1 -0
- package/client/dist/assets/mcp-DP2YfVhO.js +1 -0
- package/client/dist/assets/mcp-DUVQamDz.js +1 -0
- package/client/dist/assets/narration-B-ynWTpn.js +1 -0
- package/client/dist/assets/narration-Bj_laZwg.js +1 -0
- package/client/dist/assets/narration-BxHpmMv_.js +1 -0
- package/client/dist/assets/narration-C1Px0-0j.js +1 -0
- package/client/dist/assets/narration-CAXhGbzM.js +1 -0
- package/client/dist/assets/narration-DQ1l_Kq6.js +1 -0
- package/client/dist/assets/narration-XISXwqZd.js +1 -0
- package/client/dist/assets/narration-kwzfglQo.js +1 -0
- package/client/dist/assets/nav-1-Hh2kOz.js +1 -0
- package/client/dist/assets/nav-B34QkESm.js +1 -0
- package/client/dist/assets/nav-Bap_UXAq.js +1 -0
- package/client/dist/assets/{nav-pYuXq7sf.js → nav-BwxXIB24.js} +1 -1
- package/client/dist/assets/nav-Ch-zHBG5.js +1 -0
- package/client/dist/assets/nav-CygC_WN-.js +1 -0
- package/client/dist/assets/{nav-iwjCg5FR.js → nav-KnnLQtOQ.js} +1 -1
- package/client/dist/assets/nav-m00uxYUG.js +1 -0
- package/client/dist/assets/packet-BQ2tXfJI.js +1 -0
- package/client/dist/assets/packet-BdpOJ1Cy.js +1 -0
- package/client/dist/assets/packet-C3Ievb9R.js +1 -0
- package/client/dist/assets/packet-C4zJIG0Y.js +1 -0
- package/client/dist/assets/packet-Cx-zRuWn.js +1 -0
- package/client/dist/assets/packet-DUTGX52M.js +1 -0
- package/client/dist/assets/packet-DhsKtUPB.js +1 -0
- package/client/dist/assets/packet-z3LJ8Zyy.js +1 -0
- package/client/dist/assets/project-repositories-DYhTvwQ1.js +1 -0
- package/client/dist/assets/provider-capabilities-B-wOHfLP.js +1 -0
- package/client/dist/assets/settings-BBt2xtDQ.js +1 -0
- package/client/dist/assets/settings-BJB9RKJj.js +1 -0
- package/client/dist/assets/settings-CHwQR2rB.js +1 -0
- package/client/dist/assets/settings-CrMi3kSi.js +1 -0
- package/client/dist/assets/settings-DKyhDGD1.js +1 -0
- package/client/dist/assets/settings-Deupji9c.js +1 -0
- package/client/dist/assets/settings-DqRMmwAM.js +1 -0
- package/client/dist/assets/settings-J4rj6vo-.js +1 -0
- package/client/dist/assets/setup-2xGgu4Sk.js +1 -0
- package/client/dist/assets/setup-Ba11l2JA.js +1 -0
- package/client/dist/assets/setup-BzW4kMok.js +1 -0
- package/client/dist/assets/setup-COzwYhkJ.js +1 -0
- package/client/dist/assets/setup-CRVULhtF.js +1 -0
- package/client/dist/assets/setup-DgvlxwpE.js +1 -0
- package/client/dist/assets/setup-Dw_wYeEY.js +1 -0
- package/client/dist/assets/setup-ZPtEeJPW.js +1 -0
- package/client/dist/assets/spending-BqbdPm_4.js +1 -0
- package/client/dist/assets/square-Ci-PFcFe.js +1 -0
- package/client/dist/assets/{terminal-BFRZnMPP.js → terminal-BAzpHtpY.js} +1 -1
- package/client/dist/assets/{terminal-IahE4LW9.js → terminal-C7dHeR3x.js} +1 -1
- package/client/dist/assets/{terminal-tITa81iz.js → terminal-CMla5Qsz.js} +1 -1
- package/client/dist/assets/{terminal-BZiIu3rf.js → terminal-CdNXH-n9.js} +1 -1
- package/client/dist/assets/{terminal-ScjyXNxQ.js → terminal-Cw5bZsmV.js} +1 -1
- package/client/dist/assets/{terminal-C2NAd7BW.js → terminal-DFUP4eNv.js} +1 -1
- package/client/dist/assets/{terminal-d7GadXbN.js → terminal-DGqljeK_.js} +1 -1
- package/client/dist/assets/{terminal-QpXZU2Bn.js → terminal-cU70NodO.js} +1 -1
- package/client/dist/assets/useDesktop-RSMTyy7V.js +1 -0
- package/client/dist/assets/useSharedWebSocket-BOdS5_Iz.js +2 -0
- package/client/dist/index.html +34 -35
- package/docs/README.md +3 -0
- package/docs/agent-live-steering.md +57 -0
- package/docs/ci-cd.md +57 -0
- package/docs/code-explorer.md +48 -0
- package/docs/codex.md +12 -1
- package/docs/features/detachable-mission-windows.md +59 -0
- package/docs/guide/de/integrations/5-mcp-server.md +13 -9
- package/docs/guide/de/integrations/6-agent-chat.md +1 -0
- package/docs/guide/en/integrations/5-mcp-server.md +13 -9
- package/docs/guide/en/integrations/6-agent-chat.md +1 -0
- package/docs/guide/es/integrations/5-mcp-server.md +13 -9
- package/docs/guide/es/integrations/6-agent-chat.md +1 -0
- package/docs/guide/fr/integrations/5-mcp-server.md +13 -9
- package/docs/guide/fr/integrations/6-agent-chat.md +1 -0
- package/docs/guide/it/integrations/5-mcp-server.md +13 -9
- package/docs/guide/it/integrations/6-agent-chat.md +1 -0
- package/docs/guide/ja/integrations/5-mcp-server.md +13 -9
- package/docs/guide/ja/integrations/6-agent-chat.md +1 -0
- package/docs/guide/pt/integrations/5-mcp-server.md +13 -9
- package/docs/guide/pt/integrations/6-agent-chat.md +1 -0
- package/docs/guide/zh/integrations/5-mcp-server.md +13 -9
- package/docs/guide/zh/integrations/6-agent-chat.md +1 -0
- package/docs/internals/README.md +1 -0
- package/docs/internals/browser-capture-performance.md +55 -3
- package/docs/internals/browser-login-popups.md +45 -0
- package/docs/internals/browser-native-retina-audit.md +39 -0
- package/docs/internals/ci-cd-audit.md +39 -0
- package/docs/internals/core-runtime-updates.md +68 -0
- package/docs/internals/embedded-browser-native-webview-evaluation.md +2 -0
- package/docs/internals/implementation-reliability-audit.md +93 -0
- package/docs/internals/interactive-jobs.md +110 -6
- package/docs/internals/mcp-mission-audit.md +76 -0
- package/docs/internals/project-builder.md +404 -42
- package/docs/internals/safe-pr-review-flow.md +52 -10
- package/docs/internals/startup-recovery-audit.md +58 -0
- package/docs/mcp.md +74 -41
- package/docs/mission-processes.md +59 -0
- package/docs/multi-repo-projects.md +51 -0
- package/docs/platforms/windows-parity.md +70 -0
- package/docs/platforms/windows.md +13 -11
- package/docs/running-pipelines.md +14 -0
- package/mcp-bridge/dist/specrails-mcp.js +7186 -0
- package/package.json +9 -4
- package/server/dist/agent-chat-manager.js +537 -68
- package/server/dist/agent-chat-router.js +87 -6
- package/server/dist/agent-context-resolver.js +129 -25
- package/server/dist/agent-defaults.js +19 -11
- package/server/dist/agent-input-store.js +206 -0
- package/server/dist/agent-mcp-config.js +54 -15
- package/server/dist/agent-operator-prompt.js +255 -65
- package/server/dist/agent-spec-framing.js +202 -0
- package/server/dist/agent-steering.js +218 -0
- package/server/dist/agent-store.js +153 -0
- package/server/dist/api-not-found.js +8 -0
- package/server/dist/background-process-control.js +164 -0
- package/server/dist/background-process-service.js +61 -0
- package/server/dist/background-process-store.js +242 -0
- package/server/dist/background-windows-bootstrap.js +238 -0
- package/server/dist/blueprint-chat-manager.js +476 -62
- package/server/dist/blueprint-commit.js +21 -1
- package/server/dist/blueprint-draft-parser.js +122 -17
- package/server/dist/blueprint-generation.js +238 -0
- package/server/dist/blueprint-operator-prompt.js +91 -63
- package/server/dist/blueprint-router.js +55 -3
- package/server/dist/blueprint-spec-fixtures.js +85 -0
- package/server/dist/blueprint-spec-quality.js +57 -16
- package/server/dist/blueprint-store.js +92 -1
- package/server/dist/browser-capture-manager.js +86 -30
- package/server/dist/browser-playwright.js +168 -45
- package/server/dist/browser-viewport.js +26 -0
- package/server/dist/chat-manager.js +23 -15
- package/server/dist/chromium-archive.cjs +83 -0
- package/server/dist/chromium-resolver.js +72 -64
- package/server/dist/code-activity.js +145 -0
- package/server/dist/code-explorer-router.js +714 -114
- package/server/dist/core-compat.js +28 -1
- package/server/dist/core-execution.js +111 -0
- package/server/dist/core-package.js +4 -16
- package/server/dist/core-runtime.js +202 -0
- package/server/dist/core-update-manager.js +161 -60
- package/server/dist/core-update-state.js +29 -0
- package/server/dist/db.js +66 -35
- package/server/dist/delivery-evidence.js +142 -39
- package/server/dist/desktop-db.js +239 -43
- package/server/dist/desktop-router.js +109 -9
- package/server/dist/dev-ports.js +8 -3
- package/server/dist/file-provenance.js +34 -22
- package/server/dist/file-story-manager.js +62 -64
- package/server/dist/file-story.js +118 -35
- package/server/dist/file-summary-generator.js +46 -5
- package/server/dist/file-summary-manager.js +355 -106
- package/server/dist/framework-manager.js +98 -110
- package/server/dist/framework-reseed.js +76 -10
- package/server/dist/git-diagnostics.js +2 -2
- package/server/dist/headroom-manager.js +38 -3
- package/server/dist/host-control.js +52 -0
- package/server/dist/index.js +43 -2
- package/server/dist/interactive-job-session.js +149 -16
- package/server/dist/internal-api.js +48 -0
- package/server/dist/jira/jira-materializer.js +1 -0
- package/server/dist/json-tolerant.js +174 -0
- package/server/dist/legacy-migration.js +4 -2
- package/server/dist/loop-command-catalog.js +83 -21
- package/server/dist/loop-constants.js +6 -1
- package/server/dist/loop-decider.js +11 -1
- package/server/dist/loop-executors.js +194 -45
- package/server/dist/loop-factory.js +11 -4
- package/server/dist/loop-graph.js +90 -4
- package/server/dist/loop-run-manager.js +301 -69
- package/server/dist/loop-shell-invocation.js +21 -0
- package/server/dist/loop-step-idle.js +55 -0
- package/server/dist/loop-templates.js +31 -7
- package/server/dist/mcp/agent-capability.js +37 -4
- package/server/dist/mcp/guide.js +149 -36
- package/server/dist/mcp/mcp-admin-router.js +20 -4
- package/server/dist/mcp/mcp-server.js +89 -43
- package/server/dist/mcp/mcp-tiers.js +6 -5
- package/server/dist/mcp/mcp-token.js +3 -1
- package/server/dist/mcp/resources.js +5 -4
- package/server/dist/mcp/tools/catalog.js +4 -0
- package/server/dist/mcp/tools/code.js +125 -14
- package/server/dist/mcp/tools/context.js +153 -0
- package/server/dist/mcp/tools/git.js +15 -5
- package/server/dist/mcp/tools/jobs.js +84 -71
- package/server/dist/mcp/tools/loops.js +17 -6
- package/server/dist/mcp/tools/meta.js +74 -27
- package/server/dist/mcp/tools/mission.js +29 -0
- package/server/dist/mcp/tools/projects.js +22 -6
- package/server/dist/mcp/tools/rails.js +48 -11
- package/server/dist/mcp/tools/specs.js +86 -14
- package/server/dist/mcp/tools/support.js +1 -1
- package/server/dist/mcp/tools/types.js +117 -43
- package/server/dist/mcp/tools/watch.js +144 -51
- package/server/dist/milestone-chain-store.js +164 -0
- package/server/dist/milestone-chain.js +487 -0
- package/server/dist/milestone-progress.js +348 -0
- package/server/dist/mobile/mobile-devices.js +10 -7
- package/server/dist/mobile/mobile-gateway.js +2 -0
- package/server/dist/mobile/mobile-missions.js +214 -0
- package/server/dist/mobile/mobile-redact.js +17 -3
- package/server/dist/mobile/mobile-router.js +46 -4
- package/server/dist/mobile/mobile-ws.js +49 -4
- package/server/dist/multi-repo-bases.js +56 -0
- package/server/dist/multi-repo-checkout.js +101 -0
- package/server/dist/multi-repo-delivery.js +100 -0
- package/server/dist/multi-repo-execution-store.js +65 -0
- package/server/dist/multi-repo-execution.js +453 -0
- package/server/dist/offline-assemble.js +10 -8
- package/server/dist/openspec-runtime-plugin-commands.json +18 -0
- package/server/dist/openspec-runtime-plugin.js +120 -0
- package/server/dist/plugins/codex-spawn.js +49 -0
- package/server/dist/plugins/serena/manifest.js +2 -2
- package/server/dist/plugins/serena/templates/instructions.md +16 -0
- package/server/dist/pr-publisher.js +1 -1
- package/server/dist/profiles-router.js +3 -18
- package/server/dist/project-code-discovery.js +142 -0
- package/server/dist/project-git.js +19 -21
- package/server/dist/project-registry.js +272 -20
- package/server/dist/project-repositories.js +157 -0
- package/server/dist/project-repository-provenance.js +31 -0
- package/server/dist/project-router-background-processes.js +105 -0
- package/server/dist/project-router-git.js +75 -16
- package/server/dist/project-router-jobs.js +2 -126
- package/server/dist/project-router-loop-runs.js +72 -2
- package/server/dist/project-router-tickets.js +53 -8
- package/server/dist/project-router.js +239 -38
- package/server/dist/provider-detection.js +18 -6
- package/server/dist/provider-limit.js +64 -0
- package/server/dist/providers/claude-adapter.js +26 -1
- package/server/dist/providers/claude-background-tasks.js +18 -0
- package/server/dist/providers/claude-live-session.js +383 -0
- package/server/dist/providers/codex-adapter.js +19 -0
- package/server/dist/providers/codex-live-session.js +545 -0
- package/server/dist/providers/gemini-adapter.js +1 -0
- package/server/dist/providers/live-session-types.js +12 -0
- package/server/dist/providers/live-session.js +13 -0
- package/server/dist/providers/terminal-result.js +24 -0
- package/server/dist/queue-manager.js +2 -0
- package/server/dist/rail-isolated-launch.js +141 -16
- package/server/dist/rail-pr-decision.js +364 -99
- package/server/dist/rail-pr-store.js +24 -10
- package/server/dist/rail-worktree-release.js +34 -2
- package/server/dist/rail-worktrees-store.js +4 -4
- package/server/dist/rails-router.js +249 -55
- package/server/dist/repo-lock.js +92 -17
- package/server/dist/review-packet.js +23 -13
- package/server/dist/schemas/file-summary.v1.json +59 -59
- package/server/dist/schemas/profile.v1.json +137 -137
- package/server/dist/setup-manager.js +52 -8
- package/server/dist/shell-integration/bash-shim.bash +45 -0
- package/server/dist/shell-integration/fish-shim.fish +36 -0
- package/server/dist/shell-integration/powershell-shim.ps1 +48 -0
- package/server/dist/shell-integration/zsh-shim.zsh +47 -0
- package/server/dist/smash-runner.js +1 -0
- package/server/dist/spawn-lifecycle.js +44 -27
- package/server/dist/spec-contract-prompt.js +143 -0
- package/server/dist/spec-draft-parser.js +6 -1
- package/server/dist/spec-models.js +1 -0
- package/server/dist/stuck-run-detector.js +1 -0
- package/server/dist/terminal-manager.js +21 -1
- package/server/dist/terminal-shell-integration.js +4 -1
- package/server/dist/transient-children.js +619 -230
- package/server/dist/util/cli-prompt.js +78 -5
- package/server/dist/util/sqlite-migrations.js +20 -0
- package/server/dist/util/win-spawn.js +18 -3
- package/server/dist/util/windows-provider-shell.js +29 -0
- package/server/dist/verification-sentinel.js +14 -0
- package/server/dist/vitest-setup.js +2 -0
- package/server/dist/windows-job-supervisor.js +133 -0
- package/server/dist/workspace-manager.js +9 -30
- package/server/dist/worktree-manager.js +17 -2
- package/server/dist/worktree-overlay.js +3 -1
- package/client/dist/assets/ActivityFeedPage-tAQcWs1R.js +0 -1
- package/client/dist/assets/AgentBrowserCapture-BX8BNae5.js +0 -1
- package/client/dist/assets/AgentModeAnalyticsPane-BVAqCL0K.js +0 -2
- package/client/dist/assets/AgentModeCodePane-9XfqQc9c.js +0 -2
- package/client/dist/assets/AgentModeJobsPane-BCjLsPhc.js +0 -1
- package/client/dist/assets/AgentsPage-C8J_42sm.js +0 -87
- package/client/dist/assets/AnalyticsPage-BtQuyfJm.js +0 -1
- package/client/dist/assets/CodePage-BZ2MwdCu.js +0 -2
- package/client/dist/assets/DesktopAnalyticsPage-Bh_29V4g.js +0 -1
- package/client/dist/assets/ExportDropdown-BrtfWzEG.js +0 -1
- package/client/dist/assets/InteractiveJobComposer-BCZiSfzc.js +0 -19
- package/client/dist/assets/JobDetailModal-NAJmuYIT.js +0 -1
- package/client/dist/assets/JobDetailPage-fE0ZycUX.js +0 -1
- package/client/dist/assets/JobsPage-z5M_HVJG.js +0 -1
- package/client/dist/assets/LoopBuilderPage-j1FQS47c.js +0 -7
- package/client/dist/assets/LoopPreviewModal-DhDJjdCe.js +0 -1
- package/client/dist/assets/LoopsPage-Ll7zORZb.js +0 -1
- package/client/dist/assets/MinimizedChatsContext-Bd3OqR_S.js +0 -1
- package/client/dist/assets/PluginsPage-DN4kGvJt.js +0 -2
- package/client/dist/assets/ProjectSettingsDialog-OgsgxjzF.js +0 -1
- package/client/dist/assets/ReviewPacketPage-DFog4sXn.js +0 -1
- package/client/dist/assets/TemplatePreviewModal-L2XxqiOD.js +0 -1
- package/client/dist/assets/TicketDetailModal-CsF-AWZX.js +0 -14
- package/client/dist/assets/Trans-Bsz9_gyq.js +0 -1
- package/client/dist/assets/agent-BQgKv_2F.js +0 -1
- package/client/dist/assets/agent-C1NRDJqL.js +0 -1
- package/client/dist/assets/agent-CLNleiy6.js +0 -1
- package/client/dist/assets/agent-CmceArkQ.js +0 -1
- package/client/dist/assets/agent-D3UxQ3SR.js +0 -1
- package/client/dist/assets/agent-DB1JeE64.js +0 -1
- package/client/dist/assets/agent-DXkHcQ-D.js +0 -1
- package/client/dist/assets/agent-DjJJJ2M8.js +0 -1
- package/client/dist/assets/auth-D_5bQv5W.js +0 -1
- package/client/dist/assets/ban-E4EaZe3a.js +0 -1
- package/client/dist/assets/bot-DzuuuC5R.js +0 -1
- package/client/dist/assets/browser-BgqHDMXP.js +0 -1
- package/client/dist/assets/browser-CsKJtrpv.js +0 -1
- package/client/dist/assets/browser-Cu58EpZU.js +0 -1
- package/client/dist/assets/browser-CvXOJm-j.js +0 -1
- package/client/dist/assets/browser-DOrFh1c7.js +0 -1
- package/client/dist/assets/browser-DQv_Jo7x.js +0 -1
- package/client/dist/assets/browser-LPgxvJu2.js +0 -1
- package/client/dist/assets/browser-eL-3MIEI.js +0 -1
- package/client/dist/assets/builder-0IWtosUm.js +0 -1
- package/client/dist/assets/builder-Bf2N6XWn.js +0 -1
- package/client/dist/assets/builder-BnqaaBkT.js +0 -1
- package/client/dist/assets/builder-BxxfGgAO.js +0 -1
- package/client/dist/assets/builder-C5IIgWsq.js +0 -1
- package/client/dist/assets/builder-CHuahItu.js +0 -1
- package/client/dist/assets/builder-CjWosXL_.js +0 -1
- package/client/dist/assets/builder-CpCIOoKj.js +0 -1
- package/client/dist/assets/code-CHPkOkDS.js +0 -1
- package/client/dist/assets/commands-6tYQih5m.js +0 -1
- package/client/dist/assets/commands-BK2QinXN.js +0 -1
- package/client/dist/assets/commands-C2Nca76h.js +0 -1
- package/client/dist/assets/commands-CKdLihNX.js +0 -1
- package/client/dist/assets/commands-CYIBTAlc.js +0 -1
- package/client/dist/assets/commands-CjUtYJIM.js +0 -1
- package/client/dist/assets/commands-Cq_u_8y9.js +0 -1
- package/client/dist/assets/commands-D_ZHYQug.js +0 -1
- package/client/dist/assets/common-6MLbD-jM.js +0 -1
- package/client/dist/assets/common-BKGEu4rm.js +0 -1
- package/client/dist/assets/common-BNbnv8cE.js +0 -1
- package/client/dist/assets/common-BqGWtDbt.js +0 -1
- package/client/dist/assets/common-DBtTzeYm.js +0 -1
- package/client/dist/assets/common-DEW3Nr8n.js +0 -1
- package/client/dist/assets/common-DHsv9N5d.js +0 -1
- package/client/dist/assets/common-mkrEcW-Y.js +0 -1
- package/client/dist/assets/dashboard-B9GhC5ku.js +0 -1
- package/client/dist/assets/dashboard-CBnv6zOI.js +0 -1
- package/client/dist/assets/dashboard-CaP0fU87.js +0 -1
- package/client/dist/assets/dashboard-D4ZZ4x84.js +0 -1
- package/client/dist/assets/dashboard-DmuTQBX8.js +0 -1
- package/client/dist/assets/dashboard-DynLYj3d.js +0 -1
- package/client/dist/assets/dashboard-zj4gGFJ1.js +0 -1
- package/client/dist/assets/dialog-CdWCb02j.js +0 -45
- package/client/dist/assets/dist-bVqfYmby.js +0 -1
- package/client/dist/assets/dist-js-CWeUdf5Z.js +0 -1
- package/client/dist/assets/formatDistanceToNow-DQCvMgUc.js +0 -1
- package/client/dist/assets/getTimezoneOffsetInMilliseconds-C16cxSe1.js +0 -1
- package/client/dist/assets/git-refresh-wTW0rO0Z.js +0 -1
- package/client/dist/assets/i18n-hnX2DPmo.js +0 -2
- package/client/dist/assets/index-DIhMEAVw.js +0 -66
- package/client/dist/assets/index-DwygcU7s.css +0 -2
- package/client/dist/assets/mcp-B8X8wBLu.js +0 -1
- package/client/dist/assets/mcp-C2AojZZN.js +0 -1
- package/client/dist/assets/mcp-D8BT78_L.js +0 -1
- package/client/dist/assets/mcp-Df5RWBNk.js +0 -1
- package/client/dist/assets/mcp-Dj7BgMQW.js +0 -1
- package/client/dist/assets/mcp-Q7iT7rcz.js +0 -1
- package/client/dist/assets/mcp-YlvNvJbW.js +0 -1
- package/client/dist/assets/mcp-mKFpTSRb.js +0 -1
- package/client/dist/assets/narration-4Z2VUhZw.js +0 -1
- package/client/dist/assets/narration-BGuiEDj3.js +0 -1
- package/client/dist/assets/narration-BuSoqRmv.js +0 -1
- package/client/dist/assets/narration-CB9t29fy.js +0 -1
- package/client/dist/assets/narration-CU3x8FHD.js +0 -1
- package/client/dist/assets/narration-CWeXhfP5.js +0 -1
- package/client/dist/assets/narration-DRaDnhT5.js +0 -1
- package/client/dist/assets/narration-DtEbQgCw.js +0 -1
- package/client/dist/assets/nav-ApJVg3xu.js +0 -1
- package/client/dist/assets/nav-BKNky1Bg.js +0 -1
- package/client/dist/assets/nav-C6vWWKYx.js +0 -1
- package/client/dist/assets/nav-CXJ6Aw89.js +0 -1
- package/client/dist/assets/nav-CsmFBIDf.js +0 -1
- package/client/dist/assets/nav-DjkmQJjd.js +0 -1
- package/client/dist/assets/packet-B1IxaL5f.js +0 -1
- package/client/dist/assets/packet-Bh5kkbiB.js +0 -1
- package/client/dist/assets/packet-By8fqYxW.js +0 -1
- package/client/dist/assets/packet-CZdvA44E.js +0 -1
- package/client/dist/assets/packet-CrjHRQCP.js +0 -1
- package/client/dist/assets/packet-Dwi2pTtx.js +0 -1
- package/client/dist/assets/packet-_-ZIa0IR.js +0 -1
- package/client/dist/assets/packet-n0W6E1Hn.js +0 -1
- package/client/dist/assets/play-DNlrawbS.js +0 -1
- package/client/dist/assets/provider-capabilities-Doej9lfa.js +0 -1
- package/client/dist/assets/settings-Bd0x4TBa.js +0 -1
- package/client/dist/assets/settings-C1-7cXzC.js +0 -1
- package/client/dist/assets/settings-CAFaT38b.js +0 -1
- package/client/dist/assets/settings-Ct3v1nW2.js +0 -1
- package/client/dist/assets/settings-DHh7_IF5.js +0 -1
- package/client/dist/assets/settings-DQXAmdcv.js +0 -1
- package/client/dist/assets/settings-guzlhpup.js +0 -1
- package/client/dist/assets/settings-sZfTPMEH.js +0 -1
- package/client/dist/assets/setup-3jWaoVUO.js +0 -1
- package/client/dist/assets/setup-BjgRneb2.js +0 -1
- package/client/dist/assets/setup-BzFIjv-f.js +0 -1
- package/client/dist/assets/setup-C4VfQsxE.js +0 -1
- package/client/dist/assets/setup-DfUkpDbN.js +0 -1
- package/client/dist/assets/setup-ECe90Pmu.js +0 -1
- package/client/dist/assets/setup-dlqC4Jmm.js +0 -1
- package/client/dist/assets/setup-jwfLMiM2.js +0 -1
- package/client/dist/assets/spending-EC9xqio-.js +0 -1
- package/client/dist/assets/useDesktop-BQVt8lFd.js +0 -1
|
@@ -3,7 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.BlueprintChatManager = void 0;
|
|
6
|
+
exports.BlueprintChatManager = exports.BUILDER_TURN_INTENTS = void 0;
|
|
7
|
+
exports.planSnapshotRepair = planSnapshotRepair;
|
|
7
8
|
const crypto_1 = require("crypto");
|
|
8
9
|
const tree_kill_1 = __importDefault(require("tree-kill"));
|
|
9
10
|
const providers_1 = require("./providers");
|
|
@@ -15,8 +16,30 @@ const desktop_db_1 = require("./desktop-db");
|
|
|
15
16
|
const builder_cwd_manager_1 = require("./builder-cwd-manager");
|
|
16
17
|
const blueprint_operator_prompt_1 = require("./blueprint-operator-prompt");
|
|
17
18
|
const blueprint_draft_parser_1 = require("./blueprint-draft-parser");
|
|
19
|
+
const blueprint_draft_parser_2 = require("./blueprint-draft-parser");
|
|
20
|
+
const blueprint_generation_1 = require("./blueprint-generation");
|
|
21
|
+
const blueprint_spec_quality_1 = require("./blueprint-spec-quality");
|
|
18
22
|
const explore_draft_title_1 = require("./explore-draft-title");
|
|
19
23
|
const blueprint_store_1 = require("./blueprint-store");
|
|
24
|
+
exports.BUILDER_TURN_INTENTS = ['surprise', 'approve'];
|
|
25
|
+
function repairKindForRejection(reason) {
|
|
26
|
+
return reason === 'truncated' ? 'truncated' : 'invalid_json';
|
|
27
|
+
}
|
|
28
|
+
/** Decide whether a settled parse needs ONE repair turn and what to ask. */
|
|
29
|
+
function planSnapshotRepair(parse) {
|
|
30
|
+
if (!parse.blueprint) {
|
|
31
|
+
const last = parse.rejected[parse.rejected.length - 1];
|
|
32
|
+
if (!last)
|
|
33
|
+
return null;
|
|
34
|
+
const reasonNote = last.reason === 'missing_version' ? 'The payload must be the blueprint object itself with an integer blueprintVersion. ' : '';
|
|
35
|
+
return { kind: repairKindForRejection(last.reason), detail: `${reasonNote}${last.detail}` };
|
|
36
|
+
}
|
|
37
|
+
const audit = (0, blueprint_spec_quality_1.auditRawBlueprintForM1)(parse.rawBlueprint);
|
|
38
|
+
if (audit.claimsComplete && !audit.valid) {
|
|
39
|
+
return { kind: 'quality', detail: (0, blueprint_spec_quality_1.formatQualityIssuesForModel)(audit.issues) };
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
20
43
|
class BlueprintChatManager {
|
|
21
44
|
_broadcast;
|
|
22
45
|
_db;
|
|
@@ -115,7 +138,7 @@ class BlueprintChatManager {
|
|
|
115
138
|
return;
|
|
116
139
|
}
|
|
117
140
|
try {
|
|
118
|
-
await this._runTurn(conversation, userText, options);
|
|
141
|
+
await this._runTurn(conversation, { userText, options });
|
|
119
142
|
}
|
|
120
143
|
catch (err) {
|
|
121
144
|
if (this._disposed)
|
|
@@ -127,8 +150,64 @@ class BlueprintChatManager {
|
|
|
127
150
|
this._abortedTurns.delete(conversationId);
|
|
128
151
|
}
|
|
129
152
|
}
|
|
130
|
-
|
|
153
|
+
/**
|
|
154
|
+
* Manual repair (the panel's "retry" after a rejected snapshot, or "ask the
|
|
155
|
+
* Builder to fix" after a failed audit). Decides what to ask from the
|
|
156
|
+
* PERSISTED state, so it works after a restart, and runs ONE repair turn on
|
|
157
|
+
* the same session. Resolves as soon as the turn is scheduled.
|
|
158
|
+
*/
|
|
159
|
+
async repairSnapshot(conversationId, options = {}) {
|
|
160
|
+
if (this._disposed)
|
|
161
|
+
return { ok: false, reason: 'unknown_conversation' };
|
|
162
|
+
const conversation = (0, blueprint_store_1.getBlueprintConversation)(this._db, conversationId);
|
|
163
|
+
if (!conversation)
|
|
164
|
+
return { ok: false, reason: 'unknown_conversation' };
|
|
165
|
+
if (this._active.has(conversationId))
|
|
166
|
+
return { ok: false, reason: 'streaming' };
|
|
167
|
+
const snapshot = (0, blueprint_store_1.getBlueprintSnapshot)(this._db, conversationId);
|
|
168
|
+
let repair = null;
|
|
169
|
+
if (snapshot.issue) {
|
|
170
|
+
repair = { kind: repairKindForRejection(snapshot.issue.reason), detail: snapshot.issue.detail };
|
|
171
|
+
}
|
|
172
|
+
else if (snapshot.rawBlueprint !== null) {
|
|
173
|
+
const audit = (0, blueprint_spec_quality_1.auditRawBlueprintForM1)(snapshot.rawBlueprint);
|
|
174
|
+
if (audit.claimsComplete && !audit.valid) {
|
|
175
|
+
repair = { kind: 'quality', detail: (0, blueprint_spec_quality_1.formatQualityIssuesForModel)(audit.issues) };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// A halted batched generation (outline or partly written specs, no
|
|
179
|
+
// rejection pending) resumes from the next unfilled range instead of
|
|
180
|
+
// re-asking for a whole snapshot.
|
|
181
|
+
const resume = !repair && !snapshot.issue && snapshot.rawBlueprint !== null
|
|
182
|
+
&& (0, blueprint_generation_1.unfilledSpecIndices)(snapshot.rawBlueprint).length > 0;
|
|
183
|
+
if (!repair && !resume)
|
|
184
|
+
return { ok: false, reason: 'nothing_to_repair' };
|
|
185
|
+
const adapter = (0, providers_1.getAdapter)(conversation.provider);
|
|
186
|
+
if (!conversation.session_id || !adapter.capabilities.nativeResume)
|
|
187
|
+
return { ok: false, reason: 'no_session' };
|
|
188
|
+
const request = repair;
|
|
189
|
+
void (async () => {
|
|
190
|
+
try {
|
|
191
|
+
// Same model as the conversation; the composer's effort rides along so a
|
|
192
|
+
// manual retry / Continue generating runs exactly like a regular send.
|
|
193
|
+
const turnOptions = { reasoningEffort: options.reasoningEffort };
|
|
194
|
+
await this._runTurn(conversation, request ? { options: turnOptions, repair: request } : { options: turnOptions, resume: true });
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
if (this._disposed)
|
|
198
|
+
return;
|
|
199
|
+
console.error(`[blueprint-chat] repair turn failed (${conversationId}):`, err);
|
|
200
|
+
this._emitError(conversationId, err instanceof Error ? err.message : 'The Builder repair turn failed.');
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
this._abortedTurns.delete(conversationId);
|
|
204
|
+
}
|
|
205
|
+
})();
|
|
206
|
+
return { ok: true, kind: repair ? repair.kind : 'resume' };
|
|
207
|
+
}
|
|
208
|
+
async _runTurn(conversation, turn) {
|
|
131
209
|
const conversationId = conversation.id;
|
|
210
|
+
const { options } = turn;
|
|
132
211
|
const adapter = (0, providers_1.getAdapter)(conversation.provider);
|
|
133
212
|
const toolPolicy = (0, runtime_1.pureOutputToolPolicy)(adapter);
|
|
134
213
|
if (!toolPolicy) {
|
|
@@ -148,33 +227,42 @@ class BlueprintChatManager {
|
|
|
148
227
|
: undefined;
|
|
149
228
|
const cwd = (0, builder_cwd_manager_1.ensureBuilderCwd)();
|
|
150
229
|
const timestamp = () => new Date().toISOString();
|
|
151
|
-
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
230
|
+
// The session id the NEXT invocation resumes: the row's id at entry, then
|
|
231
|
+
// whatever the previous invocation captured (a repair turn must continue
|
|
232
|
+
// the session the rejected block came from).
|
|
233
|
+
let currentSessionId = conversation.session_id ?? null;
|
|
234
|
+
if (turn.userText !== undefined) {
|
|
235
|
+
(0, blueprint_store_1.addBlueprintMessage)(this._db, { conversationId, role: 'user', content: turn.userText, intent: options.intent ?? null });
|
|
236
|
+
// Deterministic title from the first user prompt (no AI spend).
|
|
237
|
+
if (!conversation.title) {
|
|
238
|
+
const title = (0, explore_draft_title_1.generateAutoTitle)([{ role: 'user', content: turn.userText }]);
|
|
239
|
+
if (title) {
|
|
240
|
+
(0, blueprint_store_1.updateBlueprintConversation)(this._db, conversationId, { title });
|
|
241
|
+
}
|
|
157
242
|
}
|
|
158
243
|
}
|
|
159
|
-
const invoke = async (useResume) => {
|
|
244
|
+
const invoke = async (useResume, userText) => {
|
|
160
245
|
const action = useResume ? 'chat-resume' : 'chat-turn';
|
|
161
246
|
const startedAt = new Date().toISOString();
|
|
162
247
|
let streamed = '';
|
|
163
|
-
let capturedSessionId = useResume ?
|
|
248
|
+
let capturedSessionId = useResume ? currentSessionId : null;
|
|
164
249
|
let capturedError = null;
|
|
165
250
|
// `chat-turn` / `chat-resume` intentionally ignore `systemPrompt` for
|
|
166
251
|
// providers whose normal project-chat stance lives in their cwd
|
|
167
252
|
// instructions file. The day-0 Builder has no project instructions, so
|
|
168
253
|
// its schema/operator prompt must ride in the user prompt instead.
|
|
254
|
+
// Batched generation needs a resumable session; a provider without one
|
|
255
|
+
// is told to generate everything in a single reply (legacy protocol).
|
|
256
|
+
const effectiveUser = adapter.capabilities.nativeResume ? userText : `${userText}\n\n${blueprint_operator_prompt_1.SINGLE_RESPONSE_MODE_LINE}`;
|
|
169
257
|
const prompt = adapter.capabilities.systemPromptArg
|
|
170
|
-
?
|
|
171
|
-
: `${blueprint_operator_prompt_1.BUILDER_SYSTEM_PROMPT}\n\n---\n\n${
|
|
258
|
+
? effectiveUser
|
|
259
|
+
: `${blueprint_operator_prompt_1.BUILDER_SYSTEM_PROMPT}\n\n---\n\n${effectiveUser}`;
|
|
172
260
|
console.log(`[blueprint-chat] turn start conv=${conversationId} provider=${adapter.id} action=${action} model=${model}`);
|
|
173
261
|
const buildOpts = {
|
|
174
262
|
prompt,
|
|
175
263
|
systemPrompt: adapter.capabilities.systemPromptArg ? blueprint_operator_prompt_1.BUILDER_SYSTEM_PROMPT : undefined,
|
|
176
264
|
model,
|
|
177
|
-
sessionId: useResume ?
|
|
265
|
+
sessionId: useResume ? currentSessionId ?? undefined : undefined,
|
|
178
266
|
reasoning_effort: reasoningEffort,
|
|
179
267
|
toolPolicy,
|
|
180
268
|
};
|
|
@@ -239,87 +327,413 @@ class BlueprintChatManager {
|
|
|
239
327
|
const persistSession = (sessionId) => {
|
|
240
328
|
if (this._disposed)
|
|
241
329
|
return;
|
|
330
|
+
currentSessionId = sessionId;
|
|
242
331
|
if ((0, blueprint_store_1.getBlueprintConversation)(this._db, conversationId)) {
|
|
243
332
|
(0, blueprint_store_1.updateBlueprintConversation)(this._db, conversationId, { session_id: sessionId });
|
|
244
333
|
}
|
|
245
334
|
};
|
|
246
|
-
// One agent_invocations row per settled
|
|
335
|
+
// One agent_invocations row per settled invocation, project_id NULL
|
|
336
|
+
// (day-0 spend) — a repair turn is a second spawn and bills too.
|
|
247
337
|
const record = (outcome, status) => {
|
|
248
338
|
if (this._disposed || outcome.disposed)
|
|
249
339
|
return;
|
|
250
340
|
this._recordTurn(conversation, adapter, model, outcome, status);
|
|
251
341
|
};
|
|
252
|
-
|
|
253
|
-
|
|
342
|
+
/** Persist one assistant reply: stripped transcript + unstripped raw when
|
|
343
|
+
* it carried a block. An empty stripped reply (block only) is still
|
|
344
|
+
* stored so the raw payload survives; the API hides empty rows. */
|
|
345
|
+
const persistReply = (r, stripped, hadBlocks) => {
|
|
254
346
|
const content = stripped.trim();
|
|
255
347
|
if ((0, blueprint_store_1.getBlueprintConversation)(this._db, conversationId)) {
|
|
256
|
-
(0, blueprint_store_1.addBlueprintMessage)(this._db, {
|
|
348
|
+
(0, blueprint_store_1.addBlueprintMessage)(this._db, {
|
|
349
|
+
conversationId,
|
|
350
|
+
role: 'assistant',
|
|
351
|
+
content: hadBlocks ? content : content || r.text,
|
|
352
|
+
rawContent: hadBlocks ? r.text : null,
|
|
353
|
+
});
|
|
257
354
|
persistSession(r.sessionId);
|
|
258
355
|
}
|
|
356
|
+
return hadBlocks ? content : content || r.text;
|
|
357
|
+
};
|
|
358
|
+
const persistAssistant = (r, parse) => {
|
|
359
|
+
// Generation fences (spec-detail / spec-audit) are stripped like
|
|
360
|
+
// blueprint-draft blocks — never raw JSON in the transcript.
|
|
361
|
+
const gen = (0, blueprint_generation_1.parseGenerationBlocks)(parse.stripped);
|
|
362
|
+
return persistReply(r, gen.stripped, parse.hadBlocks || gen.hadBlocks);
|
|
363
|
+
};
|
|
364
|
+
/**
|
|
365
|
+
* Apply a reply to a base snapshot (D7 patch protocol): a full
|
|
366
|
+
* blueprint-draft block wins; otherwise spec-detail / spec-audit blocks are
|
|
367
|
+
* merged into `baseRaw` by index. Returns the parse-shaped result the
|
|
368
|
+
* finish path understands, plus the transcript-safe text.
|
|
369
|
+
*/
|
|
370
|
+
const applyReply = (text, baseRaw) => {
|
|
371
|
+
const parse = (0, blueprint_draft_parser_1.parseBlueprintDraftBlocks)(text);
|
|
372
|
+
const gen = (0, blueprint_generation_1.parseGenerationBlocks)(parse.stripped);
|
|
373
|
+
if (parse.blueprint)
|
|
374
|
+
return { parse: { ...parse, stripped: gen.stripped }, stripped: gen.stripped, hadBlocks: true, gen };
|
|
375
|
+
const patches = [...gen.details, ...(gen.audit?.fixes ?? [])];
|
|
376
|
+
// An audit verdict is a patch even with zero fixes (it flips specsComplete).
|
|
377
|
+
if ((patches.length > 0 || gen.audit) && baseRaw !== null && baseRaw !== undefined) {
|
|
378
|
+
let merged = (0, blueprint_generation_1.mergeSpecDetails)(baseRaw, patches);
|
|
379
|
+
if (gen.audit)
|
|
380
|
+
merged = (0, blueprint_generation_1.withSpecsComplete)(merged, gen.audit.specsComplete);
|
|
381
|
+
const blueprint = (0, blueprint_draft_parser_2.coerceBlueprint)(merged);
|
|
382
|
+
if (blueprint) {
|
|
383
|
+
return {
|
|
384
|
+
parse: { stripped: gen.stripped, blueprint, rawBlueprint: merged, hadBlocks: true, rejected: parse.rejected, repaired: false, truncated: gen.truncated },
|
|
385
|
+
stripped: gen.stripped, hadBlocks: true, gen,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
const rejected = gen.rejected.length > 0 && parse.rejected.length === 0 && !parse.blueprint
|
|
390
|
+
? [...parse.rejected, { index: 0, reason: gen.truncated ? 'truncated' : 'invalid_json', detail: gen.rejected.join('; ') }]
|
|
391
|
+
: parse.rejected;
|
|
392
|
+
return { parse: { ...parse, stripped: gen.stripped, rejected, hadBlocks: parse.hadBlocks || gen.hadBlocks }, stripped: gen.stripped, hadBlocks: parse.hadBlocks || gen.hadBlocks, gen };
|
|
393
|
+
};
|
|
394
|
+
const finishTurn = (fullText, parse, meta) => {
|
|
395
|
+
let snapshot;
|
|
396
|
+
if (parse.blueprint) {
|
|
397
|
+
const audit = (0, blueprint_spec_quality_1.auditRawBlueprintForM1)(parse.rawBlueprint);
|
|
398
|
+
snapshot = {
|
|
399
|
+
status: 'accepted',
|
|
400
|
+
repaired: parse.repaired || meta.fromRepairTurn,
|
|
401
|
+
repairAttempted: meta.repairAttempted,
|
|
402
|
+
claimsComplete: audit.claimsComplete,
|
|
403
|
+
...(audit.claimsComplete && !audit.valid ? { qualityIssues: audit.issues } : {}),
|
|
404
|
+
...(meta.generation ? { generation: meta.generation } : {}),
|
|
405
|
+
...(meta.continuing ? { continuing: true } : {}),
|
|
406
|
+
...(meta.generationHalted ? { generationHalted: true } : {}),
|
|
407
|
+
};
|
|
408
|
+
if ((0, blueprint_store_1.getBlueprintConversation)(this._db, conversationId)) {
|
|
409
|
+
(0, blueprint_store_1.saveBlueprintSnapshot)(this._db, conversationId, { blueprint: parse.blueprint, rawBlueprint: parse.rawBlueprint });
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
else if (parse.rejected.length > 0) {
|
|
413
|
+
const last = parse.rejected[parse.rejected.length - 1];
|
|
414
|
+
snapshot = { status: 'rejected', reason: last.reason, detail: last.detail, repairAttempted: meta.repairAttempted };
|
|
415
|
+
if ((0, blueprint_store_1.getBlueprintConversation)(this._db, conversationId)) {
|
|
416
|
+
(0, blueprint_store_1.saveBlueprintSnapshotIssue)(this._db, conversationId, { reason: last.reason, detail: last.detail, at: timestamp() });
|
|
417
|
+
}
|
|
418
|
+
console.warn(`[blueprint-chat] snapshot rejected conv=${conversationId} reason=${last.reason} repairAttempted=${meta.repairAttempted}: ${last.detail}`);
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
snapshot = { status: 'none' };
|
|
422
|
+
}
|
|
259
423
|
this._broadcast({
|
|
260
424
|
type: 'blueprint.done',
|
|
261
425
|
conversationId,
|
|
262
|
-
fullText
|
|
263
|
-
blueprint,
|
|
264
|
-
rawBlueprint,
|
|
426
|
+
fullText,
|
|
427
|
+
blueprint: parse.blueprint,
|
|
428
|
+
rawBlueprint: parse.rawBlueprint,
|
|
429
|
+
snapshot,
|
|
430
|
+
...(meta.continuing ? { continuing: true } : {}),
|
|
265
431
|
timestamp: timestamp(),
|
|
266
432
|
});
|
|
267
433
|
};
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
if (!(0, blueprint_store_1.getBlueprintConversation)(this._db, conversationId)) {
|
|
273
|
-
record(r, 'aborted'); // deleted mid-turn; the spawn still billed
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
if (this._abortedTurns.delete(conversationId)) {
|
|
277
|
-
if (r.text)
|
|
278
|
-
settleText(r);
|
|
279
|
-
record(r, 'aborted');
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
// Auto-heal a stale session: a resume with no text retries once fresh.
|
|
283
|
-
if (canResume && !r.spawnFailed && !r.error && !r.text) {
|
|
284
|
-
(0, blueprint_store_1.updateBlueprintConversation)(this._db, conversationId, { session_id: null });
|
|
285
|
-
r = await invoke(false);
|
|
434
|
+
/** Shared post-invocation triage. Returns the outcome to continue with, or
|
|
435
|
+
* null when the turn is over (disposed / deleted / aborted / failed). */
|
|
436
|
+
const settle = async (first, allowAutoHeal) => {
|
|
437
|
+
let r = first;
|
|
286
438
|
if (this._disposed || r.disposed)
|
|
287
|
-
return;
|
|
439
|
+
return null;
|
|
288
440
|
if (!(0, blueprint_store_1.getBlueprintConversation)(this._db, conversationId)) {
|
|
441
|
+
record(r, 'aborted'); // deleted mid-turn; the spawn still billed
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
if (this._abortedTurns.delete(conversationId)) {
|
|
445
|
+
if (r.text) {
|
|
446
|
+
const parse = (0, blueprint_draft_parser_1.parseBlueprintDraftBlocks)(r.text);
|
|
447
|
+
finishTurn(persistAssistant(r, parse), parse, { repairAttempted: false, fromRepairTurn: false });
|
|
448
|
+
}
|
|
289
449
|
record(r, 'aborted');
|
|
290
|
-
return;
|
|
450
|
+
return null;
|
|
451
|
+
}
|
|
452
|
+
// Auto-heal a stale session: a resume with no text retries once fresh.
|
|
453
|
+
if (allowAutoHeal && !r.spawnFailed && !r.error && !r.text) {
|
|
454
|
+
(0, blueprint_store_1.updateBlueprintConversation)(this._db, conversationId, { session_id: null });
|
|
455
|
+
currentSessionId = null;
|
|
456
|
+
r = await invoke(false, turn.userText ?? '');
|
|
457
|
+
if (this._disposed || r.disposed)
|
|
458
|
+
return null;
|
|
459
|
+
if (!(0, blueprint_store_1.getBlueprintConversation)(this._db, conversationId)) {
|
|
460
|
+
record(r, 'aborted');
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
if (this._abortedTurns.delete(conversationId)) {
|
|
464
|
+
if (r.text) {
|
|
465
|
+
const parse = (0, blueprint_draft_parser_1.parseBlueprintDraftBlocks)(r.text);
|
|
466
|
+
finishTurn(persistAssistant(r, parse), parse, { repairAttempted: false, fromRepairTurn: false });
|
|
467
|
+
}
|
|
468
|
+
record(r, 'aborted');
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (r.spawnFailed) {
|
|
473
|
+
this._emitError(conversationId, `Failed to launch ${adapter.binary}. Is it installed and on PATH?`);
|
|
474
|
+
record(r, 'failed');
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
if (r.error || r.code !== 0) {
|
|
478
|
+
persistSession(null);
|
|
479
|
+
const reason = r.error ||
|
|
480
|
+
(r.stderrTail ? r.stderrTail.split('\n').filter(Boolean).slice(-3).join(' ').slice(0, 300) : '') ||
|
|
481
|
+
`${adapter.binary} exited with code ${r.code ?? 'unknown'}`;
|
|
482
|
+
this._emitError(conversationId, reason);
|
|
483
|
+
record(r, 'failed');
|
|
484
|
+
return null;
|
|
485
|
+
}
|
|
486
|
+
if (!r.text) {
|
|
487
|
+
persistSession(null);
|
|
488
|
+
const reason = (r.stderrTail ? r.stderrTail.split('\n').filter(Boolean).slice(-3).join(' ').slice(0, 300) : '') ||
|
|
489
|
+
'The Builder returned no output.';
|
|
490
|
+
this._emitError(conversationId, reason);
|
|
491
|
+
record(r, 'failed');
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
return r;
|
|
495
|
+
};
|
|
496
|
+
/** Repair-turn triage (mirrors `settle` minus the auto-heal and the error
|
|
497
|
+
* broadcasts — a failed repair never turns a successful user turn into an
|
|
498
|
+
* error): 'stop' = the turn is over (disposed / deleted / aborted), null =
|
|
499
|
+
* the repair spawn produced nothing usable (the original outcome stands). */
|
|
500
|
+
const settleRepair = (r) => {
|
|
501
|
+
if (this._disposed || r.disposed)
|
|
502
|
+
return 'stop';
|
|
503
|
+
if (!(0, blueprint_store_1.getBlueprintConversation)(this._db, conversationId)) {
|
|
504
|
+
record(r, 'aborted');
|
|
505
|
+
return 'stop';
|
|
291
506
|
}
|
|
292
507
|
if (this._abortedTurns.delete(conversationId)) {
|
|
293
|
-
if (r.text)
|
|
294
|
-
settleText(r);
|
|
295
508
|
record(r, 'aborted');
|
|
509
|
+
return 'stop';
|
|
510
|
+
}
|
|
511
|
+
if (r.spawnFailed || r.error || r.code !== 0 || !r.text) {
|
|
512
|
+
console.warn(`[blueprint-chat] repair turn produced no usable reply conv=${conversationId} code=${r.code} error=${r.error ?? ''}`);
|
|
513
|
+
record(r, 'failed');
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
return r;
|
|
517
|
+
};
|
|
518
|
+
const canResume = !!currentSessionId && adapter.capabilities.nativeResume;
|
|
519
|
+
/** The quality-repair tail (one automatic repair turn when the model's
|
|
520
|
+
* block was unusable, or it claimed completion and the gate disagrees).
|
|
521
|
+
* Patch-aware: a repair reply may be spec-detail blocks merged into the
|
|
522
|
+
* snapshot, or a full blueprint-draft block. */
|
|
523
|
+
const finishWithQualityRepair = async (text, current, meta) => {
|
|
524
|
+
const repair = planSnapshotRepair(current);
|
|
525
|
+
const canRepair = repair !== null && !!currentSessionId && adapter.capabilities.nativeResume;
|
|
526
|
+
if (!repair || !canRepair) {
|
|
527
|
+
finishTurn(text, current, { repairAttempted: false, fromRepairTurn: false, ...meta });
|
|
296
528
|
return;
|
|
297
529
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
530
|
+
console.warn(`[blueprint-chat] snapshot needs repair conv=${conversationId} kind=${repair.kind}: ${repair.detail.slice(0, 200)}`);
|
|
531
|
+
this._broadcast({
|
|
532
|
+
type: 'blueprint.repairing',
|
|
533
|
+
conversationId,
|
|
534
|
+
kind: repair.kind,
|
|
535
|
+
attempt: 1,
|
|
536
|
+
manual: false,
|
|
537
|
+
timestamp: timestamp(),
|
|
538
|
+
});
|
|
539
|
+
const r2 = settleRepair(await invoke(true, (0, blueprint_operator_prompt_1.buildSnapshotRepairPrompt)(repair.kind, repair.detail)));
|
|
540
|
+
if (r2 === 'stop')
|
|
541
|
+
return;
|
|
542
|
+
if (r2 === null) {
|
|
543
|
+
// The repair spawn failed — the original turn still stands.
|
|
544
|
+
finishTurn(text, current, { repairAttempted: true, fromRepairTurn: false, ...meta });
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
const applied = applyReply(r2.text, current.rawBlueprint);
|
|
548
|
+
const prose2 = persistReply(r2, applied.stripped, applied.hadBlocks);
|
|
549
|
+
record(r2, 'success');
|
|
550
|
+
const combinedText = prose2 ? (text ? `${text}\n\n${prose2}` : prose2) : text;
|
|
551
|
+
if (applied.parse.blueprint) {
|
|
552
|
+
finishTurn(combinedText, applied.parse, { repairAttempted: true, fromRepairTurn: true, ...meta });
|
|
553
|
+
}
|
|
554
|
+
else {
|
|
555
|
+
// Still unusable: report the ORIGINAL outcome (plus the newest
|
|
556
|
+
// rejection detail when the repair produced one) so the UI can offer a
|
|
557
|
+
// manual retry with the freshest diagnostic.
|
|
558
|
+
const merged = applied.parse.rejected.length > 0
|
|
559
|
+
? { ...current, rejected: [...current.rejected, ...applied.parse.rejected] }
|
|
560
|
+
: current;
|
|
561
|
+
finishTurn(combinedText, merged, { repairAttempted: true, fromRepairTurn: false, ...meta });
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
// ── App-driven batched generation (D7). An OUTLINE snapshot (every spec
|
|
565
|
+
// named, no bodies) on a resumable session starts the detail → audit
|
|
566
|
+
// drive: the app asks for two specs per turn as spec-detail blocks, merges
|
|
567
|
+
// them by index, announces each phase, keeps the panel live after every
|
|
568
|
+
// turn (`continuing`), then runs one audit turn and the normal quality
|
|
569
|
+
// repair. Depth is no longer capped by a single reply's output budget.
|
|
570
|
+
const driveGeneration = async (initialRaw, fullText, base, mode) => {
|
|
571
|
+
let raw = initialRaw;
|
|
572
|
+
const total = (0, blueprint_generation_1.specTitles)(raw).length;
|
|
573
|
+
const totalTurns = (0, blueprint_generation_1.projectedGenerationTurns)(total);
|
|
574
|
+
// A resume re-derives the turn ordinal from what is already written so
|
|
575
|
+
// the "turn x/y" pill stays truthful and the budget covers the rest.
|
|
576
|
+
let turnNo = mode === 'resume'
|
|
577
|
+
? 1 + Math.ceil((total - (0, blueprint_generation_1.unfilledSpecIndices)(raw).length) / blueprint_generation_1.SPECS_PER_DETAIL_TURN)
|
|
578
|
+
: 1;
|
|
579
|
+
const descriptor = (phase, from, to) => ({ phase, from, to, total, turn: turnNo, totalTurns });
|
|
580
|
+
const announce = (phase, from, to) => {
|
|
581
|
+
this._broadcast({ type: 'blueprint.generating', conversationId, ...descriptor(phase, from, to), timestamp: timestamp() });
|
|
582
|
+
};
|
|
583
|
+
const snapshotOf = (rawSnapshot) => ({
|
|
584
|
+
stripped: '', blueprint: (0, blueprint_draft_parser_2.coerceBlueprint)(rawSnapshot) ?? base.blueprint, rawBlueprint: rawSnapshot,
|
|
585
|
+
hadBlocks: true, rejected: [], repaired: base.repaired, truncated: false,
|
|
586
|
+
});
|
|
587
|
+
const emitContinuing = (rawSnapshot, generation) => {
|
|
588
|
+
finishTurn('', snapshotOf(rawSnapshot), { repairAttempted: false, fromRepairTurn: false, generation, continuing: true });
|
|
589
|
+
};
|
|
590
|
+
const halt = (rawSnapshot, generation) => {
|
|
591
|
+
console.warn(`[blueprint-chat] generation halted conv=${conversationId} phase=${generation.phase} turn=${turnNo}/${totalTurns}`);
|
|
592
|
+
finishTurn(fullText, snapshotOf((0, blueprint_generation_1.withSpecsComplete)(rawSnapshot, false)), { repairAttempted: true, fromRepairTurn: false, generation, generationHalted: true });
|
|
593
|
+
};
|
|
594
|
+
// The outline itself is the first accepted frame of the drive; a resume
|
|
595
|
+
// re-announces the next range so the panel leaves its halted state.
|
|
596
|
+
let range = (0, blueprint_generation_1.nextDetailRange)(raw);
|
|
597
|
+
emitContinuing(raw, mode === 'resume' && range
|
|
598
|
+
? descriptor('details', range.from + 1, range.to + 1)
|
|
599
|
+
: descriptor('outline', 0, 0));
|
|
600
|
+
while (range) {
|
|
601
|
+
if (turnNo >= blueprint_generation_1.MAX_GENERATION_TURNS) {
|
|
602
|
+
halt(raw, descriptor('details', range.from + 1, range.to + 1));
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
turnNo += 1;
|
|
606
|
+
const titles = (0, blueprint_generation_1.specTitles)(raw);
|
|
607
|
+
announce('details', range.from + 1, range.to + 1);
|
|
608
|
+
const r2 = settleRepair(await invoke(true, (0, blueprint_generation_1.buildDetailPrompt)(range, titles)));
|
|
609
|
+
if (r2 === 'stop')
|
|
610
|
+
return;
|
|
611
|
+
if (r2 === null) {
|
|
612
|
+
halt(raw, descriptor('details', range.from + 1, range.to + 1));
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
const applied = applyReply(r2.text, raw);
|
|
616
|
+
persistReply(r2, applied.stripped, applied.hadBlocks);
|
|
617
|
+
record(r2, 'success');
|
|
618
|
+
let merged = applied.parse.blueprint ? applied.parse.rawBlueprint : raw;
|
|
619
|
+
if (!(0, blueprint_generation_1.rangeFilled)(merged, range) && turnNo < blueprint_generation_1.MAX_GENERATION_TURNS) {
|
|
620
|
+
// ONE repair for this range (a cut-off or malformed block).
|
|
621
|
+
turnNo += 1;
|
|
622
|
+
announce('repair', range.from + 1, range.to + 1);
|
|
623
|
+
const detail = applied.gen.rejected.join('; ') || 'no spec-detail block for the requested indexes';
|
|
624
|
+
const r3 = settleRepair(await invoke(true, (0, blueprint_generation_1.buildDetailRepairPrompt)(range, titles, detail)));
|
|
625
|
+
if (r3 === 'stop')
|
|
626
|
+
return;
|
|
627
|
+
if (r3 !== null) {
|
|
628
|
+
const applied3 = applyReply(r3.text, merged);
|
|
629
|
+
persistReply(r3, applied3.stripped, applied3.hadBlocks);
|
|
630
|
+
record(r3, 'success');
|
|
631
|
+
if (applied3.parse.blueprint)
|
|
632
|
+
merged = applied3.parse.rawBlueprint;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
raw = (0, blueprint_generation_1.withSpecsComplete)(merged, false);
|
|
636
|
+
if (!(0, blueprint_generation_1.rangeFilled)(raw, range)) {
|
|
637
|
+
halt(raw, descriptor('details', range.from + 1, range.to + 1));
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
emitContinuing(raw, descriptor('details', range.from + 1, range.to + 1));
|
|
641
|
+
range = (0, blueprint_generation_1.nextDetailRange)(raw);
|
|
642
|
+
}
|
|
643
|
+
// Audit turn: the model self-audits the whole batch and may patch specs.
|
|
644
|
+
if (turnNo < blueprint_generation_1.MAX_GENERATION_TURNS) {
|
|
645
|
+
turnNo += 1;
|
|
646
|
+
announce('audit', 1, total);
|
|
647
|
+
const ra = settleRepair(await invoke(true, (0, blueprint_generation_1.buildAuditPrompt)()));
|
|
648
|
+
if (ra === 'stop')
|
|
649
|
+
return;
|
|
650
|
+
if (ra !== null) {
|
|
651
|
+
const appliedAudit = applyReply(ra.text, raw);
|
|
652
|
+
persistReply(ra, appliedAudit.stripped, appliedAudit.hadBlocks);
|
|
653
|
+
record(ra, 'success');
|
|
654
|
+
if (appliedAudit.parse.blueprint)
|
|
655
|
+
raw = appliedAudit.parse.rawBlueprint;
|
|
656
|
+
const verdict = appliedAudit.gen.audit;
|
|
657
|
+
if (!verdict) {
|
|
658
|
+
// A reply without a spec-audit verdict: let the deterministic gate judge.
|
|
659
|
+
raw = (0, blueprint_generation_1.withSpecsComplete)(raw, true);
|
|
660
|
+
}
|
|
661
|
+
else if (!verdict.specsComplete && verdict.issues.length > 0 && turnNo < blueprint_generation_1.MAX_GENERATION_TURNS) {
|
|
662
|
+
// The model found blocking problems: ONE corrections turn (spec-detail
|
|
663
|
+
// patches for the affected specs), then the deterministic gate judges.
|
|
664
|
+
turnNo += 1;
|
|
665
|
+
announce('repair', 1, total);
|
|
666
|
+
const rc = settleRepair(await invoke(true, (0, blueprint_generation_1.buildAuditIssuesPrompt)(verdict.issues)));
|
|
667
|
+
if (rc === 'stop')
|
|
668
|
+
return;
|
|
669
|
+
if (rc !== null) {
|
|
670
|
+
const appliedFix = applyReply(rc.text, raw);
|
|
671
|
+
persistReply(rc, appliedFix.stripped, appliedFix.hadBlocks);
|
|
672
|
+
record(rc, 'success');
|
|
673
|
+
if (appliedFix.parse.blueprint)
|
|
674
|
+
raw = appliedFix.parse.rawBlueprint;
|
|
675
|
+
}
|
|
676
|
+
raw = (0, blueprint_generation_1.withSpecsComplete)(raw, true);
|
|
677
|
+
}
|
|
678
|
+
else if (!verdict.specsComplete) {
|
|
679
|
+
// No actionable issues (or no turn budget left): let the gate judge.
|
|
680
|
+
raw = (0, blueprint_generation_1.withSpecsComplete)(raw, true);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
raw = (0, blueprint_generation_1.withSpecsComplete)(raw, true);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
else {
|
|
688
|
+
raw = (0, blueprint_generation_1.withSpecsComplete)(raw, true);
|
|
689
|
+
}
|
|
690
|
+
await finishWithQualityRepair(fullText, snapshotOf(raw), { generation: descriptor('audit', 1, total) });
|
|
691
|
+
};
|
|
692
|
+
// ── Manual repair turn: the request IS the repair; never nests another.
|
|
693
|
+
if (turn.repair) {
|
|
694
|
+
this._broadcast({
|
|
695
|
+
type: 'blueprint.repairing',
|
|
696
|
+
conversationId,
|
|
697
|
+
kind: turn.repair.kind,
|
|
698
|
+
attempt: 1,
|
|
699
|
+
manual: true,
|
|
700
|
+
timestamp: timestamp(),
|
|
701
|
+
});
|
|
702
|
+
const r = await settle(await invoke(canResume, (0, blueprint_operator_prompt_1.buildSnapshotRepairPrompt)(turn.repair.kind, turn.repair.detail)), false);
|
|
703
|
+
if (!r)
|
|
704
|
+
return;
|
|
705
|
+
const base = (0, blueprint_store_1.getBlueprintSnapshot)(this._db, conversationId).rawBlueprint;
|
|
706
|
+
const applied = applyReply(r.text, base);
|
|
707
|
+
const fullText = persistReply(r, applied.stripped, applied.hadBlocks);
|
|
708
|
+
record(r, 'success');
|
|
709
|
+
finishTurn(fullText, applied.parse, { repairAttempted: true, fromRepairTurn: true });
|
|
302
710
|
return;
|
|
303
711
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
712
|
+
// ── Resume a halted batched generation (manual "Continue generating").
|
|
713
|
+
if (turn.resume) {
|
|
714
|
+
const persisted = (0, blueprint_store_1.getBlueprintSnapshot)(this._db, conversationId).rawBlueprint;
|
|
715
|
+
const blueprint = (0, blueprint_draft_parser_2.coerceBlueprint)(persisted);
|
|
716
|
+
if (!blueprint || (0, blueprint_generation_1.unfilledSpecIndices)(persisted).length === 0)
|
|
717
|
+
return;
|
|
718
|
+
await driveGeneration(persisted, '', { blueprint, repaired: false }, 'resume');
|
|
311
719
|
return;
|
|
312
720
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
721
|
+
// ── Regular user turn.
|
|
722
|
+
const r = await settle(await invoke(canResume, turn.userText ?? ''), canResume);
|
|
723
|
+
if (!r)
|
|
724
|
+
return;
|
|
725
|
+
const parse = (0, blueprint_draft_parser_1.parseBlueprintDraftBlocks)(r.text);
|
|
726
|
+
const fullText = persistAssistant(r, parse);
|
|
727
|
+
record(r, 'success');
|
|
728
|
+
// ── App-driven batched generation (D7): an OUTLINE snapshot on a
|
|
729
|
+
// resumable session starts the detail → audit drive.
|
|
730
|
+
const canDrive = parse.blueprint !== null && (0, blueprint_generation_1.isOutlineSnapshot)(parse.rawBlueprint)
|
|
731
|
+
&& !!currentSessionId && adapter.capabilities.nativeResume;
|
|
732
|
+
if (canDrive) {
|
|
733
|
+
await driveGeneration(parse.rawBlueprint, fullText, { blueprint: parse.blueprint, repaired: parse.repaired }, 'outline');
|
|
316
734
|
return;
|
|
317
735
|
}
|
|
318
|
-
|
|
319
|
-
const reason = (r.stderrTail ? r.stderrTail.split('\n').filter(Boolean).slice(-3).join(' ').slice(0, 300) : '') ||
|
|
320
|
-
'The Builder returned no output.';
|
|
321
|
-
this._emitError(conversationId, reason);
|
|
322
|
-
record(r, 'failed');
|
|
736
|
+
await finishWithQualityRepair(fullText, parse, {});
|
|
323
737
|
}
|
|
324
738
|
_recordTurn(conversation, adapter, model, outcome, status) {
|
|
325
739
|
if (this._disposed)
|