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
|
@@ -89,12 +89,24 @@ function probeAuthState(id, home) {
|
|
|
89
89
|
// also live in the OS keychain, so absence is 'unknown', never a hard
|
|
90
90
|
// 'unauthenticated'.
|
|
91
91
|
return fs.existsSync(path.join(home, '.claude.json')) ? 'authenticated' : 'unknown';
|
|
92
|
-
case 'codex':
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
case 'codex': {
|
|
93
|
+
// Match the invocation's custom home without reading credential bytes.
|
|
94
|
+
// A relative override depends on the invocation cwd, so do not guess
|
|
95
|
+
// an identity from this process's different working directory.
|
|
96
|
+
const override = process.env.CODEX_HOME;
|
|
97
|
+
if (override && !path.isAbsolute(override))
|
|
98
|
+
return 'unknown';
|
|
99
|
+
const authPath = path.join(override || path.join(home, '.codex'), 'auth.json');
|
|
100
|
+
try {
|
|
101
|
+
if (!fs.statSync(authPath).isFile())
|
|
102
|
+
return 'unknown';
|
|
103
|
+
fs.accessSync(authPath, fs.constants.R_OK);
|
|
104
|
+
return 'authenticated';
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
return error.code === 'ENOENT' ? 'unauthenticated' : 'unknown';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
98
110
|
case 'gemini': {
|
|
99
111
|
// OAuth creds land under ~/.gemini; an API key via env also counts.
|
|
100
112
|
if (process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Provider usage/rate limits as a FIRST-CLASS loop signal.
|
|
3
|
+
//
|
|
4
|
+
// Run 52124009 (2026-09-04): the claude subscription hit its session limit
|
|
5
|
+
// mid-batch. The CLI answered every later spawn in ~0.5 s with a `result`
|
|
6
|
+
// frame whose text was "You've hit your session limit · resets 3am
|
|
7
|
+
// (Europe/Madrid)" and `is_error: true`. The engine saw a non-empty, exit-0
|
|
8
|
+
// reply → step `ok` → verify → decider (unparseable → continue) → fix … three
|
|
9
|
+
// full cycles until the no-progress stall guard finally stopped the run. A
|
|
10
|
+
// limit is not something to iterate on: detect it on the step's FINAL text,
|
|
11
|
+
// stop the loop at once with an honest reason, and tell the user when it
|
|
12
|
+
// resets.
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.extractLimitReset = extractLimitReset;
|
|
15
|
+
exports.classifyProviderLimit = classifyProviderLimit;
|
|
16
|
+
exports.describeProviderLimit = describeProviderLimit;
|
|
17
|
+
/** Only the tail of a transcript is judged — a spec discussing rate limiting
|
|
18
|
+
* must never trip the classifier; the provider's own notice is always last. */
|
|
19
|
+
const TAIL_CHARS = 600;
|
|
20
|
+
const PATTERNS = [
|
|
21
|
+
// claude: "You've hit your session limit · resets 3am (Europe/Madrid)"
|
|
22
|
+
// "You've hit your usage limit …", "…weekly limit…"
|
|
23
|
+
{ kind: 'session_limit', re: /\byou(?:'|’)?ve hit your (?:session|usage|weekly|daily|monthly|plan)?\s*limit\b/i },
|
|
24
|
+
// claude API error wrapper: "(error type rate_limit, HTTP 429 …)"
|
|
25
|
+
{ kind: 'rate_limit', re: /\berror type rate_limit\b/i },
|
|
26
|
+
{ kind: 'rate_limit', re: /\bHTTP 429\b|\b429 Too Many Requests\b|\brate[ _-]?limit(?:ed|s)? (?:exceeded|reached|hit)\b|\brate_limit_error\b/i },
|
|
27
|
+
// codex / openai
|
|
28
|
+
{ kind: 'quota', re: /\binsufficient_quota\b|\byou(?:'|’)?ve reached your (?:usage )?limit\b|\busage limit (?:reached|exceeded)\b/i },
|
|
29
|
+
// gemini / google
|
|
30
|
+
{ kind: 'quota', re: /\bRESOURCE_EXHAUSTED\b|\bquota (?:exceeded|exhausted)\b/i },
|
|
31
|
+
];
|
|
32
|
+
// "resets 3am (Europe/Madrid)", "resets at 14:00", "resets in 2 hours".
|
|
33
|
+
const RESETS_RE = /\bresets?\s+(?:at\s+|in\s+)?([^\n·(]*?\d[^\n·(]*?)(\s*\([^)]*\))?(?=\s*(?:\(error|[.,;]\s|\n|$))/i;
|
|
34
|
+
function extractLimitReset(text) {
|
|
35
|
+
const m = RESETS_RE.exec(text);
|
|
36
|
+
if (!m)
|
|
37
|
+
return null;
|
|
38
|
+
const value = `${m[1].trim()}${m[2] ? ` ${m[2].trim()}` : ''}`.trim().replace(/[.,;:]+$/, '');
|
|
39
|
+
return value.length > 0 && value.length <= 80 ? value : null;
|
|
40
|
+
}
|
|
41
|
+
/** Classify a step's FINAL text / error text. Null when no provider limit
|
|
42
|
+
* notice is present. Never throws. */
|
|
43
|
+
function classifyProviderLimit(text) {
|
|
44
|
+
if (!text)
|
|
45
|
+
return null;
|
|
46
|
+
const tail = text.length > TAIL_CHARS ? text.slice(-TAIL_CHARS) : text;
|
|
47
|
+
for (const { kind, re } of PATTERNS) {
|
|
48
|
+
const m = re.exec(tail);
|
|
49
|
+
if (!m)
|
|
50
|
+
continue;
|
|
51
|
+
// The provider's sentence: the line carrying the match, trimmed.
|
|
52
|
+
const lineStart = tail.lastIndexOf('\n', m.index) + 1;
|
|
53
|
+
const lineEndIdx = tail.indexOf('\n', m.index);
|
|
54
|
+
const line = tail.slice(lineStart, lineEndIdx === -1 ? undefined : lineEndIdx).trim();
|
|
55
|
+
return { kind, message: line.slice(0, 300), resetsAt: extractLimitReset(tail) };
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
/** Human line for logs/toasts: "<message> — resets 3am (Europe/Madrid)". */
|
|
60
|
+
function describeProviderLimit(limit) {
|
|
61
|
+
return limit.resetsAt && !limit.message.toLowerCase().includes('reset')
|
|
62
|
+
? `${limit.message} — resets ${limit.resetsAt}`
|
|
63
|
+
: limit.message;
|
|
64
|
+
}
|
|
@@ -11,10 +11,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
11
11
|
};
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
exports.claudeAdapter = void 0;
|
|
14
|
+
exports.isClaudeNotificationResultFrame = isClaudeNotificationResultFrame;
|
|
14
15
|
exports._normaliseClaudeModel = normaliseModel;
|
|
15
16
|
exports._resolveClaudeSpawnModel = resolveSpawnModel;
|
|
16
17
|
const child_process_1 = require("child_process");
|
|
17
18
|
const path_1 = __importDefault(require("path"));
|
|
19
|
+
const openspec_runtime_plugin_1 = require("../openspec-runtime-plugin");
|
|
18
20
|
const WHICH_CMD = process.platform === 'win32' ? 'where' : 'which';
|
|
19
21
|
const CLAUDE_MODELS = [
|
|
20
22
|
{ value: 'sonnet', label: 'Claude Sonnet', default: true },
|
|
@@ -104,6 +106,7 @@ function commonFlagsFor(opts) {
|
|
|
104
106
|
? ['--permission-mode', 'plan', '--safe-mode']
|
|
105
107
|
: []),
|
|
106
108
|
...toolArgs,
|
|
109
|
+
...(toolPolicy === 'default' ? (0, openspec_runtime_plugin_1.getOpenSpecRuntimePluginArgs)() : []),
|
|
107
110
|
'--output-format', 'stream-json',
|
|
108
111
|
'--verbose',
|
|
109
112
|
'--setting-sources',
|
|
@@ -249,6 +252,22 @@ function withAssistantUsage(ev, msg) {
|
|
|
249
252
|
carrier.model = msg.model;
|
|
250
253
|
return ev;
|
|
251
254
|
}
|
|
255
|
+
/** True when a claude `result` frame is a CLI-INTERNAL notification turn, NOT
|
|
256
|
+
* the answer to a prompt the caller wrote. Live evidence (loop run 5c958db2,
|
|
257
|
+
* claude 2.1.260): a `--resume` of a session whose previous process exited
|
|
258
|
+
* with background tasks still running makes the CLI report those tasks as
|
|
259
|
+
* orphaned and emit a turn of its own — `origin: {kind:'task-notification'}`,
|
|
260
|
+
* `num_turns: 0`, `stop_reason: null`, empty `result`, zero usage — BEFORE it
|
|
261
|
+
* processes the caller's prompt. A consumer that closes its turn on the first
|
|
262
|
+
* `result` (interactive job/loop sessions, persistent Explore turns) would
|
|
263
|
+
* settle on that frame and tear the real turn down mid-thought. The caller's
|
|
264
|
+
* own turns carry no `origin` at all. */
|
|
265
|
+
function isClaudeNotificationResultFrame(frame) {
|
|
266
|
+
const origin = frame.origin;
|
|
267
|
+
if (!origin || typeof origin !== 'object')
|
|
268
|
+
return false;
|
|
269
|
+
return origin.kind === 'task-notification';
|
|
270
|
+
}
|
|
252
271
|
function parseClaudeStreamLine(line) {
|
|
253
272
|
if (line.length === 0)
|
|
254
273
|
return null;
|
|
@@ -270,7 +289,12 @@ function parseClaudeStreamLine(line) {
|
|
|
270
289
|
return { kind: 'other', type, raw: parsed };
|
|
271
290
|
}
|
|
272
291
|
if (type === 'result') {
|
|
273
|
-
|
|
292
|
+
// A CLI-internal notification turn surfaces as a NON-terminal 'other'
|
|
293
|
+
// event so no consumer (turn-closing sessions, extractResult, recovery)
|
|
294
|
+
// mistakes it for the caller's turn result.
|
|
295
|
+
if (isClaudeNotificationResultFrame(parsed))
|
|
296
|
+
return { kind: 'other', type, raw: parsed };
|
|
297
|
+
return { kind: 'result', payload: parsed, ...(parsed.is_error === true ? { isError: true } : {}) };
|
|
274
298
|
}
|
|
275
299
|
if (type === 'assistant') {
|
|
276
300
|
const msg = parsed.message;
|
|
@@ -456,6 +480,7 @@ exports.claudeAdapter = {
|
|
|
456
480
|
profileEnvSupport: true,
|
|
457
481
|
systemPromptArg: true,
|
|
458
482
|
persistentStdin: true,
|
|
483
|
+
liveInputTransport: 'claude-stream-json',
|
|
459
484
|
supportsReasoningEffort: true,
|
|
460
485
|
reasoningEfforts: ['low', 'medium', 'high', 'xhigh'], // claude-code --effort tiers
|
|
461
486
|
supportsImageInput: true, // images ride as `@<abs-path>` prompt refs
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readClaudeBackgroundTasks = readClaudeBackgroundTasks;
|
|
4
|
+
/** Claude's authoritative background roster. null means "no valid update",
|
|
5
|
+
* whereas [] explicitly confirms that the provider has no live workers. */
|
|
6
|
+
function readClaudeBackgroundTasks(frame) {
|
|
7
|
+
if (frame?.type !== 'system' || frame.subtype !== 'background_tasks_changed' || !Array.isArray(frame.tasks))
|
|
8
|
+
return null;
|
|
9
|
+
// Claude marks live-update watchers and skip-transcript tasks as ambient:
|
|
10
|
+
// they are not foreground activity and need not finish for a step to end.
|
|
11
|
+
// Only the explicit boolean opts out; older/malformed entries still block.
|
|
12
|
+
return frame.tasks.filter((task) => task?.ambient !== true).map((task) => {
|
|
13
|
+
const item = (task ?? {});
|
|
14
|
+
const id = typeof item.task_id === 'string' ? item.task_id : '';
|
|
15
|
+
const description = typeof item.description === 'string' ? item.description.trim() : '';
|
|
16
|
+
return (description ? `${id ? `${id}: ` : ''}${description}` : id || 'task').slice(0, 500);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runClaudeLiveSession = runClaudeLiveSession;
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const promises_1 = require("node:fs/promises");
|
|
10
|
+
const node_os_1 = require("node:os");
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
const node_readline_1 = require("node:readline");
|
|
13
|
+
const win_spawn_1 = require("../util/win-spawn");
|
|
14
|
+
const cli_prompt_1 = require("../util/cli-prompt");
|
|
15
|
+
const runtime_1 = require("./runtime");
|
|
16
|
+
const live_session_types_1 = require("./live-session-types");
|
|
17
|
+
// Claude Code 2.1.261: stdin user frames enter the native command queue. The
|
|
18
|
+
// query loop handles priority "next" messages after the running tool batch and
|
|
19
|
+
// re-emits the queued_command as {type:"user",isReplay:true,uuid:source_uuid}.
|
|
20
|
+
// That replay precedes committing absorption and may also precede a cancelled
|
|
21
|
+
// turn or hooks: it confirms receipt, not model consumption. Reading requires
|
|
22
|
+
// an explicit agent acknowledgement. A successful stdin.write only means bytes
|
|
23
|
+
// were buffered, so it is never an acknowledgement.
|
|
24
|
+
// https://code.claude.com/docs/en/cli-reference#cli-flags
|
|
25
|
+
// https://code.claude.com/docs/en/agent-sdk/streaming-vs-single-mode
|
|
26
|
+
// We deliberately do not issue control_request/interrupt for steering: that
|
|
27
|
+
// aborts Claude's active tools rather than letting their results finish.
|
|
28
|
+
const MAX_IMAGE_BYTES = 8 * 1024 * 1024;
|
|
29
|
+
const STDERR_CAP = 64 * 1024;
|
|
30
|
+
const IMAGE_TYPES = {
|
|
31
|
+
'.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.webp': 'image/webp',
|
|
32
|
+
};
|
|
33
|
+
async function inputContent(input) {
|
|
34
|
+
if (!input.imagePaths?.length)
|
|
35
|
+
return input.text;
|
|
36
|
+
const content = [{ type: 'text', text: input.text }];
|
|
37
|
+
let remaining = MAX_IMAGE_BYTES;
|
|
38
|
+
for (const imagePath of input.imagePaths) {
|
|
39
|
+
try {
|
|
40
|
+
const mimeType = IMAGE_TYPES[node_path_1.default.extname(imagePath).toLowerCase()];
|
|
41
|
+
if (!mimeType)
|
|
42
|
+
throw new Error('unsupported image type');
|
|
43
|
+
// Read at most the remaining budget + one byte through one file handle:
|
|
44
|
+
// a growing file cannot evade a stat-then-read limit and exhaust memory.
|
|
45
|
+
const file = await (0, promises_1.open)(imagePath, 'r');
|
|
46
|
+
try {
|
|
47
|
+
const stat = await file.stat();
|
|
48
|
+
if (!stat.isFile() || stat.size > remaining)
|
|
49
|
+
throw new Error('the images exceed the 8 MiB input budget');
|
|
50
|
+
const bytes = Buffer.alloc(remaining + 1);
|
|
51
|
+
let length = 0;
|
|
52
|
+
for (;;) {
|
|
53
|
+
const read = await file.read(bytes, length, bytes.length - length, null);
|
|
54
|
+
length += read.bytesRead;
|
|
55
|
+
if (length > remaining)
|
|
56
|
+
throw new Error('the images exceed the 8 MiB input budget');
|
|
57
|
+
if (read.bytesRead === 0)
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
remaining -= length;
|
|
61
|
+
content.push({ type: 'image', source: { type: 'base64', media_type: mimeType, data: bytes.subarray(0, length).toString('base64') } });
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
await file.close();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
content.push({ type: 'text', text: `[Image attachment ${imagePath} was not delivered: ${error instanceof Error ? error.message : String(error)}. The original attachment is retained by Specrails. Do not infer its contents.]` });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return content;
|
|
72
|
+
}
|
|
73
|
+
/** One native Claude process, accepting input until its final result. Tool
|
|
74
|
+
* batches finish normally. If an update misses a fold boundary Claude may
|
|
75
|
+
* process it as a subsequent native turn in the SAME process; keep stdin open
|
|
76
|
+
* until those written inputs have been echoed and their result has arrived. */
|
|
77
|
+
function runClaudeLiveSession(hooks) {
|
|
78
|
+
if (hooks.adapter.id !== 'claude' || !hooks.buildOpts)
|
|
79
|
+
throw new Error('Claude live sessions require the Claude adapter and buildOpts.');
|
|
80
|
+
const opts = hooks.buildOpts;
|
|
81
|
+
return new Promise(resolveInvocation => {
|
|
82
|
+
const events = [];
|
|
83
|
+
const pending = new Map();
|
|
84
|
+
const submitted = new Map();
|
|
85
|
+
const initialId = (0, node_crypto_1.randomUUID)();
|
|
86
|
+
let child = null;
|
|
87
|
+
let ended = false;
|
|
88
|
+
let accepting = true;
|
|
89
|
+
let initialWritten = false;
|
|
90
|
+
let initialAccepted = false;
|
|
91
|
+
let sessionId = opts.sessionId ?? null;
|
|
92
|
+
let lastResultEvent = null;
|
|
93
|
+
let stderrTail = '';
|
|
94
|
+
let promptDirectory;
|
|
95
|
+
let timeout;
|
|
96
|
+
let inactivity;
|
|
97
|
+
let closeDeadline;
|
|
98
|
+
let stdoutReader;
|
|
99
|
+
let stderrReader;
|
|
100
|
+
let writeSequence = Promise.resolve();
|
|
101
|
+
let escalation;
|
|
102
|
+
const rejectPending = (reason) => {
|
|
103
|
+
for (const input of pending.values()) {
|
|
104
|
+
if (input.written)
|
|
105
|
+
input.reject(new live_session_types_1.LiveInputDeliveryError(reason, true));
|
|
106
|
+
else
|
|
107
|
+
input.resolve(false);
|
|
108
|
+
}
|
|
109
|
+
pending.clear();
|
|
110
|
+
};
|
|
111
|
+
const settle = (code, timedOut = false, spawnFailed = false) => {
|
|
112
|
+
if (ended)
|
|
113
|
+
return;
|
|
114
|
+
ended = true;
|
|
115
|
+
accepting = false;
|
|
116
|
+
clearTimeout(timeout);
|
|
117
|
+
clearTimeout(inactivity);
|
|
118
|
+
clearTimeout(closeDeadline);
|
|
119
|
+
rejectPending('Claude ended before acknowledging the live input. Delivery is uncertain; do not replay automatically.');
|
|
120
|
+
stdoutReader?.close();
|
|
121
|
+
stderrReader?.close();
|
|
122
|
+
// Leave the child's close/error listeners in place until it exits, so
|
|
123
|
+
// late EPIPE is contained and close cancels the owned SIGKILL deadline.
|
|
124
|
+
try {
|
|
125
|
+
child?.stdin?.destroy();
|
|
126
|
+
}
|
|
127
|
+
catch { /* best effort */ }
|
|
128
|
+
try {
|
|
129
|
+
child?.stdout?.destroy();
|
|
130
|
+
}
|
|
131
|
+
catch { /* best effort */ }
|
|
132
|
+
try {
|
|
133
|
+
child?.stderr?.destroy();
|
|
134
|
+
}
|
|
135
|
+
catch { /* best effort */ }
|
|
136
|
+
if (promptDirectory) {
|
|
137
|
+
try {
|
|
138
|
+
(0, node_fs_1.rmSync)(promptDirectory, { recursive: true, force: true });
|
|
139
|
+
}
|
|
140
|
+
catch { /* best effort */ }
|
|
141
|
+
}
|
|
142
|
+
resolveInvocation({ code, timedOut, spawnFailed, events, lastResultEvent, sessionId, stderrTail, child });
|
|
143
|
+
};
|
|
144
|
+
const terminate = () => {
|
|
145
|
+
if (!child || escalation)
|
|
146
|
+
return;
|
|
147
|
+
try {
|
|
148
|
+
if (child.pid)
|
|
149
|
+
(0, win_spawn_1.treeKillSafe)(child.pid, 'SIGTERM');
|
|
150
|
+
else
|
|
151
|
+
child.kill('SIGTERM');
|
|
152
|
+
}
|
|
153
|
+
catch { /* child already gone */ }
|
|
154
|
+
const ownedChild = child;
|
|
155
|
+
escalation = setTimeout(() => {
|
|
156
|
+
try {
|
|
157
|
+
if (ownedChild.pid)
|
|
158
|
+
(0, win_spawn_1.treeKillSafe)(ownedChild.pid, 'SIGKILL');
|
|
159
|
+
else
|
|
160
|
+
ownedChild.kill('SIGKILL');
|
|
161
|
+
}
|
|
162
|
+
catch { /* already gone */ }
|
|
163
|
+
}, 2000);
|
|
164
|
+
escalation.unref?.();
|
|
165
|
+
ownedChild.once('close', () => clearTimeout(escalation));
|
|
166
|
+
};
|
|
167
|
+
const expire = (kind) => {
|
|
168
|
+
if (ended)
|
|
169
|
+
return;
|
|
170
|
+
if (kind === 'wall')
|
|
171
|
+
hooks.onTimeout?.();
|
|
172
|
+
else
|
|
173
|
+
hooks.onInactivityTimeout?.();
|
|
174
|
+
terminate();
|
|
175
|
+
settle(null, true);
|
|
176
|
+
};
|
|
177
|
+
const activity = () => {
|
|
178
|
+
clearTimeout(inactivity);
|
|
179
|
+
if (!ended && hooks.inactivityTimeoutMs && hooks.inactivityTimeoutMs > 0) {
|
|
180
|
+
inactivity = setTimeout(() => expire('inactivity'), hooks.inactivityTimeoutMs);
|
|
181
|
+
inactivity.unref?.();
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
const event = (value) => {
|
|
185
|
+
events.push(value);
|
|
186
|
+
if (value.kind === 'session-started')
|
|
187
|
+
sessionId = value.sessionId;
|
|
188
|
+
if (value.kind === 'result') {
|
|
189
|
+
lastResultEvent = value;
|
|
190
|
+
if (typeof value.payload.session_id === 'string')
|
|
191
|
+
sessionId = value.payload.session_id;
|
|
192
|
+
}
|
|
193
|
+
hooks.onEvent?.(value);
|
|
194
|
+
};
|
|
195
|
+
const send = (input, onAccepted) => {
|
|
196
|
+
const fingerprint = JSON.stringify([input.text, input.imagePaths ?? []]);
|
|
197
|
+
const existing = submitted.get(input.id);
|
|
198
|
+
if (existing)
|
|
199
|
+
return existing.fingerprint === fingerprint ? existing.promise : Promise.reject(new live_session_types_1.LiveInputDeliveryError('Live input ID already has different content.', existing.written));
|
|
200
|
+
if (!accepting || ended || !child?.stdin || child.stdin.destroyed || child.stdin.writableEnded || child.killed)
|
|
201
|
+
return Promise.resolve(false);
|
|
202
|
+
let resolve, reject;
|
|
203
|
+
const promise = new Promise((yes, no) => { resolve = yes; reject = no; });
|
|
204
|
+
const entry = { id: input.id, nativeId: (0, node_crypto_1.randomUUID)(), fingerprint, written: false, promise, resolve, reject, onAccepted };
|
|
205
|
+
submitted.set(input.id, entry);
|
|
206
|
+
pending.set(entry.nativeId, entry);
|
|
207
|
+
const writing = writeSequence.then(async () => {
|
|
208
|
+
if (!accepting || ended) {
|
|
209
|
+
pending.delete(entry.nativeId);
|
|
210
|
+
entry.resolve(false);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const content = await inputContent(input);
|
|
214
|
+
if (!accepting || ended || !child?.stdin || child.stdin.destroyed || child.stdin.writableEnded || child.killed) {
|
|
215
|
+
pending.delete(entry.nativeId);
|
|
216
|
+
entry.resolve(false);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
// Mark BEFORE write: a custom writable can synchronously emit the echo,
|
|
220
|
+
// and an EPIPE callback cannot prove no bytes reached the CLI.
|
|
221
|
+
entry.written = true;
|
|
222
|
+
child.stdin.write(JSON.stringify({ type: 'user', uuid: entry.nativeId, session_id: sessionId ?? '',
|
|
223
|
+
parent_tool_use_id: null, priority: 'next', message: { role: 'user', content } }) + '\n', error => {
|
|
224
|
+
if (!error)
|
|
225
|
+
return;
|
|
226
|
+
pending.delete(entry.nativeId);
|
|
227
|
+
entry.reject(new live_session_types_1.LiveInputDeliveryError(`Claude input write failed: ${error.message}`, true));
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
// Keep input order even when an earlier message reads a large image.
|
|
231
|
+
// Waiting for its write (not its echo) still permits genuine streaming.
|
|
232
|
+
writeSequence = writing.catch(() => { });
|
|
233
|
+
void writing.catch(error => {
|
|
234
|
+
pending.delete(entry.nativeId);
|
|
235
|
+
entry.reject(error instanceof live_session_types_1.LiveInputDeliveryError ? error : new live_session_types_1.LiveInputDeliveryError(error instanceof Error ? error.message : String(error), entry.written));
|
|
236
|
+
});
|
|
237
|
+
return promise;
|
|
238
|
+
};
|
|
239
|
+
const finishAfterResult = () => {
|
|
240
|
+
if (ended || !accepting)
|
|
241
|
+
return;
|
|
242
|
+
accepting = false;
|
|
243
|
+
// Any image preparation which has NOT written yet can safely use the
|
|
244
|
+
// caller's ordinary continuation. Written entries must first receive ACK.
|
|
245
|
+
for (const [id, input] of pending)
|
|
246
|
+
if (!input.written) {
|
|
247
|
+
pending.delete(id);
|
|
248
|
+
input.resolve(false);
|
|
249
|
+
}
|
|
250
|
+
child?.stdin?.end();
|
|
251
|
+
// The native turn has finished; EOF should close its resident process.
|
|
252
|
+
// Reap a CLI that ignores EOF, without aborting an active tool batch.
|
|
253
|
+
closeDeadline = setTimeout(() => { terminate(); settle(0); }, 2000);
|
|
254
|
+
closeDeadline.unref?.();
|
|
255
|
+
};
|
|
256
|
+
try {
|
|
257
|
+
let spawnOpts = opts;
|
|
258
|
+
const extraArgs = [...(opts.extraArgs ?? []), '--replay-user-messages'];
|
|
259
|
+
// The shared Windows wrapper moves inline prompt flags to stdin and ends
|
|
260
|
+
// it. A private prompt FILE avoids that transform for this live channel.
|
|
261
|
+
if (process.platform === 'win32' && opts.systemPrompt) {
|
|
262
|
+
promptDirectory = (0, node_fs_1.mkdtempSync)(node_path_1.default.join((0, node_os_1.tmpdir)(), 'specrails-claude-live-'));
|
|
263
|
+
const promptFile = node_path_1.default.join(promptDirectory, 'system.txt');
|
|
264
|
+
(0, node_fs_1.writeFileSync)(promptFile, opts.systemPrompt, { mode: 0o600 });
|
|
265
|
+
extraArgs.push('--system-prompt-file', promptFile);
|
|
266
|
+
spawnOpts = { ...opts, systemPrompt: undefined };
|
|
267
|
+
}
|
|
268
|
+
const args = hooks.adapter.buildArgs('chat-stream', { ...spawnOpts, extraArgs });
|
|
269
|
+
child = (hooks.spawn ?? cli_prompt_1.spawnAiCli)(hooks.binary ?? hooks.adapter.binary, args, {
|
|
270
|
+
cwd: hooks.cwd, env: (0, runtime_1.buildProviderEnv)(hooks.adapter, opts, hooks.env ?? process.env), stdio: ['pipe', 'pipe', 'pipe'],
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
hooks.onSpawnError?.(error);
|
|
275
|
+
settle(null, false, true);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
child.on('error', error => { hooks.onSpawnError?.(error); settle(null, false, true); });
|
|
279
|
+
child.on('close', code => {
|
|
280
|
+
if (!ended && !lastResultEvent && !child?.killed)
|
|
281
|
+
event({ kind: 'error', message: 'Claude closed before producing a terminal result.' });
|
|
282
|
+
settle(code);
|
|
283
|
+
});
|
|
284
|
+
child.stdin?.on('error', error => {
|
|
285
|
+
if (ended)
|
|
286
|
+
return;
|
|
287
|
+
rejectPending(`Claude stdin failed: ${error.message}; delivery is uncertain.`);
|
|
288
|
+
event({ kind: 'error', message: `Claude stdin failed: ${error.message}` });
|
|
289
|
+
terminate();
|
|
290
|
+
settle(null);
|
|
291
|
+
});
|
|
292
|
+
if (!child.stdout || !child.stdin) {
|
|
293
|
+
terminate();
|
|
294
|
+
settle(null, false, true);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
stdoutReader = (0, node_readline_1.createInterface)({ input: child.stdout, crlfDelay: Infinity });
|
|
298
|
+
child.stdout.on('data', () => { activity(); hooks.onData?.('stdout'); });
|
|
299
|
+
stdoutReader.on('line', line => {
|
|
300
|
+
if (ended)
|
|
301
|
+
return;
|
|
302
|
+
try {
|
|
303
|
+
hooks.onStdoutLine?.(line);
|
|
304
|
+
let raw;
|
|
305
|
+
try {
|
|
306
|
+
raw = JSON.parse(line);
|
|
307
|
+
}
|
|
308
|
+
catch { /* adapter ignores malformed lines */ }
|
|
309
|
+
if (raw?.type === 'user' && raw.isReplay === true && raw.parent_tool_use_id == null && raw.message?.role === 'user' && typeof raw.uuid === 'string') {
|
|
310
|
+
if (raw.uuid === initialId && initialWritten && !initialAccepted) {
|
|
311
|
+
initialAccepted = true;
|
|
312
|
+
hooks.onInitialInputAccepted?.();
|
|
313
|
+
}
|
|
314
|
+
const input = pending.get(raw.uuid);
|
|
315
|
+
if (input?.written) {
|
|
316
|
+
pending.delete(raw.uuid);
|
|
317
|
+
try {
|
|
318
|
+
input.onAccepted?.();
|
|
319
|
+
input.resolve(true);
|
|
320
|
+
}
|
|
321
|
+
catch (error) {
|
|
322
|
+
input.reject(new live_session_types_1.LiveInputDeliveryError(`Claude accepted the input but local acknowledgement failed: ${String(error)}`, true));
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
// Echoes carry input resources, not tool outcomes or generated text.
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
for (const parsed of (0, runtime_1.parseStreamEvents)(hooks.adapter, line)) {
|
|
329
|
+
event(parsed);
|
|
330
|
+
if (parsed.kind === 'result') {
|
|
331
|
+
if (parsed.isError) {
|
|
332
|
+
const errors = parsed.payload.errors;
|
|
333
|
+
const reason = typeof parsed.payload.result === 'string' && parsed.payload.result || (Array.isArray(errors) ? errors.join('\n') : 'Claude returned an error result.');
|
|
334
|
+
event({ kind: 'error', message: String(reason) });
|
|
335
|
+
rejectPending('Claude failed before confirming the input. Do not replay automatically.');
|
|
336
|
+
finishAfterResult();
|
|
337
|
+
}
|
|
338
|
+
else if (initialWritten && ![...pending.values()].some(input => input.written))
|
|
339
|
+
finishAfterResult();
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
catch (error) {
|
|
344
|
+
// A callback/parser must not throw out of an EventEmitter into the
|
|
345
|
+
// sidecar's uncaught-exception handler.
|
|
346
|
+
console.error('[claude-live-session] stdout handler failed:', error);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
if (child.stderr) {
|
|
350
|
+
child.stderr.on('data', (chunk) => {
|
|
351
|
+
activity();
|
|
352
|
+
hooks.onData?.('stderr');
|
|
353
|
+
stderrTail = (stderrTail + chunk.toString()).slice(-STDERR_CAP);
|
|
354
|
+
});
|
|
355
|
+
if (hooks.onStderrLine) {
|
|
356
|
+
stderrReader = (0, node_readline_1.createInterface)({ input: child.stderr, crlfDelay: Infinity });
|
|
357
|
+
stderrReader.on('line', line => hooks.onStderrLine?.(line));
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
hooks.onSpawn?.(child);
|
|
361
|
+
activity();
|
|
362
|
+
if (hooks.timeoutMs && hooks.timeoutMs > 0) {
|
|
363
|
+
timeout = setTimeout(() => expire('wall'), hooks.timeoutMs);
|
|
364
|
+
timeout.unref?.();
|
|
365
|
+
}
|
|
366
|
+
// Initial content also uses the native channel, with a unique UUID. The
|
|
367
|
+
// caller owns initial-message persistence; replay confirms its receipt.
|
|
368
|
+
void inputContent({ id: initialId, text: opts.prompt, imagePaths: opts.imagePaths }).then(content => {
|
|
369
|
+
if (ended || !accepting || !child?.stdin || child.killed || child.stdin.destroyed)
|
|
370
|
+
return;
|
|
371
|
+
initialWritten = true;
|
|
372
|
+
child.stdin.write(JSON.stringify({ type: 'user', uuid: initialId, session_id: sessionId ?? '', parent_tool_use_id: null,
|
|
373
|
+
priority: 'next', message: { role: 'user', content } }) + '\n', error => {
|
|
374
|
+
if (error) {
|
|
375
|
+
event({ kind: 'error', message: `Claude initial input failed: ${error.message}` });
|
|
376
|
+
terminate();
|
|
377
|
+
settle(null);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
hooks.onInputReady?.({ send, acceptedReceipt: 'received' });
|
|
381
|
+
}).catch(error => { event({ kind: 'error', message: `Claude initial input failed: ${String(error)}` }); terminate(); settle(null); });
|
|
382
|
+
});
|
|
383
|
+
}
|
|
@@ -37,6 +37,9 @@ const WHICH_CMD = process.platform === 'win32' ? 'where' : 'which';
|
|
|
37
37
|
const CODEX_MIN_VERSION = '0.128.0';
|
|
38
38
|
exports._CODEX_MIN_VERSION = CODEX_MIN_VERSION;
|
|
39
39
|
const CODEX_MODELS = [
|
|
40
|
+
// Newest first. gpt-6-astra has no rate card in `server/pricing.ts` yet, so
|
|
41
|
+
// its turns show cost as unavailable (honest-metrics: never fabricated).
|
|
42
|
+
{ value: 'gpt-6-astra', label: 'GPT-6 Astra' },
|
|
40
43
|
{ value: 'gpt-5.6-sol', label: 'GPT-5.6 Sol' },
|
|
41
44
|
{ value: 'gpt-5.6-terra', label: 'GPT-5.6 Terra' },
|
|
42
45
|
{ value: 'gpt-5.6-luna', label: 'GPT-5.6 Luna' },
|
|
@@ -45,6 +48,17 @@ const CODEX_MODELS = [
|
|
|
45
48
|
{ value: 'gpt-5.4-mini', label: 'GPT-5.4 Mini' },
|
|
46
49
|
{ value: 'gpt-5.3-codex', label: 'GPT-5.3 Codex' },
|
|
47
50
|
];
|
|
51
|
+
// Model-specific CLI capabilities (models/list, reviewed 2026-09-05).
|
|
52
|
+
// Keep the provider-wide union for legacy models without current metadata.
|
|
53
|
+
const BASE_EFFORTS = ['low', 'medium', 'high', 'xhigh'];
|
|
54
|
+
const CODEX_MODEL_EFFORTS = {
|
|
55
|
+
'gpt-6-astra': [...BASE_EFFORTS, 'max', 'ultra'],
|
|
56
|
+
'gpt-5.6-sol': [...BASE_EFFORTS, 'max', 'ultra'],
|
|
57
|
+
'gpt-5.6-terra': [...BASE_EFFORTS, 'max', 'ultra'],
|
|
58
|
+
'gpt-5.6-luna': [...BASE_EFFORTS, 'max'],
|
|
59
|
+
'gpt-5.5': BASE_EFFORTS,
|
|
60
|
+
'gpt-5.4-mini': BASE_EFFORTS,
|
|
61
|
+
};
|
|
48
62
|
const SANDBOX_FLAGS = ['--sandbox', 'workspace-write'];
|
|
49
63
|
const RAIL_SANDBOX_FLAGS = ['--sandbox', 'danger-full-access'];
|
|
50
64
|
// `codex exec resume` does NOT accept `--sandbox` (the flag only exists on
|
|
@@ -55,6 +69,8 @@ const SKIP_GIT_CHECK = '--skip-git-repo-check';
|
|
|
55
69
|
function sandboxFlags(opts, rail = false) {
|
|
56
70
|
if (opts.toolPolicy === 'read-only')
|
|
57
71
|
return ['--sandbox', 'read-only'];
|
|
72
|
+
if (opts.scopedWorkingDirectories)
|
|
73
|
+
return [...SANDBOX_FLAGS];
|
|
58
74
|
return rail ? [...RAIL_SANDBOX_FLAGS] : [...SANDBOX_FLAGS];
|
|
59
75
|
}
|
|
60
76
|
function resumeSandboxFlags(opts) {
|
|
@@ -341,6 +357,7 @@ exports.codexAdapter = {
|
|
|
341
357
|
instructionsFilename: 'AGENTS.md',
|
|
342
358
|
mcpRegistration: 'cli-add',
|
|
343
359
|
capabilities: {
|
|
360
|
+
liveInputTransport: 'codex-app-server',
|
|
344
361
|
nativeResume: true,
|
|
345
362
|
nativeStreamJson: true,
|
|
346
363
|
nativeCostUsd: false,
|
|
@@ -362,6 +379,8 @@ exports.codexAdapter = {
|
|
|
362
379
|
userMcp: false,
|
|
363
380
|
},
|
|
364
381
|
modelCatalog: () => CODEX_MODELS,
|
|
382
|
+
reasoningEffortsForModel: (model) => CODEX_MODEL_EFFORTS[model]
|
|
383
|
+
?? ['minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra'],
|
|
365
384
|
defaultModel: () => 'gpt-5.5',
|
|
366
385
|
buildArgs: buildCodexArgs,
|
|
367
386
|
parseStreamLine: parseCodexStreamLine,
|