chainlesschain 0.162.197 → 0.162.200
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/bin/chainlesschain.js +14 -6
- package/package.json +4 -1
- package/scripts/command-lifecycle-report.mjs +94 -0
- package/src/assets/web-panel/assets/{AIOps-D3Gu1a5d.js → AIOps-DcQ0bWKy.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DrwAoKaz.js → ActionButton-GecwfFPt.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-C7Q-gd_3.js → Analytics-CD6iSt9v.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DgBtae-n.js → AppLayout-CDEtuEYf.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-pQ6LcA-W.js → Artifacts-DS3jAjeW.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DK61tocB.js → Audit-CcSJA048.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BOKgDFRh.js → BackgroundAgents-DRo9Morb.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Bo9G4vTP.js → Backup-Vw5MrWft.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Do_dE9_v.js → BaseInput-DNHIu823.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-COVvZzOL.js → Chat-DvAsO8-b.js} +4 -4
- package/src/assets/web-panel/assets/ChatBubbleRenderer-9aDuObay.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-Z9MJMolt.js → Checkbox-CKCa7tvn.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BVzWKVbf.js → Codegen-CIFvZdaT.js} +1 -1
- package/src/assets/web-panel/assets/{Col-C8MnYcbT.js → Col-C79yz7bK.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DQxqw15l.js → Community-DVvZskLJ.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BAUmrh3y.js → Compact-oaew61hV.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-jPAkQ3zK.js → Compliance-DqA7wmRx.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BBQyxbh8.js → Cowork-B-qGadxa.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-W5koq8Z5.js → Cron-CUlCl4sS.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BQhnu5hS.js → Crosschain-CNOlr9DU.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DD7PlI18.js → DID-DJqFCT_3.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-w_ILuwKI.js → Dashboard-CznGpphf.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-qiDUAyAo.js → Dropdown-_cJw218E.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-PDeBcI5H.js → EmailListRenderer-Dr-1BZ9C.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-SuArscRM.js → FamilyGuardDashboard-Dxf4xtSk.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BCovZaUn.js → Federation-DOiG3i_1.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DjlFdVFk.js → FormItemContext-BzbMcFB9.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DoEZ7fcS.js → GenericCardRenderer-VbBrYttP.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CV0-6GPI.js → Git-CLG8E6ED.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-B_SFN50w.js → Governance-LGJQfk_q.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-heI0Eo6k.js → Inference-DlQKx9lF.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Cz5INS5p.js → KnowledgeGraph-DU8vEouV.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BSFxiHkg.js → Logs-FZIQOdln.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BJNWIrbw.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-0TWTpE7k.js → Marketplace-C_xd-zZI.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CV4-wBLm.js → McpTools-q-YktphS.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-x5bH5rw5.js → Memory-Cq9OhDin.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DaBmUu9G.js → MobileBridge-B03_R98T.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-DZrk-qmF.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-B_zKEBif.js → Mtc-BidCKW28.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BCfKD2yg.js → MtcAudit-r-iaMVM7.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DgYfj6c_.js → Multisig-CgTUFvff.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Dz09lFUm.js → NLProgramming-B7NvzfAV.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Cuj6ugBE.js → Notes-80CWNqJI.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DK2WXjhg.js → NotificationSettings-0H6xdiY3.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-D1IAOQoo.js → OrderTableRenderer-CKP4AFWy.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-9fqnPvTw.js → Organization-B8sxCV_h.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-n5xHkhow.js → Overflow-CW9JBBhQ.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-B5AUWwH-.js → P2P-bdSQV7oZ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CoUDV6dy.js → PdhVaultBrowser-DQad42nW.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-DPRmQf_H.js → Permissions-CueexxTR.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-B37bsbEN.js → PersonalDataHub-fqxflhR8.js} +6 -6
- package/src/assets/web-panel/assets/{Pipeline-CCAuPqu9.js → Pipeline-KFwwnIMC.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B81msZdv.js → Privacy-ClnD9buY.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B-Py2NbF.js → ProjectInit-CZEz6sm3.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CYsneiRB.js → ProjectSettings-B6NzpmOI.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-Y975Mh6R.js → Projects-DYyuwPCs.js} +1 -1
- package/src/assets/web-panel/assets/Providers-C3tz_jdh.js +1 -0
- package/src/assets/web-panel/assets/{QrScannerModal-Bj_6gJ0l.js → QrScannerModal-BzuOBbqB.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BgpBCMPE.js → QuickAsk-CmNO9qSj.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DhUW3YUA.js → Recommend-VJNj3_NF.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DdeyfbkA.js → RemoteSession-CrbdbSBF.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-fxW421xd.js → Reputation-DTyMd45j.js} +1 -1
- package/src/assets/web-panel/assets/{Row-De73w1og.js → Row-DHrQ-Icz.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-3US_Q_lj.js → RssFeed-DqWxY9c5.js} +2 -2
- package/src/assets/web-panel/assets/{Search-DbZ_DU74.js → Search-ctF1Ks3J.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DoIU1vMF.js → Security-BrQz8uo5.js} +4 -4
- package/src/assets/web-panel/assets/{Services-DB_RGqpc.js → Services-D4scVFar.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DnzLaayC.js → Skeleton-oUScaOjv.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-VzVXHENF.js → Skills-CL-y0eLt.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DMfvjCAI.js → Sla-DQExhwXj.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DQQOYWbF.js → SpeechSettings-iNp_I7kN.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Bmx3FG1P.js → SyncSettings-CTDlMo0A.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-DOQyfb-2.js → Tasks-4kb8l3sc.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D6hTRT7c.js → Templates-BXcL9oXW.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CTPQZAzs.js → Tenant-DLE8eS0D.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-B7vII3oH.js → Terminal-DGpUZPPK.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BkiFJeXV.js → TimelineRenderer-C1pWXGPC.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BPPdQMNo.js → Tokens-BYfbfqhZ.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BxG8JAEI.js → Trigger-K9YfLOCw.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DHD7nMpM.js → Trust-Ctkq77Hy.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B4BJpU47.js → UkeySign-C6_CSe9J.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CRiGpFx2.js → VideoEditing-Be3rpOWs.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BSDSNiem.js → Wallet-D0UIplxk.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DLTUh5Zv.js → WebAuthn-CF9bM9I3.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-tW2MwjhD.js → WorkflowEditor-D0H1XVPY.js} +1 -1
- package/src/assets/web-panel/assets/{chat-SgsLQ3FC.js → chat-Cgzzbe0o.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BHjjLIKO.js → colors-BwNxEVS0.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-VceErdKq.js → compact-item-D60Z4Hhs.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BZ332MYl.js → createContext-MFk58XB0.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BJiw369i.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CBTjJOjn.js → hasIn-CRj2SvGO.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaCCy6lq.js → index--s45_1cb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CMVvxIS8.js → index--tquQ2ZG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BhXZEUAc.js → index-1T1rhokn.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQSmZGgs.js → index-B-M82_rx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BeiqkxJG.js → index-BE_el1Zs.js} +1 -1
- package/src/assets/web-panel/assets/{index-29wVzi-k.js → index-BhRkR7IO.js} +1 -1
- package/src/assets/web-panel/assets/{index-iYQNU9za.js → index-Bo0y96-K.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRWhLbWF.js → index-CJgu5JUK.js} +1 -1
- package/src/assets/web-panel/assets/{index-BPXFLYdW.js → index-CLWwdebO.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cr4rjlW5.js → index-CNAK5QG_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaIS_TNX.js → index-CQjJjPRD.js} +1 -1
- package/src/assets/web-panel/assets/{index-1n7xjKDU.js → index-CTDbAfae.js} +1 -1
- package/src/assets/web-panel/assets/{index-BETEjuNr.js → index-CVI_9sRK.js} +1 -1
- package/src/assets/web-panel/assets/{index-By5jBtkV.js → index-CY14oMQK.js} +1 -1
- package/src/assets/web-panel/assets/{index-DgPvuIn2.js → index-CbiTJkZf.js} +1 -1
- package/src/assets/web-panel/assets/index-CiMouosn.js +1 -0
- package/src/assets/web-panel/assets/{index-CawpdGTW.js → index-CqWpxMqx.js} +1 -1
- package/src/assets/web-panel/assets/{index-_PHrIO4O.js → index-CvB8lYUR.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOtvPdHt.js → index-D51XwtCY.js} +1 -1
- package/src/assets/web-panel/assets/{index-CrUgDQkf.js → index-D6HvK_1O.js} +1 -1
- package/src/assets/web-panel/assets/{index-BY1wexYG.js → index-D9jVIwLJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-C_B9rFQE.js → index-DA4tE98u.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5KAGxNo.js → index-DBwOtXw0.js} +1 -1
- package/src/assets/web-panel/assets/{index-BC1xuQgX.js → index-DKdNzTIb.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2u26AS3.js → index-DRySdmvN.js} +1 -1
- package/src/assets/web-panel/assets/{index-DePOeMDM.js → index-DWzyTev7.js} +1 -1
- package/src/assets/web-panel/assets/index-DXcKlwy7.js +1 -0
- package/src/assets/web-panel/assets/{index-BTlc-Bve.js → index-DYjs7jAP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLc19alH.js → index-DbROzMBp.js} +1 -1
- package/src/assets/web-panel/assets/{index-fU7wNHDB.js → index-DhFtk5PR.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_SePDWj.js → index-Di2AbMLg.js} +1 -1
- package/src/assets/web-panel/assets/{index-vIXOpcjD.js → index-DvmocQsM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcUenmCX.js → index-Dw-o0zEF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUkVN794.js → index-DysPoP38.js} +1 -1
- package/src/assets/web-panel/assets/{index-CtjLcCNU.js → index-LX9pJxm_.js} +1 -1
- package/src/assets/web-panel/assets/{index-B40dQn0G.js → index-OI_fXWx0.js} +3 -3
- package/src/assets/web-panel/assets/{index-FJ3zC9LK.js → index-eDTOX8Xj.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdefYBSw.js → index-gWKDsTzF.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpumS98o.js → index-q_GDUVAA.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-D1oZNz0D.js → initDefaultProps-C61kZqEd.js} +1 -1
- package/src/assets/web-panel/assets/{motion-C8k6doMO.js → motion-DZnT5U1L.js} +1 -1
- package/src/assets/web-panel/assets/{move-DJ4qSbYt.js → move-L8wzwbel.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CdpJD85j.js → mtc-parser-DLdYSejc.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B0V4slKA.js → omit-D53cbS59.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-Di5NiW1F.js → pickAttrs-Bbc5HPtu.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-B5OMHgEM.js → placementArrow-BkvmO860.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-C6U9IWql.js → responsiveObserve-u2y1ryS1.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BMyTH3rN.js → slide-BBqj7svU.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-C7d6BG7Z.js → statusUtils-GN0mqu2d.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CR50QnQy.js → styleChecker-BvwPKoBT.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DBEeoMb8.js → useFlexGapSupport-CCt8tnfY.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-3r099cjv.js → useFs-DXAxl2SV.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-C5IYNdTK.js → usePersonalDataHub-DihlR2dj.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DmEOLRHf.js → vnode-D7BOX2gi.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DnpUiVCB.js → zoom-CVbO-nL7.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +4 -4
- package/src/commands/agent.js +3 -3
- package/src/commands/background-session.js +145 -0
- package/src/commands/mcp.js +244 -7
- package/src/commands/serve.js +1 -1
- package/src/commands/session-show.js +129 -0
- package/src/commands/session.js +97 -145
- package/src/commands/skill.js +87 -50
- package/src/data/changelog.json +40 -1
- package/src/gateways/ws/session-protocol.js +14 -4
- package/src/gateways/ws/ws-agent-handler.js +39 -1
- package/src/harness/jsonl-session-store.js +1547 -127
- package/src/harness/mcp-client.js +2690 -409
- package/src/harness/session-index.js +80 -80
- package/src/harness/session-list-index.js +210 -7
- package/src/lazy-dispatch.js +76 -8
- package/src/lib/abort-utils.js +68 -0
- package/src/lib/agent-core.js +1 -59
- package/src/lib/background-interaction-journal.js +2 -2
- package/src/lib/chat-core.js +24 -6
- package/src/lib/command-lifecycle-report.js +516 -0
- package/src/lib/cowork-mcp-tools.js +47 -2
- package/src/lib/cowork-task-runner.js +11 -3
- package/src/lib/doctor-checkup.js +9 -7
- package/src/lib/learning/skill-improver.js +21 -2
- package/src/lib/mcp-call-ledger-store.js +116 -3
- package/src/lib/mcp-call-ledger.js +59 -14
- package/src/lib/mcp-client.js +1 -0
- package/src/lib/mcp-stdio-environment.js +48 -0
- package/src/lib/mcp-stdio-executable-identity.js +1133 -0
- package/src/lib/mcp-stdio-execution-authority.js +363 -0
- package/src/lib/mcp-stdio-package-materialization.js +1424 -0
- package/src/lib/mcp-tool-metadata.js +436 -0
- package/src/lib/mcp-tool-result.js +367 -0
- package/src/lib/observability/index.js +71 -0
- package/src/lib/packer/native-update-state.js +979 -1
- package/src/lib/packer/pack-update-applier.js +1050 -125
- package/src/lib/packer/pkg-config-generator.js +1 -0
- package/src/lib/paths.js +53 -0
- package/src/lib/pr-link-ledger.js +8 -27
- package/src/lib/pr-link-store.js +26 -0
- package/src/lib/process-execution-broker/index.js +192 -35
- package/src/lib/process-execution-broker/platform-sandbox.js +291 -24
- package/src/lib/process-tree-termination.js +253 -0
- package/src/lib/recent-session.js +17 -17
- package/src/lib/secure-file-identity.js +47 -0
- package/src/lib/secure-fs.js +21 -2
- package/src/lib/session-anti-rollback-anchor.js +766 -0
- package/src/lib/session-host-lease.js +492 -0
- package/src/lib/session-host-snapshot.js +9 -5
- package/src/lib/session-persistence-failure.js +109 -0
- package/src/lib/session-picker.js +26 -3
- package/src/lib/session-projection.js +5 -1
- package/src/lib/session-search.js +25 -11
- package/src/lib/session-tail.js +31 -1
- package/src/lib/side-effect-ledger-store.js +2 -2
- package/src/lib/skill-budget.js +222 -0
- package/src/lib/skill-execution-authority.js +385 -0
- package/src/lib/skill-execution-identity.js +39 -2
- package/src/lib/skill-loader.js +322 -86
- package/src/lib/skill-mcp.js +43 -1
- package/src/lib/turn-binding-store.js +2 -2
- package/src/repl/agent-repl.js +483 -77
- package/src/repl/bg-dashboard.js +81 -28
- package/src/repl/chat-repl.js +77 -12
- package/src/runtime/agent-core.js +428 -113
- package/src/runtime/agent-runtime.js +26 -3
- package/src/runtime/cleanup-deadline.js +143 -0
- package/src/runtime/headless-runner.js +494 -149
- package/src/runtime/headless-stream.js +504 -75
- package/src/runtime/mcp-config.js +157 -10
- package/src/runtime/mcp-tool-search.js +0 -0
- package/src/runtime/output-backpressure.js +419 -0
- package/src/runtime/pipe-safety.js +56 -21
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BUUyJ5QO.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-1mNozZ8v.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-DqnoFPgR.js +0 -1
- package/src/assets/web-panel/assets/Providers-uO-10aP1.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DosMaL-k.js +0 -1
- package/src/assets/web-panel/assets/index-0O5ePnUq.js +0 -1
- package/src/assets/web-panel/assets/index-ChAzPigF.js +0 -1
- package/src/lib/skill-process-broker.js +0 -85
package/src/repl/agent-repl.js
CHANGED
|
@@ -25,6 +25,7 @@ import path from "path";
|
|
|
25
25
|
import { randomUUID } from "node:crypto";
|
|
26
26
|
import { isPromise, isProxy } from "node:util/types";
|
|
27
27
|
import { logger } from "../lib/logger.js";
|
|
28
|
+
import { issueMcpStdioExecutionAuthority } from "../lib/mcp-stdio-execution-authority.js";
|
|
28
29
|
import { getPlanModeManager, PlanState } from "../lib/plan-mode.js";
|
|
29
30
|
import { createVimState, feedNormalKey } from "../lib/repl-vim.js";
|
|
30
31
|
import {
|
|
@@ -68,6 +69,17 @@ import {
|
|
|
68
69
|
isVerifiedSessionHostSnapshot,
|
|
69
70
|
readSessionHostResumeState,
|
|
70
71
|
} from "../lib/session-host-snapshot.js";
|
|
72
|
+
import { acquireSessionHostLease } from "../lib/session-host-lease.js";
|
|
73
|
+
import {
|
|
74
|
+
SideEffectLedger,
|
|
75
|
+
classifyToolSideEffect,
|
|
76
|
+
reconcileSideEffects,
|
|
77
|
+
} from "../lib/side-effect-ledger.js";
|
|
78
|
+
import {
|
|
79
|
+
loadSideEffectLedger,
|
|
80
|
+
persistSideEffectLedger,
|
|
81
|
+
} from "../lib/side-effect-ledger-store.js";
|
|
82
|
+
import { operationIdempotencyKey } from "../lib/idempotency.js";
|
|
71
83
|
import {
|
|
72
84
|
preserveDurableSystemMessageProvenance,
|
|
73
85
|
projectCanonicalResumeMessages,
|
|
@@ -126,6 +138,7 @@ import { expandFileRefsAsync } from "../runtime/file-ref-expander.js";
|
|
|
126
138
|
import { prepareVisionTurn, resolveVisionLlm } from "../lib/image-input.js";
|
|
127
139
|
import { composeSystemPrompt } from "../runtime/system-prompt.js";
|
|
128
140
|
import { installPipeSafety } from "../runtime/pipe-safety.js";
|
|
141
|
+
import { installOutputBackpressure } from "../runtime/output-backpressure.js";
|
|
129
142
|
import {
|
|
130
143
|
makeFallbackChatFn,
|
|
131
144
|
normalizeFallbackModels,
|
|
@@ -323,6 +336,9 @@ async function executeTool(name, args) {
|
|
|
323
336
|
* unit-testable via the `options._coreLoop` injection seam.
|
|
324
337
|
*/
|
|
325
338
|
export async function agentLoop(messages, options) {
|
|
339
|
+
const writeOut =
|
|
340
|
+
options.writeOut || ((text) => process.stdout.write(String(text)));
|
|
341
|
+
const waitForOutput = options.waitForOutput;
|
|
326
342
|
// Resume-degenerate role merge (Claude Code 2.1.187 parity), gated by the
|
|
327
343
|
// one-shot `mergeRoles` flag so it fires only on the first model call after
|
|
328
344
|
// resuming a session whose prior run produced no assistant response. Collapse
|
|
@@ -343,7 +359,7 @@ export async function agentLoop(messages, options) {
|
|
|
343
359
|
const onProviderFallback =
|
|
344
360
|
options.onProviderFallback ||
|
|
345
361
|
((info) =>
|
|
346
|
-
|
|
362
|
+
writeOut(
|
|
347
363
|
chalk.yellow(
|
|
348
364
|
`\n ⚠️ ${info.message || `已从 "${info.from}" 切换到 "${info.to}"`}\n`,
|
|
349
365
|
),
|
|
@@ -354,6 +370,9 @@ export async function agentLoop(messages, options) {
|
|
|
354
370
|
// The tool-result event carries no args; remember the last tool-executing
|
|
355
371
|
// pair so a recorded denial can show what was attempted (/permissions denials).
|
|
356
372
|
let _lastExec = null;
|
|
373
|
+
// The core loop runs tools serially. A classified non-MCP side effect stays
|
|
374
|
+
// live from its yielded `tool-executing` boundary until the matching result.
|
|
375
|
+
let _currentSideEffectOpId = null;
|
|
357
376
|
for await (const event of runCoreLoop(messages, {
|
|
358
377
|
...options,
|
|
359
378
|
// FORCE in-loop compaction off — the REPL runs its OWN post-turn compaction
|
|
@@ -380,7 +399,7 @@ export async function agentLoop(messages, options) {
|
|
|
380
399
|
event.type === "managed-checkpoint-error" || event.coverage === "none"
|
|
381
400
|
? chalk.yellow
|
|
382
401
|
: chalk.gray;
|
|
383
|
-
|
|
402
|
+
writeOut(render(`${managedCheckpointLine}\n`));
|
|
384
403
|
} else if (event.type === "checkpoint") {
|
|
385
404
|
// Remember which file snapshot lines up with the live conversation so
|
|
386
405
|
// `/rewind <n>` can restore code + conversation together (Claude-Code
|
|
@@ -393,7 +412,7 @@ export async function agentLoop(messages, options) {
|
|
|
393
412
|
tool: event.tool,
|
|
394
413
|
});
|
|
395
414
|
}
|
|
396
|
-
|
|
415
|
+
writeOut(
|
|
397
416
|
chalk.gray(` ⎌ checkpoint ${event.id} (before ${event.tool})\n`),
|
|
398
417
|
);
|
|
399
418
|
} else if (event.type === "tool-executing") {
|
|
@@ -402,12 +421,55 @@ export async function agentLoop(messages, options) {
|
|
|
402
421
|
args: event.args,
|
|
403
422
|
startedAt: options.now ? options.now() : Date.now(),
|
|
404
423
|
};
|
|
405
|
-
|
|
424
|
+
_currentSideEffectOpId = null;
|
|
425
|
+
if (options.sideEffects) {
|
|
426
|
+
const sideEffect = classifyToolSideEffect(event.tool, event.args);
|
|
427
|
+
if (sideEffect) {
|
|
428
|
+
const opId = options.sideEffects.nextOpId();
|
|
429
|
+
_currentSideEffectOpId = opId;
|
|
430
|
+
options.sideEffects.ledger
|
|
431
|
+
.prepare(opId, {
|
|
432
|
+
kind: sideEffect.kind,
|
|
433
|
+
key: sideEffect.key,
|
|
434
|
+
meta: {
|
|
435
|
+
tool: event.tool,
|
|
436
|
+
idempotencyKey: operationIdempotencyKey({
|
|
437
|
+
tool: event.tool,
|
|
438
|
+
args: event.args,
|
|
439
|
+
}),
|
|
440
|
+
},
|
|
441
|
+
})
|
|
442
|
+
.start(opId);
|
|
443
|
+
// The generator has yielded before executing the tool. Persist the
|
|
444
|
+
// started marker and recheck the host lease before resuming it.
|
|
445
|
+
options.sideEffects.persist();
|
|
446
|
+
options.sideEffects.assert?.();
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
writeOut(
|
|
406
450
|
chalk.gray(
|
|
407
451
|
` [${event.tool}] ${formatToolArgs(event.tool, event.args)}\n`,
|
|
408
452
|
),
|
|
409
453
|
);
|
|
410
454
|
} else if (event.type === "tool-result") {
|
|
455
|
+
if (options.sideEffects && _currentSideEffectOpId) {
|
|
456
|
+
const sideEffectError = event.error || event.result?.error || null;
|
|
457
|
+
if (event.permission_decision) {
|
|
458
|
+
options.sideEffects.ledger.annotate(_currentSideEffectOpId, {
|
|
459
|
+
permissionDecision: event.permission_decision,
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
if (sideEffectError) {
|
|
463
|
+
options.sideEffects.ledger.fail(
|
|
464
|
+
_currentSideEffectOpId,
|
|
465
|
+
String(sideEffectError).slice(0, 200),
|
|
466
|
+
);
|
|
467
|
+
} else {
|
|
468
|
+
options.sideEffects.ledger.commit(_currentSideEffectOpId);
|
|
469
|
+
}
|
|
470
|
+
options.sideEffects.persist();
|
|
471
|
+
_currentSideEffectOpId = null;
|
|
472
|
+
}
|
|
411
473
|
const durationMs =
|
|
412
474
|
event.result?.toolTelemetryRecord?.durationMs ??
|
|
413
475
|
(_lastExec?.tool === event.tool
|
|
@@ -438,9 +500,7 @@ export async function agentLoop(messages, options) {
|
|
|
438
500
|
}
|
|
439
501
|
}
|
|
440
502
|
if (event.error || event.result?.error) {
|
|
441
|
-
|
|
442
|
-
chalk.red(` Error: ${event.error || event.result?.error}\n`),
|
|
443
|
-
);
|
|
503
|
+
writeOut(chalk.red(` Error: ${event.error || event.result?.error}\n`));
|
|
444
504
|
// Record policy denials (not plain tool failures) into the caller's
|
|
445
505
|
// denial log for review via `/permissions denials` (Claude-Code 2.1.193
|
|
446
506
|
// recent denials). Caller passes the session log (mirrors checkpointMarks)
|
|
@@ -477,13 +537,13 @@ export async function agentLoop(messages, options) {
|
|
|
477
537
|
const sid = options?.sessionId;
|
|
478
538
|
const policy = approval.policy || "strict";
|
|
479
539
|
if (sid && policy === "strict") {
|
|
480
|
-
|
|
540
|
+
writeOut(
|
|
481
541
|
chalk.yellow(
|
|
482
542
|
` Hint: relax policy with cc session policy ${sid} --set trusted\n`,
|
|
483
543
|
),
|
|
484
544
|
);
|
|
485
545
|
} else if (sid) {
|
|
486
|
-
|
|
546
|
+
writeOut(
|
|
487
547
|
chalk.yellow(
|
|
488
548
|
` Hint: per-session policy is "${policy}" — see cc session policy ${sid}\n`,
|
|
489
549
|
),
|
|
@@ -491,26 +551,26 @@ export async function agentLoop(messages, options) {
|
|
|
491
551
|
}
|
|
492
552
|
}
|
|
493
553
|
} else if (event.result?.success) {
|
|
494
|
-
|
|
554
|
+
writeOut(chalk.green(` Done\n`));
|
|
495
555
|
}
|
|
496
556
|
} else if (event.type === "thinking") {
|
|
497
557
|
// Intermediate-step reasoning (before a tool call) — dimmed, inline.
|
|
498
558
|
if (process.env.CC_REPL_THINKING !== "0" && event.text) {
|
|
499
|
-
|
|
559
|
+
writeOut(
|
|
500
560
|
"\n" + chalk.dim("💭 " + event.text.replace(/\n/g, "\n ")) + "\n",
|
|
501
561
|
);
|
|
502
562
|
}
|
|
503
563
|
} else if (event.type === "token-usage") {
|
|
504
564
|
usageEvents.push(event);
|
|
505
565
|
} else if (event.type === "iteration-warning") {
|
|
506
|
-
|
|
566
|
+
writeOut(chalk.yellow(`\n ${event.message}\n`));
|
|
507
567
|
} else if (event.type === "iteration-budget-exhausted") {
|
|
508
|
-
|
|
509
|
-
chalk.red(`\n [Budget Exhausted] ${event.budget}\n`),
|
|
510
|
-
);
|
|
568
|
+
writeOut(chalk.red(`\n [Budget Exhausted] ${event.budget}\n`));
|
|
511
569
|
} else if (event.type === "response-complete") {
|
|
570
|
+
await waitForOutput?.();
|
|
512
571
|
return { content: event.content, usageEvents, thinking: event.thinking };
|
|
513
572
|
}
|
|
573
|
+
await waitForOutput?.();
|
|
514
574
|
}
|
|
515
575
|
return { content: "", usageEvents };
|
|
516
576
|
}
|
|
@@ -1934,7 +1994,12 @@ export function createReplMcpHostRuntimeManager(dependencies = {}) {
|
|
|
1934
1994
|
}
|
|
1935
1995
|
|
|
1936
1996
|
const sink = persistLedger
|
|
1937
|
-
? createLedgerSink(
|
|
1997
|
+
? createLedgerSink(
|
|
1998
|
+
sessionId,
|
|
1999
|
+
appendLedgerEvent === appendAuthorityEvent
|
|
2000
|
+
? { recovery }
|
|
2001
|
+
: { appendEvent: appendLedgerEvent },
|
|
2002
|
+
)
|
|
1938
2003
|
: null;
|
|
1939
2004
|
const sharedController =
|
|
1940
2005
|
!verifiedRecovery && current?.sessionId === sessionId
|
|
@@ -2050,6 +2115,21 @@ export async function runReplStartupBoundary(options, startupDependencies) {
|
|
|
2050
2115
|
"CC_REPL_STARTUP_DEPENDENCY_INVALID",
|
|
2051
2116
|
);
|
|
2052
2117
|
}
|
|
2118
|
+
const acquireHostLease = dependencyDataFunction(
|
|
2119
|
+
startupDependencies,
|
|
2120
|
+
"acquireSessionHostLease",
|
|
2121
|
+
null,
|
|
2122
|
+
);
|
|
2123
|
+
const leaseScope = options._sessionHostLeaseScope || null;
|
|
2124
|
+
const leaseSessionId = startupCandidate?.sessionId || options.sessionId;
|
|
2125
|
+
if (
|
|
2126
|
+
leaseScope &&
|
|
2127
|
+
!leaseScope.lease &&
|
|
2128
|
+
leaseSessionId &&
|
|
2129
|
+
typeof acquireHostLease === "function"
|
|
2130
|
+
) {
|
|
2131
|
+
leaseScope.lease = acquireHostLease(leaseSessionId, { hostKind: "repl" });
|
|
2132
|
+
}
|
|
2053
2133
|
const trustedWorkspaceRoot = readCwd();
|
|
2054
2134
|
return enterWorkspace(trustedWorkspaceRoot, () =>
|
|
2055
2135
|
startWorkspace(options, startupAdmission),
|
|
@@ -2058,37 +2138,155 @@ export async function runReplStartupBoundary(options, startupDependencies) {
|
|
|
2058
2138
|
|
|
2059
2139
|
/** Start the agentic REPL with non-overridable production bindings. */
|
|
2060
2140
|
export async function startAgentRepl(options = {}) {
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2141
|
+
const sessionHostLeaseScope = { lease: null };
|
|
2142
|
+
const runtimeOptions = {
|
|
2143
|
+
...options,
|
|
2144
|
+
_sessionHostLeaseScope: sessionHostLeaseScope,
|
|
2145
|
+
};
|
|
2146
|
+
try {
|
|
2147
|
+
const result = await runReplStartupBoundary(runtimeOptions, {
|
|
2148
|
+
prepareReplStartupResume,
|
|
2149
|
+
refuseReplStartupResume,
|
|
2150
|
+
acquireSessionHostLease,
|
|
2151
|
+
cwd: () => process.cwd(),
|
|
2152
|
+
runWithHostHooksV2Workspace,
|
|
2153
|
+
startAgentReplInWorkspace,
|
|
2154
|
+
});
|
|
2155
|
+
if (result?.started === false) sessionHostLeaseScope.lease?.release?.();
|
|
2156
|
+
return result;
|
|
2157
|
+
} catch (error) {
|
|
2158
|
+
sessionHostLeaseScope.lease?.release?.();
|
|
2159
|
+
throw error;
|
|
2160
|
+
}
|
|
2068
2161
|
}
|
|
2069
2162
|
|
|
2070
2163
|
async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
2164
|
+
let failureHandler = null;
|
|
2165
|
+
let disposePipeSafety = null;
|
|
2166
|
+
const flow = installOutputBackpressure({
|
|
2167
|
+
stdout: process.stdout,
|
|
2168
|
+
stderr: process.stderr,
|
|
2169
|
+
maxQueuedBytes: options.outputBackpressureMaxBytes,
|
|
2170
|
+
onFailure: (error) => failureHandler?.(error),
|
|
2171
|
+
});
|
|
2172
|
+
let restored = false;
|
|
2173
|
+
const outputScope = {
|
|
2174
|
+
flow,
|
|
2175
|
+
setFailureHandler(handler) {
|
|
2176
|
+
failureHandler = handler;
|
|
2177
|
+
},
|
|
2178
|
+
setPipeDisposer(disposer) {
|
|
2179
|
+
disposePipeSafety = disposer;
|
|
2180
|
+
},
|
|
2181
|
+
restore() {
|
|
2182
|
+
if (restored) return;
|
|
2183
|
+
restored = true;
|
|
2184
|
+
disposePipeSafety?.();
|
|
2185
|
+
flow.restore();
|
|
2186
|
+
},
|
|
2187
|
+
};
|
|
2188
|
+
try {
|
|
2189
|
+
return await startAgentReplInWorkspaceOwned(
|
|
2190
|
+
options,
|
|
2191
|
+
startupAdmission,
|
|
2192
|
+
outputScope,
|
|
2193
|
+
);
|
|
2194
|
+
} catch (error) {
|
|
2195
|
+
outputScope.restore();
|
|
2196
|
+
throw error;
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
async function startAgentReplInWorkspaceOwned(
|
|
2201
|
+
options = {},
|
|
2202
|
+
startupAdmission,
|
|
2203
|
+
outputScope,
|
|
2204
|
+
) {
|
|
2071
2205
|
// EPIPE guard: if the REPL's stdout is piped and the consumer closes (e.g.
|
|
2072
2206
|
// `cc agent | head`), the async stream `error` would otherwise crash the
|
|
2073
2207
|
// process. Route a broken pipe into the REPL's own graceful shutdown (the
|
|
2074
2208
|
// rl "close" handler — MCP disconnect, kill background tasks) when the
|
|
2075
|
-
// interface
|
|
2076
|
-
// cleanup write that also EPIPEs can't loop.
|
|
2209
|
+
// interface and its close handler exist. `_replClosing` makes it fire once so
|
|
2210
|
+
// a cleanup write that also EPIPEs can't loop. An early EPIPE remains pending
|
|
2211
|
+
// until the close handler is attached; it never skips directly to exit.
|
|
2077
2212
|
let _replRl = null;
|
|
2078
2213
|
let _replClosing = false;
|
|
2079
|
-
|
|
2214
|
+
let _replCloseReady = false;
|
|
2215
|
+
let _replCleanupStarted = false;
|
|
2216
|
+
let _turnAbort = null;
|
|
2217
|
+
let _replOutputFailure = null;
|
|
2218
|
+
const _requestReplOutputClose = (error) => {
|
|
2219
|
+
if (error && !_replOutputFailure) _replOutputFailure = error;
|
|
2220
|
+
if (error) {
|
|
2221
|
+
process.exitCode = error.code === "EPIPE" ? 0 : 1;
|
|
2222
|
+
_turnAbort?.abort(error);
|
|
2223
|
+
}
|
|
2080
2224
|
if (_replClosing) return;
|
|
2081
2225
|
_replClosing = true;
|
|
2082
|
-
if (_replRl) {
|
|
2226
|
+
if (_replRl && _replCloseReady) {
|
|
2083
2227
|
try {
|
|
2084
|
-
_replRl.close(); // triggers the graceful "close" cleanup
|
|
2085
|
-
return;
|
|
2228
|
+
_replRl.close(); // triggers the graceful "close" cleanup
|
|
2086
2229
|
} catch {
|
|
2087
|
-
|
|
2230
|
+
// The close handler owns shutdown. Leaving exitCode set allows the
|
|
2231
|
+
// event loop to drain without bypassing the teardown lifecycle.
|
|
2088
2232
|
}
|
|
2089
2233
|
}
|
|
2090
|
-
|
|
2091
|
-
|
|
2234
|
+
};
|
|
2235
|
+
const _sessionHostLeaseScope = options._sessionHostLeaseScope || null;
|
|
2236
|
+
let _sessionHostLeaseAbortListener = null;
|
|
2237
|
+
let _sessionHostLeaseAbortSignal = null;
|
|
2238
|
+
const _detachSessionHostLease = () => {
|
|
2239
|
+
if (_sessionHostLeaseAbortListener && _sessionHostLeaseAbortSignal) {
|
|
2240
|
+
_sessionHostLeaseAbortSignal.removeEventListener(
|
|
2241
|
+
"abort",
|
|
2242
|
+
_sessionHostLeaseAbortListener,
|
|
2243
|
+
);
|
|
2244
|
+
}
|
|
2245
|
+
_sessionHostLeaseAbortListener = null;
|
|
2246
|
+
_sessionHostLeaseAbortSignal = null;
|
|
2247
|
+
};
|
|
2248
|
+
const _attachSessionHostLease = () => {
|
|
2249
|
+
const signal = _sessionHostLeaseScope?.lease?.signal;
|
|
2250
|
+
if (!signal || _sessionHostLeaseAbortListener) return;
|
|
2251
|
+
_sessionHostLeaseAbortListener = () =>
|
|
2252
|
+
_requestReplOutputClose(
|
|
2253
|
+
signal.reason ||
|
|
2254
|
+
Object.assign(new Error("Session host lease was lost"), {
|
|
2255
|
+
code: "CC_SESSION_HOST_LEASE_FENCED",
|
|
2256
|
+
}),
|
|
2257
|
+
);
|
|
2258
|
+
_sessionHostLeaseAbortSignal = signal;
|
|
2259
|
+
signal.addEventListener("abort", _sessionHostLeaseAbortListener, {
|
|
2260
|
+
once: true,
|
|
2261
|
+
});
|
|
2262
|
+
if (signal.aborted) _sessionHostLeaseAbortListener();
|
|
2263
|
+
};
|
|
2264
|
+
const _replaceSessionHostLease = (lease) => {
|
|
2265
|
+
if (!_sessionHostLeaseScope) return null;
|
|
2266
|
+
const previous = _sessionHostLeaseScope.lease;
|
|
2267
|
+
if (previous === lease) return previous;
|
|
2268
|
+
_detachSessionHostLease();
|
|
2269
|
+
_sessionHostLeaseScope.lease = lease;
|
|
2270
|
+
_attachSessionHostLease();
|
|
2271
|
+
return previous;
|
|
2272
|
+
};
|
|
2273
|
+
_attachSessionHostLease();
|
|
2274
|
+
const _replOutputFlow = outputScope.flow;
|
|
2275
|
+
outputScope.setFailureHandler(_requestReplOutputClose);
|
|
2276
|
+
const _disposeReplPipeSafety = installPipeSafety(undefined, () =>
|
|
2277
|
+
_requestReplOutputClose(
|
|
2278
|
+
Object.assign(new Error("REPL output pipe closed"), { code: "EPIPE" }),
|
|
2279
|
+
),
|
|
2280
|
+
);
|
|
2281
|
+
outputScope.setPipeDisposer(_disposeReplPipeSafety);
|
|
2282
|
+
const _waitForReplOutput = async () => {
|
|
2283
|
+
try {
|
|
2284
|
+
await _replOutputFlow.wait();
|
|
2285
|
+
return true;
|
|
2286
|
+
} catch {
|
|
2287
|
+
return false;
|
|
2288
|
+
}
|
|
2289
|
+
};
|
|
2092
2290
|
const { useJsonl, candidate: _startupJsonlResume } = startupAdmission;
|
|
2093
2291
|
let model = options.model || "qwen2.5:7b";
|
|
2094
2292
|
let provider = options.provider || "ollama";
|
|
@@ -2630,10 +2828,20 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
2630
2828
|
};
|
|
2631
2829
|
if (useJsonl) {
|
|
2632
2830
|
try {
|
|
2633
|
-
sessionId = jsonlStartSession(null, meta);
|
|
2831
|
+
sessionId = jsonlStartSession(options.sessionId || null, meta);
|
|
2634
2832
|
} catch (_err) {
|
|
2635
2833
|
// Non-critical
|
|
2636
2834
|
}
|
|
2835
|
+
if (
|
|
2836
|
+
sessionId &&
|
|
2837
|
+
_sessionHostLeaseScope &&
|
|
2838
|
+
!_sessionHostLeaseScope.lease
|
|
2839
|
+
) {
|
|
2840
|
+
_sessionHostLeaseScope.lease = acquireSessionHostLease(sessionId, {
|
|
2841
|
+
hostKind: "repl",
|
|
2842
|
+
});
|
|
2843
|
+
_attachSessionHostLease();
|
|
2844
|
+
}
|
|
2637
2845
|
} else if (db) {
|
|
2638
2846
|
try {
|
|
2639
2847
|
const session = createSession(db, meta);
|
|
@@ -2771,6 +2979,79 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
2771
2979
|
let _replBaseSystem = _buildReplBaseSystem();
|
|
2772
2980
|
let _activeOutputStyle = null; // { name, body }
|
|
2773
2981
|
const messages = [{ role: "system", content: _replBaseSystem }];
|
|
2982
|
+
let _replSideEffects = null;
|
|
2983
|
+
const _prepareReplSideEffects = (
|
|
2984
|
+
targetSessionId,
|
|
2985
|
+
{ recover = false } = {},
|
|
2986
|
+
) => {
|
|
2987
|
+
if (!useJsonl || !targetSessionId) {
|
|
2988
|
+
return Object.freeze({
|
|
2989
|
+
sideEffects: null,
|
|
2990
|
+
noticeMessage: null,
|
|
2991
|
+
warning: null,
|
|
2992
|
+
});
|
|
2993
|
+
}
|
|
2994
|
+
let ledger;
|
|
2995
|
+
let loadError = null;
|
|
2996
|
+
try {
|
|
2997
|
+
ledger = loadSideEffectLedger(targetSessionId);
|
|
2998
|
+
} catch (error) {
|
|
2999
|
+
ledger = new SideEffectLedger();
|
|
3000
|
+
loadError = error;
|
|
3001
|
+
}
|
|
3002
|
+
const runNonce = `${Date.now()}:${randomUUID()}`;
|
|
3003
|
+
let sequence = 0;
|
|
3004
|
+
let noticeMessage = null;
|
|
3005
|
+
let warning = null;
|
|
3006
|
+
if (recover && !loadError) {
|
|
3007
|
+
const plan = reconcileSideEffects(ledger);
|
|
3008
|
+
if (plan.inspect.length > 0) {
|
|
3009
|
+
const lines = plan.plans
|
|
3010
|
+
.filter((entry) => entry.action === "inspect")
|
|
3011
|
+
.map((entry) => {
|
|
3012
|
+
const operation = ledger.get(entry.opId);
|
|
3013
|
+
const key = operation?.key ? ` (${operation.key})` : "";
|
|
3014
|
+
return ` - [${operation?.kind || "unknown"}]${key} - ${entry.reason}`;
|
|
3015
|
+
});
|
|
3016
|
+
noticeMessage = Object.freeze({
|
|
3017
|
+
role: "system",
|
|
3018
|
+
content:
|
|
3019
|
+
"Recovery notice: the previous REPL host stopped while irreversible operations were in flight. Their outcome is UNKNOWN. Do not blindly repeat them; verify whether each operation already took effect and ask the user when uncertain:\n" +
|
|
3020
|
+
lines.join("\n"),
|
|
3021
|
+
});
|
|
3022
|
+
warning = `Recovery: ${plan.inspect.length} interrupted non-MCP side effect(s) require verification before replay.`;
|
|
3023
|
+
}
|
|
3024
|
+
} else if (recover && loadError) {
|
|
3025
|
+
noticeMessage = Object.freeze({
|
|
3026
|
+
role: "system",
|
|
3027
|
+
content:
|
|
3028
|
+
"Recovery notice: the durable non-MCP side-effect ledger is unavailable. Read-only work may continue, but irreversible tools are blocked until recovery authority is restored.",
|
|
3029
|
+
});
|
|
3030
|
+
warning = `Recovery: non-MCP side-effect ledger is unavailable for ${targetSessionId}; irreversible tools are fail-closed.`;
|
|
3031
|
+
}
|
|
3032
|
+
const sideEffects = Object.freeze({
|
|
3033
|
+
ledger,
|
|
3034
|
+
nextOpId: () => `${runNonce}:${sequence++}`,
|
|
3035
|
+
persist: () => {
|
|
3036
|
+
if (loadError) throw loadError;
|
|
3037
|
+
const persisted = persistSideEffectLedger(targetSessionId, ledger);
|
|
3038
|
+
if (persisted === false) {
|
|
3039
|
+
const error = new Error(
|
|
3040
|
+
`Side-effect ledger persistence was rejected for ${targetSessionId}`,
|
|
3041
|
+
);
|
|
3042
|
+
error.code = "SIDE_EFFECT_LEDGER_PERSIST_FAILED";
|
|
3043
|
+
throw error;
|
|
3044
|
+
}
|
|
3045
|
+
return persisted;
|
|
3046
|
+
},
|
|
3047
|
+
assert: () => _sessionHostLeaseScope?.lease?.assert?.(),
|
|
3048
|
+
});
|
|
3049
|
+
return Object.freeze({ sideEffects, noticeMessage, warning });
|
|
3050
|
+
};
|
|
3051
|
+
const _startupReplSideEffects = _prepareReplSideEffects(sessionId, {
|
|
3052
|
+
recover: Boolean(options.sessionId && _startupJsonlResume?.ok),
|
|
3053
|
+
});
|
|
3054
|
+
_replSideEffects = _startupReplSideEffects.sideEffects;
|
|
2774
3055
|
let _mcpLedgerRecovery = null;
|
|
2775
3056
|
let _mcpLedgerRecoveryError = null;
|
|
2776
3057
|
const _prepareJsonlResumeCandidate = (targetSessionId) =>
|
|
@@ -2988,7 +3269,15 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
2988
3269
|
let connected = 0;
|
|
2989
3270
|
for (const [name, cfg] of serverEntries) {
|
|
2990
3271
|
try {
|
|
2991
|
-
|
|
3272
|
+
const authorizedConfig = { ...cfg };
|
|
3273
|
+
authorizedConfig.mcpStdioExecutionAuthority =
|
|
3274
|
+
issueMcpStdioExecutionAuthority({
|
|
3275
|
+
serverName: name,
|
|
3276
|
+
config: authorizedConfig,
|
|
3277
|
+
approvalKind: "explicit-config",
|
|
3278
|
+
approvalSource: `agent-bundle:${path.resolve(options.bundlePath)}`,
|
|
3279
|
+
});
|
|
3280
|
+
await _bundleMcpClient.connect(name, authorizedConfig);
|
|
2992
3281
|
connected += 1;
|
|
2993
3282
|
} catch (mcpErr) {
|
|
2994
3283
|
logger.log(
|
|
@@ -3280,6 +3569,12 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
3280
3569
|
throw error;
|
|
3281
3570
|
}
|
|
3282
3571
|
messages.push(...prepared.canonicalSystemMessages);
|
|
3572
|
+
if (_startupReplSideEffects.noticeMessage) {
|
|
3573
|
+
messages.push(_startupReplSideEffects.noticeMessage);
|
|
3574
|
+
}
|
|
3575
|
+
if (_startupReplSideEffects.warning) {
|
|
3576
|
+
logger.warn(_startupReplSideEffects.warning);
|
|
3577
|
+
}
|
|
3283
3578
|
_commitMcpRecoveryCandidate(messages, prepared.mcp);
|
|
3284
3579
|
if (prepared.replayMessages.length > 0) {
|
|
3285
3580
|
messages.push(...prepared.conversationMessages);
|
|
@@ -3868,7 +4163,7 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
3868
4163
|
// seam (throwIfAborted at each iteration); partial conversation is kept.
|
|
3869
4164
|
// Idle Esc presses (no active turn) are ignored, and escape-prefixed key
|
|
3870
4165
|
// sequences (arrows etc.) never reach here as bare "escape".
|
|
3871
|
-
|
|
4166
|
+
_turnAbort = null;
|
|
3872
4167
|
let _lastIdleEscAt = 0;
|
|
3873
4168
|
let _replKeypressHandler = null;
|
|
3874
4169
|
if (process.stdin.isTTY) {
|
|
@@ -4089,7 +4384,9 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
4089
4384
|
});
|
|
4090
4385
|
// Custom command wins; otherwise the built-in context-usage render.
|
|
4091
4386
|
if (_slCfg) {
|
|
4092
|
-
return _sl.renderStatusLine(_slCfg, context, {
|
|
4387
|
+
return _sl.renderStatusLine(_slCfg, context, {
|
|
4388
|
+
cwd: process.cwd(),
|
|
4389
|
+
});
|
|
4093
4390
|
}
|
|
4094
4391
|
const line = _sl.renderDefaultStatusLine(context);
|
|
4095
4392
|
return line && line.trim() ? line : null;
|
|
@@ -4423,7 +4720,7 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
4423
4720
|
` ${chalk.cyan("/add-dir")} Add an extra working root (/add-dir <dir>; no arg lists roots)`,
|
|
4424
4721
|
);
|
|
4425
4722
|
logger.log(
|
|
4426
|
-
` ${chalk.cyan("/reload-skills")}
|
|
4723
|
+
` ${chalk.cyan("/reload-skills")} Revoke process Skill grants and re-scan layers`,
|
|
4427
4724
|
);
|
|
4428
4725
|
logger.log(
|
|
4429
4726
|
` ${chalk.cyan("/reload-plugins")} Re-scan installed plugins after add/trust/upgrade`,
|
|
@@ -5283,7 +5580,11 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
5283
5580
|
dispatchAsyncHooks(
|
|
5284
5581
|
_settingsHooks,
|
|
5285
5582
|
"CwdChanged",
|
|
5286
|
-
{
|
|
5583
|
+
{
|
|
5584
|
+
old_cwd: oldCwd,
|
|
5585
|
+
cwd: newCwd,
|
|
5586
|
+
session_id: sessionId || null,
|
|
5587
|
+
},
|
|
5287
5588
|
{ cwd: newCwd, supervisor: _asyncHookSupervisor },
|
|
5288
5589
|
);
|
|
5289
5590
|
} catch {
|
|
@@ -5747,39 +6048,87 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
5747
6048
|
const resumeId = sessionArg.slice(7).trim();
|
|
5748
6049
|
try {
|
|
5749
6050
|
if (useJsonl) {
|
|
5750
|
-
const
|
|
5751
|
-
if (!
|
|
5752
|
-
const
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
);
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
()
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
const error = new Error(
|
|
5777
|
-
"Prepared JSONL session resume was not committed",
|
|
6051
|
+
const initialCandidate = _prepareJsonlResumeCandidate(resumeId);
|
|
6052
|
+
if (!initialCandidate.ok) throw initialCandidate.error;
|
|
6053
|
+
const currentLease = _sessionHostLeaseScope?.lease || null;
|
|
6054
|
+
const reuseCurrentLease = initialCandidate.sessionId === sessionId;
|
|
6055
|
+
let targetLease = reuseCurrentLease ? currentLease : null;
|
|
6056
|
+
let adoptedTargetLease = reuseCurrentLease && Boolean(currentLease);
|
|
6057
|
+
if (!targetLease) {
|
|
6058
|
+
targetLease = acquireSessionHostLease(
|
|
6059
|
+
initialCandidate.sessionId,
|
|
6060
|
+
{
|
|
6061
|
+
hostKind: "repl",
|
|
6062
|
+
},
|
|
6063
|
+
);
|
|
6064
|
+
}
|
|
6065
|
+
let prepared;
|
|
6066
|
+
try {
|
|
6067
|
+
// Re-sample after acquiring the target's write authority. The
|
|
6068
|
+
// first sample resolves/refuses the request; this one is the
|
|
6069
|
+
// exact snapshot committed into the live REPL.
|
|
6070
|
+
prepared = _prepareJsonlResumeCandidate(
|
|
6071
|
+
initialCandidate.sessionId,
|
|
6072
|
+
);
|
|
6073
|
+
if (!prepared.ok) throw prepared.error;
|
|
6074
|
+
const preparedSideEffects = _prepareReplSideEffects(
|
|
6075
|
+
prepared.sessionId,
|
|
6076
|
+
{ recover: true },
|
|
5778
6077
|
);
|
|
5779
|
-
|
|
5780
|
-
|
|
6078
|
+
const preparedMcpRuntime = _prepareMcpHostRuntime(
|
|
6079
|
+
prepared.sessionId,
|
|
6080
|
+
prepared.mcp,
|
|
6081
|
+
);
|
|
6082
|
+
const preparedMcpCommit = _prepareMcpRecoveryCommit(prepared.mcp);
|
|
6083
|
+
const hostSystemMessages = _refreshHostSystemMessages();
|
|
6084
|
+
const previousState = _captureResumeState();
|
|
6085
|
+
const preparedState = Object.freeze({
|
|
6086
|
+
sessionId: prepared.sessionId,
|
|
6087
|
+
hostSystemMessages,
|
|
6088
|
+
canonicalSystemMessages: Object.freeze([
|
|
6089
|
+
...prepared.canonicalSystemMessages,
|
|
6090
|
+
...(preparedSideEffects.noticeMessage
|
|
6091
|
+
? [preparedSideEffects.noticeMessage]
|
|
6092
|
+
: []),
|
|
6093
|
+
]),
|
|
6094
|
+
conversationMessages: prepared.conversationMessages,
|
|
6095
|
+
mcpCommit: preparedMcpCommit,
|
|
6096
|
+
mcpRuntime: preparedMcpRuntime,
|
|
6097
|
+
sanitizeRolesNextTurn:
|
|
6098
|
+
prepared.conversationMessages.at(-1)?.role === "user",
|
|
6099
|
+
logMessage: `Resumed JSONL session ${prepared.sessionId} (${prepared.rebuiltMessages.length} messages)`,
|
|
6100
|
+
});
|
|
6101
|
+
const committed = commitPreparedReplJsonlResume(
|
|
6102
|
+
prepared,
|
|
6103
|
+
() => _applyPreparedResumeState(preparedState),
|
|
6104
|
+
() => _restoreResumeState(previousState),
|
|
6105
|
+
);
|
|
6106
|
+
if (!committed) {
|
|
6107
|
+
const error = new Error(
|
|
6108
|
+
"Prepared JSONL session resume was not committed",
|
|
6109
|
+
);
|
|
6110
|
+
error.code = "CC_REPL_SESSION_RESUME_NOT_COMMITTED";
|
|
6111
|
+
throw error;
|
|
6112
|
+
}
|
|
6113
|
+
const previousLease = _replaceSessionHostLease(targetLease);
|
|
6114
|
+
adoptedTargetLease = true;
|
|
6115
|
+
_replSideEffects = preparedSideEffects.sideEffects;
|
|
6116
|
+
if (preparedSideEffects.warning) {
|
|
6117
|
+
logger.warn(preparedSideEffects.warning);
|
|
6118
|
+
}
|
|
6119
|
+
if (previousLease && previousLease !== targetLease) {
|
|
6120
|
+
try {
|
|
6121
|
+
previousLease.release?.();
|
|
6122
|
+
} catch (releaseError) {
|
|
6123
|
+
logger.warn(
|
|
6124
|
+
`Session switch committed, but the prior host lease could not be released: ${releaseError.message}`,
|
|
6125
|
+
);
|
|
6126
|
+
}
|
|
6127
|
+
}
|
|
6128
|
+
_replCompactPersistence.replace(prepared.rebuiltMessages);
|
|
6129
|
+
} finally {
|
|
6130
|
+
if (!adoptedTargetLease) targetLease?.release?.();
|
|
5781
6131
|
}
|
|
5782
|
-
_replCompactPersistence.replace(prepared.rebuiltMessages);
|
|
5783
6132
|
} else if (db) {
|
|
5784
6133
|
const existing = getSession(db, resumeId);
|
|
5785
6134
|
if (existing && existing.messages) {
|
|
@@ -5847,6 +6196,11 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
5847
6196
|
// layers (incl. .claude/skills) without restarting the session.
|
|
5848
6197
|
if (trimmed === "/reload-skills") {
|
|
5849
6198
|
try {
|
|
6199
|
+
_replSkillLoader.revokeExecutionAuthorizations?.({
|
|
6200
|
+
message:
|
|
6201
|
+
"Skill execution authorization was revoked by /reload-skills",
|
|
6202
|
+
reasonCode: "reload-skills",
|
|
6203
|
+
});
|
|
5850
6204
|
_replSkillLoader.clearCache();
|
|
5851
6205
|
const n = _replSkillLoader.loadAll().length;
|
|
5852
6206
|
_replBaseSystem = _buildReplBaseSystem();
|
|
@@ -5856,7 +6210,7 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
5856
6210
|
_persistReplContextSources();
|
|
5857
6211
|
logger.log(
|
|
5858
6212
|
chalk.green(
|
|
5859
|
-
`✔ skills reloaded — ${n} available (${_replSkillLoader.getLayerPaths().length} layers re-scanned)`,
|
|
6213
|
+
`✔ Skill grants revoked and skills reloaded — ${n} available (${_replSkillLoader.getLayerPaths().length} layers re-scanned)`,
|
|
5860
6214
|
),
|
|
5861
6215
|
);
|
|
5862
6216
|
} catch (err) {
|
|
@@ -6069,7 +6423,9 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
6069
6423
|
logger.log(chalk.gray(l));
|
|
6070
6424
|
} else {
|
|
6071
6425
|
// set — createReplGoal throws on a malformed spec (caught below).
|
|
6072
|
-
_sessionGoal = rg.createReplGoal(cmd.spec, {
|
|
6426
|
+
_sessionGoal = rg.createReplGoal(cmd.spec, {
|
|
6427
|
+
now: () => Date.now(),
|
|
6428
|
+
});
|
|
6073
6429
|
for (const l of rg.renderGoalStart(_sessionGoal))
|
|
6074
6430
|
logger.log(chalk.cyan(l));
|
|
6075
6431
|
}
|
|
@@ -7679,22 +8035,29 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
7679
8035
|
// reasoning dimmed before it. Skipped (left undefined) in replay mode.
|
|
7680
8036
|
let _liveStreamed = false;
|
|
7681
8037
|
let _liveThinkStarted = false;
|
|
8038
|
+
const _settleLiveWrite = (blocked) =>
|
|
8039
|
+
blocked ? _replOutputFlow.wait() : undefined;
|
|
7682
8040
|
const liveOpts = _streamLive
|
|
7683
8041
|
? {
|
|
7684
8042
|
onToken: (t) => {
|
|
7685
8043
|
// Separate the answer from the dimmed reasoning above it (once).
|
|
7686
|
-
|
|
7687
|
-
|
|
8044
|
+
let blocked = false;
|
|
8045
|
+
if (!_liveStreamed && _liveThinkStarted) {
|
|
8046
|
+
blocked = process.stdout.write("\n") === false;
|
|
8047
|
+
}
|
|
7688
8048
|
_liveStreamed = true;
|
|
7689
|
-
process.stdout.write(t);
|
|
8049
|
+
blocked = process.stdout.write(t) === false || blocked;
|
|
8050
|
+
return _settleLiveWrite(blocked);
|
|
7690
8051
|
},
|
|
7691
8052
|
onThinking: (t) => {
|
|
7692
8053
|
if (process.env.CC_REPL_THINKING === "0") return;
|
|
8054
|
+
let blocked = false;
|
|
7693
8055
|
if (!_liveThinkStarted) {
|
|
7694
8056
|
process.stdout.write(chalk.dim("💭 "));
|
|
7695
8057
|
_liveThinkStarted = true;
|
|
7696
8058
|
}
|
|
7697
|
-
process.stdout.write(chalk.dim(t));
|
|
8059
|
+
blocked = process.stdout.write(chalk.dim(t)) === false || blocked;
|
|
8060
|
+
return _settleLiveWrite(blocked);
|
|
7698
8061
|
},
|
|
7699
8062
|
}
|
|
7700
8063
|
: {};
|
|
@@ -7726,7 +8089,9 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
7726
8089
|
if (_settingsHooks && !_asyncHookSupervisor) {
|
|
7727
8090
|
const { AsyncHookSupervisor } =
|
|
7728
8091
|
await import("../lib/async-hook-supervisor.js");
|
|
7729
|
-
_asyncHookSupervisor = new AsyncHookSupervisor({
|
|
8092
|
+
_asyncHookSupervisor = new AsyncHookSupervisor({
|
|
8093
|
+
persistStats: true,
|
|
8094
|
+
});
|
|
7730
8095
|
}
|
|
7731
8096
|
const activeMcpRuntime = _activateMcpHostRuntime();
|
|
7732
8097
|
const activeRawMcpClient = activeMcpRuntime.rawClient || undefined;
|
|
@@ -7736,6 +8101,7 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
7736
8101
|
thinking: reasoning,
|
|
7737
8102
|
} = await agentLoop(messages, {
|
|
7738
8103
|
...liveOpts,
|
|
8104
|
+
waitForOutput: _replOutputFlow.wait,
|
|
7739
8105
|
mergeRoles: _mergeRolesThisTurn,
|
|
7740
8106
|
// Visible auto-retry feedback (Claude-Code 2.1.181): when the model's
|
|
7741
8107
|
// streaming call hits a transient connection drop and retries, tell the
|
|
@@ -7808,6 +8174,9 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
7808
8174
|
// Explicit turn-binding producer (null unless a JSONL session): the
|
|
7809
8175
|
// wrapper folds every loop event into the live table.
|
|
7810
8176
|
turnBindingFeed: _turnBindingProducer,
|
|
8177
|
+
// Non-MCP irreversible tools use the same prepare/start/settle ledger
|
|
8178
|
+
// and final lease assertion as headless, stream, and WebSocket hosts.
|
|
8179
|
+
sideEffects: _replSideEffects,
|
|
7811
8180
|
denialLog: _recentDenials,
|
|
7812
8181
|
persistRecentDenials: true,
|
|
7813
8182
|
permissionMode: _sessionTier,
|
|
@@ -8170,6 +8539,7 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
8170
8539
|
};
|
|
8171
8540
|
|
|
8172
8541
|
rl.on("line", async (input) => {
|
|
8542
|
+
if (!(await _waitForReplOutput())) return;
|
|
8173
8543
|
if (_processingLine) {
|
|
8174
8544
|
const concurrentBtw = _slashCommandsDisabled
|
|
8175
8545
|
? null
|
|
@@ -8193,10 +8563,12 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
8193
8563
|
_processingLine = true;
|
|
8194
8564
|
try {
|
|
8195
8565
|
await handleLine(input);
|
|
8566
|
+
if (!(await _waitForReplOutput())) return;
|
|
8196
8567
|
while (_pendingLines.length) {
|
|
8197
8568
|
const next = _pendingLines.shift();
|
|
8198
8569
|
logger.log(chalk.cyan(`▶ running queued input: ${next}`));
|
|
8199
8570
|
await handleLine(next);
|
|
8571
|
+
if (!(await _waitForReplOutput())) return;
|
|
8200
8572
|
}
|
|
8201
8573
|
} finally {
|
|
8202
8574
|
_processingLine = false;
|
|
@@ -8204,6 +8576,9 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
8204
8576
|
});
|
|
8205
8577
|
|
|
8206
8578
|
rl.on("close", async () => {
|
|
8579
|
+
if (_replCleanupStarted) return;
|
|
8580
|
+
_replCleanupStarted = true;
|
|
8581
|
+
_replClosing = true;
|
|
8207
8582
|
_promptInteractions.dispose();
|
|
8208
8583
|
if (process.stdin.isTTY) {
|
|
8209
8584
|
if (_replKeypressHandler) {
|
|
@@ -8386,11 +8761,42 @@ async function startAgentReplInWorkspace(options = {}, startupAdmission) {
|
|
|
8386
8761
|
}
|
|
8387
8762
|
|
|
8388
8763
|
// Shutdown runtime
|
|
8764
|
+
_detachSessionHostLease();
|
|
8765
|
+
try {
|
|
8766
|
+
_sessionHostLeaseScope?.lease?.release?.();
|
|
8767
|
+
} catch (error) {
|
|
8768
|
+
_replOutputFailure ||= error;
|
|
8769
|
+
}
|
|
8389
8770
|
try {
|
|
8390
8771
|
await shutdown();
|
|
8391
8772
|
} catch (_e) {
|
|
8392
8773
|
// Non-critical
|
|
8393
8774
|
}
|
|
8394
|
-
|
|
8775
|
+
if (!_replOutputFailure) {
|
|
8776
|
+
try {
|
|
8777
|
+
await _replOutputFlow.wait();
|
|
8778
|
+
} catch (error) {
|
|
8779
|
+
_replOutputFailure ||= error;
|
|
8780
|
+
}
|
|
8781
|
+
}
|
|
8782
|
+
const outputExitCode = _replOutputFailure
|
|
8783
|
+
? _replOutputFailure.code === "EPIPE"
|
|
8784
|
+
? 0
|
|
8785
|
+
: 1
|
|
8786
|
+
: 0;
|
|
8787
|
+
outputScope.restore();
|
|
8788
|
+
process.exit(outputExitCode);
|
|
8395
8789
|
});
|
|
8790
|
+
_replCloseReady = true;
|
|
8791
|
+
if (_replClosing) {
|
|
8792
|
+
// stdout may have broken before readline and its cleanup handler were fully
|
|
8793
|
+
// initialized. Close only now so the complete async teardown runs.
|
|
8794
|
+
queueMicrotask(() => {
|
|
8795
|
+
try {
|
|
8796
|
+
rl.close();
|
|
8797
|
+
} catch {
|
|
8798
|
+
process.exitCode = 0;
|
|
8799
|
+
}
|
|
8800
|
+
});
|
|
8801
|
+
}
|
|
8396
8802
|
}
|