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.
Files changed (228) hide show
  1. package/README.md +248 -2
  2. package/package.json +7 -4
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-D2MEn7fI.js → AIOps-lS1R0Cza.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-lCW_4Gf0.js → ActionButton-BmlgBPsj.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-Bs7i-nsS.js → Analytics-CNKczv1S.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-CK7B6S_j.js → AppLayout-BuZGJARQ.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-C8ILjpyo.js → Artifacts-Dm73Sl-O.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-Bb9cNaWc.js → Audit-BGMW7A5e.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-sC9ooXIf.js → BackgroundAgents-BQ6M54JR.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-D-DrsplT.js → Backup-DBzGP0bR.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-uCNZpwSK.js → BaseInput-D1mLCoOV.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-CsDK1uE9.js → Chat-BUfcN7p8.js} +6 -6
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-OqSDt50w.js → ChatBubbleRenderer-CY5m8ZHg.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-JhTXM1-K.js → Checkbox-Du0Yg5Pi.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-BbzZLnyD.js → Codegen-B2RXziHW.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-D4VW4m4j.js → Col-DWhekOrR.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-BXrYawxV.js → Community-HQhrkon4.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-DCihGy1u.js → Compact-izHNb4uz.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-DlyZ-lk8.js → Compliance-BDwLy41-.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-DvGZrhbO.js → Cowork-DFJhLa7K.js} +3 -3
  22. package/src/assets/web-panel/assets/{Cron-DUncZi8h.js → Cron-DYY9RG7-.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-C_hLuUcm.js → Crosschain-rr7tJTtv.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-b6YSUqxr.js → DID-D2sfHRLi.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-uvM15Cfb.js → Dashboard-q_eGdhha.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-D1-Nd4qY.js → Dropdown-Cufrh2Bz.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-8ApvL6Zc.js → EmailListRenderer-B-kdv10f.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-LYJt8811.js → FamilyGuardDashboard-D21XjgfG.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-BbI3HGpv.js → Federation-CAwRTLZH.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-DSoEKuFu.js → FormItemContext-vx3daNDF.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-B0S9OWd5.js → GenericCardRenderer-CRWY2wU4.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-DIs9Zhf3.js → Git-Q6SwauyD.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-jzZXrxcl.js → Governance-BJ1q4IQZ.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-JUPjf2ZI.js → Inference-CSWjROgD.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-DxnfJvlP.js → KnowledgeGraph-fzuQsWuY.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-iXiz8BEE.js → Logs-DVF8Mnns.js} +2 -2
  37. package/src/assets/web-panel/assets/MarkdownRenderer-BLif4QSg.js +1 -0
  38. package/src/assets/web-panel/assets/{Marketplace-Y3Xch312.js → Marketplace-BQP7LOA4.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-D7kGGbO7.js → McpTools-BNlJCmNc.js} +4 -4
  40. package/src/assets/web-panel/assets/{Memory-Do_hVxzh.js → Memory-DLLg5WQ4.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-CtrR0Tas.js → MobileBridge-CR2skNAF.js} +1 -1
  42. package/src/assets/web-panel/assets/MobileProjects-BxVavObl.js +1 -0
  43. package/src/assets/web-panel/assets/{Mtc-qo5QCTGd.js → Mtc-B17pgqMI.js} +4 -4
  44. package/src/assets/web-panel/assets/{MtcAudit-cq5mnjYj.js → MtcAudit-4UmV5cIL.js} +2 -2
  45. package/src/assets/web-panel/assets/{Multisig-Bq0MAQHw.js → Multisig-DoMEXEcU.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-DdWE6Vi2.js → NLProgramming-h9DMXFX4.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-BxMBFcIp.js → Notes-Cihn-xX8.js} +3 -3
  48. package/src/assets/web-panel/assets/{NotificationSettings-RTrAcbUe.js → NotificationSettings-BE6ZGa3R.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-DJbpGqzT.js → OrderTableRenderer-CnwojoSI.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-SQzIPdqC.js → Organization-B2vpwmjb.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-02yECh22.js → Overflow-C4z28R0-.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-BNg4pNCM.js → P2P-BVlFkwhW.js} +2 -2
  53. package/src/assets/web-panel/assets/{PdhVaultBrowser-BxPJZsD3.js → PdhVaultBrowser-BXbEdL5B.js} +3 -3
  54. package/src/assets/web-panel/assets/{Permissions-CLnDnPAz.js → Permissions-C28xs4lp.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-C5m0AjGf.js → PersonalDataHub-Dgl_rBjM.js} +4 -4
  56. package/src/assets/web-panel/assets/{Pipeline-VwOf5Dhv.js → Pipeline-3QUIhrKI.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-CC0W2hZd.js → Privacy-8Gh33OZ5.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-Dz893Bob.js → ProjectInit-BNmg4tZi.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-CxQkvl0k.js → ProjectSettings-vgMfeCf9.js} +2 -2
  60. package/src/assets/web-panel/assets/Projects-BhtAVilc.js +1 -0
  61. package/src/assets/web-panel/assets/{Providers-DeB9IkxK.js → Providers-CXoOa8eX.js} +1 -1
  62. package/src/assets/web-panel/assets/{QrScannerModal-OCeoaswn.js → QrScannerModal-BhfTF0oS.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-DenotaAj.js → QuickAsk-C746HEAj.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-Cies_jjI.js → Recommend-BSej8Eo0.js} +1 -1
  65. package/src/assets/web-panel/assets/RemoteSession-f3gmnlG3.js +5 -0
  66. package/src/assets/web-panel/assets/{Reputation-CW0mvxgZ.js → Reputation-CyvybpkN.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-SEd32qZU.js → Row-DwV2PeYn.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-BSwnJ3Lm.js → RssFeed-11GrzjZy.js} +3 -3
  69. package/src/assets/web-panel/assets/{Search-xe2m8bkC.js → Search-BjKXkrAY.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-Mq2F9Nro.js → Security-eWiFb9Yk.js} +4 -4
  71. package/src/assets/web-panel/assets/{Services-BKGw2V3P.js → Services-CdCsMAtt.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-DW95-Rxf.js → Skeleton-4Q2UTKQ5.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-CHgChCv_.js → Skills-v4rtYrRj.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-tKh6k3R7.js → Sla-CRhsFvd_.js} +1 -1
  75. package/src/assets/web-panel/assets/SpeechSettings-DLjKsDVu.js +1 -0
  76. package/src/assets/web-panel/assets/{SyncSettings-D0Fw8fVL.js → SyncSettings-D16zonl7.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-20x1GB3D.js → Tasks-Xxozz0i_.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-DJ-lts-a.js → Templates-CXJpPtCT.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-BFdGpbs7.js → Tenant-XRV0L1ZF.js} +1 -1
  80. package/src/assets/web-panel/assets/{Terminal-Xpx61vHL.js → Terminal-CYuO1i_w.js} +2 -2
  81. package/src/assets/web-panel/assets/{TimelineRenderer-C6UIvyZQ.js → TimelineRenderer-BXqitWsu.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-Dellq08f.js → Tokens-BvPrDHIy.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-VKw8d0J-.js → Trigger-DhCrSTf5.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-DNftdKT5.js → Trust-DmsuZD6K.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-DX9VAKJI.js → UkeySign-D_yrts5C.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-B2h3jO8q.js → VideoEditing-B01ihPrm.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-CjGkof7f.js → Wallet-DpUjKa-N.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-2Zfcu55P.js → WebAuthn-CL07yON6.js} +4 -4
  89. package/src/assets/web-panel/assets/{WorkflowEditor-B9eZ8UxZ.js → WorkflowEditor-CLMflnRr.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-CQNfD-YO.js → chat-DtUqe8h_.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-D4usyFT2.js → colors-DPKrgVfy.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-s4TpjvjX.js → compact-item-BTt2GtOm.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-BRCSvYxj.js → createContext-D_VeUc1J.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-Bj5nUW2v.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-AdkUbkV-.js → hasIn-1kndiylj.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BIoG5yYf.js → index-2eyAXE3d.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-nXyk8GZ9.js → index-4bna2_SR.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-B2V-eKfK.js → index-8nz_fmlj.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-D_XBHopw.js → index-B9KvcS7R.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-s_buFMEG.js → index-BAXfRKfG.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DZT36ZYq.js → index-BHpBMWCh.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BMcimU-2.js → index-BaZAbw9A.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DzRjHxEv.js → index-BepLZwgB.js} +1 -1
  104. package/src/assets/web-panel/assets/{index--00U6vXZ.js → index-Bhudc_Ez.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-C7Y8Aluc.js → index-BlDNVgBt.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BtobShro.js → index-By5n8up9.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-Cvyt-zhm.js → index-CHG-KcS4.js} +1 -1
  108. package/src/assets/web-panel/assets/index-CPcM-eqo.js +1 -0
  109. package/src/assets/web-panel/assets/{index-MMN9V6JF.js → index-CX81qSM4.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Bad4VNvz.js → index-CauoBQkH.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CCsM_Ybx.js → index-CcO04eDn.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DARsAyUp.js → index-CtF7EN49.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-C5KAQFPQ.js → index-CzjkKUmR.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-RfMr79MW.js → index-D95OFht7.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DdCB70SS.js → index-DFIZ_1Sf.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CYdoQsa1.js → index-DG2MZQ3f.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BPhkFZ1I.js → index-DJ8vXGOa.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-_IRVsV9X.js → index-Dbbymxpj.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DVKfQ0Ux.js → index-DdkplL9R.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CkwiSLhU.js → index-DfGl8CqG.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CJVEOa4i.js → index-DfKBRdSS.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-C1mJtE6q.js → index-DsJCDUJG.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BgiXR_-_.js → index-Dwqmtk65.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CJCFe2Qf.js → index-DxdTdBix.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-C484EJiS.js → index-FzdwcSy2.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-B4JJCfQ2.js → index-GsoUQ2M7.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CQhAVU5t.js → index-brCInrzq.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CKC1t3Ic.js → index-dVc-CXY4.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BQ3DXBtD.js → index-fk2Rjacw.js} +3 -3
  130. package/src/assets/web-panel/assets/{index-Cduu2Hhr.js → index-l1BETrDb.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Bw2MEnUk.js → index-m31Ka8hZ.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-D2GjI2oe.js → index-ocf06EVQ.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-CJdQrZth.js → index-sDoMHTNA.js} +1 -1
  134. package/src/assets/web-panel/assets/index-xeSyVoRe.js +1 -0
  135. package/src/assets/web-panel/assets/{initDefaultProps-Blmpk7HL.js → initDefaultProps-CvyYJd7z.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-DPBJMv1n.js → motion-DYZkhUdz.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-ButdzCM7.js → move-slnJRVT1.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-cyRC_QCe.js → mtc-parser-DVc0CKmy.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-1epSV7hz.js → omit-BCXAtHCq.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-DuPY8xJs.js → pickAttrs-DBsemz_K.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-6XZqarhe.js → placementArrow-BRtkJ-nv.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-B40pXBWM.js → responsiveObserve-Cebq7EZn.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-jbZ9Wu4n.js → slide-DT7qvId2.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-BKQQcVy4.js → statusUtils-pQiITLkG.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-NiKfWjUT.js → styleChecker-c-19BVKQ.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-bQUCvPeb.js → useFlexGapSupport-DsS5-0bE.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-CUGji7ph.js → useFs-CxGiMe5n.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-4veyN2N2.js → usePersonalDataHub-D9btVID5.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-1-nLug-Z.js → vnode-CUYFsFEN.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-dhCeRDMo.js → zoom-CXmn_35j.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/command-help-index.json +1 -1
  153. package/src/commands/cowork.js +559 -62
  154. package/src/commands/plugin.js +819 -64
  155. package/src/commands/session-location.js +318 -7
  156. package/src/constants.js +2 -2
  157. package/src/data/changelog.json +28 -2
  158. package/src/gateways/ws/action-protocol.js +293 -19
  159. package/src/gateways/ws/message-dispatcher.js +30 -0
  160. package/src/gateways/ws/remote-session-protocol.js +542 -35
  161. package/src/gateways/ws/ws-approval-gate.js +5 -0
  162. package/src/gateways/ws/ws-server.js +462 -38
  163. package/src/harness/jsonl-session-store.js +638 -2
  164. package/src/harness/prompt-compressor.js +4 -0
  165. package/src/harness/remote-session-audit.js +1 -0
  166. package/src/harness/remote-session-crypto.js +750 -50
  167. package/src/harness/remote-session-registry.js +795 -27
  168. package/src/lib/auto-mode-config.js +98 -3
  169. package/src/lib/background-agent-keeper-client.js +29 -0
  170. package/src/lib/background-agent-keeper-protocol.js +158 -10
  171. package/src/lib/background-agent-supervisor.js +870 -48
  172. package/src/lib/background-session-transport.js +23 -6
  173. package/src/lib/background-turn-bootstrap-protocol.js +64 -0
  174. package/src/lib/cowork-task-runner.js +70 -0
  175. package/src/lib/cowork-workflow.js +887 -62
  176. package/src/lib/delivery-production-adapter.js +38 -2
  177. package/src/lib/doctor-checkup.js +34 -10
  178. package/src/lib/dynamic-workflow-draft.js +535 -0
  179. package/src/lib/dynamic-workflow-facade.js +1105 -17
  180. package/src/lib/dynamic-workflow-runtime.js +2974 -0
  181. package/src/lib/execution-location-contract.js +111 -7
  182. package/src/lib/execution-location-runtime.js +3 -1
  183. package/src/lib/execution-location-target.js +910 -0
  184. package/src/lib/llm-providers.js +1 -0
  185. package/src/lib/mcp-call-ledger-store.js +35 -0
  186. package/src/lib/mcp-call-ledger.js +30 -0
  187. package/src/lib/mcp-stdio-package-materialization.js +1 -1
  188. package/src/lib/plugin-runtime/__tests__/remote-source.test.js +34 -16
  189. package/src/lib/plugin-runtime/install.js +4956 -657
  190. package/src/lib/plugin-runtime/manifest.js +3 -1
  191. package/src/lib/plugin-runtime/marketplace-artifact-readback.js +671 -31
  192. package/src/lib/plugin-runtime/marketplace-catalog.js +68 -2
  193. package/src/lib/plugin-runtime/marketplace-impact.js +208 -15
  194. package/src/lib/plugin-runtime/marketplace-network.js +317 -0
  195. package/src/lib/plugin-runtime/marketplace-pac-worker.js +15 -0
  196. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +25 -2
  197. package/src/lib/plugin-runtime/marketplace-source-cache.js +359 -0
  198. package/src/lib/plugin-runtime/policy.js +21 -6
  199. package/src/lib/plugin-runtime/publisher-trust.js +332 -0
  200. package/src/lib/plugin-runtime/remote-source.js +323 -27
  201. package/src/lib/plugin-runtime/scopes.js +317 -41
  202. package/src/lib/plugin-runtime/transaction-journal.js +806 -0
  203. package/src/lib/public-ide-capability-manifest.js +1 -1
  204. package/src/lib/remote-approval-bridge.js +745 -108
  205. package/src/lib/remote-control.js +2 -0
  206. package/src/lib/remote-membership-coordinator.js +612 -46
  207. package/src/lib/remote-membership-host-store.js +59 -10
  208. package/src/lib/runtime-provenance-ledger.js +171 -46
  209. package/src/lib/shell-approval.js +169 -6
  210. package/src/lib/sub-agent-context.js +268 -2
  211. package/src/lib/task-model-selector.js +1 -1
  212. package/src/lib/with-file-lock.js +167 -42
  213. package/src/repl/agent-repl.js +70 -29
  214. package/src/repl/remote-approval.js +29 -7
  215. package/src/runtime/agent-core.js +1695 -194
  216. package/src/runtime/headless-runner.js +22 -5
  217. package/src/runtime/headless-stream.js +19 -3
  218. package/src/workers/background-agent-keeper.js +279 -58
  219. package/src/workers/background-agent-worker.js +7 -0
  220. package/src/workers/background-turn-bootstrap.js +29 -2
  221. package/src/assets/web-panel/assets/MarkdownRenderer-GmB6DOr6.js +0 -1
  222. package/src/assets/web-panel/assets/MobileProjects-BL0Czcoj.js +0 -1
  223. package/src/assets/web-panel/assets/Projects-DDAjkUkT.js +0 -1
  224. package/src/assets/web-panel/assets/RemoteSession-Dxzl5n2T.js +0 -5
  225. package/src/assets/web-panel/assets/SpeechSettings-D6UL3dA5.js +0 -1
  226. package/src/assets/web-panel/assets/devWarning-DKJjSWRn.js +0 -1
  227. package/src/assets/web-panel/assets/index-C61cnl3K.js +0 -1
  228. 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
- BigInt(payload.sessionEpoch) < BigInt(sessionSnapshot.sessionEpoch)
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
- (sessionSnapshot.status !== "active" ||
931
- payload.status !== "closed")) ||
932
- sessionSnapshot.status === "closed"
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
- challenge.purpose !== "session.resume" ||
1595
- challenge.scopes !== null
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 - Immutable audit trail for runtime provenance
2
+ * RuntimeProvenanceLedger - bounded, hash-chained runtime provenance.
3
3
  *
4
- * Records every context source, tool call, and response that flows through
5
- * the CLI runtime. Provides hash-chained immutability guarantees.
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._entries = [];
13
- this._lastHash = options.genesisHash || "0000000000000000000000000000000000000000000000000000000000000000";
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 hash chaining for immutability
179
+ * Append an entry with an absolute index and hash-chain binding.
99
180
  */
100
181
  _append(entry) {
101
- const entryWithHash = {
102
- ...entry,
103
- index: this._entries.length,
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
- // Compute hash
107
- const hash = createHash("sha256")
108
- .update(JSON.stringify(entryWithHash))
109
- .digest("hex");
110
- entryWithHash.hash = hash;
111
- this._entries.push(entryWithHash);
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 entire chain integrity
218
+ * Verify the retained suffix and its independently stored boundary anchor.
127
219
  */
128
220
  verifyIntegrity() {
129
- let currentHash = this._entries[0]?.prevHash || "0".repeat(64);
130
- for (const entry of this._entries) {
131
- const { hash, prevHash, ...rest } = entry;
132
- if (prevHash !== currentHash) return false;
133
- const computed = createHash("sha256").update(JSON.stringify({ ...rest, prevHash: currentHash })).digest("hex");
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 true;
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 all entries for a trace
251
+ * Get retained entries for a trace.
142
252
  */
143
253
  getTraceEntries(traceId) {
144
- const indices = this._traceIndex.get(traceId) || [];
145
- return indices.map(i => this._entries[i]);
254
+ return this._indexedEntries(this._traceIndex, traceId);
146
255
  }
147
256
 
148
257
  /**
149
- * Get all entries for a span
258
+ * Get retained entries for a span.
150
259
  */
151
260
  getSpanEntries(spanId) {
152
- const indices = this._spanIndex.get(spanId) || [];
153
- return indices.map(i => this._entries[i]);
261
+ return this._indexedEntries(this._spanIndex, spanId);
154
262
  }
155
263
 
156
264
  /**
157
- * Get provenance chain for a response
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 [...this._entries];
270
+ return this._retainedEntries();
163
271
  }
164
272
 
165
273
  /**
166
- * Export ledger to JSON (for persistence/debugging)
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
- genesisHash: this._entries[0]?.prevHash,
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: this._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 we're in-memory
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: process.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
- recordInstallCommandAudit(
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: { command },
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,