chainlesschain 0.166.82 → 0.166.83

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 (183) hide show
  1. package/package.json +1 -1
  2. package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
  3. package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-DMzLSUWK.js → AIOps-D5a4i3N7.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-CgnA23oA.js → ActionButton-DxsRk5n1.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-CtXmm8Qe.js → Analytics-D-7EvH4S.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-C5RIh5jA.js → AppLayout-DDEWVr-d.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-DM525zx0.js → Artifacts-CAlJAjRB.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-ChBx6f2l.js → Audit-tuaWDOAM.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-BBHDxCda.js → BackgroundAgents-CIwRFJ50.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-B-qzCAoM.js → Backup-CpBepJlH.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-C5yoIWAD.js → BaseInput-eKguCzQc.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-NmTrci9a.js → Chat-CFrUfXDV.js} +5 -5
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-pPuUDG2V.js → ChatBubbleRenderer-DaRtY87l.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-KdFSU3vd.js → Checkbox-o5FEn6a1.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-L__BOv_4.js → Codegen-Dih8HogC.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-Dfuw4IQV.js → Col-D5r-6WZe.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-BRlEhSbx.js → Community-jeQ6bGey.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-D7dRkv8n.js → Compact-CEP7QsWp.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-CdlFYNR3.js → Compliance-B8NydOHd.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-Ey7ksHq4.js → Cowork-Bmi1zuPy.js} +3 -3
  22. package/src/assets/web-panel/assets/{Cron-DBH__wGJ.js → Cron-BAL9bwSp.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-D3nu9dw7.js → Crosschain-D8WUi2dS.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-DS6vZBNv.js → DID-CQCkYcLY.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-DwFRk2T0.js → Dashboard-DogXg6kh.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-D7b73q3I.js → Dropdown-BJBJyQJn.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-DPNaVH36.js → EmailListRenderer-CxPWquJx.js} +1 -1
  28. package/src/assets/web-panel/assets/{EvolutionSettings-BEsOtdpf.js → EvolutionSettings-BijH1x8G.js} +1 -1
  29. package/src/assets/web-panel/assets/{FamilyGuardDashboard-ijSqsSsF.js → FamilyGuardDashboard-DStwf-00.js} +1 -1
  30. package/src/assets/web-panel/assets/{Federation-C0BOzPDh.js → Federation-LU9_sNxC.js} +1 -1
  31. package/src/assets/web-panel/assets/{FormItemContext-DkF5NoAg.js → FormItemContext-DNfWhj7P.js} +1 -1
  32. package/src/assets/web-panel/assets/{GenericCardRenderer-DQsMcyJj.js → GenericCardRenderer-DWYsPjzk.js} +1 -1
  33. package/src/assets/web-panel/assets/{Git-DQRt88PU.js → Git-CA0O9ulB.js} +2 -2
  34. package/src/assets/web-panel/assets/{Governance-DIjPmDN8.js → Governance-ECShL7BJ.js} +1 -1
  35. package/src/assets/web-panel/assets/{Inference-BWMFtT7i.js → Inference-9GA2542e.js} +1 -1
  36. package/src/assets/web-panel/assets/{KnowledgeGraph-M7TfkUVl.js → KnowledgeGraph-nC5mTbEH.js} +1 -1
  37. package/src/assets/web-panel/assets/{Logs-BZv9Z6BY.js → Logs-B7IqgnDy.js} +2 -2
  38. package/src/assets/web-panel/assets/MarkdownRenderer-BqlqrJkY.js +1 -0
  39. package/src/assets/web-panel/assets/{Marketplace-Crd9MYHg.js → Marketplace-CEr0suM8.js} +1 -1
  40. package/src/assets/web-panel/assets/{McpTools-C37yOQV0.js → McpTools-DhTPQKOE.js} +3 -3
  41. package/src/assets/web-panel/assets/{Memory-BBsijJCd.js → Memory-mHRZP1w4.js} +2 -2
  42. package/src/assets/web-panel/assets/{MobileBridge-CiXIQCju.js → MobileBridge-BNfX6Rdo.js} +1 -1
  43. package/src/assets/web-panel/assets/{MobileProjects-C0KSvQm5.js → MobileProjects-8zG8f5li.js} +1 -1
  44. package/src/assets/web-panel/assets/{Mtc-C0XaQsOY.js → Mtc-CzkV3wsn.js} +2 -2
  45. package/src/assets/web-panel/assets/{MtcAudit-DPqggKhw.js → MtcAudit-DWYljJik.js} +2 -2
  46. package/src/assets/web-panel/assets/{Multisig-Bie0ZVHe.js → Multisig-kHgtvZY_.js} +3 -3
  47. package/src/assets/web-panel/assets/{NLProgramming-BbuJlQ5b.js → NLProgramming-56uQiPiY.js} +1 -1
  48. package/src/assets/web-panel/assets/{Notes-CgqrJV8w.js → Notes-DxGOZqRf.js} +3 -3
  49. package/src/assets/web-panel/assets/{NotificationSettings-CusdZEQl.js → NotificationSettings-DabaCpmo.js} +1 -1
  50. package/src/assets/web-panel/assets/{OrderTableRenderer-B7RrCvCQ.js → OrderTableRenderer-SzeQNlGT.js} +1 -1
  51. package/src/assets/web-panel/assets/{Organization-BnFpz3bb.js → Organization-D9gnPpK2.js} +4 -4
  52. package/src/assets/web-panel/assets/{Overflow-C_4_HyyZ.js → Overflow-Cqp_bXm4.js} +1 -1
  53. package/src/assets/web-panel/assets/{P2P-D0KpHxeg.js → P2P-DTeK-r0G.js} +2 -2
  54. package/src/assets/web-panel/assets/PdhVaultBrowser-CsjG85GT.js +7 -0
  55. package/src/assets/web-panel/assets/{Permissions-D2LxL66N.js → Permissions-B4ofZq3j.js} +4 -4
  56. package/src/assets/web-panel/assets/{PersonalDataHub-CvSNIxt0.js → PersonalDataHub-Cvas5cYd.js} +4 -4
  57. package/src/assets/web-panel/assets/{Pipeline-rUl-SM7V.js → Pipeline-Er3wmAew.js} +1 -1
  58. package/src/assets/web-panel/assets/{Privacy-BD8cWSNd.js → Privacy-DMFYeZox.js} +1 -1
  59. package/src/assets/web-panel/assets/{ProjectInit-RM7J4X2F.js → ProjectInit-DaVaYPy0.js} +2 -2
  60. package/src/assets/web-panel/assets/{ProjectSettings-BIH38RsB.js → ProjectSettings-dPx5q2Ac.js} +2 -2
  61. package/src/assets/web-panel/assets/Projects-N0JNeCui.js +1 -0
  62. package/src/assets/web-panel/assets/{Providers-B9Kja2RK.js → Providers-BPQo_gQa.js} +1 -1
  63. package/src/assets/web-panel/assets/{QrScannerModal-ByDKowTD.js → QrScannerModal-CD-sEsWh.js} +1 -1
  64. package/src/assets/web-panel/assets/{QuickAsk-DqEN1QOE.js → QuickAsk-LOKRJiN_.js} +1 -1
  65. package/src/assets/web-panel/assets/{Recommend-CLrYwNiv.js → Recommend-BwPXqcWy.js} +1 -1
  66. package/src/assets/web-panel/assets/{RemoteSession-DyDltVPC.js → RemoteSession-BjotndxF.js} +3 -3
  67. package/src/assets/web-panel/assets/{Reputation-BfP8rJ1-.js → Reputation-BlZ2gcbU.js} +1 -1
  68. package/src/assets/web-panel/assets/{Row-BpnP6r1H.js → Row-D399HM-d.js} +1 -1
  69. package/src/assets/web-panel/assets/{RssFeed-CBNI1lCN.js → RssFeed-C7H-ibnY.js} +2 -2
  70. package/src/assets/web-panel/assets/{Search-CLjrM-xj.js → Search-CNHCVmM1.js} +1 -1
  71. package/src/assets/web-panel/assets/{Security-dRXtg-Mq.js → Security-C70eDGYY.js} +3 -3
  72. package/src/assets/web-panel/assets/{Services-DAHCtOHL.js → Services-6xfq9G-H.js} +2 -2
  73. package/src/assets/web-panel/assets/{Skeleton-D11Jgtur.js → Skeleton-BbY2zeZV.js} +1 -1
  74. package/src/assets/web-panel/assets/{Skills-DchvTO4k.js → Skills-DYtyZ7_6.js} +1 -1
  75. package/src/assets/web-panel/assets/{Sla-BFOc2SbL.js → Sla-CkWcl5OH.js} +1 -1
  76. package/src/assets/web-panel/assets/{SpeechSettings-Dud1xDd2.js → SpeechSettings-CiknYk2P.js} +1 -1
  77. package/src/assets/web-panel/assets/{SyncSettings-CILfsA2S.js → SyncSettings-D-8JVip4.js} +2 -2
  78. package/src/assets/web-panel/assets/{Tasks-C6Qrah_5.js → Tasks-B2KnR9XC.js} +1 -1
  79. package/src/assets/web-panel/assets/{Templates--puiHyCR.js → Templates-CipXkOE-.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tenant-cz5vITz_.js → Tenant-DbwgIMmx.js} +1 -1
  81. package/src/assets/web-panel/assets/{Terminal-YRs75Gz8.js → Terminal-OtCriHEE.js} +2 -2
  82. package/src/assets/web-panel/assets/{TimelineRenderer-C5myb_QZ.js → TimelineRenderer-B9LU5qrl.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tokens-Bk60iMIj.js → Tokens-B4iFVxvH.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trigger-BAb-Fd4z.js → Trigger-BegM2v8q.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trust-BlqwmpEB.js → Trust-COkqnnFj.js} +1 -1
  86. package/src/assets/web-panel/assets/{UkeySign-C6jvuF-7.js → UkeySign-BzqKPChj.js} +1 -1
  87. package/src/assets/web-panel/assets/{VideoEditing-7zbsdQUj.js → VideoEditing-D-F2XL3C.js} +1 -1
  88. package/src/assets/web-panel/assets/{Wallet-BAouk_kp.js → Wallet-22PzRY9T.js} +4 -4
  89. package/src/assets/web-panel/assets/{WebAuthn-BQapv504.js → WebAuthn-eSMq_qtz.js} +5 -5
  90. package/src/assets/web-panel/assets/{WorkflowEditor-ChUXM-Qx.js → WorkflowEditor-BvdAakpq.js} +1 -1
  91. package/src/assets/web-panel/assets/{chat-7B6U8zgJ.js → chat-C6jhpF7E.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-C8UqaLpe.js → colors-BbbW2Pfv.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-x47giTCj.js → compact-item-CVFeLTqt.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-D6ZwjgaZ.js → createContext-DS0m7NZc.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-D50gzPS9.js +1 -0
  96. package/src/assets/web-panel/assets/{hasIn-Cv3d9-Bu.js → hasIn-DVouP0t6.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-DVBG0Jqz.js → index--AdzSlH7.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CXIUyx4U.js → index-54aHB4FL.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-WhoNHp50.js → index-8QbwhE3i.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-Dv5E07PZ.js → index-B5JRIZXi.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BTBkdyLk.js → index-B8a_c_qZ.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-DtBUgc0G.js → index-BE_u-rXr.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BMPk5D1m.js → index-BOOsA080.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-jgN2e0Oy.js → index-BXw6ivB8.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CUtcWTSe.js → index-BaUah6TO.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DD-V-N_m.js → index-Be12HoCS.js} +3 -3
  107. package/src/assets/web-panel/assets/{index-CaPZ_8kP.js → index-BhvnNFfd.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-C1ElqYDD.js → index-BrIv7C9a.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CrGQsbpb.js → index-BvCgzl0X.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-D4ZHX6wo.js → index-Bw-ZGQCH.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CXG6yiAf.js → index-BwZnPiFd.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-Ce666S9v.js → index-BwozzG6k.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BTisPSqa.js → index-ByLsH9CL.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-dbM4QvQZ.js → index-BzL3LWFX.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CUUgXcPh.js → index-C4xmLgLa.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-Dc0hePXV.js → index-C6q2MkIG.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CiVEatgH.js → index-C74emdKD.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BGxo1YH0.js → index-CIg4nqyp.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Cc2bhSuI.js → index-CIk7mg6G.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BM-NYjej.js → index-CPS8E-J6.js} +1 -1
  121. package/src/assets/web-panel/assets/index-CgensV-n.js +1 -0
  122. package/src/assets/web-panel/assets/{index-D9lFBkS4.js → index-CkdYB0_g.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CQ0-ny-o.js → index-CpTbnbUI.js} +1 -1
  124. package/src/assets/web-panel/assets/index-Ctkf06Z_.js +1 -0
  125. package/src/assets/web-panel/assets/{index-Cc6jr0Yb.js → index-CwYFDMn_.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DLHnYXVa.js → index-DGYX17YW.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DvoMGeL9.js → index-DR6TDz5H.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-EDWA9JL1.js → index-DUBkae39.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-yYdCdtY1.js → index-DotRL126.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Cbf4RqOd.js → index-DpReoAGb.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-N9hNOl1i.js → index-Ds4wbrgk.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-IVelXaiQ.js → index-DuVjTDcW.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-BUzw-kDo.js → index-JeJqXbUU.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-nogjrcQE.js → index-SdFkCtiC.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-B7Dorc7r.js → index-eaXEQFuP.js} +1 -1
  136. package/src/assets/web-panel/assets/{initDefaultProps-DkKS5xtR.js → initDefaultProps-CB5cUnQ5.js} +1 -1
  137. package/src/assets/web-panel/assets/{motion-CU-zBUIg.js → motion-bn_fWhQV.js} +1 -1
  138. package/src/assets/web-panel/assets/{move-zBE0VEd4.js → move-DY4-Odtu.js} +1 -1
  139. package/src/assets/web-panel/assets/{mtc-parser-B9WyO1je.js → mtc-parser-B5l5mjoh.js} +1 -1
  140. package/src/assets/web-panel/assets/{omit-6sCoBNTL.js → omit-rJ-Ci8CW.js} +1 -1
  141. package/src/assets/web-panel/assets/{pickAttrs-DDRv_sFc.js → pickAttrs-BMwGJd6C.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-Cy_CBDw5.js → placementArrow-CaiQyGXG.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-CIczLq9K.js → responsiveObserve-DQTO5wDH.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-DFfZCvnG.js → slide-Dg6ZDtbz.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-DW-0HUl-.js → statusUtils-bvjrktKc.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-BPYaBorP.js → styleChecker-C1geIU_x.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-DYPoOaZc.js → useFlexGapSupport-BzU3RJRi.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-ODUEWR17.js → useFs-B7l6OwLe.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-CstUt15X.js → usePersonalDataHub-BYF1L_8x.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-D2GW8xCL.js → vnode-6c2GVkT-.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-Bz6GoDwq.js → zoom-BYAY6QeD.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/commands/agent.js +21 -10
  154. package/src/data/changelog.json +26 -0
  155. package/src/gateways/ws/session-protocol.js +19 -5
  156. package/src/gateways/ws/ws-agent-handler.js +6 -0
  157. package/src/gateways/ws/ws-session-gateway.js +133 -21
  158. package/src/lib/agent-execution-policy.js +177 -0
  159. package/src/lib/authority-launch-environment.js +99 -0
  160. package/src/lib/claude-project-auto-memory.js +7 -30
  161. package/src/lib/evolution/volcengine-function-replay-store.js +38 -28
  162. package/src/lib/host-tool-policy-authority.js +151 -0
  163. package/src/lib/permission-authority.js +67 -5
  164. package/src/lib/plugin-runtime/settings.js +9 -1
  165. package/src/lib/sandbox-egress-authority-monitor.js +3 -2
  166. package/src/lib/session-manager.js +20 -5
  167. package/src/lib/settings-loader.cjs +175 -19
  168. package/src/lib/settings-source-observation.cjs +270 -0
  169. package/src/lib/sub-agent-context.js +36 -18
  170. package/src/lib/unattended-action-policy.js +456 -38
  171. package/src/repl/agent-repl.js +43 -15
  172. package/src/repl/repl-tool-executor.js +39 -0
  173. package/src/runtime/agent-core.js +272 -5
  174. package/src/runtime/agent-runtime.js +15 -3
  175. package/src/runtime/headless-runner.js +13 -4
  176. package/src/runtime/headless-stream.js +9 -0
  177. package/src/runtime/policies/agent-policy.js +5 -4
  178. package/src/assets/web-panel/assets/MarkdownRenderer-D5NZGdg3.js +0 -1
  179. package/src/assets/web-panel/assets/PdhVaultBrowser-Cfd_C9nc.js +0 -7
  180. package/src/assets/web-panel/assets/Projects-CTgx3Fxc.js +0 -1
  181. package/src/assets/web-panel/assets/devWarning-BFfV5AtN.js +0 -1
  182. package/src/assets/web-panel/assets/index-DUz_bv5i.js +0 -1
  183. package/src/assets/web-panel/assets/index-rQ59l7GO.js +0 -1
@@ -687,37 +687,47 @@ export function captureVolcengineFunctionReplayStore(value) {
687
687
  "A branded Volcengine function replay store is required",
688
688
  );
689
689
  }
690
+ function readRevocation() {
691
+ try {
692
+ const revocation = readRevocationRecord(
693
+ captured.revocationPath,
694
+ captured.descriptor,
695
+ );
696
+ return Object.freeze({
697
+ schema: revocation.schema,
698
+ replayStoreId: revocation.replayStoreId,
699
+ authorityId: revocation.authorityId,
700
+ revocationAuthorityId: revocation.revocationAuthorityId,
701
+ tenantId: revocation.tenantId,
702
+ handlerArtifactDigest: revocation.handlerArtifactDigest,
703
+ policyRevision: revocation.policyRevision,
704
+ revocationId: revocation.revocationId,
705
+ reasonDigest: revocation.reasonDigest,
706
+ authorizationRequestDigest: revocation.authorizationRequestDigest,
707
+ authorizationEvidenceDigest: revocation.authorizationEvidenceDigest,
708
+ auditEventDigest: revocation.auditEventDigest,
709
+ durabilityReceiptDigest: revocation.durabilityReceiptDigest,
710
+ evidenceResolverDigest: revocation.evidenceResolverDigest,
711
+ evidenceReadbackDigest: revocation.evidenceReadbackDigest,
712
+ revokedAt: revocation.revokedAt,
713
+ revocationDigest: revocation.revocationDigest,
714
+ });
715
+ } catch (error) {
716
+ if (error?.code === "ENOENT") return null;
717
+ throw error;
718
+ }
719
+ }
690
720
  return Object.freeze({
691
721
  descriptor: captured.descriptor,
692
722
  readRevocation() {
693
- try {
694
- const revocation = readRevocationRecord(
695
- captured.revocationPath,
696
- captured.descriptor,
697
- );
698
- return Object.freeze({
699
- schema: revocation.schema,
700
- replayStoreId: revocation.replayStoreId,
701
- authorityId: revocation.authorityId,
702
- revocationAuthorityId: revocation.revocationAuthorityId,
703
- tenantId: revocation.tenantId,
704
- handlerArtifactDigest: revocation.handlerArtifactDigest,
705
- policyRevision: revocation.policyRevision,
706
- revocationId: revocation.revocationId,
707
- reasonDigest: revocation.reasonDigest,
708
- authorizationRequestDigest: revocation.authorizationRequestDigest,
709
- authorizationEvidenceDigest: revocation.authorizationEvidenceDigest,
710
- auditEventDigest: revocation.auditEventDigest,
711
- durabilityReceiptDigest: revocation.durabilityReceiptDigest,
712
- evidenceResolverDigest: revocation.evidenceResolverDigest,
713
- evidenceReadbackDigest: revocation.evidenceReadbackDigest,
714
- revokedAt: revocation.revokedAt,
715
- revocationDigest: revocation.revocationDigest,
716
- });
717
- } catch (error) {
718
- if (error?.code === "ENOENT") return null;
719
- throw error;
720
- }
723
+ // A revocation is created exclusively at its final path. Serialize
724
+ // readback with the official writer so a live publication's partial
725
+ // bytes cannot masquerade as a corrupt crash record. After a failed or
726
+ // dead writer releases its lock, incomplete records still fail closed.
727
+ return withFileLock(captured.lockTarget, readRevocation, {
728
+ failIfUnavailable: true,
729
+ timeoutMs: 5_000,
730
+ });
721
731
  },
722
732
  revoke(value) {
723
733
  const revocation = normalizeRevocation(value, captured.descriptor);
@@ -0,0 +1,151 @@
1
+ /** Host-owned policy snapshots and synchronous, irreversible revisions.
2
+ * Revisions cover commits through this owner in this process. Persisting a
3
+ * session's latest policy does not make these revisions a durable journal.
4
+ */
5
+ import { randomUUID } from "node:crypto";
6
+ import { snapshotMcpJsonRpcInput } from "./mcp-call-ledger.js";
7
+
8
+ const AUTHORITIES = new WeakSet();
9
+ const CHILD_AUTHORITIES = new WeakMap();
10
+
11
+ function unavailable() {
12
+ const error = new Error("Host tool policy authority is unavailable");
13
+ error.code = "CC_HOST_TOOL_POLICY_AUTHORITY_UNAVAILABLE";
14
+ return error;
15
+ }
16
+
17
+ function capturePolicy(policy) {
18
+ if (policy == null) return null;
19
+ try {
20
+ const snapshot = snapshotMcpJsonRpcInput(policy);
21
+ if (typeof snapshot !== "object" || Array.isArray(snapshot))
22
+ throw unavailable();
23
+ for (const field of ["tools", "toolPolicies"]) {
24
+ const policies = snapshot[field];
25
+ if (policies == null) continue;
26
+ if (typeof policies !== "object" || Array.isArray(policies))
27
+ throw unavailable();
28
+ for (const entry of Object.values(policies)) {
29
+ if (!entry || typeof entry !== "object" || Array.isArray(entry))
30
+ throw unavailable();
31
+ for (const flag of [
32
+ "allowed",
33
+ "requiresConfirmation",
34
+ "requiresPlanApproval",
35
+ "isReadOnly",
36
+ ]) {
37
+ if (entry[flag] !== undefined && typeof entry[flag] !== "boolean")
38
+ throw unavailable();
39
+ }
40
+ if (entry.decision !== undefined && typeof entry.decision !== "string")
41
+ throw unavailable();
42
+ }
43
+ }
44
+ if (
45
+ snapshot.toolDefinitions !== undefined &&
46
+ !Array.isArray(snapshot.toolDefinitions)
47
+ )
48
+ throw unavailable();
49
+ return snapshot;
50
+ } catch {
51
+ throw unavailable();
52
+ }
53
+ }
54
+
55
+ export function captureHostToolPolicyAuthority(authority) {
56
+ if (authority == null) return null;
57
+ if (!AUTHORITIES.has(authority)) throw unavailable();
58
+ return authority;
59
+ }
60
+
61
+ /** The host retains the controller; consumers receive only `authority`. */
62
+ export function createHostToolPolicyAuthority(policy = null) {
63
+ const ownerId = randomUUID();
64
+ let snapshot = Object.freeze({
65
+ schema: "chainlesschain.host-tool-policy-authority/v1",
66
+ ownerId,
67
+ revision: 0,
68
+ policy: capturePolicy(policy),
69
+ });
70
+ let invalid = false;
71
+ const listeners = new Set();
72
+ function publish(nextPolicy) {
73
+ if (snapshot.revision >= Number.MAX_SAFE_INTEGER) throw unavailable();
74
+ snapshot = Object.freeze({
75
+ ...snapshot,
76
+ revision: snapshot.revision + 1,
77
+ policy: nextPolicy,
78
+ });
79
+ // Commit before notifying. A failing observer cannot hide a revision from
80
+ // the remaining execution monitors.
81
+ for (const listener of [...listeners]) {
82
+ try {
83
+ listener(snapshot);
84
+ } catch {
85
+ // Observer delivery does not roll back committed authority.
86
+ }
87
+ }
88
+ return snapshot;
89
+ }
90
+ const authority = Object.freeze({
91
+ getSnapshot() {
92
+ if (invalid) throw unavailable();
93
+ return snapshot;
94
+ },
95
+ subscribePolicyRevision(listener) {
96
+ if (typeof listener !== "function")
97
+ throw new TypeError("listener required");
98
+ listeners.add(listener);
99
+ return () => listeners.delete(listener);
100
+ },
101
+ });
102
+ AUTHORITIES.add(authority);
103
+ return Object.freeze({
104
+ authority,
105
+ commit(nextPolicy) {
106
+ const captured = capturePolicy(nextPolicy);
107
+ if (
108
+ !invalid &&
109
+ JSON.stringify(captured) === JSON.stringify(snapshot.policy)
110
+ )
111
+ return snapshot;
112
+ invalid = false;
113
+ return publish(captured);
114
+ },
115
+ invalidate() {
116
+ invalid = true;
117
+ return publish(snapshot.policy);
118
+ },
119
+ });
120
+ }
121
+
122
+ /** Inherit the live ceiling without introducing host definitions into a child. */
123
+ export function hostToolPolicyAuthorityForChild(value) {
124
+ const parent = captureHostToolPolicyAuthority(value);
125
+ if (!parent) return null;
126
+ if (CHILD_AUTHORITIES.has(parent)) return CHILD_AUTHORITIES.get(parent);
127
+ let previous = null;
128
+ let projected = null;
129
+ const child = Object.freeze({
130
+ getSnapshot() {
131
+ const current = parent.getSnapshot();
132
+ if (current !== previous) {
133
+ projected = Object.freeze({
134
+ ...current,
135
+ policy: current.policy
136
+ ? Object.freeze({
137
+ ...current.policy,
138
+ toolDefinitions: Object.freeze([]),
139
+ })
140
+ : null,
141
+ });
142
+ previous = current;
143
+ }
144
+ return projected;
145
+ },
146
+ subscribePolicyRevision: parent.subscribePolicyRevision,
147
+ });
148
+ AUTHORITIES.add(child);
149
+ CHILD_AUTHORITIES.set(parent, child);
150
+ return child;
151
+ }
@@ -1,14 +1,42 @@
1
1
  /** Resolve static settings plus CLI-owned workspace-scoped permission rules. */
2
2
 
3
3
  import settingsLoader from "./settings-loader.cjs";
4
+ import path from "node:path";
4
5
  import { ScopedPermissionStore } from "./scoped-permission-store.js";
5
6
 
6
- const { applyManagedPermissionPolicy, loadSettings } = settingsLoader;
7
+ const {
8
+ applyManagedPermissionPolicy,
9
+ loadSettings,
10
+ getSettingsPermissionRevision,
11
+ subscribeSettingsPermissionRevision,
12
+ } = settingsLoader;
7
13
  const KINDS = ["allow", "ask", "deny"];
14
+ const providers = new WeakMap();
15
+ const settingsAuthority = Object.freeze({
16
+ getSnapshot: getSettingsPermissionRevision,
17
+ subscribePolicyRevision: subscribeSettingsPermissionRevision,
18
+ });
19
+
20
+ function freezeSnapshot(value) {
21
+ if (value && typeof value === "object") {
22
+ for (const child of Object.values(value)) freezeSnapshot(child);
23
+ Object.freeze(value);
24
+ }
25
+ return value;
26
+ }
8
27
 
9
28
  function cloneRules(rules) {
10
29
  return Object.fromEntries(
11
- KINDS.map((kind) => [kind, [...(rules?.[kind] || [])]]),
30
+ KINDS.map((kind) => {
31
+ const entries = rules?.[kind] ?? [];
32
+ if (
33
+ !Array.isArray(entries) ||
34
+ entries.some((entry) => typeof entry !== "string")
35
+ ) {
36
+ throw new TypeError(`permission ${kind} rules must be a string array`);
37
+ }
38
+ return [kind, [...entries]];
39
+ }),
12
40
  );
13
41
  }
14
42
 
@@ -24,6 +52,7 @@ export function loadPermissionAuthority({
24
52
  baseRules = null,
25
53
  scopedStore = null,
26
54
  } = {}) {
55
+ const settingsRevision = getSettingsPermissionRevision();
27
56
  const loaded = loadSettings({
28
57
  cwd,
29
58
  settingsFile,
@@ -63,15 +92,48 @@ export function loadPermissionAuthority({
63
92
  }
64
93
  }
65
94
 
66
- return {
95
+ if (getSettingsPermissionRevision() !== settingsRevision) {
96
+ const error = new Error(
97
+ "settings changed while permission authority was loading",
98
+ );
99
+ error.code = "CC_SETTINGS_PERMISSION_AUTHORITY_CHANGED";
100
+ throw error;
101
+ }
102
+ return freezeSnapshot({
67
103
  ...loaded,
68
104
  rules,
69
105
  sources,
70
106
  scoped,
71
107
  hasRules: hasRules(rules),
72
- };
108
+ settingsRevision,
109
+ });
73
110
  }
74
111
 
75
112
  export function createPermissionRulesProvider(options = {}) {
76
- return () => loadPermissionAuthority(options);
113
+ const cwd = path.resolve(options.cwd || process.cwd());
114
+ const captured = Object.freeze({
115
+ cwd,
116
+ settingsFile: options.settingsFile
117
+ ? path.resolve(cwd, options.settingsFile)
118
+ : null,
119
+ managedSettingsFile: options.managedSettingsFile
120
+ ? path.resolve(options.managedSettingsFile)
121
+ : null,
122
+ // Environment kill switches retain live sampling semantics. The source
123
+ // object cannot be replaced through later changes to the options object.
124
+ env: options.env || process.env,
125
+ baseRules: options.baseRules
126
+ ? freezeSnapshot(cloneRules(options.baseRules))
127
+ : null,
128
+ scopedStore: options.scopedStore || null,
129
+ });
130
+ const provider = () => loadPermissionAuthority(captured);
131
+ providers.set(provider, settingsAuthority);
132
+ return Object.freeze(provider);
133
+ }
134
+
135
+ // A legacy callback cannot advertise a trusted revision subscription simply
136
+ // by copying properties onto itself. It still receives sampled revalidation.
137
+ export function permissionRulesProviderAuthority(provider) {
138
+ return providers.get(provider) || null;
77
139
  }
@@ -17,6 +17,10 @@
17
17
  import fs from "fs";
18
18
  import { discoverPlugins } from "./scopes.js";
19
19
  import { partitionByTrust, warnUntrustedOnce } from "./trust.js";
20
+ import {
21
+ isPluginAuthorityEnvironmentKey,
22
+ isValidEnvironmentKey,
23
+ } from "../authority-launch-environment.js";
20
24
 
21
25
  export const _deps = { readFileSync: fs.readFileSync };
22
26
 
@@ -68,7 +72,11 @@ export function collectPluginSettings(opts = {}) {
68
72
  !Array.isArray(parsed.env)
69
73
  ) {
70
74
  for (const [k, v] of Object.entries(parsed.env)) {
71
- if (typeof v === "string") {
75
+ if (
76
+ typeof v === "string" &&
77
+ isValidEnvironmentKey(k) &&
78
+ !isPluginAuthorityEnvironmentKey(k)
79
+ ) {
72
80
  env[k] = v;
73
81
  contributed = true;
74
82
  }
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Recheck the live shell authority while a Docker egress session exists. This
3
- * is a bounded poll, not a lossless revision subscription: changes that are
4
- * reverted between checks cannot be observed.
3
+ * uses bounded polling as a fallback. Trusted policy owners also call revoke()
4
+ * synchronously on official revisions; unobserved external changes reverted
5
+ * between polls remain outside that event guarantee.
5
6
  */
6
7
  export function createDockerEgressAuthorityMonitor({
7
8
  revalidate,
@@ -108,7 +108,7 @@ export function saveMessages(db, sessionId, messages, metadata) {
108
108
  /**
109
109
  * Get a session by ID
110
110
  */
111
- export function getSession(db, sessionId) {
111
+ export function getSession(db, sessionId, { strictMetadata = false } = {}) {
112
112
  ensureSessionsTable(db);
113
113
 
114
114
  // Try exact match first, then prefix match
@@ -127,16 +127,31 @@ export function getSession(db, sessionId) {
127
127
 
128
128
  if (!session) return null;
129
129
 
130
+ let metadata;
131
+ if (strictMetadata) {
132
+ metadata =
133
+ typeof session.metadata === "string"
134
+ ? JSON.parse(session.metadata)
135
+ : (session.metadata ?? {});
136
+ if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
137
+ const error = new TypeError("Session authority metadata is invalid");
138
+ error.code = "CC_SESSION_AUTHORITY_METADATA_INVALID";
139
+ throw error;
140
+ }
141
+ } else {
142
+ metadata =
143
+ typeof session.metadata === "string"
144
+ ? safeJsonParse(session.metadata, {})
145
+ : session.metadata || {};
146
+ }
147
+
130
148
  return {
131
149
  ...session,
132
150
  // A single corrupt (non-JSON, non-empty) column must not make the whole
133
151
  // session unloadable — that would block resume of the user's own data.
134
152
  // Matches the safeJsonParse fallback listSessions already uses.
135
153
  messages: safeJsonParse(session.messages, []),
136
- metadata:
137
- typeof session.metadata === "string"
138
- ? safeJsonParse(session.metadata, {})
139
- : session.metadata || {},
154
+ metadata,
140
155
  };
141
156
  }
142
157
 
@@ -27,9 +27,83 @@
27
27
  const fsDefault = require("node:fs");
28
28
  const path = require("node:path");
29
29
  const os = require("node:os");
30
+ const { randomUUID } = require("node:crypto");
30
31
  const { projectRootBase } = require("./project-root.cjs");
32
+ const { observeSettingsSources } = require("./settings-source-observation.cjs");
33
+ // Node >=22.12 supports synchronous require(ESM). Load these write-only
34
+ // helpers on first use: permission readers should not trigger Node 22.12's
35
+ // native require(ESM) warning just by discovering settings. Official writes
36
+ // remain synchronous and keep the runtime's warning when applicable.
37
+ let securityStoreHelpers;
38
+ let fileLockHelper;
39
+ function securityStore() {
40
+ return (securityStoreHelpers ??= require("./durable-security-store.js"));
41
+ }
42
+ function lockHelper() {
43
+ return (fileLockHelper ??= require("./with-file-lock.js").withFileLock);
44
+ }
45
+
46
+ const _deps = {
47
+ fs: fsDefault,
48
+ homedir: () => os.homedir(),
49
+ readSecurityStore: (...args) => securityStore().readSecurityStore(...args),
50
+ writeSecurityStore: (...args) => securityStore().writeSecurityStore(...args),
51
+ withFileLock: (...args) => lockHelper()(...args),
52
+ };
53
+
54
+ // A process-wide owner deliberately revokes unrelated projects too. Matching
55
+ // only contributing paths misses absent files, parent discovery and aliases.
56
+ // Only this module can advance it; raw edits and other processes are not events.
57
+ const settingsOwnerId = randomUUID();
58
+ let settingsRevision = Object.freeze({
59
+ ownerId: settingsOwnerId,
60
+ revision: 0,
61
+ state: "ready",
62
+ });
63
+ const settingsListeners = new Set();
64
+
65
+ function getSettingsPermissionRevision() {
66
+ if (settingsRevision.state !== "ready") {
67
+ const error = new Error("settings permission authority is unavailable");
68
+ error.code = "CC_SETTINGS_PERMISSION_AUTHORITY_UNAVAILABLE";
69
+ throw error;
70
+ }
71
+ return settingsRevision;
72
+ }
73
+
74
+ function subscribeSettingsPermissionRevision(listener) {
75
+ if (typeof listener !== "function") {
76
+ throw new TypeError("settings revision listener must be a function");
77
+ }
78
+ settingsListeners.add(listener);
79
+ return () => settingsListeners.delete(listener);
80
+ }
81
+
82
+ function beginSettingsMutation() {
83
+ getSettingsPermissionRevision();
84
+ const next = settingsRevision.revision + 1;
85
+ settingsRevision = Object.freeze({
86
+ ownerId: settingsOwnerId,
87
+ revision: next,
88
+ state: Number.isSafeInteger(next) ? "mutating" : "invalid",
89
+ });
90
+ // Latch before calling observers. Reentrant writers/readers cannot acquire
91
+ // the lock or obtain authority while an official write is in progress.
92
+ for (const listener of [...settingsListeners]) {
93
+ try {
94
+ listener(settingsRevision);
95
+ } catch {
96
+ // An observer cannot prevent another running shell from being revoked.
97
+ }
98
+ }
99
+ if (settingsRevision.state === "invalid") {
100
+ getSettingsPermissionRevision();
101
+ }
102
+ }
31
103
 
32
- const _deps = { fs: fsDefault, homedir: () => os.homedir() };
104
+ function finishSettingsMutation(state) {
105
+ settingsRevision = Object.freeze({ ...settingsRevision, state });
106
+ }
33
107
 
34
108
  const KINDS = Object.freeze(["allow", "ask", "deny"]);
35
109
 
@@ -88,6 +162,27 @@ function settingsPaths(cwd, explicitFile) {
88
162
  return list;
89
163
  }
90
164
 
165
+ /**
166
+ * Strict, read-only inventory for persistent-authority integration. Includes
167
+ * every ordered candidate, even absent files and files with no permission
168
+ * contribution. This does not register an anchor or grant execution authority.
169
+ */
170
+ function inspectSettingsSources(opts = {}) {
171
+ const cwd = path.resolve(opts.cwd || process.cwd());
172
+ const candidates = [
173
+ ...settingsPaths(cwd, opts.settingsFile),
174
+ managedSettingsPath(opts),
175
+ ];
176
+ return Object.freeze({
177
+ schema: "chainlesschain.settings-source-observation/v1",
178
+ cwd,
179
+ sources: observeSettingsSources(candidates, {
180
+ fs: _deps.fs,
181
+ maxBytes: opts.maxBytes,
182
+ }),
183
+ });
184
+ }
185
+
91
186
  /** Organization-controlled settings file. This layer is always highest. */
92
187
  function managedSettingsPath(opts = {}) {
93
188
  if (opts.managedSettingsFile) return path.resolve(opts.managedSettingsFile);
@@ -260,30 +355,88 @@ function scopeFile(cwd, scope) {
260
355
  * @throws if the target file exists but is malformed JSON (refuse to clobber).
261
356
  */
262
357
  function addRule({ cwd = process.cwd(), kind, rule, scope = "project" } = {}) {
358
+ const entryCwd = process.cwd();
359
+ const absoluteCwd = path.resolve(entryCwd, cwd);
360
+ // Check before lock acquisition: notification callbacks may reenter here.
361
+ getSettingsPermissionRevision();
263
362
  if (!KINDS.includes(kind)) {
264
363
  throw new Error(`kind must be allow | ask | deny (got "${kind}")`);
265
364
  }
266
- const file = scopeFile(cwd, scope);
267
- let data = {};
268
- if (_deps.fs.existsSync(file)) {
269
- const text = _deps.fs.readFileSync(file, "utf-8");
270
- try {
271
- data = JSON.parse(text) || {};
272
- } catch (err) {
273
- throw new Error(
274
- `refusing to overwrite malformed ${file} (${err.message})`,
275
- );
276
- }
365
+ if (typeof rule !== "string" || !rule.trim()) {
366
+ throw new TypeError("permission rule must be a non-empty string");
277
367
  }
278
- if (!data.permissions || typeof data.permissions !== "object") {
279
- data.permissions = {};
368
+ if (!["project", "local", "user"].includes(scope)) {
369
+ throw new TypeError("scope must be project | local | user");
280
370
  }
281
- if (!Array.isArray(data.permissions[kind])) data.permissions[kind] = [];
282
- if (data.permissions[kind].includes(rule)) return { file, added: false };
283
- data.permissions[kind].push(rule);
371
+ const file = path.resolve(entryCwd, scopeFile(absoluteCwd, scope));
284
372
  _deps.fs.mkdirSync(path.dirname(file), { recursive: true });
285
- _deps.fs.writeFileSync(file, JSON.stringify(data, null, 2) + "\n", "utf-8");
286
- return { file, added: true };
373
+ let began = false;
374
+ let committed = false;
375
+ try {
376
+ const result = _deps.withFileLock(
377
+ file,
378
+ () => {
379
+ // Atomic replacement would otherwise replace the link itself after
380
+ // reading its target. Separate file links also have separate locks.
381
+ // Directory aliases continue to address the same file and lock.
382
+ if (
383
+ _deps.fs.lstatSync(file, { throwIfNoEntry: false })?.isSymbolicLink()
384
+ ) {
385
+ throw new TypeError(
386
+ `refusing to replace a settings file symbolic link: ${file}`,
387
+ );
388
+ }
389
+ const data = _deps.readSecurityStore(file, "settings");
390
+ if (
391
+ Object.hasOwn(data, "permissions") &&
392
+ (!data.permissions ||
393
+ typeof data.permissions !== "object" ||
394
+ Array.isArray(data.permissions))
395
+ ) {
396
+ throw new TypeError(
397
+ `refusing to overwrite malformed permissions: ${file}`,
398
+ );
399
+ }
400
+ data.permissions ??= {};
401
+ // Refuse to hide a damaged rule list, including a different decision.
402
+ for (const decision of KINDS) {
403
+ if (
404
+ Object.hasOwn(data.permissions, decision) &&
405
+ (!Array.isArray(data.permissions[decision]) ||
406
+ data.permissions[decision].some(
407
+ (entry) => typeof entry !== "string",
408
+ ))
409
+ ) {
410
+ throw new TypeError(
411
+ `refusing to overwrite malformed permission rules: ${file}`,
412
+ );
413
+ }
414
+ }
415
+ data.permissions[kind] ??= [];
416
+ if (data.permissions[kind].includes(rule))
417
+ return { file, added: false };
418
+ data.permissions[kind].push(rule);
419
+ beginSettingsMutation();
420
+ began = true;
421
+ _deps.writeSecurityStore(file, "settings", data);
422
+ committed = true;
423
+ return { file, added: true };
424
+ },
425
+ { failIfUnavailable: true },
426
+ );
427
+ if (began) finishSettingsMutation("ready");
428
+ return result;
429
+ } catch (error) {
430
+ if (!error.commitState) {
431
+ error.commitState = committed ? "committed" : "not-committed";
432
+ }
433
+ if (began) {
434
+ finishSettingsMutation(
435
+ error.commitState === "unknown" ? "invalid" : "ready",
436
+ );
437
+ }
438
+ throw error;
439
+ }
287
440
  }
288
441
 
289
442
  /**
@@ -508,6 +661,7 @@ function readStringArraySetting(key, opts = {}) {
508
661
  }
509
662
 
510
663
  module.exports = {
664
+ inspectSettingsSources,
511
665
  loadSettings,
512
666
  loadSettingsConfig,
513
667
  readSettingsFile,
@@ -523,6 +677,8 @@ module.exports = {
523
677
  mergeSandboxSettings,
524
678
  ruleSource,
525
679
  addRule,
680
+ getSettingsPermissionRevision,
681
+ subscribeSettingsPermissionRevision,
526
682
  scopeFile,
527
683
  KINDS,
528
684
  _deps,