chainlesschain 0.164.0 → 0.165.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +248 -2
- package/package.json +7 -4
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-D2MEn7fI.js → AIOps-lS1R0Cza.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-lCW_4Gf0.js → ActionButton-BmlgBPsj.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Bs7i-nsS.js → Analytics-CNKczv1S.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CK7B6S_j.js → AppLayout-BuZGJARQ.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-C8ILjpyo.js → Artifacts-Dm73Sl-O.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-Bb9cNaWc.js → Audit-BGMW7A5e.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-sC9ooXIf.js → BackgroundAgents-BQ6M54JR.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-D-DrsplT.js → Backup-DBzGP0bR.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-uCNZpwSK.js → BaseInput-D1mLCoOV.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CsDK1uE9.js → Chat-BUfcN7p8.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-OqSDt50w.js → ChatBubbleRenderer-CY5m8ZHg.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-JhTXM1-K.js → Checkbox-Du0Yg5Pi.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BbzZLnyD.js → Codegen-B2RXziHW.js} +1 -1
- package/src/assets/web-panel/assets/{Col-D4VW4m4j.js → Col-DWhekOrR.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BXrYawxV.js → Community-HQhrkon4.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DCihGy1u.js → Compact-izHNb4uz.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DlyZ-lk8.js → Compliance-BDwLy41-.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DvGZrhbO.js → Cowork-DFJhLa7K.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DUncZi8h.js → Cron-DYY9RG7-.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-C_hLuUcm.js → Crosschain-rr7tJTtv.js} +1 -1
- package/src/assets/web-panel/assets/{DID-b6YSUqxr.js → DID-D2sfHRLi.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-uvM15Cfb.js → Dashboard-q_eGdhha.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-D1-Nd4qY.js → Dropdown-Cufrh2Bz.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-8ApvL6Zc.js → EmailListRenderer-B-kdv10f.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-LYJt8811.js → FamilyGuardDashboard-D21XjgfG.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BbI3HGpv.js → Federation-CAwRTLZH.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DSoEKuFu.js → FormItemContext-vx3daNDF.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-B0S9OWd5.js → GenericCardRenderer-CRWY2wU4.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DIs9Zhf3.js → Git-Q6SwauyD.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-jzZXrxcl.js → Governance-BJ1q4IQZ.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-JUPjf2ZI.js → Inference-CSWjROgD.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DxnfJvlP.js → KnowledgeGraph-fzuQsWuY.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-iXiz8BEE.js → Logs-DVF8Mnns.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BLif4QSg.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Y3Xch312.js → Marketplace-BQP7LOA4.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-D7kGGbO7.js → McpTools-BNlJCmNc.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-Do_hVxzh.js → Memory-DLLg5WQ4.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CtrR0Tas.js → MobileBridge-CR2skNAF.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-BxVavObl.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-qo5QCTGd.js → Mtc-B17pgqMI.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-cq5mnjYj.js → MtcAudit-4UmV5cIL.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-Bq0MAQHw.js → Multisig-DoMEXEcU.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DdWE6Vi2.js → NLProgramming-h9DMXFX4.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BxMBFcIp.js → Notes-Cihn-xX8.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-RTrAcbUe.js → NotificationSettings-BE6ZGa3R.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DJbpGqzT.js → OrderTableRenderer-CnwojoSI.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-SQzIPdqC.js → Organization-B2vpwmjb.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-02yECh22.js → Overflow-C4z28R0-.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BNg4pNCM.js → P2P-BVlFkwhW.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BxPJZsD3.js → PdhVaultBrowser-BXbEdL5B.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CLnDnPAz.js → Permissions-C28xs4lp.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-C5m0AjGf.js → PersonalDataHub-Dgl_rBjM.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-VwOf5Dhv.js → Pipeline-3QUIhrKI.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CC0W2hZd.js → Privacy-8Gh33OZ5.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Dz893Bob.js → ProjectInit-BNmg4tZi.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CxQkvl0k.js → ProjectSettings-vgMfeCf9.js} +2 -2
- package/src/assets/web-panel/assets/Projects-BhtAVilc.js +1 -0
- package/src/assets/web-panel/assets/{Providers-DeB9IkxK.js → Providers-CXoOa8eX.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-OCeoaswn.js → QrScannerModal-BhfTF0oS.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DenotaAj.js → QuickAsk-C746HEAj.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Cies_jjI.js → Recommend-BSej8Eo0.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-f3gmnlG3.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-CW0mvxgZ.js → Reputation-CyvybpkN.js} +1 -1
- package/src/assets/web-panel/assets/{Row-SEd32qZU.js → Row-DwV2PeYn.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BSwnJ3Lm.js → RssFeed-11GrzjZy.js} +3 -3
- package/src/assets/web-panel/assets/{Search-xe2m8bkC.js → Search-BjKXkrAY.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Mq2F9Nro.js → Security-eWiFb9Yk.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BKGw2V3P.js → Services-CdCsMAtt.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DW95-Rxf.js → Skeleton-4Q2UTKQ5.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CHgChCv_.js → Skills-v4rtYrRj.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-tKh6k3R7.js → Sla-CRhsFvd_.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-DLjKsDVu.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-D0Fw8fVL.js → SyncSettings-D16zonl7.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-20x1GB3D.js → Tasks-Xxozz0i_.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DJ-lts-a.js → Templates-CXJpPtCT.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BFdGpbs7.js → Tenant-XRV0L1ZF.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-Xpx61vHL.js → Terminal-CYuO1i_w.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-C6UIvyZQ.js → TimelineRenderer-BXqitWsu.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Dellq08f.js → Tokens-BvPrDHIy.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-VKw8d0J-.js → Trigger-DhCrSTf5.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DNftdKT5.js → Trust-DmsuZD6K.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DX9VAKJI.js → UkeySign-D_yrts5C.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-B2h3jO8q.js → VideoEditing-B01ihPrm.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CjGkof7f.js → Wallet-DpUjKa-N.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-2Zfcu55P.js → WebAuthn-CL07yON6.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-B9eZ8UxZ.js → WorkflowEditor-CLMflnRr.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CQNfD-YO.js → chat-DtUqe8h_.js} +1 -1
- package/src/assets/web-panel/assets/{colors-D4usyFT2.js → colors-DPKrgVfy.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-s4TpjvjX.js → compact-item-BTt2GtOm.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BRCSvYxj.js → createContext-D_VeUc1J.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Bj5nUW2v.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-AdkUbkV-.js → hasIn-1kndiylj.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIoG5yYf.js → index-2eyAXE3d.js} +1 -1
- package/src/assets/web-panel/assets/{index-nXyk8GZ9.js → index-4bna2_SR.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2V-eKfK.js → index-8nz_fmlj.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_XBHopw.js → index-B9KvcS7R.js} +1 -1
- package/src/assets/web-panel/assets/{index-s_buFMEG.js → index-BAXfRKfG.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZT36ZYq.js → index-BHpBMWCh.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMcimU-2.js → index-BaZAbw9A.js} +1 -1
- package/src/assets/web-panel/assets/{index-DzRjHxEv.js → index-BepLZwgB.js} +1 -1
- package/src/assets/web-panel/assets/{index--00U6vXZ.js → index-Bhudc_Ez.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7Y8Aluc.js → index-BlDNVgBt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BtobShro.js → index-By5n8up9.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cvyt-zhm.js → index-CHG-KcS4.js} +1 -1
- package/src/assets/web-panel/assets/index-CPcM-eqo.js +1 -0
- package/src/assets/web-panel/assets/{index-MMN9V6JF.js → index-CX81qSM4.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bad4VNvz.js → index-CauoBQkH.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCsM_Ybx.js → index-CcO04eDn.js} +1 -1
- package/src/assets/web-panel/assets/{index-DARsAyUp.js → index-CtF7EN49.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5KAQFPQ.js → index-CzjkKUmR.js} +1 -1
- package/src/assets/web-panel/assets/{index-RfMr79MW.js → index-D95OFht7.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdCB70SS.js → index-DFIZ_1Sf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CYdoQsa1.js → index-DG2MZQ3f.js} +1 -1
- package/src/assets/web-panel/assets/{index-BPhkFZ1I.js → index-DJ8vXGOa.js} +1 -1
- package/src/assets/web-panel/assets/{index-_IRVsV9X.js → index-Dbbymxpj.js} +1 -1
- package/src/assets/web-panel/assets/{index-DVKfQ0Ux.js → index-DdkplL9R.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkwiSLhU.js → index-DfGl8CqG.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJVEOa4i.js → index-DfKBRdSS.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1mJtE6q.js → index-DsJCDUJG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgiXR_-_.js → index-Dwqmtk65.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJCFe2Qf.js → index-DxdTdBix.js} +1 -1
- package/src/assets/web-panel/assets/{index-C484EJiS.js → index-FzdwcSy2.js} +1 -1
- package/src/assets/web-panel/assets/{index-B4JJCfQ2.js → index-GsoUQ2M7.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQhAVU5t.js → index-brCInrzq.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKC1t3Ic.js → index-dVc-CXY4.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQ3DXBtD.js → index-fk2Rjacw.js} +3 -3
- package/src/assets/web-panel/assets/{index-Cduu2Hhr.js → index-l1BETrDb.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bw2MEnUk.js → index-m31Ka8hZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2GjI2oe.js → index-ocf06EVQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJdQrZth.js → index-sDoMHTNA.js} +1 -1
- package/src/assets/web-panel/assets/index-xeSyVoRe.js +1 -0
- package/src/assets/web-panel/assets/{initDefaultProps-Blmpk7HL.js → initDefaultProps-CvyYJd7z.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DPBJMv1n.js → motion-DYZkhUdz.js} +1 -1
- package/src/assets/web-panel/assets/{move-ButdzCM7.js → move-slnJRVT1.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-cyRC_QCe.js → mtc-parser-DVc0CKmy.js} +1 -1
- package/src/assets/web-panel/assets/{omit-1epSV7hz.js → omit-BCXAtHCq.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DuPY8xJs.js → pickAttrs-DBsemz_K.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-6XZqarhe.js → placementArrow-BRtkJ-nv.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-B40pXBWM.js → responsiveObserve-Cebq7EZn.js} +1 -1
- package/src/assets/web-panel/assets/{slide-jbZ9Wu4n.js → slide-DT7qvId2.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BKQQcVy4.js → statusUtils-pQiITLkG.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-NiKfWjUT.js → styleChecker-c-19BVKQ.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-bQUCvPeb.js → useFlexGapSupport-DsS5-0bE.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CUGji7ph.js → useFs-CxGiMe5n.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-4veyN2N2.js → usePersonalDataHub-D9btVID5.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-1-nLug-Z.js → vnode-CUYFsFEN.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-dhCeRDMo.js → zoom-CXmn_35j.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +1 -1
- package/src/commands/cowork.js +559 -62
- package/src/commands/plugin.js +819 -64
- package/src/commands/session-location.js +318 -7
- package/src/constants.js +2 -2
- package/src/data/changelog.json +28 -2
- package/src/gateways/ws/action-protocol.js +293 -19
- package/src/gateways/ws/message-dispatcher.js +30 -0
- package/src/gateways/ws/remote-session-protocol.js +542 -35
- package/src/gateways/ws/ws-approval-gate.js +5 -0
- package/src/gateways/ws/ws-server.js +462 -38
- package/src/harness/jsonl-session-store.js +638 -2
- package/src/harness/prompt-compressor.js +4 -0
- package/src/harness/remote-session-audit.js +1 -0
- package/src/harness/remote-session-crypto.js +750 -50
- package/src/harness/remote-session-registry.js +795 -27
- package/src/lib/auto-mode-config.js +98 -3
- package/src/lib/background-agent-keeper-client.js +29 -0
- package/src/lib/background-agent-keeper-protocol.js +158 -10
- package/src/lib/background-agent-supervisor.js +870 -48
- package/src/lib/background-session-transport.js +23 -6
- package/src/lib/background-turn-bootstrap-protocol.js +64 -0
- package/src/lib/cowork-task-runner.js +70 -0
- package/src/lib/cowork-workflow.js +887 -62
- package/src/lib/delivery-production-adapter.js +38 -2
- package/src/lib/doctor-checkup.js +34 -10
- package/src/lib/dynamic-workflow-draft.js +535 -0
- package/src/lib/dynamic-workflow-facade.js +1105 -17
- package/src/lib/dynamic-workflow-runtime.js +2974 -0
- package/src/lib/execution-location-contract.js +111 -7
- package/src/lib/execution-location-runtime.js +3 -1
- package/src/lib/execution-location-target.js +910 -0
- package/src/lib/llm-providers.js +1 -0
- package/src/lib/mcp-call-ledger-store.js +35 -0
- package/src/lib/mcp-call-ledger.js +30 -0
- package/src/lib/mcp-stdio-package-materialization.js +1 -1
- package/src/lib/plugin-runtime/__tests__/remote-source.test.js +34 -16
- package/src/lib/plugin-runtime/install.js +4956 -657
- package/src/lib/plugin-runtime/manifest.js +3 -1
- package/src/lib/plugin-runtime/marketplace-artifact-readback.js +671 -31
- package/src/lib/plugin-runtime/marketplace-catalog.js +68 -2
- package/src/lib/plugin-runtime/marketplace-impact.js +208 -15
- package/src/lib/plugin-runtime/marketplace-network.js +317 -0
- package/src/lib/plugin-runtime/marketplace-pac-worker.js +15 -0
- package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +25 -2
- package/src/lib/plugin-runtime/marketplace-source-cache.js +359 -0
- package/src/lib/plugin-runtime/policy.js +21 -6
- package/src/lib/plugin-runtime/publisher-trust.js +332 -0
- package/src/lib/plugin-runtime/remote-source.js +323 -27
- package/src/lib/plugin-runtime/scopes.js +317 -41
- package/src/lib/plugin-runtime/transaction-journal.js +806 -0
- package/src/lib/public-ide-capability-manifest.js +1 -1
- package/src/lib/remote-approval-bridge.js +745 -108
- package/src/lib/remote-control.js +2 -0
- package/src/lib/remote-membership-coordinator.js +612 -46
- package/src/lib/remote-membership-host-store.js +59 -10
- package/src/lib/runtime-provenance-ledger.js +171 -46
- package/src/lib/shell-approval.js +169 -6
- package/src/lib/sub-agent-context.js +268 -2
- package/src/lib/task-model-selector.js +1 -1
- package/src/lib/with-file-lock.js +167 -42
- package/src/repl/agent-repl.js +70 -29
- package/src/repl/remote-approval.js +29 -7
- package/src/runtime/agent-core.js +1695 -194
- package/src/runtime/headless-runner.js +22 -5
- package/src/runtime/headless-stream.js +19 -3
- package/src/workers/background-agent-keeper.js +279 -58
- package/src/workers/background-agent-worker.js +7 -0
- package/src/workers/background-turn-bootstrap.js +29 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-GmB6DOr6.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-BL0Czcoj.js +0 -1
- package/src/assets/web-panel/assets/Projects-DDAjkUkT.js +0 -1
- package/src/assets/web-panel/assets/RemoteSession-Dxzl5n2T.js +0 -5
- package/src/assets/web-panel/assets/SpeechSettings-D6UL3dA5.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DKJjSWRn.js +0 -1
- package/src/assets/web-panel/assets/index-C61cnl3K.js +0 -1
- package/src/assets/web-panel/assets/index-D4XFHxBr.js +0 -1
|
@@ -107,6 +107,7 @@ const LEASE_FIELDS = Object.freeze([
|
|
|
107
107
|
]);
|
|
108
108
|
const AUTHENTICATION_CHALLENGE_FIELDS = Object.freeze([
|
|
109
109
|
"authorityVersion",
|
|
110
|
+
"capabilities",
|
|
110
111
|
"challengeId",
|
|
111
112
|
"connectionNonce",
|
|
112
113
|
"coordinatorId",
|
|
@@ -116,6 +117,13 @@ const AUTHENTICATION_CHALLENGE_FIELDS = Object.freeze([
|
|
|
116
117
|
"expiresAtMs",
|
|
117
118
|
"issuedAtMs",
|
|
118
119
|
"membershipEpoch",
|
|
120
|
+
"joinPolicy",
|
|
121
|
+
"joinVia",
|
|
122
|
+
"nextCredentialKeySha256",
|
|
123
|
+
"nextCredentialPublicKey",
|
|
124
|
+
"nextCredentialType",
|
|
125
|
+
"nextPrincipalId",
|
|
126
|
+
"nextSessionExpiresAt",
|
|
119
127
|
"principalId",
|
|
120
128
|
"purpose",
|
|
121
129
|
"schema",
|
|
@@ -873,13 +881,20 @@ function replayHostStore(store, { missing = false } = {}) {
|
|
|
873
881
|
throw new TypeError(`${label} has an invalid session snapshot`);
|
|
874
882
|
}
|
|
875
883
|
if (sessionSnapshot) {
|
|
884
|
+
const priorSessionEpoch = BigInt(sessionSnapshot.sessionEpoch);
|
|
885
|
+
const nextSessionEpoch = BigInt(payload.sessionEpoch);
|
|
886
|
+
const reenabled =
|
|
887
|
+
sessionSnapshot.status === "closed" &&
|
|
888
|
+
payload.status === "active" &&
|
|
889
|
+
nextSessionEpoch === priorSessionEpoch + 1n;
|
|
876
890
|
if (
|
|
877
891
|
payload.sessionId !== sessionSnapshot.sessionId ||
|
|
878
892
|
payload.agentSessionId !== sessionSnapshot.agentSessionId ||
|
|
879
893
|
payload.hostPrincipalId !== sessionSnapshot.hostPrincipalId ||
|
|
880
894
|
payload.createdAt !== sessionSnapshot.createdAt ||
|
|
881
|
-
payload.expiresAt !== sessionSnapshot.expiresAt ||
|
|
882
|
-
|
|
895
|
+
(!reenabled && payload.expiresAt !== sessionSnapshot.expiresAt) ||
|
|
896
|
+
(reenabled && payload.expiresAt < sessionSnapshot.expiresAt) ||
|
|
897
|
+
nextSessionEpoch < priorSessionEpoch
|
|
883
898
|
) {
|
|
884
899
|
throw new TypeError(`${label} rolls back the session identity`);
|
|
885
900
|
}
|
|
@@ -905,7 +920,12 @@ function replayHostStore(store, { missing = false } = {}) {
|
|
|
905
920
|
(nextEpoch === priorEpoch &&
|
|
906
921
|
canonicalJson(current) !== canonicalJson(previous)) ||
|
|
907
922
|
(nextEpoch === priorEpoch + 1n &&
|
|
908
|
-
current.status === previous.status
|
|
923
|
+
current.status === previous.status &&
|
|
924
|
+
!(
|
|
925
|
+
reenabled &&
|
|
926
|
+
current.principalId === payload.hostPrincipalId &&
|
|
927
|
+
current.status === "active"
|
|
928
|
+
))
|
|
909
929
|
) {
|
|
910
930
|
throw new TypeError(`${label} forks or skips a principal epoch`);
|
|
911
931
|
}
|
|
@@ -920,16 +940,16 @@ function replayHostStore(store, { missing = false } = {}) {
|
|
|
920
940
|
);
|
|
921
941
|
}
|
|
922
942
|
}
|
|
923
|
-
const priorSessionEpoch = BigInt(sessionSnapshot.sessionEpoch);
|
|
924
|
-
const nextSessionEpoch = BigInt(payload.sessionEpoch);
|
|
925
943
|
if (
|
|
926
944
|
nextSessionEpoch > priorSessionEpoch + 1n ||
|
|
927
945
|
(nextSessionEpoch === priorSessionEpoch &&
|
|
928
946
|
payload.status !== sessionSnapshot.status) ||
|
|
929
947
|
(nextSessionEpoch === priorSessionEpoch + 1n &&
|
|
930
|
-
(
|
|
931
|
-
|
|
932
|
-
|
|
948
|
+
!(
|
|
949
|
+
(sessionSnapshot.status === "active" &&
|
|
950
|
+
payload.status === "closed") ||
|
|
951
|
+
reenabled
|
|
952
|
+
))
|
|
933
953
|
) {
|
|
934
954
|
throw new TypeError(`${label} forks or reopens the session epoch`);
|
|
935
955
|
}
|
|
@@ -1591,8 +1611,17 @@ export class DurableRemoteMembershipHostStore {
|
|
|
1591
1611
|
challenge.credentialType !== "ed25519" ||
|
|
1592
1612
|
challenge.credentialPublicKey !==
|
|
1593
1613
|
bootstrap.hostCredentialPublicKeySpki ||
|
|
1594
|
-
|
|
1595
|
-
challenge.
|
|
1614
|
+
!["session.resume", "session.reenable"].includes(challenge.purpose) ||
|
|
1615
|
+
(challenge.purpose === "session.resume" &&
|
|
1616
|
+
(challenge.scopes !== null ||
|
|
1617
|
+
challenge.capabilities !== null ||
|
|
1618
|
+
challenge.joinPolicy !== null ||
|
|
1619
|
+
challenge.joinVia !== null ||
|
|
1620
|
+
challenge.nextCredentialType !== null ||
|
|
1621
|
+
challenge.nextCredentialPublicKey !== null ||
|
|
1622
|
+
challenge.nextCredentialKeySha256 !== null ||
|
|
1623
|
+
challenge.nextPrincipalId !== null ||
|
|
1624
|
+
challenge.nextSessionExpiresAt !== null))
|
|
1596
1625
|
) {
|
|
1597
1626
|
throw trustRejected("authentication challenge is not host-bound");
|
|
1598
1627
|
}
|
|
@@ -1604,6 +1633,26 @@ export class DurableRemoteMembershipHostStore {
|
|
|
1604
1633
|
canonicalInteger(challenge.membershipEpoch, "challenge.membershipEpoch");
|
|
1605
1634
|
safeTimestamp(challenge.issuedAtMs, "challenge.issuedAtMs");
|
|
1606
1635
|
safeTimestamp(challenge.expiresAtMs, "challenge.expiresAtMs");
|
|
1636
|
+
if (challenge.purpose === "session.reenable") {
|
|
1637
|
+
if (
|
|
1638
|
+
!Array.isArray(challenge.scopes) ||
|
|
1639
|
+
challenge.scopes.length === 0 ||
|
|
1640
|
+
challenge.capabilities !== null ||
|
|
1641
|
+
challenge.joinVia !== null ||
|
|
1642
|
+
!challenge.joinPolicy ||
|
|
1643
|
+
typeof challenge.joinPolicy !== "object" ||
|
|
1644
|
+
Array.isArray(challenge.joinPolicy) ||
|
|
1645
|
+
challenge.nextCredentialType !== "ed25519" ||
|
|
1646
|
+
typeof challenge.nextCredentialPublicKey !== "string" ||
|
|
1647
|
+
!DIGEST_RE.test(String(challenge.nextCredentialKeySha256)) ||
|
|
1648
|
+
challenge.nextPrincipalId !==
|
|
1649
|
+
`ed25519:${challenge.nextCredentialKeySha256}` ||
|
|
1650
|
+
!Number.isSafeInteger(challenge.nextSessionExpiresAt) ||
|
|
1651
|
+
challenge.nextSessionExpiresAt <= challenge.issuedAtMs
|
|
1652
|
+
) {
|
|
1653
|
+
throw trustRejected("re-enable challenge is malformed");
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1607
1656
|
if (
|
|
1608
1657
|
challenge.expiresAtMs <= challenge.issuedAtMs ||
|
|
1609
1658
|
challenge.expiresAtMs <= safeTimestamp(this._now(), "host clock") ||
|
|
@@ -1,16 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* RuntimeProvenanceLedger -
|
|
2
|
+
* RuntimeProvenanceLedger - bounded, hash-chained runtime provenance.
|
|
3
3
|
*
|
|
4
|
-
* Records
|
|
5
|
-
*
|
|
4
|
+
* Records context sources, tool calls and responses that flow through the CLI
|
|
5
|
+
* runtime. The in-memory view is deliberately a retained window: every entry
|
|
6
|
+
* keeps an absolute index, and the hash of the last evicted entry anchors the
|
|
7
|
+
* first retained entry. Exports state explicitly when older entries are no
|
|
8
|
+
* longer resident instead of claiming that the retained suffix is a complete
|
|
9
|
+
* history.
|
|
6
10
|
*/
|
|
7
11
|
|
|
8
12
|
import { createHash } from "node:crypto";
|
|
9
13
|
|
|
14
|
+
export const DEFAULT_RUNTIME_PROVENANCE_MAX_ENTRIES = 4_096;
|
|
15
|
+
const DEFAULT_GENESIS_HASH = "0".repeat(64);
|
|
16
|
+
|
|
17
|
+
function positiveEntryLimit(value) {
|
|
18
|
+
const parsed = Number(value);
|
|
19
|
+
if (!Number.isSafeInteger(parsed) || parsed <= 0) {
|
|
20
|
+
throw new TypeError(
|
|
21
|
+
"runtime provenance maxEntries must be a positive integer",
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
return parsed;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function freezeJsonSnapshot(value) {
|
|
28
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
29
|
+
for (const nested of Object.values(value)) freezeJsonSnapshot(nested);
|
|
30
|
+
Object.freeze(value);
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
|
|
10
35
|
class RuntimeProvenanceLedger {
|
|
11
36
|
constructor(options = {}) {
|
|
12
|
-
this.
|
|
13
|
-
|
|
37
|
+
this._maxEntries = positiveEntryLimit(
|
|
38
|
+
options.maxEntries ?? DEFAULT_RUNTIME_PROVENANCE_MAX_ENTRIES,
|
|
39
|
+
);
|
|
40
|
+
this._genesisHash = options.genesisHash || DEFAULT_GENESIS_HASH;
|
|
41
|
+
this._lastHash = this._genesisHash;
|
|
42
|
+
this._entries = new Array(this._maxEntries);
|
|
43
|
+
this._retainedStart = 0;
|
|
44
|
+
this._retainedCount = 0;
|
|
45
|
+
this._nextIndex = 0;
|
|
46
|
+
this._evictedThroughIndex = null;
|
|
47
|
+
this._evictedThroughHash = null;
|
|
48
|
+
this._entriesByIndex = new Map();
|
|
14
49
|
this._spanIndex = new Map();
|
|
15
50
|
this._traceIndex = new Map();
|
|
16
51
|
}
|
|
@@ -94,97 +129,187 @@ class RuntimeProvenanceLedger {
|
|
|
94
129
|
});
|
|
95
130
|
}
|
|
96
131
|
|
|
132
|
+
_addIndex(index, key, absoluteIndex) {
|
|
133
|
+
if (!key) return;
|
|
134
|
+
let bucket = index.get(key);
|
|
135
|
+
if (!bucket) {
|
|
136
|
+
bucket = new Set();
|
|
137
|
+
index.set(key, bucket);
|
|
138
|
+
}
|
|
139
|
+
bucket.add(absoluteIndex);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
_removeIndex(index, key, absoluteIndex) {
|
|
143
|
+
if (!key) return;
|
|
144
|
+
const bucket = index.get(key);
|
|
145
|
+
if (!bucket) return;
|
|
146
|
+
bucket.delete(absoluteIndex);
|
|
147
|
+
if (bucket.size === 0) index.delete(key);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
_evictOldest() {
|
|
151
|
+
const evicted = this._entries[this._retainedStart];
|
|
152
|
+
if (!evicted) {
|
|
153
|
+
throw new Error("runtime provenance ring is internally inconsistent");
|
|
154
|
+
}
|
|
155
|
+
this._entriesByIndex.delete(evicted.index);
|
|
156
|
+
this._removeIndex(this._traceIndex, evicted.traceId, evicted.index);
|
|
157
|
+
this._removeIndex(this._spanIndex, evicted.span, evicted.index);
|
|
158
|
+
this._evictedThroughIndex = evicted.index;
|
|
159
|
+
this._evictedThroughHash = evicted.hash;
|
|
160
|
+
this._entries[this._retainedStart] = undefined;
|
|
161
|
+
this._retainedStart = (this._retainedStart + 1) % this._maxEntries;
|
|
162
|
+
this._retainedCount -= 1;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
_retainedEntries() {
|
|
166
|
+
const retained = new Array(this._retainedCount);
|
|
167
|
+
for (let offset = 0; offset < this._retainedCount; offset += 1) {
|
|
168
|
+
retained[offset] =
|
|
169
|
+
this._entries[(this._retainedStart + offset) % this._maxEntries];
|
|
170
|
+
}
|
|
171
|
+
return retained;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
_retainedAnchorHash() {
|
|
175
|
+
return this._evictedThroughHash || this._genesisHash;
|
|
176
|
+
}
|
|
177
|
+
|
|
97
178
|
/**
|
|
98
|
-
* Append entry with
|
|
179
|
+
* Append an entry with an absolute index and hash-chain binding.
|
|
99
180
|
*/
|
|
100
181
|
_append(entry) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
182
|
+
// The returned entries are also the ring's storage records. Snapshot the
|
|
183
|
+
// caller's JSON data before hashing so later mutations cannot invalidate
|
|
184
|
+
// the hash chain, then recursively freeze the snapshot so storage keys
|
|
185
|
+
// used during eviction cannot be rewritten through get/export results.
|
|
186
|
+
const payload = { ...entry };
|
|
187
|
+
delete payload.index;
|
|
188
|
+
delete payload.prevHash;
|
|
189
|
+
delete payload.hash;
|
|
190
|
+
const serialized = JSON.stringify({
|
|
191
|
+
...payload,
|
|
192
|
+
index: this._nextIndex,
|
|
104
193
|
prevHash: this._lastHash,
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const hash = createHash("sha256")
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
this.
|
|
194
|
+
});
|
|
195
|
+
const snapshot = JSON.parse(serialized);
|
|
196
|
+
const hash = createHash("sha256").update(serialized).digest("hex");
|
|
197
|
+
snapshot.hash = hash;
|
|
198
|
+
const entryWithHash = freezeJsonSnapshot(snapshot);
|
|
199
|
+
|
|
200
|
+
if (this._retainedCount === this._maxEntries) this._evictOldest();
|
|
201
|
+
const writeIndex =
|
|
202
|
+
(this._retainedStart + this._retainedCount) % this._maxEntries;
|
|
203
|
+
this._entries[writeIndex] = entryWithHash;
|
|
204
|
+
this._retainedCount += 1;
|
|
205
|
+
this._entriesByIndex.set(entryWithHash.index, entryWithHash);
|
|
206
|
+
this._addIndex(
|
|
207
|
+
this._traceIndex,
|
|
208
|
+
entryWithHash.traceId,
|
|
209
|
+
entryWithHash.index,
|
|
210
|
+
);
|
|
211
|
+
this._addIndex(this._spanIndex, entryWithHash.span, entryWithHash.index);
|
|
212
|
+
this._nextIndex += 1;
|
|
112
213
|
this._lastHash = hash;
|
|
113
|
-
// Index
|
|
114
|
-
if (entry.traceId) {
|
|
115
|
-
if (!this._traceIndex.has(entry.traceId)) this._traceIndex.set(entry.traceId, []);
|
|
116
|
-
this._traceIndex.get(entry.traceId).push(entryWithHash.index);
|
|
117
|
-
}
|
|
118
|
-
if (entry.span) {
|
|
119
|
-
if (!this._spanIndex.has(entry.span)) this._spanIndex.set(entry.span, []);
|
|
120
|
-
this._spanIndex.get(entry.span).push(entryWithHash.index);
|
|
121
|
-
}
|
|
122
214
|
return entryWithHash;
|
|
123
215
|
}
|
|
124
216
|
|
|
125
217
|
/**
|
|
126
|
-
* Verify
|
|
218
|
+
* Verify the retained suffix and its independently stored boundary anchor.
|
|
127
219
|
*/
|
|
128
220
|
verifyIntegrity() {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
221
|
+
const entries = this._retainedEntries();
|
|
222
|
+
let currentHash = this._retainedAnchorHash();
|
|
223
|
+
let expectedIndex =
|
|
224
|
+
this._evictedThroughIndex === null ? 0 : this._evictedThroughIndex + 1;
|
|
225
|
+
for (const entry of entries) {
|
|
226
|
+
if (entry.index !== expectedIndex || entry.prevHash !== currentHash) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
const { hash } = entry;
|
|
230
|
+
const entryForHash = { ...entry };
|
|
231
|
+
delete entryForHash.hash;
|
|
232
|
+
const computed = createHash("sha256")
|
|
233
|
+
.update(JSON.stringify(entryForHash))
|
|
234
|
+
.digest("hex");
|
|
134
235
|
if (computed !== hash) return false;
|
|
135
236
|
currentHash = hash;
|
|
237
|
+
expectedIndex += 1;
|
|
136
238
|
}
|
|
137
|
-
return
|
|
239
|
+
return currentHash === this._lastHash && expectedIndex === this._nextIndex;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
_indexedEntries(index, key) {
|
|
243
|
+
const indices = index.get(key);
|
|
244
|
+
if (!indices) return [];
|
|
245
|
+
return [...indices]
|
|
246
|
+
.map((absoluteIndex) => this._entriesByIndex.get(absoluteIndex))
|
|
247
|
+
.filter(Boolean);
|
|
138
248
|
}
|
|
139
249
|
|
|
140
250
|
/**
|
|
141
|
-
* Get
|
|
251
|
+
* Get retained entries for a trace.
|
|
142
252
|
*/
|
|
143
253
|
getTraceEntries(traceId) {
|
|
144
|
-
|
|
145
|
-
return indices.map(i => this._entries[i]);
|
|
254
|
+
return this._indexedEntries(this._traceIndex, traceId);
|
|
146
255
|
}
|
|
147
256
|
|
|
148
257
|
/**
|
|
149
|
-
* Get
|
|
258
|
+
* Get retained entries for a span.
|
|
150
259
|
*/
|
|
151
260
|
getSpanEntries(spanId) {
|
|
152
|
-
|
|
153
|
-
return indices.map(i => this._entries[i]);
|
|
261
|
+
return this._indexedEntries(this._spanIndex, spanId);
|
|
154
262
|
}
|
|
155
263
|
|
|
156
264
|
/**
|
|
157
|
-
* Get provenance
|
|
265
|
+
* Get the retained provenance window for a response.
|
|
158
266
|
*/
|
|
159
267
|
getProvenance(options = {}) {
|
|
160
268
|
if (options.traceId) return this.getTraceEntries(options.traceId);
|
|
161
269
|
if (options.span) return this.getSpanEntries(options.span);
|
|
162
|
-
return
|
|
270
|
+
return this._retainedEntries();
|
|
163
271
|
}
|
|
164
272
|
|
|
165
273
|
/**
|
|
166
|
-
* Export
|
|
274
|
+
* Export the retained window without presenting it as complete history.
|
|
167
275
|
*/
|
|
168
276
|
export() {
|
|
277
|
+
const entries = this._retainedEntries();
|
|
278
|
+
const evictedEntries = this._nextIndex - entries.length;
|
|
279
|
+
const truncated = evictedEntries > 0;
|
|
169
280
|
return {
|
|
170
|
-
|
|
281
|
+
// Compatibility: genesisHash remains the hash immediately before the
|
|
282
|
+
// first exported entry, just as it was when every entry was retained.
|
|
283
|
+
genesisHash: entries[0]?.prevHash,
|
|
284
|
+
originalGenesisHash: this._genesisHash,
|
|
171
285
|
lastHash: this._lastHash,
|
|
172
|
-
entries
|
|
286
|
+
entries,
|
|
173
287
|
verified: this.verifyIntegrity(),
|
|
288
|
+
verificationScope: truncated ? "retained-window" : "complete",
|
|
289
|
+
totalEntries: this._nextIndex,
|
|
290
|
+
retainedEntries: entries.length,
|
|
291
|
+
evictedEntries,
|
|
292
|
+
truncated,
|
|
293
|
+
anchor: {
|
|
294
|
+
hash: this._retainedAnchorHash(),
|
|
295
|
+
evictedThroughIndex: this._evictedThroughIndex,
|
|
296
|
+
firstRetainedIndex: entries[0]?.index ?? null,
|
|
297
|
+
},
|
|
174
298
|
exportedAt: new Date().toISOString(),
|
|
175
299
|
};
|
|
176
300
|
}
|
|
177
301
|
|
|
178
302
|
/**
|
|
179
|
-
* Flush pending entries to disk (called on exit)
|
|
303
|
+
* Flush pending entries to disk (called on exit).
|
|
180
304
|
*/
|
|
181
305
|
flush() {
|
|
182
|
-
// In production this would persist to disk; for now
|
|
306
|
+
// In production this would persist to disk; for now the bounded retained
|
|
307
|
+
// window and its eviction anchor remain available in memory.
|
|
183
308
|
return Promise.resolve(true);
|
|
184
309
|
}
|
|
185
310
|
}
|
|
186
311
|
|
|
187
|
-
// Export global singleton instance
|
|
312
|
+
// Export global singleton instance.
|
|
188
313
|
const runtimeProvenanceLedger = new RuntimeProvenanceLedger();
|
|
189
314
|
export default runtimeProvenanceLedger;
|
|
190
315
|
export { RuntimeProvenanceLedger, runtimeProvenanceLedger };
|
|
@@ -32,6 +32,129 @@ import {
|
|
|
32
32
|
resolveInstallPolicy,
|
|
33
33
|
} from "./install-command-policy.js";
|
|
34
34
|
|
|
35
|
+
const SHELL_EXECUTION_DESCRIPTOR_VERSION =
|
|
36
|
+
"chainlesschain.shell-execution-descriptor/v1";
|
|
37
|
+
|
|
38
|
+
function deepFreezeData(value, seen = new WeakSet()) {
|
|
39
|
+
if (!value || typeof value !== "object" || Object.isFrozen(value))
|
|
40
|
+
return value;
|
|
41
|
+
if (seen.has(value)) return value;
|
|
42
|
+
seen.add(value);
|
|
43
|
+
for (const child of Object.values(value)) deepFreezeData(child, seen);
|
|
44
|
+
return Object.freeze(value);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function cloneData(value, label) {
|
|
48
|
+
try {
|
|
49
|
+
return structuredClone(value);
|
|
50
|
+
} catch (cause) {
|
|
51
|
+
throw new Error(`${label} must be structured-cloneable`, { cause });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Capture only the declared run_shell data contract and freeze it. */
|
|
56
|
+
export function snapshotShellExecutionArgs(args = {}, fallbackCommand = null) {
|
|
57
|
+
const source = args && typeof args === "object" ? args : {};
|
|
58
|
+
const snapshot = {
|
|
59
|
+
command:
|
|
60
|
+
source.command !== undefined
|
|
61
|
+
? cloneData(source.command, "command")
|
|
62
|
+
: cloneData(fallbackCommand ?? null, "command"),
|
|
63
|
+
};
|
|
64
|
+
for (const key of ["cwd", "shell", "run_in_background", "timeout"]) {
|
|
65
|
+
if (source[key] !== undefined) snapshot[key] = cloneData(source[key], key);
|
|
66
|
+
}
|
|
67
|
+
return deepFreezeData(snapshot);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Build the bounded, secret-free data tuple shown to ApprovalGate and later
|
|
72
|
+
* consumed at dispatch. Runtime objects/callbacks never enter this descriptor.
|
|
73
|
+
*/
|
|
74
|
+
export function createShellExecutionDescriptor({
|
|
75
|
+
args,
|
|
76
|
+
workspace = null,
|
|
77
|
+
shellInvocation = null,
|
|
78
|
+
pluginInvocation = null,
|
|
79
|
+
pluginSandboxPolicy = null,
|
|
80
|
+
pluginSandboxExecutionContract = null,
|
|
81
|
+
sandbox = null,
|
|
82
|
+
environmentRef = null,
|
|
83
|
+
} = {}) {
|
|
84
|
+
const shellArgs = snapshotShellExecutionArgs(args);
|
|
85
|
+
const descriptor = {
|
|
86
|
+
...shellArgs,
|
|
87
|
+
execution: {
|
|
88
|
+
version: SHELL_EXECUTION_DESCRIPTOR_VERSION,
|
|
89
|
+
mode: shellArgs.run_in_background === true ? "background" : "foreground",
|
|
90
|
+
workspace: workspace || null,
|
|
91
|
+
shell: shellInvocation
|
|
92
|
+
? {
|
|
93
|
+
kind: shellInvocation.kind || null,
|
|
94
|
+
useDefaultShell: shellInvocation.useDefaultShell === true,
|
|
95
|
+
file: shellInvocation.file || null,
|
|
96
|
+
argv: Array.isArray(shellInvocation.argv)
|
|
97
|
+
? [...shellInvocation.argv]
|
|
98
|
+
: [],
|
|
99
|
+
}
|
|
100
|
+
: null,
|
|
101
|
+
plugin: pluginInvocation
|
|
102
|
+
? {
|
|
103
|
+
command: pluginInvocation.command || null,
|
|
104
|
+
id: pluginInvocation.pluginId || null,
|
|
105
|
+
version: pluginInvocation.pluginVersion || null,
|
|
106
|
+
source: pluginInvocation.pluginSource || null,
|
|
107
|
+
bin: pluginInvocation.binName || null,
|
|
108
|
+
path: pluginInvocation.binPath || null,
|
|
109
|
+
runtime: pluginInvocation.runtime || null,
|
|
110
|
+
argv: Array.isArray(pluginInvocation.args)
|
|
111
|
+
? [...pluginInvocation.args]
|
|
112
|
+
: [],
|
|
113
|
+
executableSha256:
|
|
114
|
+
pluginInvocation.executableIdentity?.sha256 || null,
|
|
115
|
+
sandboxPolicy: pluginSandboxPolicy
|
|
116
|
+
? cloneData(pluginSandboxPolicy, "pluginSandboxPolicy")
|
|
117
|
+
: null,
|
|
118
|
+
sandboxExecution: pluginSandboxExecutionContract
|
|
119
|
+
? {
|
|
120
|
+
version:
|
|
121
|
+
pluginSandboxExecutionContract.contractVersion || null,
|
|
122
|
+
kind: pluginSandboxExecutionContract.kind || null,
|
|
123
|
+
pluginRoot: pluginSandboxExecutionContract.pluginRoot || null,
|
|
124
|
+
workingDirectory:
|
|
125
|
+
pluginSandboxExecutionContract.workingDirectory || null,
|
|
126
|
+
runtimePath:
|
|
127
|
+
pluginSandboxExecutionContract.runtimePath || null,
|
|
128
|
+
entrySha256:
|
|
129
|
+
pluginSandboxExecutionContract.entryIdentity?.sha256 ||
|
|
130
|
+
null,
|
|
131
|
+
runtimeSha256:
|
|
132
|
+
pluginSandboxExecutionContract.runtimeIdentity?.sha256 ||
|
|
133
|
+
null,
|
|
134
|
+
}
|
|
135
|
+
: null,
|
|
136
|
+
}
|
|
137
|
+
: null,
|
|
138
|
+
sandbox: sandbox ? cloneData(sandbox, "sandbox") : null,
|
|
139
|
+
environment: environmentRef
|
|
140
|
+
? cloneData(environmentRef, "environmentRef")
|
|
141
|
+
: null,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
return deepFreezeData(descriptor);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function shellApprovalAction(riskLevel) {
|
|
148
|
+
return riskLevel ? `${riskLevel}-risk` : null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function commitShellApprovalSideEffects(result) {
|
|
152
|
+
const audit = result?.installAudit || null;
|
|
153
|
+
if (!audit) return false;
|
|
154
|
+
recordInstallCommandAudit(audit.entry, audit.options || {});
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
|
|
35
158
|
export const SHELL_TO_RISK = {
|
|
36
159
|
allow: RISK.LOW,
|
|
37
160
|
warn: RISK.MEDIUM,
|
|
@@ -41,10 +164,16 @@ export const SHELL_TO_RISK = {
|
|
|
41
164
|
|
|
42
165
|
export async function evaluateShellCommandWithApproval({
|
|
43
166
|
command,
|
|
167
|
+
args = null,
|
|
44
168
|
sessionId = null,
|
|
45
169
|
approvalGate = null,
|
|
46
170
|
shellPolicyOptions = {},
|
|
47
171
|
installPolicy = null,
|
|
172
|
+
workspace = null,
|
|
173
|
+
targetEnv = null,
|
|
174
|
+
policyEnv = process.env,
|
|
175
|
+
policyVersion = null,
|
|
176
|
+
deferSideEffects = false,
|
|
48
177
|
} = {}) {
|
|
49
178
|
const shellPolicy = sharedShellPolicy.evaluateShellCommandPolicy(
|
|
50
179
|
command,
|
|
@@ -62,8 +191,9 @@ export async function evaluateShellCommandWithApproval({
|
|
|
62
191
|
// CC_INSTALL_RISK_FLOOR) so the real run_shell path picks it up with no extra
|
|
63
192
|
// wiring. Both unset → disabled → the block below is skipped, byte-unchanged.
|
|
64
193
|
const effectiveInstallPolicy =
|
|
65
|
-
installPolicy || resolveInstallPolicy({ env:
|
|
194
|
+
installPolicy || resolveInstallPolicy({ env: policyEnv });
|
|
66
195
|
let install = null;
|
|
196
|
+
let installAudit = null;
|
|
67
197
|
if (effectiveInstallPolicy && effectiveInstallPolicy.enabled) {
|
|
68
198
|
const cls = classifyCodeAcquisition(command);
|
|
69
199
|
if (cls.flagged) {
|
|
@@ -72,8 +202,8 @@ export async function evaluateShellCommandWithApproval({
|
|
|
72
202
|
riskLevel = applyRiskFloor(riskLevel, effectiveInstallPolicy.riskFloor);
|
|
73
203
|
}
|
|
74
204
|
if (effectiveInstallPolicy.audit) {
|
|
75
|
-
|
|
76
|
-
{
|
|
205
|
+
installAudit = {
|
|
206
|
+
entry: {
|
|
77
207
|
command,
|
|
78
208
|
shellDecision: shellPolicy.decision,
|
|
79
209
|
riskLevel,
|
|
@@ -82,8 +212,12 @@ export async function evaluateShellCommandWithApproval({
|
|
|
82
212
|
global: hasGlobalInstall(cls),
|
|
83
213
|
sessionId,
|
|
84
214
|
},
|
|
85
|
-
effectiveInstallPolicy.auditOpts || {},
|
|
86
|
-
|
|
215
|
+
options: effectiveInstallPolicy.auditOpts || {},
|
|
216
|
+
};
|
|
217
|
+
if (!deferSideEffects) {
|
|
218
|
+
recordInstallCommandAudit(installAudit.entry, installAudit.options);
|
|
219
|
+
installAudit = null;
|
|
220
|
+
}
|
|
87
221
|
}
|
|
88
222
|
}
|
|
89
223
|
}
|
|
@@ -100,6 +234,7 @@ export async function evaluateShellCommandWithApproval({
|
|
|
100
234
|
riskLevel,
|
|
101
235
|
policy: null,
|
|
102
236
|
install,
|
|
237
|
+
installAudit,
|
|
103
238
|
};
|
|
104
239
|
}
|
|
105
240
|
|
|
@@ -114,14 +249,29 @@ export async function evaluateShellCommandWithApproval({
|
|
|
114
249
|
riskLevel,
|
|
115
250
|
policy: null,
|
|
116
251
|
install,
|
|
252
|
+
installAudit,
|
|
117
253
|
};
|
|
118
254
|
}
|
|
119
255
|
|
|
256
|
+
const operationArgs = args
|
|
257
|
+
? Object.isFrozen(args)
|
|
258
|
+
? args
|
|
259
|
+
: deepFreezeData(cloneData(args, "run_shell approval args"))
|
|
260
|
+
: snapshotShellExecutionArgs({ command });
|
|
261
|
+
const effectivePolicyVersion =
|
|
262
|
+
typeof policyVersion === "string" && policyVersion
|
|
263
|
+
? policyVersion
|
|
264
|
+
: `shell-policy:${shellPolicy.decision}:${shellPolicy.ruleId || "none"}`;
|
|
265
|
+
const action = shellApprovalAction(riskLevel);
|
|
120
266
|
const gateResult = await approvalGate.decide({
|
|
121
267
|
sessionId,
|
|
122
268
|
riskLevel,
|
|
123
269
|
tool: "run_shell",
|
|
124
|
-
args:
|
|
270
|
+
args: operationArgs,
|
|
271
|
+
cwd: workspace,
|
|
272
|
+
targetEnv,
|
|
273
|
+
policyVersion: effectivePolicyVersion,
|
|
274
|
+
action,
|
|
125
275
|
});
|
|
126
276
|
|
|
127
277
|
return {
|
|
@@ -133,6 +283,19 @@ export async function evaluateShellCommandWithApproval({
|
|
|
133
283
|
riskLevel,
|
|
134
284
|
policy: gateResult.policy,
|
|
135
285
|
install,
|
|
286
|
+
installAudit,
|
|
287
|
+
authorization: gateResult.authorization || null,
|
|
288
|
+
authorizationContext: gateResult.authorization
|
|
289
|
+
? {
|
|
290
|
+
tool: "run_shell",
|
|
291
|
+
action,
|
|
292
|
+
args: operationArgs,
|
|
293
|
+
workspace,
|
|
294
|
+
session: sessionId,
|
|
295
|
+
targetEnv,
|
|
296
|
+
policyVersion: effectivePolicyVersion,
|
|
297
|
+
}
|
|
298
|
+
: null,
|
|
136
299
|
// Explainability passthrough (autoMode.decisions wrapper attaches these):
|
|
137
300
|
// which gate rule fired and why — surfaced in the permission chain.
|
|
138
301
|
gateReason: gateResult.reason ?? null,
|