chainlesschain 0.162.170 → 0.162.172

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 (186) hide show
  1. package/bin/chainlesschain.js +8 -0
  2. package/package.json +6 -1
  3. package/src/assets/web-panel/assets/{AIOps-BTXN24I3.js → AIOps-oKCWU-LK.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-BBB1VF4j.js → ActionButton-4CBfc5E4.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-BVCXq0k6.js → Analytics-BEmR-k_b.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-C3EOo2s5.js → AppLayout-D6a4ZnrC.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-CsJTZSMv.js → Artifacts-BRWIHCPl.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-CP0AllJ_.js → Audit-CzGKlkTc.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-BCAjs08m.js → BackgroundAgents-CmMYN10o.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-BxQI5XH4.js → Backup-CJ6e0ukD.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-Bu-PNzC5.js → BaseInput-BpEvDrNt.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-DjPQynup.js → Chat-wWuwwjKu.js} +4 -4
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CygkRopu.js → ChatBubbleRenderer-CJLyGo_u.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-BxL6xm7Z.js → Checkbox-C6pW60Br.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-CcyB7h_6.js → Codegen-DF-nP22Y.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-8NQiKJJx.js → Col-BuueEwZW.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-B31qy5OS.js → Community-DuE0Yzwr.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-C-5fAsZ4.js → Compact-BrHim8EB.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-BTSccvF0.js → Compliance-DgAet8f_.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-BXctU9IK.js → Cowork-B9wY05lx.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-CxVFX9NG.js → Cron-CvNBxfJX.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-DEF3dq8M.js → Crosschain-BnZRENa0.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-BmKcE9he.js → DID-DiqYLHTI.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-CECBq_wG.js → Dashboard-t3SsRzZL.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-U-iuPB0n.js → Dropdown-BCjMLam9.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-D8BIlSPL.js → EmailListRenderer-D2v9-IHJ.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BzQGfUH-.js → FamilyGuardDashboard-_iQu35qa.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-4_WlOqLZ.js → Federation-Bkty8VqB.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-gtrW-DdF.js → FormItemContext-DdPW81BY.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-BLcvJJB6.js → GenericCardRenderer-DrNYM4Zj.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-Bk0janGD.js → Git-BjF-B2h0.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-CcfyMlV8.js → Governance-DPhGdJ1v.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-CBLrAf4M.js → Inference--PPksOVj.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-ClguhteZ.js → KnowledgeGraph-y5WdV_JV.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-Dp_oeKfJ.js → Logs-B6_x7zba.js} +2 -2
  36. package/src/assets/web-panel/assets/MarkdownRenderer-Bg8zSyF8.js +1 -0
  37. package/src/assets/web-panel/assets/{Marketplace-BHk50smM.js → Marketplace-CHpfMu1A.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-BAY3CV6J.js → McpTools-qqjtX3Cf.js} +5 -5
  39. package/src/assets/web-panel/assets/{Memory-w0pG2AKx.js → Memory-hASSgxbw.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-C0VkDUE3.js → MobileBridge-Dwh7Bhcf.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-BCvQ80I9.js → MobileProjects-D09voh7W.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-DSIl41Tt.js → Mtc-9G1dXeId.js} +5 -5
  43. package/src/assets/web-panel/assets/{MtcAudit-D1mzUlIr.js → MtcAudit-CWtYXj6f.js} +2 -2
  44. package/src/assets/web-panel/assets/{Multisig-CeJz4VSS.js → Multisig-bDI0EnDk.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-_O3aweu8.js → NLProgramming-CTanRaBP.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-Dt7_pO86.js → Notes-BdQENJFv.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-Dhg3Nktv.js → NotificationSettings-JvnQdStO.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-QsAPcTb2.js → OrderTableRenderer-BMGL9RPJ.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-BuiaUPkv.js → Organization-sBZnIb2D.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-C3jb6knl.js → Overflow-CzOhNGE6.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-BOMyrLkb.js → P2P-D_D2yqda.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-UvLStCgS.js → PdhVaultBrowser-D5lKd_Kx.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-B9cN0dJH.js → Permissions-L5s-wENg.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-DNjW5qro.js → PersonalDataHub-iI49x6cH.js} +3 -3
  55. package/src/assets/web-panel/assets/{Pipeline-CFLyZ6Sh.js → Pipeline-DPHqyk09.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-D3w6vOxf.js → Privacy-B-ZL9360.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-cwcVsn8K.js → ProjectInit-f05YzsN2.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-aUoAroc-.js → ProjectSettings-DZLKS6ex.js} +2 -2
  59. package/src/assets/web-panel/assets/{Projects-CrzQv7Zv.js → Projects-ButF3DyM.js} +1 -1
  60. package/src/assets/web-panel/assets/{Providers-jZaPizKR.js → Providers-CFDSXnkR.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-DNzmwcfg.js → QrScannerModal-1N6Sdxdm.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-m-5Gwt70.js → QuickAsk-tEqRwRSR.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-CrrAjNxP.js → Recommend-D4ZVHIwz.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-BDCMjRFe.js → RemoteSession-Cqm32lhm.js} +2 -2
  65. package/src/assets/web-panel/assets/{Reputation-CPCt1Jc8.js → Reputation-BnjVsU_a.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-C-RorxHs.js → Row-DzpHyTuz.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-CnQs4TuY.js → RssFeed-Du5-ouwx.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-B1jkeFZY.js → Search-CYztyf2o.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-CGKI3vvd.js → Security-C1hVxy8Z.js} +3 -3
  70. package/src/assets/web-panel/assets/{Services-DQjesYF8.js → Services-BscEbAZ2.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-C9Ipj0A6.js → Skeleton-B2sMLqKQ.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-D2j54i9O.js → Skills-CoHKax06.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-xhrVjTeb.js → Sla-Bpie5KO6.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-C6KMOUCa.js → SpeechSettings-BX63ijn5.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-CmIPU5wR.js → SyncSettings-Bf72so5A.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-B-T1J42r.js → Tasks-CVB2PZk4.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-Aq669sjw.js → Templates-q0qyclJx.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-BKWUWNXB.js → Tenant-CW-W-i0k.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-DEeAvA8L.js → Terminal-D7QoPiXQ.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-C465ySdn.js → TimelineRenderer-BaRDAbyA.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-BgVqF-bX.js → Tokens-D6U4PRW8.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-BMNHmxwH.js → Trigger-ClBDWdLo.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-B_adk89L.js → Trust-C_M6rWPq.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-Biw38mog.js → UkeySign-bXHx8s4C.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-AC-eaw5k.js → VideoEditing-BcIt_ieI.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-8lQ5_t0X.js → Wallet-Dd-4jcLs.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-JDmH_-DF.js → WebAuthn-B4F6yxQK.js} +5 -5
  88. package/src/assets/web-panel/assets/{WorkflowEditor-DHQAdITG.js → WorkflowEditor-BEHkpfJq.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-C3qauUVv.js → chat-D7hhRpIO.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-DLP70JGe.js → colors-AMRhrRzS.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-DjsoqA5t.js → compact-item-BYpsOET5.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-CfEdl1in.js → createContext-CoUkR4LQ.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-BRylvxzY.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-DWwHHlBG.js → hasIn-CJKJMKki.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-Dfka-vzJ.js → index-8pmZHnQU.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DgQ92xdO.js → index-BBJFiZ9Y.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-VtCz3A64.js → index-BP69Ul3S.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-C8wrUFzY.js → index-BTFHYauX.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-D5VL0NYy.js → index-BUJt2ar4.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-B-rD2rhi.js → index-Bj30Aq6h.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-gu8zBhtp.js → index-BlpuqGt5.js} +1 -1
  102. package/src/assets/web-panel/assets/index-Bzvxvzlk.js +1 -0
  103. package/src/assets/web-panel/assets/{index-CgruUvB3.js → index-C19xZKIP.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DTEcPJGf.js → index-C6bg22vc.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-C4k6JGm_.js → index-CH6XEWdj.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-C0xMzvk8.js → index-CK1Kknpl.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-UEbYl2pu.js → index-CNyLbBGj.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Dmt1HDWZ.js → index-COg__P6M.js} +19 -19
  109. package/src/assets/web-panel/assets/{index-ArZCi1rK.js → index-CRlJOWsf.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BqPuyN4p.js → index-CScG8TAY.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-B4gCFHtB.js → index-CdL9cQIE.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-C47EiQ7d.js → index-Ck35u_0v.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-Dn2rNMmv.js → index-CkLZQtsh.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-T5emAyFT.js → index-DFoujkWD.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DbFnfyKh.js → index-DFwh0R9h.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CsEk9s04.js → index-DStN9E7o.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DTDpF8MS.js → index-DcozYrXV.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-_g5q2hF3.js → index-De5mYp86.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Bp_WNm2_.js → index-DfEVOzNb.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-OfMwkFIo.js → index-Dfna8sKa.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BcDeMCUK.js → index-DjbMaBLf.js} +1 -1
  122. package/src/assets/web-panel/assets/index-Dl6H3dxS.js +1 -0
  123. package/src/assets/web-panel/assets/{index-D-te-S9f.js → index-Dpl_SJuk.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DKsWujXP.js → index-DyF9uYzB.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BydBh7oT.js → index-HF3GvATm.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DAcBi6F-.js → index-OJmXGn8n.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CNeLedtU.js → index-ZPdNPhUq.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Ds1BfT_C.js → index-djikyGz3.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-CbF27GqZ.js → index-gQWWnP3_.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CnhJbWsl.js → index-owVbLJnH.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Lh0e2afo.js → index-tWEDZHzj.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DbjUePgq.js → index-ttTl376q.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-nuZaMsMy.js → index-z5rYvstM.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-C_pMmi75.js → initDefaultProps-B_Uk-wzg.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-BvKgS96o.js → motion-ez7H8y8b.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-C-1U4R1I.js → move-CKWUhhhX.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-D6BC968-.js → mtc-parser-DkNl7ocj.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-DxOZvcGQ.js → omit-C0uA2ytw.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-LpzmHdkw.js → pickAttrs-CySaWMPl.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-Bm--qom1.js → placementArrow-BWL3-3xo.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-CVZZlhJf.js → responsiveObserve-BRy_wJog.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-DD1xINGx.js → slide-DmmvSaBD.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-LrjHAy63.js → statusUtils-C_7SYY0K.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-BqknYxTe.js → styleChecker-DYgBJGDh.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-Dljy3diT.js → useFlexGapSupport-nPkoZkT6.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-OedUtPLc.js → useFs-CzpsfP4_.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-Cz-kxbP_.js → usePersonalDataHub-Bo2vvMWl.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-C8ZuTk8W.js → vnode-D-hXAnHb.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-CjbgJYXQ.js → zoom-DW7seTGG.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/commands/agent.js +39 -14
  152. package/src/commands/background-session.js +12 -1
  153. package/src/commands/permissions.js +24 -1
  154. package/src/gateways/ws/ws-agent-handler.js +26 -1
  155. package/src/gateways/ws/ws-approval-gate.js +131 -0
  156. package/src/index.js +63 -845
  157. package/src/lib/agent-ipc-bus.js +331 -0
  158. package/src/lib/agent-worktree.js +173 -5
  159. package/src/lib/background-agent-supervisor.js +193 -4
  160. package/src/lib/context-source-ledger.js +164 -0
  161. package/src/lib/execution-trace/index.js +10 -0
  162. package/src/lib/execution-trace/metrics-collector.js +218 -0
  163. package/src/lib/execution-trace/trace-context.js +182 -0
  164. package/src/lib/hook-manager.js +17 -0
  165. package/src/lib/hooks-v2-runtime.js +278 -0
  166. package/src/lib/interaction-adapter.js +26 -5
  167. package/src/lib/metrics-collector.js +127 -0
  168. package/src/lib/observability/index.js +33 -0
  169. package/src/lib/observability/otlp-exporter.js +260 -0
  170. package/src/lib/otlp-exporter.js +45 -0
  171. package/src/lib/process-execution-broker/SPAWN_AUDIT_REPORT.md +117 -0
  172. package/src/lib/process-execution-broker/index.js +450 -0
  173. package/src/lib/process-execution-broker/patch-child-process.js +50 -0
  174. package/src/lib/process-execution-broker/spawn-audit.json +3814 -0
  175. package/src/lib/repl-rewind.js +62 -14
  176. package/src/lib/runtime-provenance-ledger.js +190 -0
  177. package/src/lib/session-hooks.js +41 -0
  178. package/src/lib/turn-binding.js +134 -0
  179. package/src/program-base.js +4 -1
  180. package/src/repl/agent-repl.js +77 -3
  181. package/src/repl/repl-turn-binding.js +91 -0
  182. package/src/runtime/headless-runner.js +59 -0
  183. package/src/assets/web-panel/assets/MarkdownRenderer-RQ1HbTY5.js +0 -1
  184. package/src/assets/web-panel/assets/devWarning-Cwuuqc_f.js +0 -1
  185. package/src/assets/web-panel/assets/index-BkTk-zJK.js +0 -1
  186. package/src/assets/web-panel/assets/index-C-BSTEhe.js +0 -1
@@ -26,6 +26,7 @@ import { runnableTaskModel } from "../../lib/runnable-provider.js";
26
26
  import { PlanState } from "../../lib/plan-mode.js";
27
27
  import { CLISlotFiller } from "../../lib/slot-filler.js";
28
28
  import { createAbortError, isAbortError } from "../../lib/abort-utils.js";
29
+ import { createWsApprovalGate } from "./ws-approval-gate.js";
29
30
 
30
31
  export class WSAgentHandler {
31
32
  /**
@@ -34,7 +35,7 @@ export class WSAgentHandler {
34
35
  * @param {import("../../lib/interaction-adapter.js").WebSocketInteractionAdapter} options.interaction
35
36
  * @param {object} [options.db]
36
37
  */
37
- constructor({ session, interaction, db }) {
38
+ constructor({ session, interaction, db, approvalGate }) {
38
39
  this.session = session;
39
40
  this.interaction = interaction;
40
41
  this.db = db || null;
@@ -44,6 +45,27 @@ export class WSAgentHandler {
44
45
  // P0-2: monotonic sequence for crash-safe side-effect ledger op ids. The
45
46
  // session id + a per-op nonce keep ids unique across turns and processes.
46
47
  this._sideEffectSeq = 0;
48
+ // P0 authority: permission-gate-over-WS. An explicitly injected gate wins
49
+ // (tests / embedders); otherwise one is built lazily on the first turn
50
+ // when CC_WS_APPROVAL_GATE=1 — its confirmer raises confirm questions
51
+ // over the interaction adapter WITH an approval binding the client must
52
+ // echo back on approve (mismatch → deny). Default (env unset, nothing
53
+ // injected): approvalGate stays null and loopOptions are byte-identical.
54
+ this._approvalGate = approvalGate || null;
55
+ this._approvalGateInit = Boolean(approvalGate);
56
+ }
57
+
58
+ /** Resolve the session's approval gate (lazy, opt-in; null when disabled). */
59
+ async _ensureApprovalGate() {
60
+ if (this._approvalGateInit) return this._approvalGate;
61
+ this._approvalGateInit = true;
62
+ if (process.env.CC_WS_APPROVAL_GATE === "1") {
63
+ this._approvalGate = await createWsApprovalGate({
64
+ sessionId: this.session.id,
65
+ interaction: this.interaction,
66
+ });
67
+ }
68
+ return this._approvalGate;
47
69
  }
48
70
 
49
71
  /**
@@ -127,6 +149,9 @@ export class WSAgentHandler {
127
149
  slotFiller,
128
150
  interaction: this.interaction,
129
151
  signal: abortController.signal,
152
+ // P0 authority: null unless opted in (byte-identical default — agent
153
+ // core already defaults `options.approvalGate || null`).
154
+ approvalGate: await this._ensureApprovalGate(),
130
155
  };
131
156
 
132
157
  // P0-2: crash-safe side-effect ledger for the IDE/bridge path — mirrors
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Permission-gate-over-WS — the approval-BINDING producer for the WS path.
3
+ *
4
+ * The consumer side has been wired for a while: WebSocketInteractionAdapter
5
+ * stores `options.binding` on a pending request, rides it out on the message,
6
+ * and `_resolvePending` rejects an approve whose echoed binding mismatches
7
+ * (deny, fail closed). What was missing is the PRODUCER: nothing on the WS
8
+ * path ever raised an approval request WITH a binding, because the WS agent
9
+ * handler wired no ApprovalGate at all (CONFIRM-tier decisions fell closed).
10
+ *
11
+ * This module supplies both halves:
12
+ * - `buildWsApprovalConfirmer` — the gate confirmer that computes
13
+ * `approvalBindingDigest({toolCallId, args, policyDigest})` (mirroring the
14
+ * headless-stream `interactiveConfirm` producer) and asks the WS client
15
+ * over the interaction adapter with the binding attached. Timeout /
16
+ * disconnect / any transport error → false (fail closed).
17
+ * - `createWsApprovalGate` — a session-scoped gate whose CONFIRM decisions
18
+ * route to that confirmer. Policy tiers stay authoritative on the shared
19
+ * singleton gate (so `sessions.policy.set` over WS keeps working and no
20
+ * global confirmer is ever mutated — a per-session confirmer on the
21
+ * process-wide singleton would race across concurrent WS sessions).
22
+ *
23
+ * Default byte-identical: the WS handler only builds this when
24
+ * `CC_WS_APPROVAL_GATE=1` (or a gate is injected); otherwise loopOptions
25
+ * carry `approvalGate: null` exactly as before.
26
+ */
27
+
28
+ import { approvalBindingDigest } from "../../lib/agent-authority.js";
29
+
30
+ /**
31
+ * Build the binding-attaching confirmer for one WS session.
32
+ *
33
+ * @param {object} opts
34
+ * @param {{askConfirm: Function}} opts.interaction - the session's WS adapter
35
+ * @param {string} opts.sessionId
36
+ * @returns {(ctx?: object) => Promise<boolean>}
37
+ */
38
+ export function buildWsApprovalConfirmer({ interaction, sessionId }) {
39
+ let approvalSeq = 0;
40
+ return async (ctx = {}) => {
41
+ const command = ctx.command ?? ctx.args?.command ?? null;
42
+ const risk = ctx.riskLevel || ctx.risk || "unknown";
43
+ // Bind this approval to the exact call it authorizes (same recipe as the
44
+ // headless-stream producer): request identity + normalized args + the
45
+ // policy/rule in force. The client must echo it back on approve.
46
+ const binding = approvalBindingDigest({
47
+ toolCallId: `${sessionId}:appr-${++approvalSeq}`,
48
+ args: ctx.args ?? (command != null ? { command } : null),
49
+ policyDigest: ctx.rule || ctx.riskLevel || ctx.risk || null,
50
+ });
51
+ const what = ctx.tool || ctx.toolName || "tool";
52
+ const detail = command != null ? `: ${String(command).slice(0, 200)}` : "";
53
+ try {
54
+ const ok = await interaction.askConfirm(
55
+ `Approve ${what}${detail}? (risk: ${risk})`,
56
+ {
57
+ default: false,
58
+ binding,
59
+ // Structured context so UIs can render a proper approval card
60
+ // instead of parsing the question text.
61
+ approval: {
62
+ tool: what,
63
+ command,
64
+ risk,
65
+ rule: ctx.rule || null,
66
+ },
67
+ },
68
+ );
69
+ return ok === true;
70
+ } catch {
71
+ // timeout / disconnect / interrupt → fail closed, never approve
72
+ return false;
73
+ }
74
+ };
75
+ }
76
+
77
+ /**
78
+ * Create a session-scoped approval gate for the WS agent handler.
79
+ *
80
+ * Policy lookups delegate to the persistent singleton gate (per-session tiers
81
+ * set via `sessions.policy.set` stay live); CONFIRM decisions route to the
82
+ * binding-attaching WS confirmer. Returns null on any load failure so the
83
+ * caller degrades to the legacy no-gate path (fail closed at CONFIRM).
84
+ *
85
+ * @param {object} opts
86
+ * @param {string} opts.sessionId
87
+ * @param {{askConfirm: Function}} opts.interaction
88
+ * @param {object} [opts.deps] - test seams: `loadSingletons`, `loadSessionCore`
89
+ * @returns {Promise<object|null>}
90
+ */
91
+ export async function createWsApprovalGate({
92
+ sessionId,
93
+ interaction,
94
+ deps = {},
95
+ }) {
96
+ try {
97
+ const loadSingletons =
98
+ deps.loadSingletons ||
99
+ (() => import("../../lib/session-core-singletons.js"));
100
+ const loadSessionCore =
101
+ deps.loadSessionCore || (() => import("@chainlesschain/session-core"));
102
+ const [singletons, core] = await Promise.all([
103
+ loadSingletons(),
104
+ loadSessionCore(),
105
+ ]);
106
+ const inner = await singletons.getApprovalGate();
107
+ const confirmer =
108
+ deps.confirmer || buildWsApprovalConfirmer({ interaction, sessionId });
109
+ const gate = new core.ApprovalGate({
110
+ defaultPolicy: core.APPROVAL_POLICY?.STRICT || "strict",
111
+ confirm: confirmer,
112
+ });
113
+ return {
114
+ // Explicit ctx.policy always wins inside decide(); resolve it from the
115
+ // singleton on every call so mid-session `sessions.policy.set` applies.
116
+ decide: (ctx = {}) =>
117
+ gate.decide({
118
+ ...ctx,
119
+ policy:
120
+ ctx.policy || inner.getSessionPolicy(ctx.sessionId || sessionId),
121
+ }),
122
+ hasConfirmer: () => gate.hasConfirmer(),
123
+ setConfirmer: (fn) => gate.setConfirmer(fn),
124
+ getSessionPolicy: (sid) => inner.getSessionPolicy(sid || sessionId),
125
+ setSessionPolicy: (sid, policy) =>
126
+ inner.setSessionPolicy(sid || sessionId, policy),
127
+ };
128
+ } catch {
129
+ return null; // degrade to the legacy no-gate path
130
+ }
131
+ }