specrails-desktop 2.35.0 → 2.42.1
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-BPAzDICW.js → DocsDialog-Dj6mt4ga.js} +2 -2
- package/client/dist/assets/{DocsPage-Dqo4Hn6G.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-CcZMcEN5.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 +90 -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 +538 -67
- 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 +147 -16
- package/server/dist/agent-operator-prompt.js +259 -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 +131 -9
- package/server/dist/dev-ports.js +8 -3
- package/server/dist/external-mcp.js +370 -0
- package/server/dist/file-provenance.js +19 -12
- 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/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/profiles-router.js +3 -18
- package/server/dist/project-code-discovery.js +142 -0
- package/server/dist/project-git.js +18 -20
- 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 +45 -7
- 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 +1 -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-LCBJ5WiD.js +0 -1
- package/client/dist/assets/AgentBrowserCapture-B-xQpyZr.js +0 -1
- package/client/dist/assets/AgentModeAnalyticsPane-BI1Vcf3T.js +0 -2
- package/client/dist/assets/AgentModeCodePane-BTRwCl9h.js +0 -2
- package/client/dist/assets/AgentModeJobsPane-VzeBJLqP.js +0 -1
- package/client/dist/assets/AgentsPage-CJj1K24O.js +0 -87
- package/client/dist/assets/AnalyticsPage-CQpV5_fX.js +0 -1
- package/client/dist/assets/CodePage-9-tFh0jB.js +0 -2
- package/client/dist/assets/DesktopAnalyticsPage-BcZ0_O_C.js +0 -1
- package/client/dist/assets/ExportDropdown-BrtfWzEG.js +0 -1
- package/client/dist/assets/InteractiveJobComposer-D36fZWai.js +0 -19
- package/client/dist/assets/JobDetailModal-BxsktbkQ.js +0 -1
- package/client/dist/assets/JobDetailPage-WWyCy6Sp.js +0 -1
- package/client/dist/assets/JobsPage-CEbM7uxU.js +0 -1
- package/client/dist/assets/LoopBuilderPage-CYsSN8io.js +0 -7
- package/client/dist/assets/LoopPreviewModal-BJhgX5wY.js +0 -1
- package/client/dist/assets/LoopsPage-DB4OqMot.js +0 -1
- package/client/dist/assets/MinimizedChatsContext-CcjBHMHd.js +0 -1
- package/client/dist/assets/PluginsPage-CR8K4nM_.js +0 -2
- package/client/dist/assets/ProjectSettingsDialog-C45-qhF4.js +0 -1
- package/client/dist/assets/ReviewPacketPage-Cz_QQeC3.js +0 -1
- package/client/dist/assets/TemplatePreviewModal-wFBd2vQP.js +0 -1
- package/client/dist/assets/TicketDetailModal-BvZoyDAL.js +0 -14
- package/client/dist/assets/Trans-DXZ-BLXb.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-C0ImhVKp.js +0 -1
- package/client/dist/assets/getTimezoneOffsetInMilliseconds-owhDdTXs.js +0 -1
- package/client/dist/assets/git-refresh-wTW0rO0Z.js +0 -1
- package/client/dist/assets/i18n-DwgvwTnx.js +0 -2
- package/client/dist/assets/index-DhjjFyU5.js +0 -66
- package/client/dist/assets/index-xBFsOEiJ.css +0 -2
- package/client/dist/assets/mcp-Czd_iyp0.js +0 -1
- package/client/dist/assets/mcp-D2pc5GGx.js +0 -1
- package/client/dist/assets/mcp-D4ZjtIx3.js +0 -1
- package/client/dist/assets/mcp-DIfBUv2D.js +0 -1
- package/client/dist/assets/mcp-DsTwmjST.js +0 -1
- package/client/dist/assets/mcp-SMkn8boG.js +0 -1
- package/client/dist/assets/mcp-fSfiVYAc.js +0 -1
- package/client/dist/assets/mcp-uDkXYu4L.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-BQX3P7Cq.js +0 -1
- package/client/dist/assets/useDesktop-BzX769yH.js +0 -1
|
@@ -40,6 +40,9 @@ const result_event_1 = require("./result-event");
|
|
|
40
40
|
const db_1 = require("./db");
|
|
41
41
|
const stream_display_1 = require("./util/stream-display");
|
|
42
42
|
const runtime_1 = require("./providers/runtime");
|
|
43
|
+
const terminal_result_1 = require("./providers/terminal-result");
|
|
44
|
+
const claude_background_tasks_1 = require("./providers/claude-background-tasks");
|
|
45
|
+
const loop_constants_1 = require("./loop-constants");
|
|
43
46
|
/** Claude's stream-json result frames do not carry a turn id. Hash a canonical
|
|
44
47
|
* representation of the real frame instead: an exact/semantic retransmission
|
|
45
48
|
* remains identifiable even after the next stdin turn has been armed, while a
|
|
@@ -58,6 +61,11 @@ function canonicalJson(value) {
|
|
|
58
61
|
function resultFrameSignature(frame) {
|
|
59
62
|
return (0, node_crypto_1.createHash)('sha256').update(canonicalJson(frame)).digest('hex');
|
|
60
63
|
}
|
|
64
|
+
/** Bound unproductive reply/continue cycles for the same unfinished workers.
|
|
65
|
+
* A blocking collection can take as long as the owner's ordinary step budget;
|
|
66
|
+
* repeatedly returning without joining the workers cannot spin forever. */
|
|
67
|
+
const MAX_BACKGROUND_HANDOFFS = 3;
|
|
68
|
+
const MAX_TOTAL_BACKGROUND_HANDOFFS = 12;
|
|
61
69
|
/** The claude CLI's synthetic no-op marker: the result text of a frame emitted
|
|
62
70
|
* for a command the CLI could not resolve (nothing was sent to the model). */
|
|
63
71
|
exports.UNKNOWN_COMMAND_RE = /^Unknown command:/;
|
|
@@ -120,6 +128,7 @@ class InteractiveJobSession {
|
|
|
120
128
|
_onSettle;
|
|
121
129
|
_settleMode;
|
|
122
130
|
_zombieTimeoutMs;
|
|
131
|
+
_onZombieTimeoutHook;
|
|
123
132
|
_quiescentEofGraceMs;
|
|
124
133
|
/** Armed by the quiescent graceful teardown: SIGTERM escalation if the child
|
|
125
134
|
* ignores the stdin EOF. Cleared on close/settle/dispose. */
|
|
@@ -158,11 +167,16 @@ class InteractiveJobSession {
|
|
|
158
167
|
_sessionId = null;
|
|
159
168
|
/** Last completed turn's `result` payload (output chaining — see SettleInfo). */
|
|
160
169
|
_resultText = null;
|
|
170
|
+
_resultIsError = false;
|
|
161
171
|
/** True once ANY assistant-derived event was observed across the whole
|
|
162
172
|
* session life (isModelWorkEvent). Feeds the zero-work settle predicate:
|
|
163
173
|
* real turns always emit assistant events; the synthetic `Unknown command:`
|
|
164
174
|
* frame never does. */
|
|
165
175
|
_sawModelWork = false;
|
|
176
|
+
/** Authoritative live roster, never a reason to complete an automatic step. */
|
|
177
|
+
_liveBackgroundTasks = [];
|
|
178
|
+
_backgroundHandoffs = 0;
|
|
179
|
+
_totalBackgroundHandoffs = 0;
|
|
166
180
|
/** Previous turn's CUMULATIVE `total_cost_usd` / `num_turns` reading. The
|
|
167
181
|
* persistent stream-json transport reports both cumulatively per turn, so we
|
|
168
182
|
* accumulate deltas against these baselines (HIGH-2). Reset to 0 when the
|
|
@@ -199,6 +213,7 @@ class InteractiveJobSession {
|
|
|
199
213
|
this._onSettle = deps.onSettle;
|
|
200
214
|
this._settleMode = deps.settleMode ?? 'finalize';
|
|
201
215
|
this._zombieTimeoutMs = deps.zombieTimeoutMs ?? 0;
|
|
216
|
+
this._onZombieTimeoutHook = deps.onZombieTimeout;
|
|
202
217
|
this._quiescentEofGraceMs = deps.quiescentEofGraceMs ?? 5000;
|
|
203
218
|
this._nextEventSeq = deps.nextEventSeq ?? null;
|
|
204
219
|
this._persistTurnUsage = deps.persistTurnUsage ?? null;
|
|
@@ -208,12 +223,37 @@ class InteractiveJobSession {
|
|
|
208
223
|
}
|
|
209
224
|
/** Spawn the resident child and run the first turn (the freestyle prompt). */
|
|
210
225
|
start(spec, firstPrompt) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
226
|
+
// Keep slash-command expansion intact: the lifecycle rule belongs in the
|
|
227
|
+
// system context, not in the command's argument string. Preserve any
|
|
228
|
+
// existing appended system prompt supplied by the queue/loop owner.
|
|
229
|
+
const args = [...spec.args];
|
|
230
|
+
if (this._adapter.id === 'claude' && this._settleMode === 'auto') {
|
|
231
|
+
const index = args.indexOf('--append-system-prompt');
|
|
232
|
+
if (index >= 0)
|
|
233
|
+
args[index + 1] = `${args[index + 1] ?? ''}\n\n${loop_constants_1.FOREGROUND_RULE}`;
|
|
234
|
+
else
|
|
235
|
+
args.push('--append-system-prompt', loop_constants_1.FOREGROUND_RULE);
|
|
236
|
+
}
|
|
237
|
+
let child;
|
|
238
|
+
try {
|
|
239
|
+
child = this._spawn(spec.binary, args, {
|
|
240
|
+
env: spec.env ?? process.env,
|
|
241
|
+
// stdin MUST be piped — it is the per-turn transport.
|
|
242
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
243
|
+
cwd: spec.cwd,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
// Local preparation (including managed skills) can fail synchronously,
|
|
248
|
+
// before there is a child to emit error/close. Settle through the normal
|
|
249
|
+
// owner callback so no interactive slot or step timer leaks.
|
|
250
|
+
this._resultText = `Could not start ${this._adapter.id}: ${error instanceof Error ? error.message : String(error)}`;
|
|
251
|
+
this._resultIsError = true;
|
|
252
|
+
this._persistLog('stderr', this._resultText);
|
|
253
|
+
this._emitLog('stderr', this._resultText);
|
|
254
|
+
this._settle('crashed');
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
217
257
|
this._child = child;
|
|
218
258
|
this._childClosed = false;
|
|
219
259
|
this._stdinFailed = false;
|
|
@@ -272,7 +312,7 @@ class InteractiveJobSession {
|
|
|
272
312
|
* an immediate prompt only after a confirmed stdin write. Returns false if the
|
|
273
313
|
* session is gone OR the write could not be delivered (stdin destroyed/EPIPE). */
|
|
274
314
|
send(text) {
|
|
275
|
-
if (this._disposed || this._finalizing || !this._child)
|
|
315
|
+
if (this._disposed || this._settled || this._finalizing || !this._child)
|
|
276
316
|
return false;
|
|
277
317
|
const queued = this._streaming;
|
|
278
318
|
if (queued) {
|
|
@@ -392,6 +432,8 @@ class InteractiveJobSession {
|
|
|
392
432
|
* write; false when stdin is gone/destroyed or the write throws (EPIPE) — the
|
|
393
433
|
* caller must NOT treat an unconfirmed turn as accepted. */
|
|
394
434
|
_writeTurn(text) {
|
|
435
|
+
if (this._disposed || this._settled || this._finalizing || this._terminationStarted)
|
|
436
|
+
return false;
|
|
395
437
|
const child = this._child;
|
|
396
438
|
if (!child || !child.stdin || child.stdin.destroyed || this._stdinFailed)
|
|
397
439
|
return false;
|
|
@@ -431,20 +473,39 @@ class InteractiveJobSession {
|
|
|
431
473
|
parsed = JSON.parse(line);
|
|
432
474
|
}
|
|
433
475
|
catch { /* plain text */ }
|
|
476
|
+
// Keep the live roster current before deciding whether a result completes
|
|
477
|
+
// the step or needs the parent to join its unfinished workers.
|
|
478
|
+
this._trackBackgroundTasks(parsed);
|
|
479
|
+
// parseStreamEvents is pure, so classifying the frame through the adapter
|
|
480
|
+
// BEFORE the drop logic is safe — and it is the adapter that knows a claude
|
|
481
|
+
// `result` frame carrying `origin.kind === 'task-notification'` is a
|
|
482
|
+
// CLI-internal notification turn, not this turn's terminal result.
|
|
483
|
+
const adapterEvents = (0, runtime_1.parseStreamEvents)(this._adapter, line);
|
|
434
484
|
// A late retransmission can arrive after the next queued prompt has already
|
|
435
|
-
// been written. Drop it BEFORE
|
|
436
|
-
//
|
|
437
|
-
//
|
|
485
|
+
// been written. Drop it BEFORE event persistence: adding it to the next
|
|
486
|
+
// turn's event buffer corrupts live totals, while persisting it beyond the
|
|
487
|
+
// prior checkpoint would make crash recovery count it again.
|
|
438
488
|
if (parsed?.type === 'result') {
|
|
439
489
|
// A terminal frame with no active turn is causally unassignable. Drop it
|
|
440
|
-
// before
|
|
490
|
+
// before persistence so raw recovery cannot count it.
|
|
441
491
|
if (!this._awaitingResult)
|
|
442
492
|
return;
|
|
493
|
+
if (!adapterEvents.some((ev) => ev.kind === 'result')) {
|
|
494
|
+
// Notification turn (loop run 5c958db2): the CLI answered its OWN
|
|
495
|
+
// orphaned-background-task notice, not the prompt we wrote — the real
|
|
496
|
+
// turn is still coming. Closing the turn here auto-settled the session
|
|
497
|
+
// and tore the child down mid-thought as a zero-work failure. Leave the
|
|
498
|
+
// turn armed, and do not persist the frame as a `result` row either
|
|
499
|
+
// (crash recovery counts persisted result rows as completed turns).
|
|
500
|
+
const note = `↷ ${this._adapter.id} reported a background-task notification (not this turn's result) — continuing.`;
|
|
501
|
+
this._persistLog('stdout', note);
|
|
502
|
+
this._emitLog('stdout', note);
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
443
505
|
const signature = resultFrameSignature(parsed);
|
|
444
506
|
if (this._acceptedResultSignatures.has(signature))
|
|
445
507
|
return;
|
|
446
508
|
}
|
|
447
|
-
const adapterEvents = (0, runtime_1.parseStreamEvents)(this._adapter, line);
|
|
448
509
|
for (const adapterEvent of adapterEvents) {
|
|
449
510
|
this._turnEvents.push(adapterEvent);
|
|
450
511
|
if (!this._sawModelWork && isModelWorkEvent(adapterEvent))
|
|
@@ -486,6 +547,47 @@ class InteractiveJobSession {
|
|
|
486
547
|
}
|
|
487
548
|
}
|
|
488
549
|
}
|
|
550
|
+
/** Mirror claude's `system/background_tasks_changed` roster. Any other frame
|
|
551
|
+
* (or a non-claude provider, which never emits it) leaves the roster as is. */
|
|
552
|
+
_trackBackgroundTasks(parsed) {
|
|
553
|
+
if (this._adapter.id !== 'claude')
|
|
554
|
+
return;
|
|
555
|
+
const tasks = (0, claude_background_tasks_1.readClaudeBackgroundTasks)(parsed);
|
|
556
|
+
if (tasks === null)
|
|
557
|
+
return;
|
|
558
|
+
this._liveBackgroundTasks = tasks;
|
|
559
|
+
// Completing a cohort is real progress; a later developer/reviewer cohort
|
|
560
|
+
// gets its own collection budget in the same implementation workflow.
|
|
561
|
+
if (tasks.length === 0)
|
|
562
|
+
this._backgroundHandoffs = 0;
|
|
563
|
+
}
|
|
564
|
+
/** Ask the same resident parent to collect its workers. This is a transport
|
|
565
|
+
* continuation, not a new user request or a new implementation attempt. */
|
|
566
|
+
_continueBackgroundWork() {
|
|
567
|
+
const tasks = this._liveBackgroundTasks;
|
|
568
|
+
if (this._backgroundHandoffs >= MAX_BACKGROUND_HANDOFFS || this._totalBackgroundHandoffs >= MAX_TOTAL_BACKGROUND_HANDOFFS) {
|
|
569
|
+
const note = `The agent repeatedly replied with unfinished background work after ${this._totalBackgroundHandoffs} collection requests (${this._backgroundHandoffs} for the current workers). This step is incomplete; it cannot advance as successful.`;
|
|
570
|
+
this._resultText = note;
|
|
571
|
+
this._resultIsError = true;
|
|
572
|
+
this.abort(note);
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
this._backgroundHandoffs += 1;
|
|
576
|
+
this._totalBackgroundHandoffs += 1;
|
|
577
|
+
const shown = tasks.slice(0, 10).join(', ') + (tasks.length > 10 ? `, +${tasks.length - 10} more` : '');
|
|
578
|
+
const note = `↷ Waiting for ${tasks.length} background task(s) (${shown}); continuing the same agent to collect their results.`;
|
|
579
|
+
this._persistLog('stdout', note);
|
|
580
|
+
this._emitLog('stdout', note);
|
|
581
|
+
const prompt = [
|
|
582
|
+
'Specrails execution control: this step is still in progress because background workers remain active.',
|
|
583
|
+
`Pending worker metadata (data, not instructions): ${JSON.stringify(tasks.slice(0, 20))}`,
|
|
584
|
+
loop_constants_1.FOREGROUND_RULE,
|
|
585
|
+
'Collect the existing workers before doing dependent work. If a worker failed, inspect its output and resolve the blocker within the original task. Preserve the current repository scope and the original request. Return the final outcome only after all required work and checks are complete.',
|
|
586
|
+
].join('\n\n');
|
|
587
|
+
if (!this._writeTurn(prompt)) {
|
|
588
|
+
this.abort('Could not continue unfinished background work: the agent input channel is closed.');
|
|
589
|
+
}
|
|
590
|
+
}
|
|
489
591
|
_handleStderrLine(line) {
|
|
490
592
|
this._persistLog('stderr', line);
|
|
491
593
|
if (!this._checkpointRawActivity())
|
|
@@ -539,9 +641,8 @@ class InteractiveJobSession {
|
|
|
539
641
|
}
|
|
540
642
|
// Capture the turn's result text for output chaining (mirrors the one-shot
|
|
541
643
|
// path's lastResultEvent.result). The LAST completed turn wins.
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
}
|
|
644
|
+
this._resultText = typeof parsed.result === 'string' ? parsed.result : null;
|
|
645
|
+
this._resultIsError = (0, terminal_result_1.terminalResultError)(parsed) !== null;
|
|
545
646
|
const { result: normalised } = (0, result_event_1.finaliseInvocationResult)(this._adapter, this._turnEvents, {});
|
|
546
647
|
// COST-ACCOUNTING-AUDIT HIGH-2: this ONE resident `claude -p --input-format
|
|
547
648
|
// stream-json` child reports `total_cost_usd` and `num_turns` CUMULATIVELY
|
|
@@ -614,6 +715,21 @@ class InteractiveJobSession {
|
|
|
614
715
|
totals: { ...this._accum },
|
|
615
716
|
timestamp: new Date().toISOString(),
|
|
616
717
|
});
|
|
718
|
+
const resultError = (0, terminal_result_1.terminalResultError)(parsed);
|
|
719
|
+
if (resultError) {
|
|
720
|
+
// The terminal result still owns real usage: checkpoint it above before
|
|
721
|
+
// ending the session. Never auto-finalize or dispatch a queued prompt
|
|
722
|
+
// after a max-turns/provider execution failure, even if stdout previously
|
|
723
|
+
// included a PASS or the resident child would eventually exit with 0.
|
|
724
|
+
this._finalizing = true;
|
|
725
|
+
this._terminationReason = 'crashed';
|
|
726
|
+
this._clearZombieTimer();
|
|
727
|
+
const note = `✖ Provider turn failed — ${resultError}`;
|
|
728
|
+
this._persistLog('stderr', note);
|
|
729
|
+
this._emitLog('stderr', note);
|
|
730
|
+
this._terminateChildTree('crashed');
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
617
733
|
// Feed the next queued prompt (if any) now that the turn is idle. Deferred to a
|
|
618
734
|
// microtask so any stray/duplicate result for THIS just-settled turn that is
|
|
619
735
|
// sitting in the same synchronous stdout batch is processed (and rejected by
|
|
@@ -645,7 +761,10 @@ class InteractiveJobSession {
|
|
|
645
761
|
return;
|
|
646
762
|
if (this._streaming || this._pending.length > 0)
|
|
647
763
|
return;
|
|
648
|
-
this.
|
|
764
|
+
if (this._liveBackgroundTasks.length > 0)
|
|
765
|
+
this._continueBackgroundWork();
|
|
766
|
+
else
|
|
767
|
+
this._finalizeQuiescent();
|
|
649
768
|
});
|
|
650
769
|
}
|
|
651
770
|
}
|
|
@@ -815,11 +934,19 @@ class InteractiveJobSession {
|
|
|
815
934
|
const timeoutSec = Math.round(this._zombieTimeoutMs / 1000);
|
|
816
935
|
const note = `[zombie-detection] Interactive job ${this._jobId} produced no output for ${timeoutSec}s — auto-terminating`;
|
|
817
936
|
console.error(note);
|
|
937
|
+
try {
|
|
938
|
+
this._onZombieTimeoutHook?.();
|
|
939
|
+
}
|
|
940
|
+
catch { /* owner hook must never block teardown */ }
|
|
818
941
|
this.abort(note);
|
|
819
942
|
}
|
|
820
943
|
_settle(reason) {
|
|
821
944
|
if (this._settled)
|
|
822
945
|
return;
|
|
946
|
+
// A terminal error received during graceful teardown overrides an earlier
|
|
947
|
+
// finalize request, including a teardown timer armed before the error.
|
|
948
|
+
if (this._terminationReason === 'crashed')
|
|
949
|
+
reason = 'crashed';
|
|
823
950
|
this._settled = true;
|
|
824
951
|
// Fold any unfinished turn BEFORE snapshotting totals so a mid-turn
|
|
825
952
|
// finalize/crash keeps that turn's spend (CRIT-4).
|
|
@@ -867,6 +994,7 @@ class InteractiveJobSession {
|
|
|
867
994
|
estimated: this._inflightEstimated,
|
|
868
995
|
activeDurationMs: this._activeDurationMs,
|
|
869
996
|
resultText: this._resultText,
|
|
997
|
+
resultIsError: this._resultIsError,
|
|
870
998
|
zeroWork,
|
|
871
999
|
});
|
|
872
1000
|
}
|
|
@@ -882,6 +1010,11 @@ class InteractiveJobSession {
|
|
|
882
1010
|
* settles because its owner already flushed/reconciles the job separately.
|
|
883
1011
|
*/
|
|
884
1012
|
_terminateChildTree(reason) {
|
|
1013
|
+
// Close admission synchronously, before SIGTERM. A child may take seconds
|
|
1014
|
+
// to exit; neither a queued user prompt nor an auto-collection microtask
|
|
1015
|
+
// may start another turn in that window (including a late result frame).
|
|
1016
|
+
this._finalizing = true;
|
|
1017
|
+
this._clearZombieTimer();
|
|
885
1018
|
if (reason !== null && this._terminationReason === null)
|
|
886
1019
|
this._terminationReason = reason;
|
|
887
1020
|
const child = this._child;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Loopback client for the app's OWN REST API, authenticated with the master
|
|
3
|
+
// token held server-side. Precedent: the MCP domain tools (`apiCall`), which
|
|
4
|
+
// reuse every router's validation instead of re-implementing it. The milestone
|
|
5
|
+
// launch chain uses it to launch chunks through the ordinary rails launch
|
|
6
|
+
// route — the single authority for its ~15 guards — so a chunk launch behaves
|
|
7
|
+
// byte-identically to a dashboard launch and every 4xx becomes a typed reason.
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.createInternalApi = createInternalApi;
|
|
10
|
+
exports.internalApiError = internalApiError;
|
|
11
|
+
const auth_1 = require("./auth");
|
|
12
|
+
function createInternalApi(deps) {
|
|
13
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
14
|
+
const token = deps.token ?? auth_1.loadOrGenerateToken;
|
|
15
|
+
return {
|
|
16
|
+
async call(method, path, body) {
|
|
17
|
+
const res = await fetchImpl(`http://127.0.0.1:${deps.port}/api${path}`, {
|
|
18
|
+
method,
|
|
19
|
+
headers: {
|
|
20
|
+
Authorization: `Bearer ${token()}`,
|
|
21
|
+
...(body !== undefined ? { 'content-type': 'application/json' } : {}),
|
|
22
|
+
},
|
|
23
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
24
|
+
});
|
|
25
|
+
const text = await res.text();
|
|
26
|
+
let data;
|
|
27
|
+
try {
|
|
28
|
+
data = text ? JSON.parse(text) : null;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
data = text;
|
|
32
|
+
}
|
|
33
|
+
return { ok: res.ok, status: res.status, body: data };
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Extract the router's `{ error, detail }` from a failed response body. */
|
|
38
|
+
function internalApiError(res) {
|
|
39
|
+
const body = res.body;
|
|
40
|
+
if (body && typeof body === 'object') {
|
|
41
|
+
const obj = body;
|
|
42
|
+
return {
|
|
43
|
+
error: typeof obj.error === 'string' ? obj.error : `http_${res.status}`,
|
|
44
|
+
...(typeof obj.detail === 'string' ? { detail: obj.detail } : {}),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return { error: `http_${res.status}`, ...(typeof body === 'string' && body ? { detail: body.slice(0, 200) } : {}) };
|
|
48
|
+
}
|
|
@@ -131,6 +131,7 @@ function mapIssueToTicket(issue, localId, conn, existing) {
|
|
|
131
131
|
labels: issue.fields.labels ?? [],
|
|
132
132
|
assignee: issue.fields.assignee?.displayName ?? issue.fields.assignee?.emailAddress ?? null,
|
|
133
133
|
prerequisites: existing?.prerequisites ?? [],
|
|
134
|
+
...(existing?.repositoryIds ? { repositoryIds: [...existing.repositoryIds] } : {}),
|
|
134
135
|
metadata: existing?.metadata ?? {},
|
|
135
136
|
comments: existing?.comments ?? [],
|
|
136
137
|
attachments: existing?.attachments,
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ─── Tolerant JSON parsing for model-emitted payloads ─────────────────────────
|
|
3
|
+
//
|
|
4
|
+
// A model writing a ~20 KB JSON snapshot by hand makes small, predictable
|
|
5
|
+
// mistakes: a raw newline inside a string, an unescaped inner quote, a
|
|
6
|
+
// trailing comma, a nested ```json fence, a stray comment. `JSON.parse`
|
|
7
|
+
// rejects all of them and the whole snapshot used to be dropped silently.
|
|
8
|
+
//
|
|
9
|
+
// `parseJsonTolerant` first tries strict `JSON.parse`; only when that fails
|
|
10
|
+
// does it run ONE deterministic repair pass (a small string-aware state
|
|
11
|
+
// machine — never a regex over the whole text, so repairs inside string
|
|
12
|
+
// literals can't corrupt structure) and parses again. The result says whether
|
|
13
|
+
// a repair was needed and which kinds were applied, so callers can log/badge
|
|
14
|
+
// it. It never throws.
|
|
15
|
+
//
|
|
16
|
+
// Client mirror: client/src/lib/json-tolerant.ts — keep the two in sync.
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.repairJsonText = repairJsonText;
|
|
19
|
+
exports.parseJsonTolerant = parseJsonTolerant;
|
|
20
|
+
const VALID_ESCAPES = '"\\/bfnrtu';
|
|
21
|
+
function isJsonWhitespace(ch) {
|
|
22
|
+
return ch === ' ' || ch === '\t' || ch === '\r' || ch === '\n';
|
|
23
|
+
}
|
|
24
|
+
/** One string-aware pass over `source` fixing the common model mistakes. */
|
|
25
|
+
function repairJsonText(source) {
|
|
26
|
+
const repairs = new Set();
|
|
27
|
+
let text = source.trim();
|
|
28
|
+
// A nested code fence around the payload (```json … ``` inside the
|
|
29
|
+
// blueprint-draft block). Leading and trailing fences are stripped
|
|
30
|
+
// independently: the outer lazy fence regex may already have eaten one.
|
|
31
|
+
const leadingFence = /^```[A-Za-z0-9_-]*[ \t]*\r?\n/.exec(text);
|
|
32
|
+
if (leadingFence) {
|
|
33
|
+
text = text.slice(leadingFence[0].length);
|
|
34
|
+
repairs.add('nested_fence');
|
|
35
|
+
}
|
|
36
|
+
const trailingFence = /\r?\n[ \t]*```[ \t]*$/.exec(text);
|
|
37
|
+
if (trailingFence) {
|
|
38
|
+
text = text.slice(0, trailingFence.index);
|
|
39
|
+
repairs.add('nested_fence');
|
|
40
|
+
}
|
|
41
|
+
// Prose before/after the object ("Here is the snapshot: {...} Done.").
|
|
42
|
+
const first = text.indexOf('{');
|
|
43
|
+
const last = text.lastIndexOf('}');
|
|
44
|
+
if (first !== -1 && last > first && (first > 0 || last < text.length - 1)) {
|
|
45
|
+
text = text.slice(first, last + 1);
|
|
46
|
+
repairs.add('trimmed_wrapper');
|
|
47
|
+
}
|
|
48
|
+
let out = '';
|
|
49
|
+
let inString = false;
|
|
50
|
+
for (let i = 0; i < text.length; i++) {
|
|
51
|
+
const ch = text[i];
|
|
52
|
+
if (inString) {
|
|
53
|
+
if (ch === '\\') {
|
|
54
|
+
const next = text[i + 1];
|
|
55
|
+
if (next === undefined) {
|
|
56
|
+
repairs.add('dangling_escape');
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
if (VALID_ESCAPES.includes(next)) {
|
|
60
|
+
out += ch + next;
|
|
61
|
+
i += 1;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
// `\'` and friends are not JSON escapes — keep the character, drop the
|
|
65
|
+
// backslash (a raw newline after a backslash becomes a real escape).
|
|
66
|
+
out += next === '\n' ? '\\n' : next;
|
|
67
|
+
i += 1;
|
|
68
|
+
repairs.add('invalid_escape');
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (ch === '"') {
|
|
72
|
+
// Terminator, or a stray inner quote? A real terminator is followed
|
|
73
|
+
// (after whitespace) by a structural character or the end of input.
|
|
74
|
+
let j = i + 1;
|
|
75
|
+
while (j < text.length && isJsonWhitespace(text[j]))
|
|
76
|
+
j += 1;
|
|
77
|
+
const after = text[j];
|
|
78
|
+
if (after === undefined || after === ',' || after === '}' || after === ']' || after === ':') {
|
|
79
|
+
inString = false;
|
|
80
|
+
out += ch;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
out += '\\"';
|
|
84
|
+
repairs.add('inner_quote');
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (ch === '\n') {
|
|
88
|
+
out += '\\n';
|
|
89
|
+
repairs.add('raw_newline');
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (ch === '\r') {
|
|
93
|
+
repairs.add('raw_newline');
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (ch === '\t') {
|
|
97
|
+
out += '\\t';
|
|
98
|
+
repairs.add('raw_control');
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const code = ch.charCodeAt(0);
|
|
102
|
+
if (code < 0x20) {
|
|
103
|
+
out += '\\u' + code.toString(16).padStart(4, '0');
|
|
104
|
+
repairs.add('raw_control');
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
out += ch;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
// Outside a string literal.
|
|
111
|
+
if (ch === '"') {
|
|
112
|
+
inString = true;
|
|
113
|
+
out += ch;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (ch === ',') {
|
|
117
|
+
let j = i + 1;
|
|
118
|
+
while (j < text.length && isJsonWhitespace(text[j]))
|
|
119
|
+
j += 1;
|
|
120
|
+
if (text[j] === '}' || text[j] === ']') {
|
|
121
|
+
repairs.add('trailing_comma');
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
out += ch;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (ch === '/' && text[i + 1] === '/') {
|
|
128
|
+
const end = text.indexOf('\n', i);
|
|
129
|
+
i = end === -1 ? text.length : end;
|
|
130
|
+
repairs.add('comment');
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (ch === '/' && text[i + 1] === '*') {
|
|
134
|
+
const end = text.indexOf('*/', i + 2);
|
|
135
|
+
i = end === -1 ? text.length : end + 1;
|
|
136
|
+
repairs.add('comment');
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
out += ch;
|
|
140
|
+
}
|
|
141
|
+
return { text: out, repairs: [...repairs] };
|
|
142
|
+
}
|
|
143
|
+
function describeParseError(err, text) {
|
|
144
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
145
|
+
const match = /position (\d+)/i.exec(message);
|
|
146
|
+
const position = match ? Number(match[1]) : null;
|
|
147
|
+
let excerpt = null;
|
|
148
|
+
if (position !== null && Number.isFinite(position)) {
|
|
149
|
+
const start = Math.max(0, position - 40);
|
|
150
|
+
const end = Math.min(text.length, position + 40);
|
|
151
|
+
excerpt = text.slice(start, end).replace(/\s+/g, ' ');
|
|
152
|
+
}
|
|
153
|
+
return { error: message, position, excerpt };
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Strict `JSON.parse` first; on failure ONE repair pass, then parse again.
|
|
157
|
+
* `repaired` is true only when the strict parse failed AND the repaired text
|
|
158
|
+
* parsed. Never throws.
|
|
159
|
+
*/
|
|
160
|
+
function parseJsonTolerant(source) {
|
|
161
|
+
try {
|
|
162
|
+
return { ok: true, value: JSON.parse(source), repaired: false, repairs: [] };
|
|
163
|
+
}
|
|
164
|
+
catch (strictErr) {
|
|
165
|
+
const { text, repairs } = repairJsonText(source);
|
|
166
|
+
try {
|
|
167
|
+
const value = JSON.parse(text);
|
|
168
|
+
return { ok: true, value, repaired: true, repairs };
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return { ok: false, ...describeParseError(strictErr, source) };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -227,8 +227,10 @@ function moveOverwriting(src, dest) {
|
|
|
227
227
|
fs.renameSync(src, dest);
|
|
228
228
|
}
|
|
229
229
|
catch {
|
|
230
|
-
// Cross-device fallback.
|
|
231
|
-
|
|
230
|
+
// Cross-device fallback. JS traversal avoids Node 22's native Unicode copy
|
|
231
|
+
// failure on Windows (nodejs/node#61878). The destination is cleared before
|
|
232
|
+
// this copy; remove the source state only after copying succeeds.
|
|
233
|
+
fs.cpSync(src, dest, { recursive: true, filter: () => true, mode: fs.constants.COPYFILE_FICLONE });
|
|
232
234
|
fs.rmSync(src, { recursive: true, force: true });
|
|
233
235
|
}
|
|
234
236
|
}
|