chainlesschain 0.163.8 → 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 (228) hide show
  1. package/package.json +4 -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-CavM7W3k.js → AIOps-D2MEn7fI.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-CUvZGabQ.js → ActionButton-lCW_4Gf0.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-DeBnWnbe.js → Analytics-Bs7i-nsS.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-DbI5kxvd.js → AppLayout-CK7B6S_j.js} +5 -5
  9. package/src/assets/web-panel/assets/{Artifacts-D93bigKm.js → Artifacts-C8ILjpyo.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-CBNvfUZa.js → Audit-Bb9cNaWc.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-CJLyh_YU.js → BackgroundAgents-sC9ooXIf.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-D_0yoehD.js → Backup-D-DrsplT.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-TJxmbObW.js → BaseInput-uCNZpwSK.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-CE0dto1q.js → Chat-CsDK1uE9.js} +6 -6
  15. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CZ5-yYiD.js → ChatBubbleRenderer-OqSDt50w.js} +1 -1
  16. package/src/assets/web-panel/assets/{Checkbox-Ck1RVIVo.js → Checkbox-JhTXM1-K.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-qpoyf6DK.js → Codegen-BbzZLnyD.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-DUyPWjIE.js → Col-D4VW4m4j.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-D_S1BemS.js → Community-BXrYawxV.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-BjxeK-Gc.js → Compact-DCihGy1u.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-Dd3CEJsu.js → Compliance-DlyZ-lk8.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-B4QG7-ad.js → Cowork-DvGZrhbO.js} +3 -3
  23. package/src/assets/web-panel/assets/{Cron-BtZnids5.js → Cron-DUncZi8h.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-CHPfCBFD.js → Crosschain-C_hLuUcm.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-DT8DCEOK.js → DID-b6YSUqxr.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-COQab5_U.js → Dashboard-uvM15Cfb.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-BY1PsQuU.js → Dropdown-D1-Nd4qY.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer-CsuAuaq3.js → EmailListRenderer-8ApvL6Zc.js} +1 -1
  29. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BqpinD-j.js → FamilyGuardDashboard-LYJt8811.js} +1 -1
  30. package/src/assets/web-panel/assets/{Federation-D0gkfQFv.js → Federation-BbI3HGpv.js} +1 -1
  31. package/src/assets/web-panel/assets/{FormItemContext-BqgE-axK.js → FormItemContext-DSoEKuFu.js} +1 -1
  32. package/src/assets/web-panel/assets/{GenericCardRenderer-D0hJ2KvC.js → GenericCardRenderer-B0S9OWd5.js} +1 -1
  33. package/src/assets/web-panel/assets/{Git-CmMB0uPY.js → Git-DIs9Zhf3.js} +2 -2
  34. package/src/assets/web-panel/assets/{Governance-BnVEI0Dk.js → Governance-jzZXrxcl.js} +1 -1
  35. package/src/assets/web-panel/assets/{Inference-YTAMihRP.js → Inference-JUPjf2ZI.js} +1 -1
  36. package/src/assets/web-panel/assets/{KnowledgeGraph-0ax7VHop.js → KnowledgeGraph-DxnfJvlP.js} +1 -1
  37. package/src/assets/web-panel/assets/{Logs-B9TRcokL.js → Logs-iXiz8BEE.js} +2 -2
  38. package/src/assets/web-panel/assets/MarkdownRenderer-GmB6DOr6.js +1 -0
  39. package/src/assets/web-panel/assets/{Marketplace-B6CSuD_H.js → Marketplace-Y3Xch312.js} +1 -1
  40. package/src/assets/web-panel/assets/{McpTools-CjMXvOVU.js → McpTools-D7kGGbO7.js} +3 -3
  41. package/src/assets/web-panel/assets/{Memory-CXRF71U3.js → Memory-Do_hVxzh.js} +2 -2
  42. package/src/assets/web-panel/assets/{MobileBridge-DQgNp_oS.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-6hDTRPe1.js → Mtc-qo5QCTGd.js} +2 -2
  45. package/src/assets/web-panel/assets/{MtcAudit-BlVHU1DS.js → MtcAudit-cq5mnjYj.js} +2 -2
  46. package/src/assets/web-panel/assets/{Multisig-DP9pzEbV.js → Multisig-Bq0MAQHw.js} +3 -3
  47. package/src/assets/web-panel/assets/{NLProgramming-Djorh8EV.js → NLProgramming-DdWE6Vi2.js} +1 -1
  48. package/src/assets/web-panel/assets/{Notes-oLZ-JkUg.js → Notes-BxMBFcIp.js} +4 -4
  49. package/src/assets/web-panel/assets/{NotificationSettings-Cg288VH3.js → NotificationSettings-RTrAcbUe.js} +1 -1
  50. package/src/assets/web-panel/assets/{OrderTableRenderer-Bb1O3Ofr.js → OrderTableRenderer-DJbpGqzT.js} +1 -1
  51. package/src/assets/web-panel/assets/{Organization-CBdo-bHs.js → Organization-SQzIPdqC.js} +2 -2
  52. package/src/assets/web-panel/assets/{Overflow-qZdnVumx.js → Overflow-02yECh22.js} +1 -1
  53. package/src/assets/web-panel/assets/{P2P-D4kNfGNQ.js → P2P-BNg4pNCM.js} +2 -2
  54. package/src/assets/web-panel/assets/{PdhVaultBrowser-DnlMemM7.js → PdhVaultBrowser-BxPJZsD3.js} +5 -5
  55. package/src/assets/web-panel/assets/{Permissions-DHucHFBJ.js → Permissions-CLnDnPAz.js} +3 -3
  56. package/src/assets/web-panel/assets/{PersonalDataHub-BovlOIPR.js → PersonalDataHub-C5m0AjGf.js} +4 -4
  57. package/src/assets/web-panel/assets/{Pipeline-Deru3CQY.js → Pipeline-VwOf5Dhv.js} +1 -1
  58. package/src/assets/web-panel/assets/{Privacy-Bq5oTTbU.js → Privacy-CC0W2hZd.js} +1 -1
  59. package/src/assets/web-panel/assets/{ProjectInit-BfzxVWAz.js → ProjectInit-Dz893Bob.js} +2 -2
  60. package/src/assets/web-panel/assets/{ProjectSettings-CKC6XBtH.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-C_jx4TWX.js → Providers-DeB9IkxK.js} +1 -1
  63. package/src/assets/web-panel/assets/{QrScannerModal-BdIHeVGC.js → QrScannerModal-OCeoaswn.js} +1 -1
  64. package/src/assets/web-panel/assets/{QuickAsk-BwZwAcPD.js → QuickAsk-DenotaAj.js} +1 -1
  65. package/src/assets/web-panel/assets/{Recommend-BNTt0L-m.js → Recommend-Cies_jjI.js} +1 -1
  66. package/src/assets/web-panel/assets/{RemoteSession-Biyn2-Ro.js → RemoteSession-Dxzl5n2T.js} +3 -3
  67. package/src/assets/web-panel/assets/{Reputation-D6VpG32B.js → Reputation-CW0mvxgZ.js} +1 -1
  68. package/src/assets/web-panel/assets/{Row-D_74OvQQ.js → Row-SEd32qZU.js} +1 -1
  69. package/src/assets/web-panel/assets/{RssFeed-BTr0a-BQ.js → RssFeed-BSwnJ3Lm.js} +3 -3
  70. package/src/assets/web-panel/assets/{Search-C3MCFoNU.js → Search-xe2m8bkC.js} +1 -1
  71. package/src/assets/web-panel/assets/{Security-CqW9aJ6s.js → Security-Mq2F9Nro.js} +3 -3
  72. package/src/assets/web-panel/assets/{Services-Cw5GNaHF.js → Services-BKGw2V3P.js} +2 -2
  73. package/src/assets/web-panel/assets/{Skeleton-DZps5qeY.js → Skeleton-DW95-Rxf.js} +1 -1
  74. package/src/assets/web-panel/assets/{Skills-C6NQ1znT.js → Skills-CHgChCv_.js} +1 -1
  75. package/src/assets/web-panel/assets/{Sla-DFP8G2Sh.js → Sla-tKh6k3R7.js} +1 -1
  76. package/src/assets/web-panel/assets/{SpeechSettings-ESt6MB6v.js → SpeechSettings-D6UL3dA5.js} +1 -1
  77. package/src/assets/web-panel/assets/{SyncSettings-BHnN98aM.js → SyncSettings-D0Fw8fVL.js} +2 -2
  78. package/src/assets/web-panel/assets/{Tasks-NiSCaOf-.js → Tasks-20x1GB3D.js} +1 -1
  79. package/src/assets/web-panel/assets/{Templates-DsKFhW2C.js → Templates-DJ-lts-a.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tenant-CQ0E0ze5.js → Tenant-BFdGpbs7.js} +1 -1
  81. package/src/assets/web-panel/assets/{Terminal-D_rBu_by.js → Terminal-Xpx61vHL.js} +2 -2
  82. package/src/assets/web-panel/assets/{TimelineRenderer-D3Vm4Po4.js → TimelineRenderer-C6UIvyZQ.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tokens-DNTxRH6q.js → Tokens-Dellq08f.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trigger-Dgprz1ms.js → Trigger-VKw8d0J-.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trust-B2rUnVBD.js → Trust-DNftdKT5.js} +1 -1
  86. package/src/assets/web-panel/assets/{UkeySign-DEGQNc6_.js → UkeySign-DX9VAKJI.js} +1 -1
  87. package/src/assets/web-panel/assets/{VideoEditing-jlsAx3Eh.js → VideoEditing-B2h3jO8q.js} +1 -1
  88. package/src/assets/web-panel/assets/{Wallet-8jQih1ij.js → Wallet-CjGkof7f.js} +4 -4
  89. package/src/assets/web-panel/assets/{WebAuthn-XLeO6xIB.js → WebAuthn-2Zfcu55P.js} +4 -4
  90. package/src/assets/web-panel/assets/{WorkflowEditor-De_dgDAG.js → WorkflowEditor-B9eZ8UxZ.js} +1 -1
  91. package/src/assets/web-panel/assets/{chat-CI19R_Sk.js → chat-CQNfD-YO.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-DsYTOYN3.js → colors-D4usyFT2.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-CM3-t_Qr.js → compact-item-s4TpjvjX.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-BjxlBRZv.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-RDaWX_4i.js → hasIn-AdkUbkV-.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BN6UPD2E.js → index--00U6vXZ.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CiECJi-Q.js → index-B2V-eKfK.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CnHH7bnD.js → index-B4JJCfQ2.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CjTrRt13.js → index-BIoG5yYf.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-Dxge-xWl.js → index-BMcimU-2.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-9R6BxAr0.js → index-BPhkFZ1I.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BHNYPO0b.js → index-BQ3DXBtD.js} +3 -3
  104. package/src/assets/web-panel/assets/{index-Cpqm1qfU.js → index-Bad4VNvz.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-B9O9YyWE.js → index-BgiXR_-_.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-B5REnKt8.js → index-BtobShro.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-D6sm5-Xq.js → index-Bw2MEnUk.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DcPFB8qJ.js → index-C1mJtE6q.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BKJr-TZp.js → index-C484EJiS.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Drlnwr8F.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-Dsij_KsN.js → index-C7Y8Aluc.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-IeiL9RKc.js → index-CCsM_Ybx.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-B-Z8eFUJ.js → index-CJCFe2Qf.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CyOGN6a5.js → index-CJVEOa4i.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-B0PMlbMs.js → index-CJdQrZth.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-nAH87mQP.js → index-CKC1t3Ic.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BGqqJfL0.js → index-CQhAVU5t.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Cd9OJhHG.js → index-CYdoQsa1.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-D0zcy54x.js → index-Cduu2Hhr.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DIUnNOjG.js → index-CkwiSLhU.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CVQMeiwH.js → index-Cvyt-zhm.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BlT2VAEK.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-C0yx-jtQ.js → index-DARsAyUp.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-Bi46Xu4u.js → index-DVKfQ0Ux.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Cd3euP_4.js → index-DZT36ZYq.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BCnZyIMA.js → index-D_XBHopw.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-C4gkzxkw.js → index-DdCB70SS.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-B7WBt_4T.js → index-DzRjHxEv.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DX7tuWVJ.js → index-MMN9V6JF.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DoQA0-52.js → index-RfMr79MW.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DXXtGMUJ.js → index-_IRVsV9X.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-pPL66J85.js → index-nXyk8GZ9.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-DyIWssPC.js → index-s_buFMEG.js} +1 -1
  136. package/src/assets/web-panel/assets/{initDefaultProps-BTL88of4.js → initDefaultProps-Blmpk7HL.js} +1 -1
  137. package/src/assets/web-panel/assets/{motion-BUB2pXwB.js → motion-DPBJMv1n.js} +1 -1
  138. package/src/assets/web-panel/assets/{move-egCkkOMm.js → move-ButdzCM7.js} +1 -1
  139. package/src/assets/web-panel/assets/{mtc-parser-DAWhZC8c.js → mtc-parser-cyRC_QCe.js} +1 -1
  140. package/src/assets/web-panel/assets/{omit-CvOxe_6d.js → omit-1epSV7hz.js} +1 -1
  141. package/src/assets/web-panel/assets/{pickAttrs-DZUSLZ5Z.js → pickAttrs-DuPY8xJs.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-BERxGNMY.js → placementArrow-6XZqarhe.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-DZuDfZ9n.js → responsiveObserve-B40pXBWM.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-DO756sgI.js → slide-jbZ9Wu4n.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-BRQlIz28.js → statusUtils-BKQQcVy4.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-DCSfdybl.js → styleChecker-NiKfWjUT.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-LD8dWVve.js → useFlexGapSupport-bQUCvPeb.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-BX9uW2LK.js → useFs-CUGji7ph.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-BPSlPuHU.js → usePersonalDataHub-4veyN2N2.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-BmOILC9V.js → vnode-1-nLug-Z.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-1iKowKGg.js → zoom-dhCeRDMo.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/command-help-index.json +3 -3
  154. package/src/commands/cowork.js +174 -19
  155. package/src/commands/permissions.js +240 -16
  156. package/src/commands/plugin.js +1293 -56
  157. package/src/commands/session-location.js +276 -0
  158. package/src/commands/session.js +2 -0
  159. package/src/data/changelog.json +15 -2
  160. package/src/gateways/ws/action-protocol.js +35 -10
  161. package/src/gateways/ws/remote-session-protocol.js +24 -1
  162. package/src/gateways/ws/ws-agent-handler.js +12 -0
  163. package/src/gateways/ws/ws-server.js +48 -12
  164. package/src/harness/jsonl-session-store.js +341 -24
  165. package/src/harness/mcp-client.js +8 -1
  166. package/src/harness/remote-session-audit.js +1 -0
  167. package/src/harness/remote-session-crypto.js +210 -2
  168. package/src/harness/remote-session-registry.js +159 -6
  169. package/src/harness/session-list-index.js +233 -14
  170. package/src/lib/agent-authority.js +6 -0
  171. package/src/lib/background-agent-keeper-client.js +248 -0
  172. package/src/lib/background-agent-keeper-protocol.js +147 -0
  173. package/src/lib/background-agent-supervisor.js +520 -40
  174. package/src/lib/background-interaction-resolver.js +12 -0
  175. package/src/lib/background-turn-bootstrap-protocol.js +126 -0
  176. package/src/lib/cowork-workflow.js +336 -16
  177. package/src/lib/dynamic-workflow-facade.js +648 -0
  178. package/src/lib/execution-location-contract.js +551 -0
  179. package/src/lib/execution-location-runtime.js +130 -0
  180. package/src/lib/ide-context.js +94 -6
  181. package/src/lib/mcp-stdio-package-materialization.js +166 -14
  182. package/src/lib/packer/pkg-config-generator.js +2 -0
  183. package/src/lib/permission-authority.js +77 -0
  184. package/src/lib/permission-side-effect-center.js +495 -0
  185. package/src/lib/plugin-runtime/install.js +514 -13
  186. package/src/lib/plugin-runtime/marketplace-artifact-readback.js +900 -0
  187. package/src/lib/plugin-runtime/marketplace-catalog.js +1181 -0
  188. package/src/lib/plugin-runtime/marketplace-impact.js +408 -0
  189. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1567 -0
  190. package/src/lib/plugin-security.js +60 -3
  191. package/src/lib/process-execution-broker/index.js +1095 -57
  192. package/src/lib/process-execution-broker/linux-bwrap-descriptor-launch.js +375 -0
  193. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +90 -16
  194. package/src/lib/process-execution-broker/linux-generic-bwrap.js +159 -18
  195. package/src/lib/process-execution-broker/macos-mcp-launcher-contract.js +278 -0
  196. package/src/lib/process-execution-broker/macos-mcp-launcher-protocol.json +23 -0
  197. package/src/lib/process-execution-broker/macos-mcp-launcher.c +1497 -0
  198. package/src/lib/process-execution-broker/mcp-fd-entry-bootstrap.js +37 -0
  199. package/src/lib/process-execution-broker/platform-sandbox.js +2330 -279
  200. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  201. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  202. package/src/lib/process-execution-broker/windows-sandbox.cs +50 -4
  203. package/src/lib/public-ide-capability-manifest.js +3 -0
  204. package/src/lib/remote-approval-bridge.js +123 -17
  205. package/src/lib/remote-membership-authority.js +632 -0
  206. package/src/lib/remote-membership-coordinator.js +2409 -0
  207. package/src/lib/remote-membership-host-store.js +1750 -0
  208. package/src/lib/scoped-permission-store.js +369 -0
  209. package/src/lib/session-anti-rollback-anchor.js +262 -5
  210. package/src/lib/sub-agent-context.js +4 -0
  211. package/src/lib/workflow-definition-contract.js +149 -0
  212. package/src/repl/agent-repl.js +41 -7
  213. package/src/repl/chat-repl.js +2 -0
  214. package/src/repl/clipboard-image.js +735 -16
  215. package/src/repl/ide-status.js +1 -1
  216. package/src/repl/prompt-interactions.js +59 -6
  217. package/src/runtime/agent-core.js +83 -3
  218. package/src/runtime/headless-runner.js +30 -25
  219. package/src/runtime/headless-stream.js +32 -25
  220. package/src/workers/background-agent-keeper.js +498 -0
  221. package/src/workers/background-agent-worker.js +358 -13
  222. package/src/workers/background-turn-bootstrap.js +143 -0
  223. package/src/assets/web-panel/assets/MarkdownRenderer-yySN5YNM.js +0 -1
  224. package/src/assets/web-panel/assets/MobileProjects-DlPwcCbq.js +0 -1
  225. package/src/assets/web-panel/assets/Projects-CMolGhae.js +0 -1
  226. package/src/assets/web-panel/assets/devWarning-S1ld2LwU.js +0 -1
  227. package/src/assets/web-panel/assets/index-Drz6yq0m.js +0 -1
  228. package/src/assets/web-panel/assets/index-uWiUs7S_.js +0 -1
@@ -0,0 +1,276 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { TextDecoder } from "node:util";
4
+ import {
5
+ buildExecutionLocationCatalog,
6
+ buildExecutionLocationHandoffPreview,
7
+ } from "../lib/execution-location-contract.js";
8
+ import { captureAmbientExecutionLocation } from "../lib/execution-location-runtime.js";
9
+ import { getVerifiedSessionExecutionLocationAuthority } from "../harness/jsonl-session-store.js";
10
+ import {
11
+ sameFileStatIdentity,
12
+ samePathHandleFileIdentity,
13
+ withTrustedFileParentSync,
14
+ } from "../lib/secure-file-identity.js";
15
+
16
+ const MAX_HANDOFF_FACTS_BYTES = 1024 * 1024;
17
+ export const SESSION_EXECUTION_LOCATION_AUTHORITY_SCHEMA =
18
+ "cc-session-execution-location-authority/v1";
19
+
20
+ function readHandoffFacts(filePath, deps = {}) {
21
+ const runtimeFs = deps.fs || fs;
22
+ const withTrustedParent =
23
+ deps.withTrustedFileParentSync || withTrustedFileParentSync;
24
+ return withTrustedParent(
25
+ runtimeFs,
26
+ path.resolve(filePath),
27
+ ({ canonicalPath, parentDevice }) => {
28
+ const before = runtimeFs.lstatSync(canonicalPath, { bigint: true });
29
+ if (
30
+ before.isSymbolicLink() ||
31
+ !before.isFile() ||
32
+ Number(before.nlink) !== 1
33
+ ) {
34
+ throw new Error("handoff facts must be a regular, single-link file");
35
+ }
36
+ const size = Number(before.size);
37
+ if (size <= 0 || size > MAX_HANDOFF_FACTS_BYTES) {
38
+ throw new Error(
39
+ `handoff facts must be 1..${MAX_HANDOFF_FACTS_BYTES} bytes`,
40
+ );
41
+ }
42
+ let descriptor = null;
43
+ try {
44
+ descriptor = runtimeFs.openSync(
45
+ canonicalPath,
46
+ runtimeFs.constants.O_RDONLY |
47
+ Number(runtimeFs.constants.O_NOFOLLOW || 0),
48
+ );
49
+ const opened = runtimeFs.fstatSync(descriptor, { bigint: true });
50
+ const samePathHandle =
51
+ deps.samePathHandleFileIdentity || samePathHandleFileIdentity;
52
+ if (
53
+ !opened.isFile() ||
54
+ Number(opened.nlink) !== 1 ||
55
+ !samePathHandle(before, opened, parentDevice, deps.runtime)
56
+ ) {
57
+ throw new Error("handoff facts identity changed while opening");
58
+ }
59
+ const bounded = Buffer.allocUnsafe(MAX_HANDOFF_FACTS_BYTES + 1);
60
+ let bytesRead = 0;
61
+ while (bytesRead < bounded.length) {
62
+ const count = runtimeFs.readSync(
63
+ descriptor,
64
+ bounded,
65
+ bytesRead,
66
+ bounded.length - bytesRead,
67
+ null,
68
+ );
69
+ if (count === 0) break;
70
+ bytesRead += count;
71
+ }
72
+ if (bytesRead > MAX_HANDOFF_FACTS_BYTES) {
73
+ throw new Error(
74
+ `handoff facts exceed ${MAX_HANDOFF_FACTS_BYTES} bytes`,
75
+ );
76
+ }
77
+ const after = runtimeFs.fstatSync(descriptor, { bigint: true });
78
+ if (
79
+ Number(after.size) !== bytesRead ||
80
+ !(deps.sameFileStatIdentity || sameFileStatIdentity)(opened, after)
81
+ ) {
82
+ throw new Error("handoff facts changed while being read");
83
+ }
84
+ return JSON.parse(
85
+ new TextDecoder("utf-8", { fatal: true }).decode(
86
+ bounded.subarray(0, bytesRead),
87
+ ),
88
+ );
89
+ } finally {
90
+ if (descriptor !== null) runtimeFs.closeSync(descriptor);
91
+ }
92
+ },
93
+ { runtime: deps.runtime },
94
+ );
95
+ }
96
+
97
+ export function projectCurrentExecutionLocation(options = {}, deps = {}) {
98
+ const binding = (
99
+ deps.captureAmbientExecutionLocation || captureAmbientExecutionLocation
100
+ )(options, deps);
101
+ return {
102
+ schema: SESSION_EXECUTION_LOCATION_AUTHORITY_SCHEMA,
103
+ authority: "current-process-observation",
104
+ binding,
105
+ };
106
+ }
107
+
108
+ export function projectSessionExecutionLocation(sessionId, deps = {}) {
109
+ const authority = (
110
+ deps.getVerifiedSessionExecutionLocationAuthority ||
111
+ getVerifiedSessionExecutionLocationAuthority
112
+ )(sessionId);
113
+ return {
114
+ schema: SESSION_EXECUTION_LOCATION_AUTHORITY_SCHEMA,
115
+ authority: "verified-session-start",
116
+ sessionId: authority.sessionId,
117
+ headHash: authority.headHash,
118
+ eventCount: authority.eventCount,
119
+ binding: authority.binding,
120
+ };
121
+ }
122
+
123
+ export function projectExecutionLocationComparison(options = {}, deps = {}) {
124
+ return buildExecutionLocationCatalog(
125
+ (deps.captureAmbientExecutionLocation || captureAmbientExecutionLocation)(
126
+ options,
127
+ deps,
128
+ ),
129
+ );
130
+ }
131
+
132
+ export function projectExecutionLocationHandoff(
133
+ sessionId,
134
+ target,
135
+ factsPath,
136
+ deps = {},
137
+ ) {
138
+ const source = projectSessionExecutionLocation(sessionId, deps);
139
+ const facts = (deps.readHandoffFacts || readHandoffFacts)(factsPath, deps);
140
+ return {
141
+ ...buildExecutionLocationHandoffPreview({
142
+ sourceBinding: source.binding,
143
+ sourceAuthority: {
144
+ sessionId: source.sessionId,
145
+ headHash: source.headHash,
146
+ eventCount: source.eventCount,
147
+ },
148
+ target,
149
+ facts,
150
+ }),
151
+ session: {
152
+ sessionId: source.sessionId,
153
+ headHash: source.headHash,
154
+ eventCount: source.eventCount,
155
+ },
156
+ };
157
+ }
158
+
159
+ function renderBinding(binding) {
160
+ const git = binding.source.git;
161
+ return [
162
+ `Location: ${binding.location}`,
163
+ `Observed: ${binding.observed ? "yes" : "no"}`,
164
+ `Working directory: ${binding.source.cwd || "unknown"}`,
165
+ `Git root: ${git.root || "not detected"}`,
166
+ `Git head: ${git.head || "unknown"}`,
167
+ `Git commit: ${git.commit || "unknown"}`,
168
+ `Tools: ${binding.runtime.tools.join(", ") || "none observed"}`,
169
+ `Model: ${binding.model.provider || "unknown"}/${binding.model.name || "unknown"}`,
170
+ `Credential source: ${binding.model.credentialSource}`,
171
+ `Network policy: ${binding.policy.network}`,
172
+ `Sandbox strength: ${binding.policy.sandbox}`,
173
+ `Data boundary: ${binding.policy.dataBoundary.kind} (${binding.policy.dataBoundary.root || "unknown"})`,
174
+ "Remote Control: controls this host; it is not a remote execution location",
175
+ ].join("\n");
176
+ }
177
+
178
+ function writeProjection(projection, options = {}) {
179
+ if (options.json) {
180
+ process.stdout.write(`${JSON.stringify(projection, null, 2)}\n`);
181
+ return;
182
+ }
183
+ if (projection.binding) {
184
+ process.stdout.write(`${renderBinding(projection.binding)}\n`);
185
+ return;
186
+ }
187
+ if (Array.isArray(projection.locations)) {
188
+ process.stdout.write(
189
+ `${projection.locations
190
+ .map(
191
+ (entry) =>
192
+ `${entry.location.padEnd(10)} ${entry.availability.padEnd(24)} launch=${entry.capabilities.launch} resume=${entry.capabilities.resume} sandbox=${entry.policy.sandbox} network=${entry.policy.network}`,
193
+ )
194
+ .join(
195
+ "\n",
196
+ )}\nRemote Control is a control plane, not an execution location.\n`,
197
+ );
198
+ return;
199
+ }
200
+ process.stdout.write(
201
+ `${projection.allowed ? "ALLOWED" : "BLOCKED"}\n${
202
+ projection.blockers.length > 0
203
+ ? `Blockers:\n${projection.blockers.map((item) => `- ${item}`).join("\n")}\n`
204
+ : ""
205
+ }`,
206
+ );
207
+ }
208
+
209
+ function runAction(action, options = {}) {
210
+ try {
211
+ const projection = action();
212
+ writeProjection(projection, options);
213
+ return projection.allowed === false ? 2 : 0;
214
+ } catch (error) {
215
+ process.stderr.write(`Execution location failed: ${error.message}\n`);
216
+ return 1;
217
+ }
218
+ }
219
+
220
+ export function registerSessionLocationSubcommands(session) {
221
+ const location = session
222
+ .command("location")
223
+ .description(
224
+ "Inspect verified execution location, capabilities, and handoff safety",
225
+ );
226
+
227
+ location
228
+ .command("current")
229
+ .description("Observe where this CLI process is executing")
230
+ .option("--json", "Machine-readable JSON output")
231
+ .action((options) => {
232
+ process.exitCode = runAction(
233
+ () => projectCurrentExecutionLocation({}, {}),
234
+ options,
235
+ );
236
+ });
237
+
238
+ location
239
+ .command("show <id>")
240
+ .description("Show the execution location anchored by session_start")
241
+ .option("--json", "Machine-readable JSON output")
242
+ .action((id, options) => {
243
+ process.exitCode = runAction(
244
+ () => projectSessionExecutionLocation(id),
245
+ options,
246
+ );
247
+ });
248
+
249
+ location
250
+ .command("compare")
251
+ .description(
252
+ "Compare current and declared Local/WSL/SSH/Container/Cloud capabilities",
253
+ )
254
+ .option("--json", "Machine-readable JSON output")
255
+ .action((options) => {
256
+ process.exitCode = runAction(
257
+ () => projectExecutionLocationComparison({}, {}),
258
+ options,
259
+ );
260
+ });
261
+
262
+ location
263
+ .command("handoff <id> <target>")
264
+ .description("Preview a fail-closed, secret-free session handoff")
265
+ .requiredOption(
266
+ "--facts <path>",
267
+ "Versioned Git/summary/artifact/permission/target evidence JSON",
268
+ )
269
+ .option("--json", "Machine-readable JSON output")
270
+ .action((id, target, options) => {
271
+ process.exitCode = runAction(
272
+ () => projectExecutionLocationHandoff(id, target, options.facts),
273
+ options,
274
+ );
275
+ });
276
+ }
@@ -66,6 +66,7 @@ import { executionBroker } from "../lib/process-execution-broker/index.js";
66
66
  import { registerSessionMcpRecoveryCommands } from "./session-mcp-recovery.js";
67
67
  import { registerSessionShowSubcommand } from "./session-show.js";
68
68
  import { registerSessionObservabilitySubcommand } from "./session-observability.js";
69
+ import { registerSessionLocationSubcommands } from "./session-location.js";
69
70
 
70
71
  export const _deps = {
71
72
  execFileSync: (...args) => executionBroker.execFileSync(...args),
@@ -222,6 +223,7 @@ export function registerSessionCommand(program) {
222
223
  .description("Conversation session management");
223
224
 
224
225
  registerSessionMcpRecoveryCommands(session);
226
+ registerSessionLocationSubcommands(session);
225
227
 
226
228
  // session list
227
229
  session
@@ -1,6 +1,19 @@
1
1
  {
2
2
  "source": "CHANGELOG.md",
3
3
  "releases": [
4
+ {
5
+ "productVersion": null,
6
+ "cliVersion": "0.164.0",
7
+ "cliVersions": ["0.163.8", "0.164.0"],
8
+ "date": "2026-08-15",
9
+ "title": "",
10
+ "sections": [
11
+ {
12
+ "heading": "Added — cc CLI 0.164.0: governed marketplace, execution authority, and native isolation hardening",
13
+ "body": "> `chainlesschain` **0.163.8 → 0.164.0** (candidate; not yet published,\n> 2026-08-15).\n> CLI-only candidate; `@chainlesschain/personal-data-hub` remains **0.4.57**\n> and `@chainlesschain/agent-sdk` remains **0.1.7**.\n\n- **Native clipboard images**: `/paste-image` can attach bounded PNG, JPEG,\n GIF, and WebP clipboard payloads to the next vision turn. Windows, macOS,\n Wayland, and X11 host adapters use literal arguments, private temporary\n files, signature checks, byte/count limits, and the Process Broker boundary.\n- **Scoped execution and context authority**: runtime permissions now expose\n exact side-effect explanations and scoped decisions, while session execution\n locations, IDE context-center evidence, prompt interactions, and durable\n workflow definitions carry versioned identities instead of ambient context.\n- **Governed plugin marketplace**: catalog, multi-registry candidate selection,\n install authority, update-impact review, artifact byte readback, and remote\n artifact verification bind publisher, digest, signature, source, policy, and\n approval evidence before plugin installation or update.\n- **Background keeper containment**: an independent keeper records Worker and\n descendant PIDs, retires interrupted turns under bounded Windows identity and\n cleanup budgets, and emits strict formal/smoke evidence contracts. The local\n real-spawn regression is green; the three-platform formal keeper aggregate is\n still required before P1-2 can be marked complete.\n- **MCP capsule boundary evidence**: materialized capsules bind the exact Node\n builtin capability set and OS execution-context requirements. Formal evidence\n now hashes and reparses each live result and schedules three independent\n fresh-isolate probes per platform across a two-hour span; smoke evidence is\n explicitly non-qualifying.\n- **Session and remote-approval hardening**: canonical session persistence gains\n additional crash and anti-rollback checks. Client-hosted remote approval uses\n durable same-machine membership epochs and fails closed on stale, revoked, or\n unavailable authority. Signed coordinator/host lease modules are included as\n a foundation only; they are not yet wired as a complete cross-host dispatch\n fence and do not claim distributed consensus or revoke closure.\n- **Linux dynamic-native isolation candidate**: strict Linux native execution\n recursively attests the ELF startup graph, snapshots caller-owned runtime and\n plugin bytes, exposes only a read-only descriptor-bound namespace, and blocks\n loader-input acquisition and nested mount namespaces with a dynamic-only\n seccomp profile. The typed claim is limited to pathname-visible loader input;\n broad `sharedLibraryClosure` remains false, JIT/custom loaders are excluded,\n and packed Linux runtimes fail closed until separately supported.\n- **macOS signed launcher candidate**: a fixed signed/root helper contract can\n copy and hash runtime and entry descriptors into root-protected snapshots,\n gate entry until the runtime pathname is removed, supervise the target, and\n fail closed when ownership, receipt, protocol, or signing evidence differs.\n It remains disabled until the protected x64/arm64 workflow proves Developer\n ID signing, notarization, root package installation, and the full live race\n matrix; it does not claim shared-library closure.\n- **Compatibility and reliability boundary**: reaching the documented\n `0.164.0` removal floor does not replace representative telemetry. All 25\n compatibility aliases remain retained because approved cohort export,\n three-platform reporting coverage, accepted points, and per-command usage are\n still absent. The scheduler campaign remains incomplete, and the uncommitted\n remote `run_shell` lease-consumption vertical is excluded after its expanded\n parallel matrix did not finish fully green.\n- **Release authority hardening**: manual npm workflow runs are dry-run only;\n production packaging and publishing require an immutable `v-npm-*` tag-push\n event. Operator-controlled version text is no longer interpolated into shell\n scripts, release Actions are commit-pinned, and independent readback validates\n a canonical numeric SemVer before resolving the tag and attested artifact.\n- **Release status**: final tag, source SHA, workflow run IDs, package digests,\n provenance, and registry readback are intentionally omitted until the exact\n `0.164.0` release merge commit passes complete `CLI CI` and\n `CLI Strict Sandbox` matrices on Linux, Windows, and macOS, followed by the\n dedicated npm release and independent public readback workflows."
14
+ }
15
+ ]
16
+ },
4
17
  {
5
18
  "productVersion": null,
6
19
  "cliVersion": "0.163.8",
@@ -10,7 +23,7 @@
10
23
  "sections": [
11
24
  {
12
25
  "heading": "Added — cc CLI 0.163.8: governed recovery, merge review, and MCP resource templates",
13
- "body": "> `chainlesschain` **0.163.7 → 0.163.8** (candidate; not yet published,\n> 2026-08-14).\n> CLI-only candidate; `@chainlesschain/personal-data-hub` remains **0.4.57**\n> and `@chainlesschain/agent-sdk` remains **0.1.7**.\n\n- **Crash-safe scheduler source persistence**: Agenda and Cowork authoritative\n stores now reject unreadable, malformed, and non-object records instead of\n treating them as empty state. Generation replacement uses private exclusive\n temporary files, complete short-write loops, file fsync, atomic rename, and\n POSIX directory fsync, while distinguishing pre-rename `not-committed`\n failures from post-rename durability-unknown outcomes.\n- **Deterministic scheduler disk-fault closure**: fault injection covers ENOSPC,\n partial writes, file and directory fsync failures, rename failures, corrupted\n source stores, native SQLite `SQLITE_FULL` transaction rollback, Automation\n source rollback atomicity, database truncation, and clean reopen behavior.\n Routine and Loop retain their existing durable-store and append/CAS\n protections.\n- **Governed Automation runtime recovery**: scheduler-backed Automation work can\n expose exact-fence, control-revision, capability-bound pause and resume safe\n points. Revisioned incidents support bounded retry or cancellation; retry\n revalidates the exact dead-letter occurrence, run identity, fence, and error\n evidence, while manual incidents are not silently replayed.\n- **Governed multi-agent merge review**: `cc team merge-review` subcommands\n `preview|show|apply|rollback` provide stable file and hunk selection,\n digest-bound decisions, durable conflict evidence, guarded cross-branch batch\n publication, and retained-history rollback. Git hooks, repository-local\n configuration, inherited environment, stale revisions, oversized selections,\n and changed branch identities fail closed.\n- **Read-only MCP resource templates**: templates-only MCP servers can now\n register the existing resource surface. The new\n `list_mcp_resource_templates {server?}` tool reads the bounded discovery\n cache, supports explicit server filtering, and lets the model instantiate a\n concrete URI before using the existing `read_mcp_resource` boundary. It does\n not add an implicit network request, subscription, or automatic URI\n expansion.\n- **Explicit optional-protocol decisions**: resource templates enter the\n production read-only surface; resource subscriptions, peer-controlled\n logging, and completion remain deferred pending bounded consumers and\n cancellation/recovery UX. MCP sampling remains undeclared and server\n `createMessage` requests continue to return JSON-RPC `-32601`.\n- **Transaction-time scheduler fencing**: claim, renewal, and settlement paths\n now read their lease clock inside the write transaction, preventing queue\n wait time from turning a pre-transaction timestamp into a stale lease or\n settlement decision.\n- **Formal scheduler soak evidence gate**: Linux, Windows, and macOS workflows\n now exercise two-worker contention, lease/fence recovery, heartbeat renewal,\n stale settlement rejection, outcome-unknown no-replay, DST/backlog behavior,\n SQLite integrity, descendant cleanup, and bounded resource trends. The\n campaign verifier requires at least four identity-bound formal segments whose\n authoritative starts span at least 72 natural hours, with no gap above\n 30 hours.\n- **Release boundary**: the scheduler soak implementation and smoke matrices are\n present, but the required 72-hour formal campaign has not completed; P2-4\n therefore remains partially complete. Signed native distribution,\n representative alias-removal telemetry, and the entire unmerged P2-2 native\n clipboard-image host work remain outside this candidate.\n- **Release status**: final tag, source SHA, workflow run IDs, package digests,\n provenance, and registry readback are intentionally omitted until the exact\n `0.163.8` release merge commit passes complete `CLI CI` and\n `CLI Strict Sandbox` matrices on Linux, Windows, and macOS, followed by the\n dedicated npm release and independent public readback workflows."
26
+ "body": "> `chainlesschain` **0.163.7 → 0.163.8** (published from exact SHA\n> `a0631cb4f97f45ff7fcef9c19d346ed2b8387da6`, 2026-08-14).\n> CLI-only release; `@chainlesschain/personal-data-hub` remains **0.4.57**\n> and `@chainlesschain/agent-sdk` remains **0.1.7**.\n\n- **Crash-safe scheduler source persistence**: Agenda and Cowork authoritative\n stores now reject unreadable, malformed, and non-object records instead of\n treating them as empty state. Generation replacement uses private exclusive\n temporary files, complete short-write loops, file fsync, atomic rename, and\n POSIX directory fsync, while distinguishing pre-rename `not-committed`\n failures from post-rename durability-unknown outcomes.\n- **Deterministic scheduler disk-fault closure**: fault injection covers ENOSPC,\n partial writes, file and directory fsync failures, rename failures, corrupted\n source stores, native SQLite `SQLITE_FULL` transaction rollback, Automation\n source rollback atomicity, database truncation, and clean reopen behavior.\n Routine and Loop retain their existing durable-store and append/CAS\n protections.\n- **Governed Automation runtime recovery**: scheduler-backed Automation work can\n expose exact-fence, control-revision, capability-bound pause and resume safe\n points. Revisioned incidents support bounded retry or cancellation; retry\n revalidates the exact dead-letter occurrence, run identity, fence, and error\n evidence, while manual incidents are not silently replayed.\n- **Governed multi-agent merge review**: `cc team merge-review` subcommands\n `preview|show|apply|rollback` provide stable file and hunk selection,\n digest-bound decisions, durable conflict evidence, guarded cross-branch batch\n publication, and retained-history rollback. Git hooks, repository-local\n configuration, inherited environment, stale revisions, oversized selections,\n and changed branch identities fail closed.\n- **Read-only MCP resource templates**: templates-only MCP servers can now\n register the existing resource surface. The new\n `list_mcp_resource_templates {server?}` tool reads the bounded discovery\n cache, supports explicit server filtering, and lets the model instantiate a\n concrete URI before using the existing `read_mcp_resource` boundary. It does\n not add an implicit network request, subscription, or automatic URI\n expansion.\n- **Explicit optional-protocol decisions**: resource templates enter the\n production read-only surface; resource subscriptions, peer-controlled\n logging, and completion remain deferred pending bounded consumers and\n cancellation/recovery UX. MCP sampling remains undeclared and server\n `createMessage` requests continue to return JSON-RPC `-32601`.\n- **Transaction-time scheduler fencing**: claim, renewal, and settlement paths\n now read their lease clock inside the write transaction, preventing queue\n wait time from turning a pre-transaction timestamp into a stale lease or\n settlement decision.\n- **Formal scheduler soak evidence gate**: Linux, Windows, and macOS workflows\n now exercise two-worker contention, lease/fence recovery, heartbeat renewal,\n stale settlement rejection, outcome-unknown no-replay, DST/backlog behavior,\n SQLite integrity, descendant cleanup, and bounded resource trends. The\n campaign verifier requires at least four identity-bound formal segments whose\n authoritative starts span at least 72 natural hours, with no gap above\n 30 hours.\n- **Release boundary**: the scheduler soak implementation and smoke matrices are\n present, but the required 72-hour formal campaign has not completed; P2-4\n therefore remains partially complete. Signed native distribution,\n representative alias-removal telemetry, and the later P2-2 native\n clipboard-image host work remain outside this immutable release.\n- **Published release evidence**: immutable tag `v-npm-0-163-8` resolves to\n exact source commit `a0631cb4f97f45ff7fcef9c19d346ed2b8387da6`. Its\n three-OS `CLI CI` (`31804468633`) and `CLI Strict Sandbox` (`31804468464`)\n matrices passed; the dedicated npm release (`31806101423`) and independent\n public readback (`31807574517`) succeeded. npm reports `latest=0.163.8`;\n tarball SHA-1 is `655557b5c5b897b23a29975708abbf8d5cd31e88` and SHA-256\n is `862a0f450da013740a1c21d084233b002982b4b816f156e4949b6110eda80e12`."
14
27
  }
15
28
  ]
16
29
  },
@@ -23,7 +36,7 @@
23
36
  "sections": [
24
37
  {
25
38
  "heading": "Added — cc CLI 0.163.7: governed scheduler migration and causal observability",
26
- "body": "> `chainlesschain` **0.163.6 → 0.163.7** (published from exact SHA\n> `3e997168621c53708a1682868c6cc4edc9baf15b`, 2026-08-14).\n> CLI-only release; `@chainlesschain/personal-data-hub` remains **0.4.57**\n> and `@chainlesschain/agent-sdk` remains **0.1.7**.\n\n- **Five-domain migration journal**: Agenda, Cowork Cron, Routine, Automation,\n and Loop migrations use the scheduler store schema-v5 journal with\n domain-typed source locators, immutable source/target digest bindings,\n idempotent recovery, and fail-closed rejection of conflicting or ambiguous\n legacy entries.\n- **Governed rollback controls**: the new scheduler migration `list`, `show`,\n and `rollback` commands expose redacted migration status and blockers.\n Rollback requires the latest evidence digest, an interactive TTY, and the\n exact typed challenge before reopening any legacy source.\n- **Target-first recovery and CAS fencing**: rollback stops or restores the\n scheduler target before restoring the legacy source, validates target\n revision, definition and execution evidence, and makes terminal source\n restoration retry-safe across process crashes. This is not a claim of one\n atomic transaction across independent stores or filesystems.\n- **Fail-closed source identity**: Windows drive and UNC paths are canonicalized\n while relative, incomplete and device-namespace paths are rejected.\n Automation migration requires an existing native SQLite database and refuses\n the non-durable sql.js fallback; Loop restoration remains bound to its durable\n retirement fence, marker and original source digest.\n- **Windows persistence hardening**: team adjudication atomic replacement\n retries only transient Windows `EACCES`, `EBUSY`, and `EPERM` sharing\n failures with bounded backoff and authority-path revalidation. Exhausted,\n non-transient, and non-Windows replacement failures continue to fail closed.\n- **Cross-platform CI hardening**: migration fixtures verify retirement fences\n and canonical source identities consistently across operating systems, while\n distributed-queue and authority test workers use bounded lifetimes and attach\n result observers before short-lived children can exit. Terminal Skill\n authority fixtures now use an explicit parent acknowledgement before clean\n exit, removing Windows IPC exit-before-message ordering ambiguity without\n weakening concurrent revocation assertions.\n- **Verified causal delivery reports**: scoped sessions can be bound by exact\n transcript head and event count to digest-protected delivery states. The new\n session observability commands export a redacted session-to-delivery graph\n spanning diffs, gates, artifacts, pull requests, and merges, with exact\n workspace, team, and policy filters.\n- **Fail-closed call-ledger budgets**: `call-ledger@1` brackets model, retry,\n compaction, subagent, isolated-skill, and tool calls with known or unknown\n settlements. Strict budget mode rejects exceeded and unevaluable results\n instead of treating missing token, cost, retry, or tool-latency evidence as\n zero.\n- **Background recovery authority hardening**: verified transcript CAS,\n delegated recovery leases, IPC sender/nonce binding, bootstrap guards, exact\n process-group termination checks, and terminal cleanup prevent uncertain or\n still-live descendants from authorizing recovery or worktree deletion.\n- **Causal evidence boundary**: report bindings prove exact verified revisions,\n not that a model call semantically caused a source hunk. Scope labels are not\n identity or membership proofs, digests are not signatures, anti-rollback is\n machine-local, and incomplete or legacy ledgers remain partial or unknown.\n- **Release boundary**: deterministic scheduler disk-fault closure landed after\n this immutable release and is not attributed to its tarball. The\n three-platform long-soak campaign, signed native distribution, and\n representative alias-removal telemetry remained outside this release.\n- **Published release evidence**: immutable tag `v-npm-0-163-7` resolves to\n exact source commit `3e997168621c53708a1682868c6cc4edc9baf15b`. Its Linux,\n Windows, and macOS `CLI CI` (`31745391661`, attempt 2) and\n `CLI Strict Sandbox` (`31745391321`) matrices passed; the dedicated npm\n release (`31748153519`) completed its exact-SHA gate, immutable package,\n Trusted Publishing, and signed provenance, and the independent public\n readback (`31749404980`) succeeded. npm reports `latest=0.163.7`; the public\n tarball SHA-1 is `5bfb7471643cfe4d4cd0b0a382b31c63fc1efdff` and SHA-256 is\n `d7ca295e6cdb4e442ee7ad6bb9cc0b9d923f40de4eae395974d91b4dfab83a9d`."
39
+ "body": "> `chainlesschain` **0.163.6 → 0.163.7** (published from exact SHA\n> `3e997168621c53708a1682868c6cc4edc9baf15b`, 2026-08-14).\n> CLI-only release; `@chainlesschain/personal-data-hub` remains **0.4.57**\n> and `@chainlesschain/agent-sdk` remains **0.1.7**.\n\n- **Five-domain migration journal**: Agenda, Cowork Cron, Routine, Automation,\n and Loop migrations use the scheduler store schema-v5 journal with\n domain-typed source locators, immutable source/target digest bindings,\n idempotent recovery, and fail-closed rejection of conflicting or ambiguous\n legacy entries.\n- **Governed rollback controls**: the new scheduler migration `list`, `show`,\n and `rollback` commands expose redacted migration status and blockers.\n Rollback requires the latest evidence digest, an interactive TTY, and the\n exact typed challenge before reopening any legacy source.\n- **Target-first recovery and CAS fencing**: rollback stops or restores the\n scheduler target before restoring the legacy source, validates target\n revision, definition and execution evidence, and makes terminal source\n restoration retry-safe across process crashes. This is not a claim of one\n atomic transaction across independent stores or filesystems.\n- **Fail-closed source identity**: Windows drive and UNC paths are canonicalized\n while relative, incomplete and device-namespace paths are rejected.\n Automation migration requires an existing native SQLite database and refuses\n the non-durable sql.js fallback; Loop restoration remains bound to its durable\n retirement fence, marker and original source digest.\n- **Windows persistence hardening**: team adjudication atomic replacement\n retries only transient Windows `EACCES`, `EBUSY`, and `EPERM` sharing\n failures with bounded backoff and authority-path revalidation. Exhausted,\n non-transient, and non-Windows replacement failures continue to fail closed.\n- **Cross-platform CI hardening**: migration fixtures verify retirement fences\n and canonical source identities consistently across operating systems, while\n distributed-queue and authority test workers use bounded lifetimes and attach\n result observers before short-lived children can exit. Terminal Skill\n authority fixtures now use an explicit parent acknowledgement before clean\n exit, removing Windows IPC exit-before-message ordering ambiguity without\n weakening concurrent revocation assertions.\n- **Verified causal delivery reports**: scoped sessions can be bound by exact\n transcript head and event count to digest-protected delivery states. The new\n session observability commands export a redacted session-to-delivery graph\n spanning diffs, gates, artifacts, pull requests, and merges, with exact\n workspace, team, and policy filters.\n- **Fail-closed call-ledger budgets**: `call-ledger@1` brackets model, retry,\n compaction, subagent, isolated-skill, and tool calls with known or unknown\n settlements. Strict budget mode rejects exceeded and unevaluable results\n instead of treating missing token, cost, retry, or tool-latency evidence as\n zero.\n- **Background recovery authority hardening**: verified transcript CAS,\n delegated recovery leases, IPC sender/nonce binding, bootstrap guards, exact\n process-group termination checks, and terminal cleanup prevent uncertain or\n still-live descendants from authorizing recovery or worktree deletion.\n- **Causal evidence boundary**: report bindings prove exact verified revisions,\n not that a model call semantically caused a source hunk. Scope labels are not\n identity or membership proofs, digests are not signatures, anti-rollback is\n machine-local, and incomplete or legacy ledgers remain partial or unknown.\n- **Published release evidence**: immutable tag `v-npm-0-163-7` resolves to\n exact source commit `3e997168621c53708a1682868c6cc4edc9baf15b`. Its\n three-OS `CLI CI` (`31745391661`, attempt 2) and `CLI Strict Sandbox`\n (`31745391321`) matrices passed; the dedicated npm release (`31748153519`)\n completed exact-SHA gating, immutable artifact, CycloneDX SBOM, Trusted\n Publishing, signed provenance, registry byte verification, and npmmirror\n synchronization. Independent readback (`31749404980`) verified the public\n tarball byte-for-byte against the immutable artifact. npm reports\n `latest=0.163.7`; tarball SHA-1 is\n `5bfb7471643cfe4d4cd0b0a382b31c63fc1efdff` and SHA-256 is\n `d7ca295e6cdb4e442ee7ad6bb9cc0b9d923f40de4eae395974d91b4dfab83a9d`.\n- **Release boundary**: deterministic scheduler disk-fault closure landed\n after this immutable release and must not be attributed to its tarball. The\n three-OS long-soak exit campaign, signed native distribution, and\n representative alias-removal telemetry remain open."
27
40
  }
28
41
  ]
29
42
  },
@@ -310,9 +310,21 @@ export async function handleWorkflowGet(server, id, ws, message) {
310
310
  const { id: wfId } = message || {};
311
311
  if (!wfId) return _sendError(server, ws, id, "MISSING_ID", "id required");
312
312
  try {
313
- const { getWorkflow } = await import("../../lib/cowork-workflow.js");
314
- const workflow = getWorkflow(_cwd(server), wfId);
315
- server._send(ws, { id, type: "workflow:get", workflow: workflow || null });
313
+ const { getWorkflowRecord } = await import("../../lib/cowork-workflow.js");
314
+ const record = getWorkflowRecord(_cwd(server), wfId);
315
+ server._send(ws, {
316
+ id,
317
+ type: "workflow:get",
318
+ workflow: record?.definition || null,
319
+ definitionAuthority: record
320
+ ? {
321
+ status: record.status,
322
+ recordSchema: record.recordSchema,
323
+ definitionSchema: record.definitionSchema,
324
+ definitionDigest: record.definitionDigest,
325
+ }
326
+ : null,
327
+ });
316
328
  } catch (err) {
317
329
  _sendError(server, ws, id, "WORKFLOW_GET_FAILED", err.message);
318
330
  }
@@ -330,7 +342,7 @@ export async function handleWorkflowSave(server, id, ws, message) {
330
342
  );
331
343
  }
332
344
  try {
333
- const { validateWorkflow, saveWorkflow } =
345
+ const { getWorkflowRecord, validateWorkflow, saveWorkflow } =
334
346
  await import("../../lib/cowork-workflow.js");
335
347
  const result = validateWorkflow(workflow);
336
348
  if (!result.valid) {
@@ -343,11 +355,14 @@ export async function handleWorkflowSave(server, id, ws, message) {
343
355
  );
344
356
  }
345
357
  saveWorkflow(_cwd(server), workflow);
358
+ const record = getWorkflowRecord(_cwd(server), workflow.id);
346
359
  server._send(ws, {
347
360
  id,
348
361
  type: "workflow:save",
349
362
  saved: true,
350
363
  workflowId: workflow.id,
364
+ definitionDigest: record.definitionDigest,
365
+ definitionSchema: record.definitionSchema,
351
366
  });
352
367
  } catch (err) {
353
368
  _sendError(server, ws, id, "WORKFLOW_SAVE_FAILED", err.message);
@@ -367,14 +382,16 @@ export async function handleWorkflowRemove(server, id, ws, message) {
367
382
  }
368
383
 
369
384
  export async function handleWorkflowRun(server, id, ws, message) {
370
- const { id: wfId } = message || {};
385
+ const { id: wfId, definitionDigest } = message || {};
371
386
  if (!wfId) return _sendError(server, ws, id, "MISSING_ID", "id required");
372
387
 
373
388
  try {
374
- const { getWorkflow, executeWorkflow } =
389
+ const { getWorkflowRecord, getWorkflowVersion, executeWorkflow } =
375
390
  await import("../../lib/cowork-workflow.js");
376
- const workflow = getWorkflow(_cwd(server), wfId);
377
- if (!workflow) {
391
+ const definitionRecord = definitionDigest
392
+ ? getWorkflowVersion(_cwd(server), wfId, definitionDigest)
393
+ : getWorkflowRecord(_cwd(server), wfId);
394
+ if (!definitionRecord) {
378
395
  return _sendError(
379
396
  server,
380
397
  ws,
@@ -385,7 +402,13 @@ export async function handleWorkflowRun(server, id, ws, message) {
385
402
  }
386
403
 
387
404
  const runId = `wf-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
388
- server._send(ws, { id, type: "workflow:started", runId, workflowId: wfId });
405
+ server._send(ws, {
406
+ id,
407
+ type: "workflow:started",
408
+ runId,
409
+ workflowId: wfId,
410
+ definitionDigest: definitionRecord.definitionDigest,
411
+ });
389
412
 
390
413
  const onStepStart = ({ stepId, message: stepMessage }) => {
391
414
  server._send(ws, {
@@ -408,7 +431,8 @@ export async function handleWorkflowRun(server, id, ws, message) {
408
431
  };
409
432
 
410
433
  const record = await executeWorkflow({
411
- workflow,
434
+ workflow: definitionRecord.definition,
435
+ definitionDigest: definitionRecord.definitionDigest,
412
436
  cwd: _cwd(server),
413
437
  onStepStart,
414
438
  onStepComplete,
@@ -420,6 +444,7 @@ export async function handleWorkflowRun(server, id, ws, message) {
420
444
  runId,
421
445
  status: record?.status || "completed",
422
446
  steps: record?.steps || [],
447
+ definitionDigest: record?.definitionDigest,
423
448
  });
424
449
  } catch (err) {
425
450
  _sendError(server, ws, id, "WORKFLOW_RUN_FAILED", err.message);
@@ -129,6 +129,10 @@ export function handleRemoteSessionCreate(server, clientId, ws, message) {
129
129
  agentSessionId: message.sessionId,
130
130
  name: message.name,
131
131
  scopes: message.scopes,
132
+ // A local/headless approval bridge asks the server to persist a
133
+ // principal/session epoch before it exposes pairing credentials. Older
134
+ // or ordinary server-hosted sessions remain on their in-memory path.
135
+ durableMembership: message.requireDurableMembershipAuthority === true,
132
136
  });
133
137
  audit(server, {
134
138
  sessionId: result.session.sessionId,
@@ -446,7 +450,7 @@ export async function handleRemoteSessionPublish(
446
450
  return;
447
451
  }
448
452
  const requiredScope = CLIENT_EVENT_SCOPES[message.event.type];
449
- const { session } = server.remoteSessions.authorize(
453
+ const { session, membership } = server.remoteSessions.authorize(
450
454
  message.remoteSessionId,
451
455
  clientId,
452
456
  requiredScope || "observe",
@@ -508,6 +512,13 @@ export async function handleRemoteSessionPublish(
508
512
  scopes: ["approve"],
509
513
  principalId: clientId,
510
514
  sessionId: message.remoteSessionId,
515
+ ...(membership
516
+ ? {
517
+ remoteSessionId: membership.sessionId,
518
+ sessionEpoch: membership.sessionEpoch,
519
+ membershipEpoch: membership.membershipEpoch,
520
+ }
521
+ : {}),
511
522
  };
512
523
  const approved = message.event.answer ?? message.event.approved;
513
524
  if (approved === true || approved === "true" || approved === "yes") {
@@ -538,6 +549,11 @@ export async function handleRemoteSessionPublish(
538
549
  "Remote session host is not reachable for this control event",
539
550
  );
540
551
  }
552
+ if (message.event.type === "approval.resolve" && !membership) {
553
+ throw new Error(
554
+ "Durable Remote membership authority is required before forwarding an approval",
555
+ );
556
+ }
541
557
  }
542
558
  // Idempotent forward: a control event with a stable commandId runs its
543
559
  // side effect (audit + dispatch into the host agent) AT MOST ONCE, so a
@@ -594,6 +610,13 @@ export async function handleRemoteSessionPublish(
594
610
  remoteSessionId: message.remoteSessionId,
595
611
  agentSessionId: session.agentSessionId,
596
612
  from: clientId,
613
+ ...(membership
614
+ ? {
615
+ membershipAuthority: membership.authorityVersion,
616
+ sessionEpoch: membership.sessionEpoch,
617
+ membershipEpoch: membership.membershipEpoch,
618
+ }
619
+ : {}),
597
620
  event: message.event,
598
621
  });
599
622
  reply(server, ws, message.id, "remote-session-published", {
@@ -20,6 +20,7 @@ import {
20
20
  persistSideEffectLedger,
21
21
  } from "../../lib/side-effect-ledger-store.js";
22
22
  import { operationIdempotencyKey } from "../../lib/idempotency.js";
23
+ import { collectToolResourceIdentifiers } from "../../lib/permission-side-effect-center.js";
23
24
  import {
24
25
  detectTaskType,
25
26
  selectModelForTask,
@@ -1289,6 +1290,12 @@ export class WSAgentHandler {
1289
1290
  key: se.key,
1290
1291
  meta: {
1291
1292
  tool: event.tool,
1293
+ toolUseId: event.tool_use_id || null,
1294
+ turnId: event.turn_id || null,
1295
+ resources: collectToolResourceIdentifiers(
1296
+ event.tool,
1297
+ event.args,
1298
+ ),
1292
1299
  idempotencyKey: operationIdempotencyKey({
1293
1300
  tool: event.tool,
1294
1301
  args: event.args,
@@ -1329,6 +1336,11 @@ export class WSAgentHandler {
1329
1336
  currentTodoWrite = null;
1330
1337
  if (currentSideEffectOpId) {
1331
1338
  const err = event.error || event.result?.error || null;
1339
+ if (event.permission_decision) {
1340
+ sideEffectLedger.annotate(currentSideEffectOpId, {
1341
+ permissionDecision: event.permission_decision,
1342
+ });
1343
+ }
1332
1344
  if (event.result?._diffReviewAudit) {
1333
1345
  diffReviewFollowUps.observe(
1334
1346
  sideEffectLedger,
@@ -37,6 +37,7 @@ import {
37
37
  isApprovalRequestEvent,
38
38
  } from "../../harness/remote-session-push.js";
39
39
  import { createRemoteSessionPushSender } from "../../harness/remote-session-push-senders.js";
40
+ import { DurableRemoteMembershipAuthority } from "../../lib/remote-membership-authority.js";
40
41
  import { RemoteSessionRelay } from "../remote-session-relay.js";
41
42
  import { handleRemoteSessionPublish } from "./remote-session-protocol.js";
42
43
  import { handleTaskDetail, handleTaskHistory } from "./task-protocol.js";
@@ -273,7 +274,19 @@ export class ChainlessChainWSServer extends EventEmitter {
273
274
  /** Local authorization state for multi-device Remote Sessions. */
274
275
  this.remoteSessions =
275
276
  options.remoteSessionRegistry ||
276
- new RemoteSessionRegistry({ policy: this.remoteSessionPolicy });
277
+ new RemoteSessionRegistry({
278
+ policy: this.remoteSessionPolicy,
279
+ membershipAuthority:
280
+ options.remoteMembershipAuthority === null
281
+ ? null
282
+ : () =>
283
+ options.remoteMembershipAuthority ||
284
+ new DurableRemoteMembershipAuthority(
285
+ options.remoteMembershipStateFile
286
+ ? { filePath: options.remoteMembershipStateFile }
287
+ : {},
288
+ ),
289
+ });
277
290
  /**
278
291
  * Optional durable sink (JSONL) for the audit trail. Enabled only when a
279
292
  * sink is injected or CHAINLESSCHAIN_REMOTE_SESSION_AUDIT_FILE is set; the
@@ -502,16 +515,36 @@ export class ChainlessChainWSServer extends EventEmitter {
502
515
  // remaining clients finalizes itself).
503
516
  cleanupBgAttachments(client);
504
517
  this.clients.delete(clientId);
505
- for (const affected of this.remoteSessions.removeClient(clientId)) {
506
- if (affected.closed)
507
- this.remoteSessionCrypto.delete(affected.sessionId);
508
- if (affected.closed)
509
- this.remoteSessionPairingSecrets.delete(affected.sessionId);
518
+ try {
519
+ for (const affected of this.remoteSessions.removeClient(clientId)) {
520
+ if (affected.closed)
521
+ this.remoteSessionCrypto.delete(affected.sessionId);
522
+ if (affected.closed)
523
+ this.remoteSessionPairingSecrets.delete(affected.sessionId);
524
+ this.remoteSessionAudit?.record({
525
+ sessionId: affected.sessionId,
526
+ actor: clientId,
527
+ action: affected.closed ? "session.closed" : "device.disconnected",
528
+ detail: { reason: "disconnect" },
529
+ });
530
+ }
531
+ } catch (error) {
532
+ // A durable membership transition that cannot be committed must never
533
+ // be represented as a successful revoke/close. The socket is already
534
+ // gone (so this principal cannot send another frame), and every future
535
+ // durable authorization still re-checks the authority store.
510
536
  this.remoteSessionAudit?.record({
511
- sessionId: affected.sessionId,
537
+ sessionId: null,
512
538
  actor: clientId,
513
- action: affected.closed ? "session.closed" : "device.disconnected",
514
- detail: { reason: "disconnect" },
539
+ action: "membership.state-error",
540
+ detail: {
541
+ reason: "disconnect-transition-failed",
542
+ errorCode: error?.code || null,
543
+ },
544
+ });
545
+ this.emit("client-error", {
546
+ clientId,
547
+ error: error?.message || String(error),
515
548
  });
516
549
  }
517
550
  this.emit("disconnection", { clientId });
@@ -539,11 +572,12 @@ export class ChainlessChainWSServer extends EventEmitter {
539
572
  return this._dispatcher.dispatch(clientId, ws, message);
540
573
  }
541
574
 
542
- /** Read the same .claude settings rules used by the Agent Core. */
575
+ /** Read the same static + scoped authority used by the Agent Core. */
543
576
  async _handlePermissionRulesGet(id, ws) {
544
577
  try {
545
- const { loadSettings } = await import("../../lib/settings-loader.cjs");
546
- const loaded = loadSettings({ cwd: this.projectRoot });
578
+ const { loadPermissionAuthority } =
579
+ await import("../../lib/permission-authority.js");
580
+ const loaded = loadPermissionAuthority({ cwd: this.projectRoot });
547
581
  this._send(ws, {
548
582
  id,
549
583
  type: "permission-rules",
@@ -551,6 +585,8 @@ export class ChainlessChainWSServer extends EventEmitter {
551
585
  sources: loaded.sources,
552
586
  files: loaded.files,
553
587
  managed: loaded.managed || null,
588
+ managedFile: loaded.managedFile || null,
589
+ scoped: loaded.scoped || null,
554
590
  });
555
591
  } catch (error) {
556
592
  this._send(ws, {