chainlesschain 0.163.7 → 0.164.0

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 (252) hide show
  1. package/package.json +5 -1
  2. package/scripts/macos-mcp-launcher-build.mjs +317 -0
  3. package/scripts/macos-mcp-launcher-postinstall.sh +54 -0
  4. package/scripts/macos-mcp-launcher-preinstall.sh +61 -0
  5. package/src/assets/web-panel/assets/{AIOps-axqQfwv8.js → AIOps-D2MEn7fI.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-DV-Ro0By.js → ActionButton-lCW_4Gf0.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-Bt72WEVu.js → Analytics-Bs7i-nsS.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-BtepG55E.js → AppLayout-CK7B6S_j.js} +5 -5
  9. package/src/assets/web-panel/assets/{Artifacts-B7KaJ7S_.js → Artifacts-C8ILjpyo.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-FNFaUg7A.js → Audit-Bb9cNaWc.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-DFb6J2wQ.js → BackgroundAgents-sC9ooXIf.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-CC7YBhyj.js → Backup-D-DrsplT.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-RkgTNVtj.js → BaseInput-uCNZpwSK.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-hHEmGZy-.js → Chat-CsDK1uE9.js} +6 -6
  15. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CAP9YhHv.js → ChatBubbleRenderer-OqSDt50w.js} +1 -1
  16. package/src/assets/web-panel/assets/{Checkbox-z5wXOQP1.js → Checkbox-JhTXM1-K.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-DVaDJnxy.js → Codegen-BbzZLnyD.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-CJmaRDR5.js → Col-D4VW4m4j.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-DF29_2bI.js → Community-BXrYawxV.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-DtkQkBzn.js → Compact-DCihGy1u.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-xoHDxp7I.js → Compliance-DlyZ-lk8.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-BUm-R7ht.js → Cowork-DvGZrhbO.js} +2 -2
  23. package/src/assets/web-panel/assets/{Cron-Cgl14ZkB.js → Cron-DUncZi8h.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-BNcbmoqh.js → Crosschain-C_hLuUcm.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-Bwja0Zo9.js → DID-b6YSUqxr.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-Bk5XjEdJ.js → Dashboard-uvM15Cfb.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-Ci36Oitq.js → Dropdown-D1-Nd4qY.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer--U04ZN4q.js → EmailListRenderer-8ApvL6Zc.js} +1 -1
  29. package/src/assets/web-panel/assets/{FamilyGuardDashboard-B2gNPR2s.js → FamilyGuardDashboard-LYJt8811.js} +1 -1
  30. package/src/assets/web-panel/assets/{Federation-C4KghYn7.js → Federation-BbI3HGpv.js} +1 -1
  31. package/src/assets/web-panel/assets/{FormItemContext-QL7x_Q_0.js → FormItemContext-DSoEKuFu.js} +1 -1
  32. package/src/assets/web-panel/assets/{GenericCardRenderer-F3Ryltwm.js → GenericCardRenderer-B0S9OWd5.js} +1 -1
  33. package/src/assets/web-panel/assets/{Git-2HassK5k.js → Git-DIs9Zhf3.js} +2 -2
  34. package/src/assets/web-panel/assets/{Governance-DoBIp7oe.js → Governance-jzZXrxcl.js} +1 -1
  35. package/src/assets/web-panel/assets/{Inference--W01QhZ-.js → Inference-JUPjf2ZI.js} +1 -1
  36. package/src/assets/web-panel/assets/{KnowledgeGraph-DmvwqGpT.js → KnowledgeGraph-DxnfJvlP.js} +1 -1
  37. package/src/assets/web-panel/assets/{Logs-BBJ4yAel.js → Logs-iXiz8BEE.js} +2 -2
  38. package/src/assets/web-panel/assets/{MarkdownRenderer-BLCZMzhJ.js → MarkdownRenderer-GmB6DOr6.js} +1 -1
  39. package/src/assets/web-panel/assets/{Marketplace-D5lNngSI.js → Marketplace-Y3Xch312.js} +1 -1
  40. package/src/assets/web-panel/assets/{McpTools-CkEVOMKH.js → McpTools-D7kGGbO7.js} +4 -4
  41. package/src/assets/web-panel/assets/{Memory-B1Ow1xVE.js → Memory-Do_hVxzh.js} +2 -2
  42. package/src/assets/web-panel/assets/{MobileBridge-SgYbUfb6.js → MobileBridge-CtrR0Tas.js} +1 -1
  43. package/src/assets/web-panel/assets/MobileProjects-BL0Czcoj.js +1 -0
  44. package/src/assets/web-panel/assets/{Mtc-DcTXSSma.js → Mtc-qo5QCTGd.js} +2 -2
  45. package/src/assets/web-panel/assets/{MtcAudit-Dt3WG4oj.js → MtcAudit-cq5mnjYj.js} +2 -2
  46. package/src/assets/web-panel/assets/{Multisig-B9B38UZx.js → Multisig-Bq0MAQHw.js} +3 -3
  47. package/src/assets/web-panel/assets/{NLProgramming-B0S4GGvG.js → NLProgramming-DdWE6Vi2.js} +1 -1
  48. package/src/assets/web-panel/assets/{Notes-DZ5U58Ng.js → Notes-BxMBFcIp.js} +3 -3
  49. package/src/assets/web-panel/assets/{NotificationSettings-PjL5ZW34.js → NotificationSettings-RTrAcbUe.js} +1 -1
  50. package/src/assets/web-panel/assets/{OrderTableRenderer-DrAX2ESt.js → OrderTableRenderer-DJbpGqzT.js} +1 -1
  51. package/src/assets/web-panel/assets/{Organization-Cv1GYs-c.js → Organization-SQzIPdqC.js} +4 -4
  52. package/src/assets/web-panel/assets/{Overflow-Bbkp_PL3.js → Overflow-02yECh22.js} +1 -1
  53. package/src/assets/web-panel/assets/{P2P-BD8QUgoZ.js → P2P-BNg4pNCM.js} +2 -2
  54. package/src/assets/web-panel/assets/{PdhVaultBrowser-BO-2PeaB.js → PdhVaultBrowser-BxPJZsD3.js} +3 -3
  55. package/src/assets/web-panel/assets/{Permissions-D_OPVa02.js → Permissions-CLnDnPAz.js} +4 -4
  56. package/src/assets/web-panel/assets/{PersonalDataHub-mh-pEmaB.js → PersonalDataHub-C5m0AjGf.js} +4 -4
  57. package/src/assets/web-panel/assets/{Pipeline-6JC2EDdb.js → Pipeline-VwOf5Dhv.js} +1 -1
  58. package/src/assets/web-panel/assets/{Privacy-CUshzUAG.js → Privacy-CC0W2hZd.js} +1 -1
  59. package/src/assets/web-panel/assets/{ProjectInit-Cs2Aalri.js → ProjectInit-Dz893Bob.js} +2 -2
  60. package/src/assets/web-panel/assets/{ProjectSettings-1ak49tcj.js → ProjectSettings-CxQkvl0k.js} +2 -2
  61. package/src/assets/web-panel/assets/Projects-DDAjkUkT.js +1 -0
  62. package/src/assets/web-panel/assets/{Providers-CXXxvafH.js → Providers-DeB9IkxK.js} +1 -1
  63. package/src/assets/web-panel/assets/{QrScannerModal-PTcDsF58.js → QrScannerModal-OCeoaswn.js} +1 -1
  64. package/src/assets/web-panel/assets/{QuickAsk-CDwucrJw.js → QuickAsk-DenotaAj.js} +1 -1
  65. package/src/assets/web-panel/assets/{Recommend-CJlLVRXR.js → Recommend-Cies_jjI.js} +1 -1
  66. package/src/assets/web-panel/assets/{RemoteSession-DlN-ETsO.js → RemoteSession-Dxzl5n2T.js} +3 -3
  67. package/src/assets/web-panel/assets/{Reputation-DI23LR6m.js → Reputation-CW0mvxgZ.js} +1 -1
  68. package/src/assets/web-panel/assets/{Row-Cl7UQMrM.js → Row-SEd32qZU.js} +1 -1
  69. package/src/assets/web-panel/assets/{RssFeed-CexHNfh8.js → RssFeed-BSwnJ3Lm.js} +3 -3
  70. package/src/assets/web-panel/assets/{Search-BneBWvRN.js → Search-xe2m8bkC.js} +1 -1
  71. package/src/assets/web-panel/assets/{Security-DX7Phgrp.js → Security-Mq2F9Nro.js} +4 -4
  72. package/src/assets/web-panel/assets/{Services-BWXO8Mte.js → Services-BKGw2V3P.js} +2 -2
  73. package/src/assets/web-panel/assets/{Skeleton-DCyOjKPJ.js → Skeleton-DW95-Rxf.js} +1 -1
  74. package/src/assets/web-panel/assets/{Skills-CXqERsTB.js → Skills-CHgChCv_.js} +1 -1
  75. package/src/assets/web-panel/assets/{Sla-bhbrbz8E.js → Sla-tKh6k3R7.js} +1 -1
  76. package/src/assets/web-panel/assets/{SpeechSettings-3IPU0HBZ.js → SpeechSettings-D6UL3dA5.js} +1 -1
  77. package/src/assets/web-panel/assets/{SyncSettings-DBNTQLbM.js → SyncSettings-D0Fw8fVL.js} +2 -2
  78. package/src/assets/web-panel/assets/{Tasks-quP0bkN-.js → Tasks-20x1GB3D.js} +1 -1
  79. package/src/assets/web-panel/assets/{Templates-BouWmgho.js → Templates-DJ-lts-a.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tenant-qv0D9s7z.js → Tenant-BFdGpbs7.js} +1 -1
  81. package/src/assets/web-panel/assets/{Terminal-BxvbE8BB.js → Terminal-Xpx61vHL.js} +2 -2
  82. package/src/assets/web-panel/assets/{TimelineRenderer-D-IeLnJ2.js → TimelineRenderer-C6UIvyZQ.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tokens-CFMKKyVG.js → Tokens-Dellq08f.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trigger-L8as3UuJ.js → Trigger-VKw8d0J-.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trust-MxmA4VZG.js → Trust-DNftdKT5.js} +1 -1
  86. package/src/assets/web-panel/assets/{UkeySign-C0VvJYRi.js → UkeySign-DX9VAKJI.js} +1 -1
  87. package/src/assets/web-panel/assets/{VideoEditing-Bf5QZj8N.js → VideoEditing-B2h3jO8q.js} +1 -1
  88. package/src/assets/web-panel/assets/{Wallet-BIJ9riRz.js → Wallet-CjGkof7f.js} +4 -4
  89. package/src/assets/web-panel/assets/{WebAuthn-B8p9Mhkw.js → WebAuthn-2Zfcu55P.js} +4 -4
  90. package/src/assets/web-panel/assets/{WorkflowEditor-BVsuaPen.js → WorkflowEditor-B9eZ8UxZ.js} +1 -1
  91. package/src/assets/web-panel/assets/{chat-BfkjoKpV.js → chat-CQNfD-YO.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-DeAlsWK8.js → colors-D4usyFT2.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-Cs97bz5j.js → compact-item-s4TpjvjX.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-BqbG60LH.js → createContext-BRCSvYxj.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-DKJjSWRn.js +1 -0
  96. package/src/assets/web-panel/assets/{hasIn-i_RY0b1X.js → hasIn-AdkUbkV-.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BOVkf1K3.js → index--00U6vXZ.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-B-3tEpTc.js → index-B2V-eKfK.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-D2B4VPyP.js → index-B4JJCfQ2.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BkBi5TmC.js → index-BIoG5yYf.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-79V_zv1s.js → index-BMcimU-2.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-U4f5izHz.js → index-BPhkFZ1I.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DiSkx4UB.js → index-BQ3DXBtD.js} +3 -3
  104. package/src/assets/web-panel/assets/{index-dIHr4B_u.js → index-Bad4VNvz.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CIG8fQ2_.js → index-BgiXR_-_.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DqBgBpgp.js → index-BtobShro.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-ZxO_-E8a.js → index-Bw2MEnUk.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DUUrv141.js → index-C1mJtE6q.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Bm7lLR4c.js → index-C484EJiS.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-COdGA-8n.js → index-C5KAQFPQ.js} +1 -1
  111. package/src/assets/web-panel/assets/index-C61cnl3K.js +1 -0
  112. package/src/assets/web-panel/assets/{index-CED2PL_y.js → index-C7Y8Aluc.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-YXgLng0K.js → index-CCsM_Ybx.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-0-agYlWL.js → index-CJCFe2Qf.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-B5UkyA3c.js → index-CJVEOa4i.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-B1CbOH1i.js → index-CJdQrZth.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-s1opAL-M.js → index-CKC1t3Ic.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-yObj1O4n.js → index-CQhAVU5t.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CgsqdnRV.js → index-CYdoQsa1.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Dk7-v4hP.js → index-Cduu2Hhr.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-B-JVTrpr.js → index-CkwiSLhU.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CeWoNHau.js → index-Cvyt-zhm.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CE2VtTlp.js → index-D2GjI2oe.js} +1 -1
  124. package/src/assets/web-panel/assets/index-D4XFHxBr.js +1 -0
  125. package/src/assets/web-panel/assets/{index-DmbfhJUP.js → index-DARsAyUp.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BESLFt4q.js → index-DVKfQ0Ux.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-PT_5sBMA.js → index-DZT36ZYq.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-gyFpvL7l.js → index-D_XBHopw.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BYUVuwKt.js → index-DdCB70SS.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BcUXAB2s.js → index-DzRjHxEv.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Dk2qouAz.js → index-MMN9V6JF.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-D9evtvg2.js → index-RfMr79MW.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-BuLQobzW.js → index-_IRVsV9X.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-Cf3WCLmy.js → index-nXyk8GZ9.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-CG3PRyAL.js → index-s_buFMEG.js} +1 -1
  136. package/src/assets/web-panel/assets/{initDefaultProps-C9h9yKL3.js → initDefaultProps-Blmpk7HL.js} +1 -1
  137. package/src/assets/web-panel/assets/{motion-BvmLsPdu.js → motion-DPBJMv1n.js} +1 -1
  138. package/src/assets/web-panel/assets/{move-CoL4ekU1.js → move-ButdzCM7.js} +1 -1
  139. package/src/assets/web-panel/assets/{mtc-parser-C4pMy6xV.js → mtc-parser-cyRC_QCe.js} +1 -1
  140. package/src/assets/web-panel/assets/{omit-DPuJfNxx.js → omit-1epSV7hz.js} +1 -1
  141. package/src/assets/web-panel/assets/{pickAttrs-D0KEeaK2.js → pickAttrs-DuPY8xJs.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-BpkyINxt.js → placementArrow-6XZqarhe.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-DQI_wOq8.js → responsiveObserve-B40pXBWM.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-DYfdDiRg.js → slide-jbZ9Wu4n.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-B5dtvb0D.js → statusUtils-BKQQcVy4.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-CF310mSj.js → styleChecker-NiKfWjUT.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-D1Qp4BLp.js → useFlexGapSupport-bQUCvPeb.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-C7_iyvJK.js → useFs-CUGji7ph.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-DZUt_fIm.js → usePersonalDataHub-4veyN2N2.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-D3dsi0lZ.js → vnode-1-nLug-Z.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-WdbOlvdQ.js → zoom-dhCeRDMo.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/command-help-index.json +6 -6
  154. package/src/commands/automation.js +103 -1
  155. package/src/commands/cowork.js +174 -19
  156. package/src/commands/permissions.js +240 -16
  157. package/src/commands/plugin.js +1293 -56
  158. package/src/commands/session-location.js +276 -0
  159. package/src/commands/session.js +2 -0
  160. package/src/commands/team-merge-review.js +937 -0
  161. package/src/commands/team.js +2 -0
  162. package/src/data/changelog.json +27 -1
  163. package/src/gateways/ws/action-protocol.js +35 -10
  164. package/src/gateways/ws/remote-session-protocol.js +24 -1
  165. package/src/gateways/ws/ws-agent-handler.js +12 -0
  166. package/src/gateways/ws/ws-server.js +48 -12
  167. package/src/harness/jsonl-session-store.js +341 -24
  168. package/src/harness/mcp-client.js +8 -1
  169. package/src/harness/remote-session-audit.js +1 -0
  170. package/src/harness/remote-session-crypto.js +210 -2
  171. package/src/harness/remote-session-registry.js +159 -6
  172. package/src/harness/session-list-index.js +233 -14
  173. package/src/lib/agent-authority.js +6 -0
  174. package/src/lib/agent-schedule-store.js +139 -28
  175. package/src/lib/agent-team/team-merge-review-store.js +765 -0
  176. package/src/lib/agent-team/team-merge-review-transaction.js +1223 -0
  177. package/src/lib/agent-team/team-merge-review.js +1847 -0
  178. package/src/lib/automation-center-incidents.js +314 -0
  179. package/src/lib/automation-center-runtime.js +448 -0
  180. package/src/lib/automation-center.js +182 -38
  181. package/src/lib/automation-engine.js +41 -0
  182. package/src/lib/automation-execution-authority.js +241 -12
  183. package/src/lib/automation-execution-incident.js +737 -0
  184. package/src/lib/background-agent-keeper-client.js +248 -0
  185. package/src/lib/background-agent-keeper-protocol.js +147 -0
  186. package/src/lib/background-agent-supervisor.js +520 -40
  187. package/src/lib/background-interaction-resolver.js +12 -0
  188. package/src/lib/background-turn-bootstrap-protocol.js +126 -0
  189. package/src/lib/cowork-cron.js +85 -14
  190. package/src/lib/cowork-workflow.js +336 -16
  191. package/src/lib/dynamic-workflow-facade.js +648 -0
  192. package/src/lib/execution-location-contract.js +551 -0
  193. package/src/lib/execution-location-runtime.js +130 -0
  194. package/src/lib/ide-context.js +94 -6
  195. package/src/lib/mcp-stdio-package-materialization.js +166 -14
  196. package/src/lib/packer/pkg-config-generator.js +2 -0
  197. package/src/lib/permission-authority.js +77 -0
  198. package/src/lib/permission-side-effect-center.js +495 -0
  199. package/src/lib/plugin-runtime/install.js +514 -13
  200. package/src/lib/plugin-runtime/marketplace-artifact-readback.js +900 -0
  201. package/src/lib/plugin-runtime/marketplace-catalog.js +1181 -0
  202. package/src/lib/plugin-runtime/marketplace-impact.js +408 -0
  203. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1567 -0
  204. package/src/lib/plugin-security.js +60 -3
  205. package/src/lib/process-execution-broker/index.js +1095 -57
  206. package/src/lib/process-execution-broker/linux-bwrap-descriptor-launch.js +375 -0
  207. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +90 -16
  208. package/src/lib/process-execution-broker/linux-generic-bwrap.js +159 -18
  209. package/src/lib/process-execution-broker/macos-mcp-launcher-contract.js +278 -0
  210. package/src/lib/process-execution-broker/macos-mcp-launcher-protocol.json +23 -0
  211. package/src/lib/process-execution-broker/macos-mcp-launcher.c +1497 -0
  212. package/src/lib/process-execution-broker/mcp-fd-entry-bootstrap.js +37 -0
  213. package/src/lib/process-execution-broker/platform-sandbox.js +2330 -279
  214. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  215. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  216. package/src/lib/process-execution-broker/windows-sandbox.cs +50 -4
  217. package/src/lib/public-ide-capability-manifest.js +3 -0
  218. package/src/lib/remote-approval-bridge.js +123 -17
  219. package/src/lib/remote-membership-authority.js +632 -0
  220. package/src/lib/remote-membership-coordinator.js +2409 -0
  221. package/src/lib/remote-membership-host-store.js +1750 -0
  222. package/src/lib/scheduler-kernel/agenda-adapter.js +17 -7
  223. package/src/lib/scheduler-kernel/automation-adapter.js +105 -11
  224. package/src/lib/scheduler-kernel/automation-event-adapter.js +87 -11
  225. package/src/lib/scheduler-kernel/contract.js +91 -0
  226. package/src/lib/scheduler-kernel/cowork-cron-adapter.js +12 -1
  227. package/src/lib/scheduler-kernel/loop-adapter.js +7 -1
  228. package/src/lib/scheduler-kernel/routine-adapter.js +7 -1
  229. package/src/lib/scheduler-kernel/runtime-control-capabilities.js +31 -0
  230. package/src/lib/scheduler-kernel/runtime.js +176 -3
  231. package/src/lib/scheduler-kernel/store.js +1253 -45
  232. package/src/lib/scoped-permission-store.js +369 -0
  233. package/src/lib/session-anti-rollback-anchor.js +262 -5
  234. package/src/lib/sub-agent-context.js +4 -0
  235. package/src/lib/workflow-definition-contract.js +149 -0
  236. package/src/repl/agent-repl.js +41 -7
  237. package/src/repl/chat-repl.js +2 -0
  238. package/src/repl/clipboard-image.js +735 -16
  239. package/src/repl/ide-status.js +1 -1
  240. package/src/repl/prompt-interactions.js +59 -6
  241. package/src/runtime/agent-core.js +93 -3
  242. package/src/runtime/headless-runner.js +30 -25
  243. package/src/runtime/headless-stream.js +32 -25
  244. package/src/runtime/mcp-config.js +81 -10
  245. package/src/workers/background-agent-keeper.js +498 -0
  246. package/src/workers/background-agent-worker.js +358 -13
  247. package/src/workers/background-turn-bootstrap.js +143 -0
  248. package/src/assets/web-panel/assets/MobileProjects-BWdOvQAj.js +0 -1
  249. package/src/assets/web-panel/assets/Projects-BV4oApsm.js +0 -1
  250. package/src/assets/web-panel/assets/devWarning-DPty0mGN.js +0 -1
  251. package/src/assets/web-panel/assets/index-Bt7g0Vq_.js +0 -1
  252. package/src/assets/web-panel/assets/index-ChVT0p9u.js +0 -1
@@ -12,6 +12,14 @@ import {
12
12
  buildAutomationCenterProjection,
13
13
  runAutomationCenterAction,
14
14
  } from "../lib/automation-center.js";
15
+ import {
16
+ automationCenterIncidentActionErrorEnvelope,
17
+ runAutomationCenterIncidentAction,
18
+ } from "../lib/automation-center-incidents.js";
19
+ import {
20
+ automationCenterRuntimeActionErrorEnvelope,
21
+ runAutomationCenterRuntimeAction,
22
+ } from "../lib/automation-center-runtime.js";
15
23
  import {
16
24
  createAutomationCenterRoutine,
17
25
  editAutomationCenterRoutine,
@@ -22,6 +30,7 @@ import { parseJsonOption } from "../lib/parse-json-option.js";
22
30
  import { AutomationSchedulerBridge } from "../lib/scheduler-kernel/automation-adapter.js";
23
31
  import { AutomationEventDispatcher } from "../lib/scheduler-kernel/automation-event-adapter.js";
24
32
  import { openSchedulerStore } from "../lib/scheduler-kernel/store.js";
33
+ import { resolveAutomationCenterRuntimeControl } from "../lib/scheduler-kernel/runtime-control-capabilities.js";
25
34
  import {
26
35
  RoutineSchedulerBridge,
27
36
  routineBridgeRunId,
@@ -288,7 +297,8 @@ export function registerAutomationCommand(program) {
288
297
  if (
289
298
  actionCommand &&
290
299
  (actionCommand.name().endsWith("-v2") ||
291
- actionCommand.name().startsWith("center-routine-"))
300
+ actionCommand.name().startsWith("center-routine-") ||
301
+ actionCommand.name() === "center-runtime-action")
292
302
  )
293
303
  return;
294
304
  const db = await _prepare(thisCommand);
@@ -446,9 +456,13 @@ function _wire(root) {
446
456
  .option("--json", "Output as JSON")
447
457
  .action(async (opts, cmd) => {
448
458
  const db = _dbFromCtx(cmd);
459
+ let schedulerStore;
449
460
  try {
461
+ schedulerStore = openSchedulerStore();
450
462
  const projection = buildAutomationCenterProjection(db, {
451
463
  limit: Number(opts.limit),
464
+ schedulerStore,
465
+ runtimeCapabilityForKind: resolveAutomationCenterRuntimeControl,
452
466
  });
453
467
  if (opts.json) console.log(JSON.stringify(projection, null, 2));
454
468
  else {
@@ -465,6 +479,94 @@ function _wire(root) {
465
479
  logger.error(e.message);
466
480
  process.exitCode = 1;
467
481
  } finally {
482
+ schedulerStore?.close();
483
+ await shutdown();
484
+ }
485
+ });
486
+
487
+ root
488
+ .command("center-runtime-action <occurrenceId> <pause|resume>")
489
+ .description("Pause or resume one exact fenced scheduler occurrence")
490
+ .requiredOption(
491
+ "--expected-fence <fence>",
492
+ "Exact scheduler fence shown by center-projection",
493
+ )
494
+ .requiredOption(
495
+ "--expected-control-revision <revision>",
496
+ "Exact runtime-control revision shown by center-projection",
497
+ )
498
+ .option("--json", "Output as JSON")
499
+ .action(async (occurrenceId, action, opts) => {
500
+ let schedulerStore;
501
+ try {
502
+ schedulerStore = openSchedulerStore();
503
+ const result = runAutomationCenterRuntimeAction(schedulerStore, {
504
+ capabilityForKind: resolveAutomationCenterRuntimeControl,
505
+ occurrenceId,
506
+ action,
507
+ expectedFence: Number(opts.expectedFence),
508
+ expectedControlRevision: Number(opts.expectedControlRevision),
509
+ });
510
+ if (opts.json) console.log(JSON.stringify(result, null, 2));
511
+ else logger.success(`${occurrenceId} ${action} completed`);
512
+ } catch (error) {
513
+ if (opts.json) {
514
+ console.log(
515
+ JSON.stringify(
516
+ automationCenterRuntimeActionErrorEnvelope(error, {
517
+ occurrenceId,
518
+ action,
519
+ }),
520
+ null,
521
+ 2,
522
+ ),
523
+ );
524
+ } else logger.error(error.message);
525
+ process.exitCode = 1;
526
+ } finally {
527
+ schedulerStore?.close();
528
+ await shutdown();
529
+ }
530
+ });
531
+
532
+ root
533
+ .command("center-incident-action <incidentId> <retry|cancel>")
534
+ .description("Retry or cancel a revision-gated Automation Center incident")
535
+ .requiredOption(
536
+ "--expected-revision <revision>",
537
+ "Exact incident revision shown by center-projection",
538
+ )
539
+ .option("--json", "Output as JSON")
540
+ .action(async (incidentId, action, opts, cmd) => {
541
+ const db = _dbFromCtx(cmd);
542
+ let schedulerStore;
543
+ try {
544
+ // Cancellation is incident-local. Retry alone needs the scheduler's
545
+ // dead-letter evidence and owns this short-lived handle.
546
+ if (action === "retry") schedulerStore = openSchedulerStore();
547
+ const result = runAutomationCenterIncidentAction(db, schedulerStore, {
548
+ incidentId,
549
+ action,
550
+ expectedRevision: opts.expectedRevision,
551
+ });
552
+ if (opts.json) console.log(JSON.stringify(result, null, 2));
553
+ else logger.success(`${incidentId} ${action} completed`);
554
+ } catch (error) {
555
+ if (opts.json) {
556
+ console.log(
557
+ JSON.stringify(
558
+ automationCenterIncidentActionErrorEnvelope(error, {
559
+ incidentId,
560
+ action,
561
+ }),
562
+ null,
563
+ 2,
564
+ ),
565
+ );
566
+ } else logger.error(error.message);
567
+ process.exitCode = 1;
568
+ } finally {
569
+ schedulerStore?.close();
468
570
  await shutdown();
469
571
  }
470
572
  });
@@ -9,6 +9,14 @@ import fs from "fs";
9
9
  import path from "path";
10
10
  import { logger } from "../lib/logger.js";
11
11
 
12
+ async function loadCoworkWorkflowRecord(cwd, id, definitionDigest) {
13
+ const { getWorkflowRecord, getWorkflowVersion } =
14
+ await import("../lib/cowork-workflow.js");
15
+ return definitionDigest
16
+ ? getWorkflowVersion(cwd, id, definitionDigest)
17
+ : getWorkflowRecord(cwd, id);
18
+ }
19
+
12
20
  export function registerCoworkCommand(program) {
13
21
  const cowork = program
14
22
  .command("cowork")
@@ -799,6 +807,145 @@ export function registerCoworkCommand(program) {
799
807
  console.log(JSON.stringify(wf, null, 2));
800
808
  });
801
809
 
810
+ workflow
811
+ .command("versions <id>")
812
+ .description("List immutable saved definition versions")
813
+ .option("--json", "Machine-readable JSON output")
814
+ .action(async (id, options) => {
815
+ try {
816
+ const { listWorkflowVersions } =
817
+ await import("../lib/cowork-workflow.js");
818
+ const versions = listWorkflowVersions(process.cwd(), id);
819
+ if (options.json) {
820
+ console.log(JSON.stringify(versions, null, 2));
821
+ return;
822
+ }
823
+ if (versions.length === 0) {
824
+ logger.log(chalk.gray(`No versioned definitions found for '${id}'.`));
825
+ return;
826
+ }
827
+ logger.log(chalk.bold(`${versions.length} immutable version(s):`));
828
+ for (const version of versions) {
829
+ logger.log(` ${version.definitionDigest} ${version.name}`);
830
+ }
831
+ } catch (err) {
832
+ logger.error(err.message);
833
+ process.exitCode = 1;
834
+ }
835
+ });
836
+
837
+ workflow
838
+ .command("manifest <id>")
839
+ .description(
840
+ "Project a versioned, digest-bound workflow definition and DAG plan",
841
+ )
842
+ .option(
843
+ "--definition-digest <sha256>",
844
+ "Inspect an immutable saved definition version",
845
+ )
846
+ .option("--json", "Machine-readable JSON output")
847
+ .action(async (id, options) => {
848
+ try {
849
+ const [{ createDynamicWorkflowManifest }, record] = await Promise.all([
850
+ import("../lib/dynamic-workflow-facade.js"),
851
+ loadCoworkWorkflowRecord(process.cwd(), id, options.definitionDigest),
852
+ ]);
853
+ if (!record) {
854
+ logger.error(`Workflow not found: ${id}`);
855
+ process.exitCode = 1;
856
+ return;
857
+ }
858
+ const projected = createDynamicWorkflowManifest(record.definition);
859
+ const manifest = Object.freeze({
860
+ ...projected,
861
+ definitionAuthority: Object.freeze({
862
+ status: record.status,
863
+ recordSchema: record.recordSchema,
864
+ definitionSchema: record.definitionSchema,
865
+ definitionDigest: record.definitionDigest,
866
+ }),
867
+ });
868
+ if (options.json) {
869
+ console.log(JSON.stringify(manifest, null, 2));
870
+ return;
871
+ }
872
+ logger.log(chalk.bold(`${manifest.definition.name}`));
873
+ logger.log(` schema: ${manifest.schema}`);
874
+ logger.log(` digest: ${manifest.definitionDigest}`);
875
+ logger.log(` authority: ${record.status}`);
876
+ logger.log(` adapter: ${manifest.adapter}`);
877
+ logger.log(` plan: ${manifest.plan.mode}`);
878
+ logger.log(
879
+ ` task calls: ${manifest.plan.worstCaseTaskCalls ?? "unknown"}`,
880
+ );
881
+ logger.log(
882
+ ` resumable: ${manifest.runtimeClaims.durablePauseResume ? "yes" : "no"}`,
883
+ );
884
+ } catch (err) {
885
+ logger.error(err.message);
886
+ process.exitCode = 1;
887
+ }
888
+ });
889
+
890
+ workflow
891
+ .command("preflight <id>")
892
+ .description(
893
+ "Evaluate capability, permission, sandbox, scale, and cost gates",
894
+ )
895
+ .option(
896
+ "--definition-digest <sha256>",
897
+ "Preflight an immutable saved definition version",
898
+ )
899
+ .option("--max-parallel <n>", "Requested maximum parallel steps", "4")
900
+ .option("--json", "Machine-readable JSON output")
901
+ .action(async (id, options) => {
902
+ try {
903
+ const [
904
+ { buildDynamicWorkflowPreflight },
905
+ { captureAmbientExecutionLocation },
906
+ record,
907
+ ] = await Promise.all([
908
+ import("../lib/dynamic-workflow-facade.js"),
909
+ import("../lib/execution-location-runtime.js"),
910
+ loadCoworkWorkflowRecord(process.cwd(), id, options.definitionDigest),
911
+ ]);
912
+ if (!record) {
913
+ logger.error(`Workflow not found: ${id}`);
914
+ process.exitCode = 1;
915
+ return;
916
+ }
917
+ const preflight = buildDynamicWorkflowPreflight({
918
+ workflow: record.definition,
919
+ definitionAuthority: record,
920
+ executionLocation: captureAmbientExecutionLocation(),
921
+ maxParallel: options.maxParallel,
922
+ });
923
+ if (options.json) {
924
+ console.log(JSON.stringify(preflight, null, 2));
925
+ } else {
926
+ const color = preflight.allowed ? chalk.green : chalk.red;
927
+ logger.log(color(preflight.allowed ? "READY" : "BLOCKED"));
928
+ logger.log(` definition: ${preflight.definition.definitionDigest}`);
929
+ logger.log(
930
+ ` task calls: ${preflight.scale.worstCaseTaskCalls ?? "unknown"}`,
931
+ );
932
+ logger.log(
933
+ ` tokens/USD: ${preflight.cost.projectedTokens ?? "unknown"} / ${preflight.cost.projectedUsd ?? "unknown"}`,
934
+ );
935
+ for (const blocker of preflight.blockers) {
936
+ logger.log(chalk.red(` blocker: ${blocker}`));
937
+ }
938
+ for (const warning of preflight.warnings) {
939
+ logger.log(chalk.yellow(` warning: ${warning}`));
940
+ }
941
+ }
942
+ process.exitCode = preflight.allowed ? 0 : 2;
943
+ } catch (err) {
944
+ logger.error(err.message);
945
+ process.exitCode = 1;
946
+ }
947
+ });
948
+
802
949
  workflow
803
950
  .command("add <file>")
804
951
  .description("Add a workflow from a JSON definition file")
@@ -832,6 +979,10 @@ export function registerCoworkCommand(program) {
832
979
  workflow
833
980
  .command("run <id>")
834
981
  .description("Execute a saved workflow end-to-end")
982
+ .option(
983
+ "--definition-digest <sha256>",
984
+ "Replay an immutable saved definition version",
985
+ )
835
986
  .option("--continue-on-error", "Keep running after a step fails", false)
836
987
  .option("--max-parallel <n>", "Max parallel steps per batch", "4")
837
988
  .option(
@@ -840,28 +991,32 @@ export function registerCoworkCommand(program) {
840
991
  false,
841
992
  )
842
993
  .action(async (id, options) => {
843
- const [
844
- { getWorkflow, executeWorkflow, _deps: wfDeps },
845
- { runCoworkTask },
846
- ] = await Promise.all([
847
- import("../lib/cowork-workflow.js"),
848
- import("../lib/cowork-task-runner.js"),
849
- ]);
850
- const wf = getWorkflow(process.cwd(), id);
851
- if (!wf) {
852
- logger.error(`Workflow not found: ${id}`);
853
- process.exit(1);
854
- }
855
- wfDeps.runTask = runCoworkTask;
856
-
857
- logger.log(
858
- chalk.bold(
859
- `\nExecuting workflow '${wf.name}' (${wf.steps.length} steps)...`,
860
- ),
861
- );
994
+ const [{ executeWorkflow, _deps: wfDeps }, { runCoworkTask }] =
995
+ await Promise.all([
996
+ import("../lib/cowork-workflow.js"),
997
+ import("../lib/cowork-task-runner.js"),
998
+ ]);
862
999
  try {
1000
+ const record = await loadCoworkWorkflowRecord(
1001
+ process.cwd(),
1002
+ id,
1003
+ options.definitionDigest,
1004
+ );
1005
+ if (!record) {
1006
+ logger.error(`Workflow not found: ${id}`);
1007
+ process.exitCode = 1;
1008
+ return;
1009
+ }
1010
+ const wf = record.definition;
1011
+ wfDeps.runTask = runCoworkTask;
1012
+ logger.log(
1013
+ chalk.bold(
1014
+ `\nExecuting workflow '${wf.name}' (${wf.steps.length} steps, ${record.definitionDigest})...`,
1015
+ ),
1016
+ );
863
1017
  const result = await executeWorkflow({
864
1018
  workflow: wf,
1019
+ definitionDigest: record.definitionDigest,
865
1020
  cwd: process.cwd(),
866
1021
  maxParallel: parseInt(options.maxParallel, 10) || 4,
867
1022
  continueOnError: !!options.continueOnError,
@@ -3,15 +3,18 @@
3
3
  * permission ruleset (Claude-Code `permissions.{allow,ask,deny}` parity).
4
4
  *
5
5
  * cc permissions list [--json] merged ruleset + source file
6
+ * cc permissions activity [--session <id>] actual resources/effects/recovery
6
7
  * cc permissions test <tool> <args...> dry-run: which rule decides?
7
8
  * cc permissions add <allow|ask|deny> <rule> append a rule to a settings file
8
9
  * cc permissions allow|ask|deny <rule> convenience aliases for add
10
+ * cc permissions scoped <decision> <rule> add a workspace-bound TTL rule
11
+ * cc permissions revoke <id> --revision <n> CAS-revoke a scoped rule
9
12
  * [--local | --user] (default target: project)
10
13
  *
11
- * The ruleset is loaded by settings-loader (user < project < local < env) and
12
- * evaluated by permission-rules (deny > ask > allow). This command only reads
13
- * and edits the files / runs the engine — it does not yet gate the agent tool
14
- * loop (that wiring is a separate, riskier step).
14
+ * The ruleset is loaded by the shared permission authority resolver and
15
+ * evaluated by permission-rules (deny > ask > allow). Scoped mutations are
16
+ * CLI-owned and live outside the repository; IDE clients call this surface
17
+ * instead of editing authority files directly.
15
18
  */
16
19
 
17
20
  import chalk from "chalk";
@@ -24,7 +27,37 @@ const KIND_COLOR = {
24
27
  };
25
28
 
26
29
  const RUNTIME_ADVISORY =
27
- "settings rules are enforced by the Agent Core when loaded into the active runtime; managed host policy and ApprovalGate still apply.";
30
+ "permission rules are enforced by Agent Core; scoped rules are refreshed before every tool call, while managed host policy and ApprovalGate still apply.";
31
+
32
+ const DURATION_UNITS = Object.freeze({
33
+ s: 1000,
34
+ m: 60 * 1000,
35
+ h: 60 * 60 * 1000,
36
+ d: 24 * 60 * 60 * 1000,
37
+ });
38
+
39
+ function parseDurationMs(value) {
40
+ const match = String(value || "")
41
+ .trim()
42
+ .toLowerCase()
43
+ .match(/^(\d+)(s|m|h|d)$/);
44
+ if (!match) {
45
+ throw new Error("duration must be an integer followed by s, m, h, or d");
46
+ }
47
+ const duration = Number(match[1]) * DURATION_UNITS[match[2]];
48
+ if (!Number.isSafeInteger(duration) || duration < 1000) {
49
+ throw new Error("duration must be at least 1s and within the safe range");
50
+ }
51
+ return duration;
52
+ }
53
+
54
+ function parseNonNegativeInteger(value, label) {
55
+ const number = Number(value);
56
+ if (!Number.isSafeInteger(number) || number < 0) {
57
+ throw new Error(`${label} must be a non-negative integer`);
58
+ }
59
+ return number;
60
+ }
28
61
 
29
62
  function printRuntimeAdvisory() {
30
63
  logger.log(chalk.yellow(RUNTIME_ADVISORY));
@@ -49,7 +82,12 @@ function buildArgs(tool, positional, rulesMod) {
49
82
  return {};
50
83
  }
51
84
 
52
- async function persistPermissionRule(decision, rule, options, operation = "add") {
85
+ async function persistPermissionRule(
86
+ decision,
87
+ rule,
88
+ options,
89
+ operation = "add",
90
+ ) {
53
91
  try {
54
92
  const kind = String(decision || "").toLowerCase();
55
93
  if (!["allow", "ask", "deny"].includes(kind)) {
@@ -110,11 +148,13 @@ export function registerPermissionsCommand(program) {
110
148
  .option("--settings <file>", "Also merge an explicit settings file")
111
149
  .action(async (options) => {
112
150
  try {
113
- const { loadSettings } = await import("../lib/settings-loader.cjs");
114
- const { rules, sources, files, managed, managedFile } = loadSettings({
115
- cwd: process.cwd(),
116
- settingsFile: options.settings,
117
- });
151
+ const { loadPermissionAuthority } =
152
+ await import("../lib/permission-authority.js");
153
+ const { rules, sources, files, managed, managedFile, scoped } =
154
+ loadPermissionAuthority({
155
+ cwd: process.cwd(),
156
+ settingsFile: options.settings,
157
+ });
118
158
  if (options.json) {
119
159
  console.log(
120
160
  JSON.stringify(
@@ -124,8 +164,9 @@ export function registerPermissionsCommand(program) {
124
164
  files,
125
165
  managed,
126
166
  managedFile,
167
+ scoped,
127
168
  enforcement: {
128
- status: "advisory/not enforced",
169
+ status: "enforced",
129
170
  note: RUNTIME_ADVISORY,
130
171
  },
131
172
  },
@@ -144,7 +185,7 @@ export function registerPermissionsCommand(program) {
144
185
  "(or create .claude/settings.json with a permissions block)",
145
186
  ),
146
187
  );
147
- return;
188
+ if (!scoped?.rules?.length) return;
148
189
  }
149
190
  for (const kind of ["deny", "ask", "allow"]) {
150
191
  if (rules[kind].length === 0) continue;
@@ -191,6 +232,17 @@ export function registerPermissionsCommand(program) {
191
232
  );
192
233
  }
193
234
  }
235
+ if (scoped?.rules?.length) {
236
+ logger.log(chalk.bold("\nworkspace-scoped rules"));
237
+ for (const record of scoped.rules) {
238
+ const status = record.effectiveStatus || record.status;
239
+ const color = status === "active" ? chalk.green : chalk.gray;
240
+ logger.log(
241
+ ` ${color(status.padEnd(28))} ${record.id} r${record.revision} ${record.decision} ${record.rule}`,
242
+ );
243
+ }
244
+ logger.log(chalk.dim(` authority: ${scoped.file}`));
245
+ }
194
246
  } catch (err) {
195
247
  logger.error(chalk.red(`permissions list failed: ${err.message}`));
196
248
  process.exitCode = 1;
@@ -246,6 +298,82 @@ export function registerPermissionsCommand(program) {
246
298
  }
247
299
  });
248
300
 
301
+ // ── activity ──────────────────────────────────────────────────────────
302
+ cmd
303
+ .command("activity")
304
+ .description(
305
+ "Show actual resource, side-effect, permission, and recovery evidence",
306
+ )
307
+ .option("-s, --session <id>", "Persisted CLI session", "default")
308
+ .option("-n, --limit <n>", "Maximum side-effect records", "50")
309
+ .option("--json", "Output the versioned center projection as JSON")
310
+ .action(async (options) => {
311
+ try {
312
+ const sessionId = String(options.session || "default").trim();
313
+ const limit = Math.max(
314
+ 1,
315
+ Math.min(100, parseNonNegativeInteger(options.limit, "limit")),
316
+ );
317
+ const { loadSideEffectLedger } =
318
+ await import("../lib/side-effect-ledger-store.js");
319
+ const { loadTurnBindingLog } =
320
+ await import("../lib/turn-binding-store.js");
321
+ const { loadMcpLedgerRecovery } =
322
+ await import("../lib/mcp-call-ledger-store.js");
323
+ const { sessionExists } =
324
+ await import("../harness/jsonl-session-store.js");
325
+ const { buildPermissionSideEffectCenter } =
326
+ await import("../lib/permission-side-effect-center.js");
327
+ const mcpRecords = sessionExists(sessionId)
328
+ ? loadMcpLedgerRecovery(sessionId).records
329
+ : [];
330
+ const projection = buildPermissionSideEffectCenter({
331
+ sessionId,
332
+ operations: loadSideEffectLedger(sessionId).list(),
333
+ mcpRecords,
334
+ turns: loadTurnBindingLog(sessionId).list(),
335
+ limit,
336
+ });
337
+ if (options.json) {
338
+ console.log(JSON.stringify(projection, null, 2));
339
+ return;
340
+ }
341
+ if (projection.entries.length === 0) {
342
+ logger.log(
343
+ chalk.gray(`No side-effect evidence for session ${sessionId}.`),
344
+ );
345
+ return;
346
+ }
347
+ logger.log(
348
+ chalk.bold(
349
+ `${projection.entries.length} actual side effect(s) · ${projection.summary.irreversible} irreversible · ${projection.summary.inspect} need inspection`,
350
+ ),
351
+ );
352
+ for (const entry of projection.entries) {
353
+ const coverage =
354
+ entry.recovery.coverage === "full"
355
+ ? chalk.green(entry.recovery.coverage)
356
+ : entry.recovery.coverage === "partial"
357
+ ? chalk.yellow(entry.recovery.coverage)
358
+ : chalk.red(entry.recovery.coverage);
359
+ logger.log(
360
+ `${chalk.cyan(entry.tool)} ${entry.kind} ${entry.state} · recovery ${coverage}/${entry.recovery.action}`,
361
+ );
362
+ for (const [kind, values] of Object.entries(entry.resources)) {
363
+ if (values.length) {
364
+ logger.log(chalk.gray(` ${kind}: ${values.join(", ")}`));
365
+ }
366
+ }
367
+ for (const warning of entry.unresolvedResources) {
368
+ logger.log(chalk.yellow(` unresolved: ${warning}`));
369
+ }
370
+ }
371
+ } catch (err) {
372
+ logger.error(chalk.red(`permissions activity failed: ${err.message}`));
373
+ process.exitCode = 1;
374
+ }
375
+ });
376
+
249
377
  // ── test (dry-run) ─────────────────────────────────────────────────────
250
378
  cmd
251
379
  .command("test <tool> [args...]")
@@ -256,13 +384,14 @@ export function registerPermissionsCommand(program) {
256
384
  .option("--settings <file>", "Also merge an explicit settings file")
257
385
  .action(async (tool, args, options) => {
258
386
  try {
259
- const { loadSettings, ruleSource } =
260
- await import("../lib/settings-loader.cjs");
387
+ const { ruleSource } = await import("../lib/settings-loader.cjs");
388
+ const { loadPermissionAuthority } =
389
+ await import("../lib/permission-authority.js");
261
390
  // .cjs default-export interop: module.exports surfaces as `.default`.
262
391
  const rulesMod = await import("../lib/permission-rules.cjs");
263
392
  const mod = rulesMod.default || rulesMod;
264
393
 
265
- const { rules, sources } = loadSettings({
394
+ const { rules, sources } = loadPermissionAuthority({
266
395
  cwd: process.cwd(),
267
396
  settingsFile: options.settings,
268
397
  });
@@ -392,4 +521,99 @@ export function registerPermissionsCommand(program) {
392
521
  await persistPermissionRule(decision, rule, options, decision);
393
522
  });
394
523
  }
524
+
525
+ cmd
526
+ .command("scoped <decision> <rule>")
527
+ .description(
528
+ "Create a workspace-bound, expiring rule in the CLI security store",
529
+ )
530
+ .requiredOption(
531
+ "--expires-in <duration>",
532
+ "TTL such as 30s, 15m, 2h, or 1d",
533
+ )
534
+ .option("--reason <text>", "Human-readable reason for the grant")
535
+ .option(
536
+ "--expected-generation <n>",
537
+ "Create only if the store generation still matches",
538
+ )
539
+ .option("--json", "Output as JSON")
540
+ .action(async (decision, rule, options) => {
541
+ try {
542
+ const ttlMs = parseDurationMs(options.expiresIn);
543
+ const expectedGeneration =
544
+ options.expectedGeneration === undefined
545
+ ? null
546
+ : parseNonNegativeInteger(
547
+ options.expectedGeneration,
548
+ "expected generation",
549
+ );
550
+ const { ScopedPermissionStore } =
551
+ await import("../lib/scoped-permission-store.js");
552
+ const store = new ScopedPermissionStore({ cwd: process.cwd() });
553
+ const record = store.add({
554
+ decision,
555
+ rule,
556
+ expiresAt: Date.now() + ttlMs,
557
+ reason: options.reason || "",
558
+ expectedGeneration,
559
+ });
560
+ if (options.json) {
561
+ console.log(
562
+ JSON.stringify(
563
+ {
564
+ record,
565
+ authority: {
566
+ file: store.filePath,
567
+ workspace: store.workspace,
568
+ },
569
+ },
570
+ null,
571
+ 2,
572
+ ),
573
+ );
574
+ return;
575
+ }
576
+ logger.log(
577
+ `${KIND_COLOR[record.decision].bold("✓ scoped " + record.decision)} ${record.rule}`,
578
+ );
579
+ logger.log(
580
+ chalk.gray(
581
+ ` ${record.id} r${record.revision}; expires ${new Date(record.expiresAt).toISOString()}`,
582
+ ),
583
+ );
584
+ } catch (err) {
585
+ logger.error(chalk.red(`permissions scoped failed: ${err.message}`));
586
+ process.exitCode = 1;
587
+ }
588
+ });
589
+
590
+ cmd
591
+ .command("revoke <id>")
592
+ .description("Revoke a workspace-scoped rule with revision CAS")
593
+ .requiredOption("--revision <n>", "Expected record revision")
594
+ .option("--json", "Output as JSON")
595
+ .action(async (id, options) => {
596
+ try {
597
+ const expectedRevision = parseNonNegativeInteger(
598
+ options.revision,
599
+ "revision",
600
+ );
601
+ const { ScopedPermissionStore } =
602
+ await import("../lib/scoped-permission-store.js");
603
+ const store = new ScopedPermissionStore({ cwd: process.cwd() });
604
+ const record = store.revoke({ id, expectedRevision });
605
+ if (options.json) {
606
+ console.log(JSON.stringify({ record }, null, 2));
607
+ return;
608
+ }
609
+ logger.log(
610
+ chalk.green(
611
+ `Revoked ${record.id} at revision ${record.revision} (${record.rule})`,
612
+ ),
613
+ );
614
+ } catch (err) {
615
+ logger.error(chalk.red(`permissions revoke failed: ${err.message}`));
616
+ process.exitCode = 1;
617
+ }
618
+ });
395
619
  }