chainlesschain 0.162.188 → 0.162.193

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 (337) hide show
  1. package/README.md +61 -11
  2. package/bin/chainlesschain.js +7 -52
  3. package/completions/_cc +209 -0
  4. package/completions/cc.bash +18 -0
  5. package/completions/cc.fish +13 -0
  6. package/completions/cc.ps1 +226 -0
  7. package/package.json +10 -2
  8. package/src/assets/web-panel/assets/{AIOps-Brr1LVcE.js → AIOps-DBLkaTje.js} +1 -1
  9. package/src/assets/web-panel/assets/{ActionButton-DQU74DKG.js → ActionButton-BAy-Qebo.js} +1 -1
  10. package/src/assets/web-panel/assets/{Analytics-CYp9178y.js → Analytics-Dfb1Mlau.js} +3 -3
  11. package/src/assets/web-panel/assets/{AppLayout-DW4SCYsW.js → AppLayout-BbFkN8m0.js} +5 -5
  12. package/src/assets/web-panel/assets/{Artifacts-CYlD_ed1.js → Artifacts-kM4-cEEH.js} +1 -1
  13. package/src/assets/web-panel/assets/{Audit-CWl1rZOi.js → Audit-BSQfYWf3.js} +1 -1
  14. package/src/assets/web-panel/assets/{BackgroundAgents-BOR-LPsa.js → BackgroundAgents-CWDbI_fG.js} +1 -1
  15. package/src/assets/web-panel/assets/{Backup-DLpG7j1X.js → Backup-BxLPbq_Q.js} +1 -1
  16. package/src/assets/web-panel/assets/{BaseInput-B35K9wdr.js → BaseInput-DuIbdrp6.js} +1 -1
  17. package/src/assets/web-panel/assets/{Chat-CwUJb9gB.js → Chat-NEmjGahU.js} +5 -5
  18. package/src/assets/web-panel/assets/{ChatBubbleRenderer-1v6aMS1m.js → ChatBubbleRenderer-DfJEo-5_.js} +1 -1
  19. package/src/assets/web-panel/assets/{Checkbox-pi3-tPNW.js → Checkbox-CaoeG3Ns.js} +1 -1
  20. package/src/assets/web-panel/assets/{Codegen-FyNF35eL.js → Codegen-BFf_g3xY.js} +1 -1
  21. package/src/assets/web-panel/assets/{Col-tGt_JDEr.js → Col-CNOd8mdQ.js} +1 -1
  22. package/src/assets/web-panel/assets/{Community-CC7LonQX.js → Community-BhpDqz-i.js} +1 -1
  23. package/src/assets/web-panel/assets/{Compact-BGXrHHjE.js → Compact-CQ42T7Z6.js} +1 -1
  24. package/src/assets/web-panel/assets/{Compliance-DSW0TBZ8.js → Compliance-DI5PcLMN.js} +1 -1
  25. package/src/assets/web-panel/assets/{Cowork-Bhk7rbvE.js → Cowork-wYYZe0wR.js} +3 -3
  26. package/src/assets/web-panel/assets/{Cron-DxyiQ2NZ.js → Cron-Dlq03DD_.js} +2 -2
  27. package/src/assets/web-panel/assets/{Crosschain-B2ZkxHok.js → Crosschain-BzqS8PP3.js} +1 -1
  28. package/src/assets/web-panel/assets/{DID-yOJV99eJ.js → DID-It55Yem7.js} +2 -2
  29. package/src/assets/web-panel/assets/{Dashboard-CKsttz7D.js → Dashboard-9HkH6oxn.js} +2 -2
  30. package/src/assets/web-panel/assets/{Dropdown-CVFldXSL.js → Dropdown-00e2YWRB.js} +1 -1
  31. package/src/assets/web-panel/assets/{EmailListRenderer-Bufv638J.js → EmailListRenderer-By-ugRDL.js} +1 -1
  32. package/src/assets/web-panel/assets/{FamilyGuardDashboard-4ncjoIjL.js → FamilyGuardDashboard-C396yu5m.js} +1 -1
  33. package/src/assets/web-panel/assets/{Federation-DsknEDoX.js → Federation-BME5sbZY.js} +1 -1
  34. package/src/assets/web-panel/assets/{FormItemContext-Cqe5jWXA.js → FormItemContext-B4TEZCr-.js} +1 -1
  35. package/src/assets/web-panel/assets/{GenericCardRenderer-NAJaFKxc.js → GenericCardRenderer-_9CX9ieY.js} +1 -1
  36. package/src/assets/web-panel/assets/{Git-CszKQpnl.js → Git-BrS6WVSr.js} +2 -2
  37. package/src/assets/web-panel/assets/{Governance-BXGodXi6.js → Governance-BMdCWnKF.js} +1 -1
  38. package/src/assets/web-panel/assets/{Inference-CkoYuG2c.js → Inference-Bcp3vzcA.js} +1 -1
  39. package/src/assets/web-panel/assets/{KnowledgeGraph-DFlEr_T0.js → KnowledgeGraph-DlLuqGY5.js} +1 -1
  40. package/src/assets/web-panel/assets/{Logs-CVaENddA.js → Logs-D-W_6x09.js} +2 -2
  41. package/src/assets/web-panel/assets/MarkdownRenderer-DElGPxCZ.js +1 -0
  42. package/src/assets/web-panel/assets/{Marketplace-CDlLT0fw.js → Marketplace-Dzn2guvI.js} +1 -1
  43. package/src/assets/web-panel/assets/{McpTools-DdwOyszN.js → McpTools-uPict-KL.js} +6 -6
  44. package/src/assets/web-panel/assets/{Memory-DKQnkKuG.js → Memory-BCw43kOb.js} +2 -2
  45. package/src/assets/web-panel/assets/{MobileBridge-DGseqlzJ.js → MobileBridge-DmV8Wv7F.js} +1 -1
  46. package/src/assets/web-panel/assets/{MobileProjects-COBbEOlj.js → MobileProjects-C-HaCmSM.js} +1 -1
  47. package/src/assets/web-panel/assets/{Mtc-O61Vwyli.js → Mtc-C6jxJ34Y.js} +5 -5
  48. package/src/assets/web-panel/assets/{MtcAudit-Dw2SyasS.js → MtcAudit-Za8ExwhQ.js} +5 -5
  49. package/src/assets/web-panel/assets/{Multisig-hSu_l8kf.js → Multisig-KKDbuEgb.js} +3 -3
  50. package/src/assets/web-panel/assets/{NLProgramming-CX1Epurr.js → NLProgramming-Dj97zbCk.js} +1 -1
  51. package/src/assets/web-panel/assets/{Notes-R9xX8o8_.js → Notes-DBXvMraU.js} +4 -4
  52. package/src/assets/web-panel/assets/{NotificationSettings-jtSNLCuK.js → NotificationSettings-DOxITLYl.js} +1 -1
  53. package/src/assets/web-panel/assets/OrderTableRenderer-7DVjZwMM.js +1 -0
  54. package/src/assets/web-panel/assets/{Organization-Pu2WO-U3.js → Organization-D1i73mjb.js} +4 -4
  55. package/src/assets/web-panel/assets/{Overflow-BjnqUyFp.js → Overflow-kW6Q3rvg.js} +1 -1
  56. package/src/assets/web-panel/assets/{P2P-jjkvz44c.js → P2P-C-v_8p2v.js} +2 -2
  57. package/src/assets/web-panel/assets/PdhVaultBrowser-tUbbY64W.js +7 -0
  58. package/src/assets/web-panel/assets/{Permissions-D4yDpivd.js → Permissions-DkHxEZ58.js} +4 -4
  59. package/src/assets/web-panel/assets/{PersonalDataHub-0qsL6iH1.js → PersonalDataHub-DWuMPGrK.js} +5 -5
  60. package/src/assets/web-panel/assets/{Pipeline-Cx7Ybrk2.js → Pipeline-30IYXWWm.js} +1 -1
  61. package/src/assets/web-panel/assets/{Privacy-PbfR_M_V.js → Privacy-DZNQ4RrH.js} +1 -1
  62. package/src/assets/web-panel/assets/{ProjectInit-CyV6Gsub.js → ProjectInit-De2MCElf.js} +2 -2
  63. package/src/assets/web-panel/assets/{ProjectSettings-C7KZ2Wdk.js → ProjectSettings-5uHk9wsC.js} +2 -2
  64. package/src/assets/web-panel/assets/{Projects-DQDjO-yK.js → Projects-XjDfrFLb.js} +1 -1
  65. package/src/assets/web-panel/assets/{Providers-DyFVBBMX.js → Providers-Bgwj6gcE.js} +1 -1
  66. package/src/assets/web-panel/assets/{QrScannerModal-CzB1BC9_.js → QrScannerModal-gKql9umv.js} +1 -1
  67. package/src/assets/web-panel/assets/{QuickAsk-Bk636mC1.js → QuickAsk-BWvmwkh7.js} +1 -1
  68. package/src/assets/web-panel/assets/{Recommend-DoWxHIT3.js → Recommend-Uok4hZPd.js} +1 -1
  69. package/src/assets/web-panel/assets/{RemoteSession-oOVIv9wq.js → RemoteSession-DLJzTk9a.js} +3 -3
  70. package/src/assets/web-panel/assets/{Reputation-BucoReGG.js → Reputation-ZVwIPMSO.js} +1 -1
  71. package/src/assets/web-panel/assets/{Row-DzmOdJU7.js → Row-CN04HxWR.js} +1 -1
  72. package/src/assets/web-panel/assets/{RssFeed-C1tK7KGU.js → RssFeed-BdSrEG4g.js} +3 -3
  73. package/src/assets/web-panel/assets/{Search-CSnInOqk.js → Search-5PwVd0IR.js} +1 -1
  74. package/src/assets/web-panel/assets/{Security-dlejr15l.js → Security-DdBo4zjN.js} +3 -3
  75. package/src/assets/web-panel/assets/{Services-BioPZuNh.js → Services-D3letU7M.js} +2 -2
  76. package/src/assets/web-panel/assets/{Skeleton-DWMibwpC.js → Skeleton--Jb83f1v.js} +1 -1
  77. package/src/assets/web-panel/assets/{Skills-BAAnx1B2.js → Skills-Bg-CulHX.js} +1 -1
  78. package/src/assets/web-panel/assets/{Sla-jWNp4hNO.js → Sla-7QOa7S-X.js} +1 -1
  79. package/src/assets/web-panel/assets/{SpeechSettings-y5kqKha-.js → SpeechSettings-DQwppjRw.js} +1 -1
  80. package/src/assets/web-panel/assets/{SyncSettings-B9GNsc3e.js → SyncSettings-dNPQGL-s.js} +2 -2
  81. package/src/assets/web-panel/assets/{Tasks-BDBYKRen.js → Tasks-Ggs-Z48q.js} +1 -1
  82. package/src/assets/web-panel/assets/{Templates-DRiE5eaN.js → Templates-78TYHgRO.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tenant-BGlAvExF.js → Tenant-xHwwv9vO.js} +1 -1
  84. package/src/assets/web-panel/assets/{Terminal-B8uzrbNY.js → Terminal-BJXSJfm4.js} +2 -2
  85. package/src/assets/web-panel/assets/{TimelineRenderer-Df48iveY.js → TimelineRenderer-fLbjRhJw.js} +1 -1
  86. package/src/assets/web-panel/assets/{Tokens-CcmHndN6.js → Tokens-oMSBSBmB.js} +1 -1
  87. package/src/assets/web-panel/assets/{Trigger-DPkWxmQ2.js → Trigger-CfnY_wX_.js} +1 -1
  88. package/src/assets/web-panel/assets/{Trust-DTb5a5AV.js → Trust-AdyTgYKO.js} +1 -1
  89. package/src/assets/web-panel/assets/{UkeySign-CBmg5vch.js → UkeySign-C5K_81dS.js} +1 -1
  90. package/src/assets/web-panel/assets/{VideoEditing-B0mZrz4O.js → VideoEditing-vcGVDqki.js} +1 -1
  91. package/src/assets/web-panel/assets/{Wallet-Bxs7_mpd.js → Wallet-hhOc3hlY.js} +4 -4
  92. package/src/assets/web-panel/assets/{WebAuthn-C8x3cMxU.js → WebAuthn-CVloC11s.js} +3 -3
  93. package/src/assets/web-panel/assets/{WorkflowEditor-DPrNznrP.js → WorkflowEditor-CYeE32R5.js} +1 -1
  94. package/src/assets/web-panel/assets/{chat-D3bYWu7S.js → chat-CNROR5bN.js} +1 -1
  95. package/src/assets/web-panel/assets/{colors-DY-PwMu4.js → colors-Cjx-cnwU.js} +1 -1
  96. package/src/assets/web-panel/assets/{compact-item-LDk10Kw6.js → compact-item-DOIfelvD.js} +1 -1
  97. package/src/assets/web-panel/assets/{createContext-C-2MZnFq.js → createContext-DfA7UZ8u.js} +1 -1
  98. package/src/assets/web-panel/assets/devWarning-ChcCBGs7.js +1 -0
  99. package/src/assets/web-panel/assets/{hasIn-BQIBjcnB.js → hasIn-BMSCzcfM.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CQVb2dWp.js → index-5-HXgOX5.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BdXnYMCZ.js → index-AWg-0M1S.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Cx6D_dx2.js → index-B4iYzpkL.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-_HRO_cIu.js → index-B5Udeb_6.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DlRYqt3S.js → index-B7gf77CJ.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BrnRO9yE.js → index-BEMwBBHk.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-VCh5zNJo.js → index-BM1y_9hM.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BRI3ngNg.js → index-BUonmKSE.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-C3GNvExG.js → index-BbQ2eQ8H.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DSvo_bp0.js → index-BemJ2u_E.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-L6qixyLc.js → index-BolaOQxx.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BI4KgcYC.js → index-BxOk9vkG.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CY4KnaO9.js → index-By61ojUx.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-L3smcoQX.js → index-C2K9SNVX.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BX2b9Orc.js → index-C3L5gdiD.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Cz4b6Z_7.js → index-C7xn0Nub.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-COG61sRv.js → index-CAnvhwg6.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C7FC8cP2.js → index-CEKMcOyU.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BN-xdSWZ.js → index-CNC5onm4.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DY2FIrmz.js → index-CVL27kXC.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CiTvBAr-.js → index-CVm1_i3t.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DhRt9cYJ.js → index-CdYBye8B.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-B5pgtZnY.js → index-ClNMrqEY.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-7xKu7Fns.js → index-Cs6l7uRu.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-D4K1weKc.js → index-CshQbilz.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-k7C_oDCO.js → index-Cyweh0Hy.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-D3Oq-DLL.js → index-DBpWXFed.js} +3 -3
  127. package/src/assets/web-panel/assets/{index-DYyLJPlF.js → index-DHtpHZAQ.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Dh-tkpKQ.js → index-DLmn0BoK.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-8JC9BJa1.js → index-DPAWBrMf.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Dd2Km97U.js → index-DjEsxO5h.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-KFZO_lcx.js → index-FBc_CJBd.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DTIZpPtG.js → index-Icdoqmzt.js} +1 -1
  133. package/src/assets/web-panel/assets/index-Q2IajL54.js +1 -0
  134. package/src/assets/web-panel/assets/index-bRkHgOMc.js +1 -0
  135. package/src/assets/web-panel/assets/{index-lmm9p-jm.js → index-dCd8cSUq.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-HasPt4-h.js → index-m2vG9gG_.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-CaslYch6.js → index-mTpHoEzr.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-CbR6ROOa.js → index-ti_lnTWl.js} +1 -1
  139. package/src/assets/web-panel/assets/{initDefaultProps-zQPSHf2C.js → initDefaultProps-Bu8k7H1Y.js} +1 -1
  140. package/src/assets/web-panel/assets/{motion-CKCStGVk.js → motion-s3iVK41k.js} +1 -1
  141. package/src/assets/web-panel/assets/{move-BufVDGYF.js → move-B6B-E5Jz.js} +1 -1
  142. package/src/assets/web-panel/assets/{mtc-parser-DcaFxy5D.js → mtc-parser-BiYgTidA.js} +1 -1
  143. package/src/assets/web-panel/assets/{omit-EScpkGdo.js → omit-pU1RdUDA.js} +1 -1
  144. package/src/assets/web-panel/assets/{pickAttrs-72hG_qfT.js → pickAttrs-Cdoq_SeM.js} +1 -1
  145. package/src/assets/web-panel/assets/{placementArrow-CMFWiH20.js → placementArrow-DIuvAn2K.js} +1 -1
  146. package/src/assets/web-panel/assets/{responsiveObserve-DKQHS41p.js → responsiveObserve-8w16YR2D.js} +1 -1
  147. package/src/assets/web-panel/assets/{slide-QVAFHTIQ.js → slide-VZ01cZe3.js} +1 -1
  148. package/src/assets/web-panel/assets/{statusUtils-DIz38e2G.js → statusUtils-lh8YMN8Z.js} +1 -1
  149. package/src/assets/web-panel/assets/{styleChecker-zK5cyLby.js → styleChecker-CmDyreec.js} +1 -1
  150. package/src/assets/web-panel/assets/{useFlexGapSupport-DhZngk62.js → useFlexGapSupport-hiJWMU5y.js} +1 -1
  151. package/src/assets/web-panel/assets/{useFs-BvV2cvkg.js → useFs-Thnu-Iaj.js} +1 -1
  152. package/src/assets/web-panel/assets/{usePersonalDataHub-CRmxb9l3.js → usePersonalDataHub-LBdOxjwY.js} +1 -1
  153. package/src/assets/web-panel/assets/{vnode-CgQIbobP.js → vnode-Cg6lFY_X.js} +1 -1
  154. package/src/assets/web-panel/assets/{zoom-D4XrrO0R.js → zoom-DVfsR1YO.js} +1 -1
  155. package/src/assets/web-panel/index.html +1 -1
  156. package/src/cli-help.js +181 -0
  157. package/src/command-help-index.json +181 -0
  158. package/src/command-manifest.json +1107 -175
  159. package/src/command-surface-policy.js +197 -0
  160. package/src/commands/agent.js +98 -33
  161. package/src/commands/artifacts.js +400 -2
  162. package/src/commands/background-session.js +41 -3
  163. package/src/commands/checkpoint-managed.js +1059 -0
  164. package/src/commands/checkpoint-restore-recovery.js +1476 -0
  165. package/src/commands/checkpoint.js +950 -22
  166. package/src/commands/compact.js +101 -25
  167. package/src/commands/config.js +506 -20
  168. package/src/commands/doctor.js +4 -1
  169. package/src/commands/hub.js +1 -1
  170. package/src/commands/mcp.js +688 -24
  171. package/src/commands/pack.js +16 -2
  172. package/src/commands/plugin.js +20 -12
  173. package/src/commands/session-mcp-recovery.js +218 -0
  174. package/src/commands/session.js +470 -110
  175. package/src/commands/setup.js +36 -10
  176. package/src/commands/skill.js +181 -110
  177. package/src/commands/status.js +21 -5
  178. package/src/commands/team-distributed.js +3324 -0
  179. package/src/commands/team.js +1130 -74
  180. package/src/commands/update.js +68 -6
  181. package/src/constants.js +11 -0
  182. package/src/data/changelog.json +26 -0
  183. package/src/gateways/ws/action-protocol.js +10 -0
  184. package/src/gateways/ws/session-protocol.js +555 -27
  185. package/src/gateways/ws/ws-agent-handler.js +541 -14
  186. package/src/gateways/ws/ws-session-gateway.js +129 -22
  187. package/src/gateways/ws/ws-session-state.js +431 -0
  188. package/src/harness/background-task-manager.js +233 -36
  189. package/src/harness/jsonl-session-store.js +2551 -167
  190. package/src/harness/mcp-client.js +802 -61
  191. package/src/harness/prompt-compressor.js +227 -27
  192. package/src/harness/session-index.js +89 -38
  193. package/src/harness/session-list-index.js +254 -0
  194. package/src/harness/structured-handoff.js +410 -0
  195. package/src/lazy-dispatch.js +747 -84
  196. package/src/lib/__tests__/logger.test.js +50 -2
  197. package/src/lib/advisor-runtime.js +1047 -0
  198. package/src/lib/agent-core.js +2 -0
  199. package/src/lib/agent-sandbox.js +120 -26
  200. package/src/lib/agent-session-export.js +20 -0
  201. package/src/lib/agent-team/task-lease.js +271 -3
  202. package/src/lib/agent-team/team-adjudication.js +1501 -0
  203. package/src/lib/agent-team/team-budget.js +4 -1
  204. package/src/lib/agent-team/team-control-store.js +582 -0
  205. package/src/lib/agent-team/team-distributed-queue.js +5246 -0
  206. package/src/lib/agent-team/team-process-checkpoint.js +211 -0
  207. package/src/lib/agent-team/team-runner.js +543 -24
  208. package/src/lib/agent-team/team-worktree.js +1403 -95
  209. package/src/lib/artifact-store.js +131 -8
  210. package/src/lib/background-agent-supervisor.js +185 -13
  211. package/src/lib/background-interaction-journal.js +37 -9
  212. package/src/lib/background-launch-profile.js +1058 -0
  213. package/src/lib/checkpoint-restore-already-completed-controller.js +902 -0
  214. package/src/lib/checkpoint-restore-orchestrator.js +987 -0
  215. package/src/lib/checkpoint-restore-partial-rollback-controller.js +1953 -0
  216. package/src/lib/checkpoint-restore-recovery-controller.js +689 -0
  217. package/src/lib/checkpoint-restore-recovery.js +884 -0
  218. package/src/lib/checkpoint-restore-retention.js +126 -0
  219. package/src/lib/checkpoint-restore-saga.js +5079 -0
  220. package/src/lib/checkpoint-restore-session-recovery.js +1178 -0
  221. package/src/lib/checkpoint-restore-workspace-target-verifier.js +270 -0
  222. package/src/lib/checkpoint-store.js +1688 -97
  223. package/src/lib/checkpoint-timeline-authority.js +522 -0
  224. package/src/lib/checkpoint-timeline.js +642 -0
  225. package/src/lib/config-keys.js +18 -119
  226. package/src/lib/config-manager.js +446 -27
  227. package/src/lib/config-redaction.js +57 -0
  228. package/src/lib/config-schema.js +853 -0
  229. package/src/lib/cowork-mcp-tools.js +5 -0
  230. package/src/lib/cowork-task-runner.js +458 -63
  231. package/src/lib/delivery-coordinator.js +1234 -0
  232. package/src/lib/delivery-evidence.js +450 -0
  233. package/src/lib/doctor-checkup.js +199 -14
  234. package/src/lib/executable-path.js +34 -0
  235. package/src/lib/fatal-handler.js +16 -0
  236. package/src/lib/file-checkpoint.js +4909 -186
  237. package/src/lib/file-lines.js +125 -0
  238. package/src/lib/headless-config-command.js +16 -5
  239. package/src/lib/hook-runner.cjs +139 -38
  240. package/src/lib/hooks-v2-workspace-context.js +10 -0
  241. package/src/lib/impacted-gate-selector.js +424 -0
  242. package/src/lib/interaction-adapter.js +62 -0
  243. package/src/lib/jsonl-session-store.js +1 -35
  244. package/src/lib/logger.js +66 -14
  245. package/src/lib/managed-checkpoint-render.js +60 -0
  246. package/src/lib/managed-tool-checkpoint.js +194 -0
  247. package/src/lib/mcp-call-ledger-store.js +1069 -0
  248. package/src/lib/mcp-call-ledger.js +747 -0
  249. package/src/lib/mcp-client.js +5 -0
  250. package/src/lib/mcp-conflict-scheduler.js +468 -0
  251. package/src/lib/mcp-effect-contract.js +102 -0
  252. package/src/lib/mcp-headers-helper-trust.js +145 -0
  253. package/src/lib/mcp-headers-helper.js +616 -0
  254. package/src/lib/mcp-host-recovery-runtime.js +131 -0
  255. package/src/lib/mcp-ledger-recovery-admission.js +1065 -0
  256. package/src/lib/mcp-recovery-adjudication.js +443 -0
  257. package/src/lib/output-context.js +86 -0
  258. package/src/lib/packer/file-identity.js +170 -0
  259. package/src/lib/packer/index.js +3 -0
  260. package/src/lib/packer/native-update-state.js +277 -0
  261. package/src/lib/packer/pack-update-applier.js +1983 -136
  262. package/src/lib/packer/pack-update-checker.js +34 -0
  263. package/src/lib/packer/pack-update-downloader.js +875 -86
  264. package/src/lib/packer/pack-update-signature.js +86 -0
  265. package/src/lib/packer/pkg-config-generator.js +6 -0
  266. package/src/lib/paths.js +65 -10
  267. package/src/lib/plan-mode.js +831 -14
  268. package/src/lib/plan-persistence.js +540 -0
  269. package/src/lib/plugin-runtime/hooks.js +227 -69
  270. package/src/lib/plugin-runtime/plugin-options.js +189 -44
  271. package/src/lib/pr-automation-policy.js +146 -8
  272. package/src/lib/process-execution-broker/credential-agent.js +7 -0
  273. package/src/lib/process-execution-broker/index.js +491 -13
  274. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +28 -1
  275. package/src/lib/process-execution-broker/linux-generic-bwrap.js +28 -4
  276. package/src/lib/process-execution-broker/platform-sandbox.js +92 -70
  277. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  278. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  279. package/src/lib/process-execution-broker/windows-sandbox.cs +284 -19
  280. package/src/lib/process-execution-broker/workspace-transaction.js +4459 -0
  281. package/src/lib/project-instructions.js +165 -29
  282. package/src/lib/project-mcp-trust.js +67 -0
  283. package/src/lib/public-ide-capability-manifest.js +272 -0
  284. package/src/lib/public-ide-capability-validation.js +351 -0
  285. package/src/lib/secret-store.js +267 -43
  286. package/src/lib/secure-file-identity.js +433 -0
  287. package/src/lib/secure-fs.js +1089 -0
  288. package/src/lib/security-audit.js +58 -0
  289. package/src/lib/service-manager.js +34 -13
  290. package/src/lib/session-budget-runtime.js +1452 -0
  291. package/src/lib/session-host-snapshot.js +388 -0
  292. package/src/lib/session-message-provenance.js +429 -0
  293. package/src/lib/session-projection.js +804 -0
  294. package/src/lib/session-resource-budget.js +1495 -0
  295. package/src/lib/settings-hooks.cjs +138 -22
  296. package/src/lib/settings-loader.cjs +25 -2
  297. package/src/lib/side-effect-ledger-store.js +45 -23
  298. package/src/lib/skill-execution-identity.js +217 -0
  299. package/src/lib/skill-loader.js +299 -18
  300. package/src/lib/sub-agent-context.js +236 -28
  301. package/src/lib/sub-agent-registry.js +5 -0
  302. package/src/lib/subagent-contract.js +94 -0
  303. package/src/lib/todo-manager.js +185 -18
  304. package/src/lib/todo-persistence.js +417 -0
  305. package/src/lib/turn-binding-store.js +41 -23
  306. package/src/lib/turn-binding.js +160 -2
  307. package/src/lib/with-file-lock.js +165 -24
  308. package/src/lib/ws-chat-handler.js +21 -0
  309. package/src/program-base.js +18 -0
  310. package/src/repl/advisor-command.js +103 -0
  311. package/src/repl/agent-repl.js +2175 -146
  312. package/src/repl/btw-command.js +93 -10
  313. package/src/repl/clipboard-image.js +119 -0
  314. package/src/repl/config-summary.js +64 -108
  315. package/src/repl/prompt-editor.js +233 -0
  316. package/src/repl/prompt-interactions.js +344 -0
  317. package/src/repl/prompt-stash.js +354 -0
  318. package/src/repl/prompt-suggestions.js +312 -0
  319. package/src/repl/repl-keybindings.js +227 -0
  320. package/src/repl/session-recap.js +217 -0
  321. package/src/repl/slash-command-registry.js +22 -0
  322. package/src/repl/terminal-layout.js +88 -0
  323. package/src/runtime/agent-core.js +1630 -447
  324. package/src/runtime/coding-agent-contract-shared.cjs +13 -1
  325. package/src/runtime/coding-agent-managed-tool-policy.cjs +7 -2
  326. package/src/runtime/diagnostics.js +32 -13
  327. package/src/runtime/headless-runner.js +310 -118
  328. package/src/runtime/headless-stream.js +356 -95
  329. package/src/runtime/mcp-config.js +148 -14
  330. package/src/runtime/policies/agent-policy.js +14 -0
  331. package/src/runtime/status-diagnostics-lite.js +137 -0
  332. package/src/assets/web-panel/assets/MarkdownRenderer-7iWGwZ-r.js +0 -1
  333. package/src/assets/web-panel/assets/OrderTableRenderer-BU2Yqq5H.js +0 -1
  334. package/src/assets/web-panel/assets/PdhVaultBrowser-69ca_WeR.js +0 -7
  335. package/src/assets/web-panel/assets/devWarning-B4dXIJqD.js +0 -1
  336. package/src/assets/web-panel/assets/index-C-C7DaG6.js +0 -1
  337. package/src/assets/web-panel/assets/index-DkfWzWtd.js +0 -1
@@ -78,19 +78,55 @@ function settingsFiles(cwd, explicitFile) {
78
78
  return list;
79
79
  }
80
80
 
81
- function readJson(file, onWarn) {
81
+ function sha256Content(content) {
82
+ return crypto
83
+ .createHash("sha256")
84
+ .update(Buffer.isBuffer(content) ? content : String(content))
85
+ .digest("hex");
86
+ }
87
+
88
+ function readJsonRecord(
89
+ file,
90
+ onWarn,
91
+ { kind = "settings", errors = null } = {},
92
+ ) {
93
+ if (!_deps.fs.existsSync(file)) return null;
94
+ let raw = null;
82
95
  try {
83
- if (!_deps.fs.existsSync(file)) return null;
84
- const parsed = JSON.parse(_deps.fs.readFileSync(file, "utf-8"));
85
- return parsed && typeof parsed === "object" ? parsed : null;
96
+ raw = _deps.fs.readFileSync(file, "utf-8");
97
+ const parsed = JSON.parse(raw);
98
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
99
+ throw new TypeError("settings root must be a JSON object");
100
+ }
101
+ return {
102
+ data: parsed,
103
+ digest: sha256Content(raw),
104
+ sourceFile: path.resolve(file),
105
+ };
86
106
  } catch (err) {
87
107
  const msg = `hooks: ignoring malformed ${file} (${err.message})`;
108
+ const record = Object.freeze({
109
+ code:
110
+ kind === "managed"
111
+ ? "CC_MANAGED_SETTINGS_INVALID"
112
+ : "CC_SETTINGS_HOOKS_INVALID",
113
+ kind,
114
+ sourceFile: path.resolve(file),
115
+ digest: raw == null ? null : sha256Content(raw),
116
+ authorityBearing: true,
117
+ message: msg,
118
+ });
119
+ if (Array.isArray(errors)) errors.push(record);
88
120
  if (typeof onWarn === "function") onWarn(msg);
89
121
  else process.stderr.write(msg + "\n");
90
- return null; // fail-open
122
+ return null;
91
123
  }
92
124
  }
93
125
 
126
+ function readJson(file, onWarn) {
127
+ return readJsonRecord(file, onWarn)?.data || null;
128
+ }
129
+
94
130
  function managedSettingsFile(env = process.env) {
95
131
  if (env.CC_MANAGED_SETTINGS) return path.resolve(env.CC_MANAGED_SETTINGS);
96
132
  if (process.platform === "win32") {
@@ -100,7 +136,31 @@ function managedSettingsFile(env = process.env) {
100
136
  return "/etc/chainlesschain/managed-settings.json";
101
137
  }
102
138
 
103
- function appendHookBlock(merged, data) {
139
+ function attachAuthoritySource(target, source) {
140
+ if (!source) return target;
141
+ const authoritySource = Object.freeze({
142
+ kind:
143
+ source.kind === "managed"
144
+ ? "managed"
145
+ : source.kind === "plugin"
146
+ ? "plugin"
147
+ : "settings",
148
+ sourceFile:
149
+ typeof source.sourceFile === "string" && source.sourceFile
150
+ ? path.resolve(source.sourceFile)
151
+ : null,
152
+ digest: String(source.digest || ""),
153
+ });
154
+ Object.defineProperty(target, "authoritySource", {
155
+ value: authoritySource,
156
+ enumerable: true,
157
+ writable: false,
158
+ configurable: false,
159
+ });
160
+ return target;
161
+ }
162
+
163
+ function appendHookBlock(merged, data, authoritySource) {
104
164
  const block =
105
165
  data && data.hooks && typeof data.hooks === "object" ? data.hooks : null;
106
166
  if (!block) return false;
@@ -109,9 +169,9 @@ function appendHookBlock(merged, data) {
109
169
  if (!Array.isArray(groups)) continue;
110
170
  for (const g of groups) {
111
171
  if (!g || typeof g !== "object" || !Array.isArray(g.hooks)) continue;
112
- const cmds = g.hooks.filter(
113
- (h) => h && h.type === "command" && h.command,
114
- );
172
+ const cmds = g.hooks
173
+ .filter((h) => h && h.type === "command" && h.command)
174
+ .map((h) => attachAuthoritySource({ ...h }, authoritySource));
115
175
  if (cmds.length === 0) continue;
116
176
  if (!merged[event]) merged[event] = [];
117
177
  merged[event].push({ matcher: g.matcher ?? null, hooks: cmds });
@@ -123,7 +183,7 @@ function appendHookBlock(merged, data) {
123
183
 
124
184
  /**
125
185
  * Load + concatenate the `hooks` blocks across the hierarchy.
126
- * @returns {{ hooks: Record<string, Array<{matcher:string|null, hooks:Array<{type,command,timeout}>}>>, files:string[] }}
186
+ * @returns {{ hooks: Record<string, Array<{matcher:string|null, hooks:Array<{type,command,timeout,authoritySource?}>}>>, files:string[], authorityErrors?:Array<object> }}
127
187
  */
128
188
  function loadHooks({
129
189
  cwd = process.cwd(),
@@ -133,15 +193,23 @@ function loadHooks({
133
193
  } = {}) {
134
194
  const merged = {};
135
195
  const files = [];
196
+ const authorityErrors = [];
136
197
  const managedFile = managedSettingsFile(env);
137
198
  let managed = null;
199
+ let managedRecord = null;
138
200
  if (_deps.fs.existsSync(managedFile)) {
139
- managed = readJson(managedFile, onWarn);
140
- if (!managed) {
201
+ const managedErrors = [];
202
+ managedRecord = readJsonRecord(managedFile, onWarn, {
203
+ kind: "managed",
204
+ errors: managedErrors,
205
+ });
206
+ managed = managedRecord?.data || null;
207
+ if (!managedRecord) {
141
208
  const error = new Error(
142
209
  `managed settings are unreadable or malformed: ${managedFile}`,
143
210
  );
144
211
  error.code = "CC_MANAGED_SETTINGS_INVALID";
212
+ if (managedErrors[0]) error.authorityError = managedErrors[0];
145
213
  throw error;
146
214
  }
147
215
  }
@@ -160,12 +228,33 @@ function loadHooks({
160
228
  const resolved = path.resolve(file);
161
229
  if (seenPaths.has(resolved)) continue;
162
230
  seenPaths.add(resolved);
163
- const data = readJson(file, onWarn);
164
- const contributed = appendHookBlock(merged, data);
231
+ const record = readJsonRecord(file, onWarn, {
232
+ kind: "settings",
233
+ errors: authorityErrors,
234
+ });
235
+ const contributed = record
236
+ ? appendHookBlock(merged, record.data, {
237
+ kind: "settings",
238
+ sourceFile: record.sourceFile,
239
+ digest: record.digest,
240
+ })
241
+ : false;
165
242
  if (contributed) files.push(file);
166
243
  }
167
- if (managed && appendHookBlock(merged, managed)) files.push(managedFile);
244
+ if (
245
+ managedRecord &&
246
+ appendHookBlock(merged, managed, {
247
+ kind: "managed",
248
+ sourceFile: managedRecord.sourceFile,
249
+ digest: managedRecord.digest,
250
+ })
251
+ ) {
252
+ files.push(managedFile);
253
+ }
168
254
  const result = { hooks: merged, files };
255
+ if (authorityErrors.length > 0) {
256
+ result.authorityErrors = authorityErrors;
257
+ }
169
258
  if (managed) {
170
259
  result.managed = managed;
171
260
  result.managedFile = managedFile;
@@ -173,6 +262,32 @@ function loadHooks({
173
262
  return result;
174
263
  }
175
264
 
265
+ /**
266
+ * Preserve loader failures across plugin-hook merging without making them look
267
+ * like a hook event. The runtime consumes this non-enumerable, immutable host
268
+ * metadata and blocks tool execution rather than running a partial authority
269
+ * set. Returns an object even when there are no valid hooks but errors exist.
270
+ */
271
+ function attachAuthorityErrors(hooks, errors) {
272
+ const target = hooks && typeof hooks === "object" ? hooks : {};
273
+ const normalized = Array.isArray(errors)
274
+ ? errors.map((entry) =>
275
+ Object.freeze({
276
+ sourceFile: entry?.sourceFile || entry?.file || null,
277
+ code: entry?.code || "CC_HOOK_AUTHORITY_INVALID",
278
+ message: entry?.message || null,
279
+ }),
280
+ )
281
+ : [];
282
+ Object.defineProperty(target, "_authorityErrors", {
283
+ value: Object.freeze(normalized),
284
+ enumerable: false,
285
+ writable: false,
286
+ configurable: false,
287
+ });
288
+ return target;
289
+ }
290
+
176
291
  /**
177
292
  * Compile a matcher into a test fn (pipe / wildcard / regex). Inlined twin of
178
293
  * hook-manager.compileMatcher so this .cjs has no ESM dependency.
@@ -224,7 +339,7 @@ function umbrellaFor(tool) {
224
339
  * `event` is stamped on each hook so a supervisor can key runs by (event+cmd).
225
340
  *
226
341
  * @returns {Array<{command:string, timeout?:number, event:string,
227
- * async:boolean, asyncRewake:boolean}>}
342
+ * async:boolean, asyncRewake:boolean, authoritySource?:object}>}
228
343
  */
229
344
  function collectHooks(hooksBlock, event, toolName) {
230
345
  const groups = (hooksBlock && hooksBlock[event]) || [];
@@ -245,8 +360,8 @@ function collectHooks(hooksBlock, event, toolName) {
245
360
  for (const g of groups) {
246
361
  const fn = compileMatcher(g.matcher);
247
362
  if (fn(umbrella) || (raw && fn(raw)) || (mcpServer && fn(mcpServer))) {
248
- for (const h of g.hooks)
249
- out.push({
363
+ for (const h of g.hooks) {
364
+ const collected = {
250
365
  command: h.command,
251
366
  timeout: h.timeout,
252
367
  event,
@@ -260,16 +375,16 @@ function collectHooks(hooksBlock, event, toolName) {
260
375
  ...(h.environmentAllowlist != null
261
376
  ? { environmentAllowlist: h.environmentAllowlist }
262
377
  : {}),
263
- ...(h.envAllowlist != null
264
- ? { envAllowlist: h.envAllowlist }
265
- : {}),
378
+ ...(h.envAllowlist != null ? { envAllowlist: h.envAllowlist } : {}),
266
379
  ...(h.sandboxPolicy !== undefined
267
380
  ? { sandboxPolicy: h.sandboxPolicy }
268
381
  : {}),
269
382
  ...(h.requiredBoundaries !== undefined
270
383
  ? { requiredBoundaries: h.requiredBoundaries }
271
384
  : {}),
272
- });
385
+ };
386
+ out.push(attachAuthoritySource(collected, h.authoritySource));
387
+ }
273
388
  }
274
389
  }
275
390
  return out;
@@ -413,6 +528,7 @@ function projectHookTrustNotice({ cwd = process.cwd(), settingsFile } = {}) {
413
528
 
414
529
  module.exports = {
415
530
  loadHooks,
531
+ attachAuthorityErrors,
416
532
  projectHookTrustNotice,
417
533
  collectHooks,
418
534
  compileMatcher,
@@ -294,13 +294,22 @@ function addRule({ cwd = process.cwd(), kind, rule, scope = "project" } = {}) {
294
294
  * model / env vars for a run without editing .chainlesschain/config.json.
295
295
  *
296
296
  * @param {object} [opts] { cwd, settingsFile, onWarn }
297
- * @returns {{ model: string|null, env: Record<string,string>, files: string[] }}
297
+ * @returns {{
298
+ * model: string|null,
299
+ * modelSource: string|null,
300
+ * env: Record<string,string>,
301
+ * envSources: Record<string,string>,
302
+ * files: string[]
303
+ * }}
298
304
  */
299
305
  function loadSettingsConfig(opts = {}) {
300
306
  const cwd = opts.cwd || process.cwd();
301
307
  let model = null;
308
+ let modelSource = null;
302
309
  const env = {};
310
+ const envSources = {};
303
311
  let sandbox = null;
312
+ let managedSandbox = null;
304
313
  const files = [];
305
314
  for (const file of settingsPaths(cwd, opts.settingsFile)) {
306
315
  const data = readSettingsFile(file, { onWarn: opts.onWarn });
@@ -308,12 +317,14 @@ function loadSettingsConfig(opts = {}) {
308
317
  let contributed = false;
309
318
  if (typeof data.model === "string" && data.model.trim()) {
310
319
  model = data.model.trim();
320
+ modelSource = file;
311
321
  contributed = true;
312
322
  }
313
323
  if (data.env && typeof data.env === "object" && !Array.isArray(data.env)) {
314
324
  for (const [k, v] of Object.entries(data.env)) {
315
325
  if (typeof v === "string") {
316
326
  env[k] = v;
327
+ envSources[k] = file;
317
328
  contributed = true;
318
329
  }
319
330
  }
@@ -334,12 +345,14 @@ function loadSettingsConfig(opts = {}) {
334
345
  let contributed = false;
335
346
  if (typeof data.model === "string" && data.model.trim()) {
336
347
  model = data.model.trim();
348
+ modelSource = managed.file;
337
349
  contributed = true;
338
350
  }
339
351
  if (data.env && typeof data.env === "object" && !Array.isArray(data.env)) {
340
352
  for (const [k, v] of Object.entries(data.env)) {
341
353
  if (typeof v === "string") {
342
354
  env[k] = v;
355
+ envSources[k] = managed.file;
343
356
  contributed = true;
344
357
  }
345
358
  }
@@ -349,12 +362,22 @@ function loadSettingsConfig(opts = {}) {
349
362
  typeof data.sandbox === "object" &&
350
363
  !Array.isArray(data.sandbox)
351
364
  ) {
365
+ managedSandbox = JSON.parse(JSON.stringify(data.sandbox));
352
366
  sandbox = mergeSandboxSettings(sandbox, data.sandbox);
353
367
  contributed = true;
354
368
  }
355
369
  if (contributed) files.push(managed.file);
356
370
  }
357
- return { model, env, sandbox, files };
371
+ return {
372
+ model,
373
+ modelSource,
374
+ env,
375
+ envSources,
376
+ sandbox,
377
+ managedSandbox,
378
+ files,
379
+ managedFile: managed.settings ? managed.file : null,
380
+ };
358
381
  }
359
382
 
360
383
  function mergeSandboxSettings(base, overlay) {
@@ -12,6 +12,7 @@
12
12
  import {
13
13
  appendEvent as storeAppendEvent,
14
14
  readEvents as storeReadEvents,
15
+ findLatestEvent as storeFindLatestEvent,
15
16
  } from "../harness/jsonl-session-store.js";
16
17
  import {
17
18
  SideEffectLedger,
@@ -24,14 +25,38 @@ export const SIDE_EFFECT_LEDGER_EVENT = "side_effect_ledger";
24
25
  export const _deps = {
25
26
  appendEvent: storeAppendEvent,
26
27
  readEvents: storeReadEvents,
28
+ findLatestEvent: storeFindLatestEvent,
27
29
  };
28
30
 
31
+ function findLatestLedgerEvent(sessionId) {
32
+ if (
33
+ typeof _deps.findLatestEvent === "function" &&
34
+ _deps.findLatestEvent !== storeFindLatestEvent
35
+ ) {
36
+ return _deps.findLatestEvent(sessionId, SIDE_EFFECT_LEDGER_EVENT);
37
+ }
38
+ // Existing tests and embedders historically injected only readEvents.
39
+ if (_deps.readEvents !== storeReadEvents) {
40
+ const events = _deps.readEvents(sessionId) || [];
41
+ for (let index = events.length - 1; index >= 0; index -= 1) {
42
+ const event = events[index];
43
+ if (event?.type === SIDE_EFFECT_LEDGER_EVENT) return event;
44
+ }
45
+ return null;
46
+ }
47
+ return storeFindLatestEvent(sessionId, SIDE_EFFECT_LEDGER_EVENT);
48
+ }
49
+
29
50
  export class SideEffectLedgerPersistenceError extends Error {
30
51
  constructor(operation, sessionId, cause) {
31
- const detail = cause?.message || String(cause || "unknown persistence error");
32
- super(`Side-effect ledger ${operation} failed for ${sessionId}: ${detail}`, {
33
- cause,
34
- });
52
+ const detail =
53
+ cause?.message || String(cause || "unknown persistence error");
54
+ super(
55
+ `Side-effect ledger ${operation} failed for ${sessionId}: ${detail}`,
56
+ {
57
+ cause,
58
+ },
59
+ );
35
60
  this.name = "SideEffectLedgerPersistenceError";
36
61
  this.code =
37
62
  operation === "read"
@@ -91,9 +116,9 @@ export function persistSideEffectLedger(sessionId, ledger, opts = {}) {
91
116
  */
92
117
  export function loadSideEffectLedger(sessionId, opts = {}) {
93
118
  const failIfUnavailable = opts.failIfUnavailable !== false;
94
- let events = [];
119
+ let event = null;
95
120
  try {
96
- events = _deps.readEvents(sessionId) || [];
121
+ event = findLatestLedgerEvent(sessionId);
97
122
  } catch (error) {
98
123
  const fallback = persistenceFailure(
99
124
  "read",
@@ -103,25 +128,22 @@ export function loadSideEffectLedger(sessionId, opts = {}) {
103
128
  );
104
129
  if (fallback === false) return new SideEffectLedger(opts);
105
130
  }
106
- for (let i = events.length - 1; i >= 0; i--) {
107
- const e = events[i];
108
- if (
109
- e &&
110
- e.type === SIDE_EFFECT_LEDGER_EVENT &&
111
- e.data &&
112
- Array.isArray(e.data.ops)
113
- ) {
114
- try {
115
- return SideEffectLedger.fromJSON(e.data, opts);
116
- } catch (error) {
117
- const fallback = persistenceFailure(
118
- "read",
119
- sessionId || "<missing-session>",
120
- error,
121
- failIfUnavailable,
131
+ if (event) {
132
+ try {
133
+ if (!Array.isArray(event?.data?.ops)) {
134
+ throw new TypeError(
135
+ "latest side-effect ledger snapshot must contain an ops array",
122
136
  );
123
- if (fallback === false) return new SideEffectLedger(opts);
124
137
  }
138
+ return SideEffectLedger.fromJSON(event.data, opts);
139
+ } catch (error) {
140
+ const fallback = persistenceFailure(
141
+ "read",
142
+ sessionId || "<missing-session>",
143
+ error,
144
+ failIfUnavailable,
145
+ );
146
+ if (fallback === false) return new SideEffectLedger(opts);
125
147
  }
126
148
  }
127
149
  return new SideEffectLedger(opts);
@@ -0,0 +1,217 @@
1
+ import { createHash } from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+
5
+ export const SKILL_EXECUTION_IDENTITY_VERSION = 1;
6
+
7
+ const EXECUTION_REASONS = new Set(["run_skill", "cli_skill_run"]);
8
+
9
+ function sha256(parts) {
10
+ const digest = createHash("sha256");
11
+ for (const part of parts) {
12
+ const bytes = Buffer.isBuffer(part) ? part : Buffer.from(String(part));
13
+ digest.update(String(bytes.length));
14
+ digest.update("\0");
15
+ digest.update(bytes);
16
+ digest.update("\0");
17
+ }
18
+ return `sha256:${digest.digest("hex")}`;
19
+ }
20
+
21
+ function canonicalRealPath(value) {
22
+ let result = fs.realpathSync(path.resolve(value)).replace(/\\/g, "/");
23
+ if (process.platform === "win32") result = result.toLowerCase();
24
+ return result;
25
+ }
26
+
27
+ function securityError(code, message, details = {}) {
28
+ const error = new Error(
29
+ message,
30
+ details.cause ? { cause: details.cause } : {},
31
+ );
32
+ error.name = "SkillExecutionSecurityError";
33
+ error.code = code;
34
+ if (details.skillId) error.skillId = details.skillId;
35
+ if (details.previousDigest) error.previousDigest = details.previousDigest;
36
+ if (details.currentDigest) error.currentDigest = details.currentDigest;
37
+ return error;
38
+ }
39
+
40
+ function readStableRegularFile(file, options = {}) {
41
+ let before;
42
+ try {
43
+ before = fs.lstatSync(file);
44
+ } catch (cause) {
45
+ if (options.optional && cause?.code === "ENOENT") return null;
46
+ throw securityError(
47
+ "CC_SKILL_COMPONENT_UNAVAILABLE",
48
+ `Skill component is unavailable: ${path.basename(file)}`,
49
+ { cause },
50
+ );
51
+ }
52
+ if (before.isSymbolicLink() || !before.isFile()) {
53
+ throw securityError(
54
+ "CC_SKILL_COMPONENT_UNSAFE",
55
+ `Skill component must be a regular, non-symlink file: ${path.basename(file)}`,
56
+ );
57
+ }
58
+
59
+ const bytes = fs.readFileSync(file);
60
+ const after = fs.lstatSync(file);
61
+ if (
62
+ before.size !== after.size ||
63
+ before.mtimeMs !== after.mtimeMs ||
64
+ before.ino !== after.ino
65
+ ) {
66
+ throw securityError(
67
+ "CC_SKILL_SNAPSHOT_RACE",
68
+ `Skill component changed while its identity was being captured: ${path.basename(file)}`,
69
+ );
70
+ }
71
+ return Object.freeze({
72
+ bytes,
73
+ size: bytes.length,
74
+ digest: sha256([bytes]),
75
+ });
76
+ }
77
+
78
+ /**
79
+ * Capture the exact files the legacy runtime could execute or interpret.
80
+ * SKILL.md covers frontmatter, instructions, and embedded MCP declarations;
81
+ * handler.js covers the only handler path used by current CLI dispatch.
82
+ */
83
+ export function captureSkillExecutionSnapshot(options = {}) {
84
+ if (!options.skillDir) {
85
+ throw new TypeError("captureSkillExecutionSnapshot requires skillDir");
86
+ }
87
+ const rootRealPath = canonicalRealPath(options.skillDir);
88
+ const skillMdPath = path.join(rootRealPath, "SKILL.md");
89
+ const handlerPath = path.join(rootRealPath, "handler.js");
90
+ const skillMd = readStableRegularFile(skillMdPath);
91
+ const handler = readStableRegularFile(handlerPath, { optional: true });
92
+ const skillId = String(options.skillId || path.basename(rootRealPath));
93
+ const source = String(options.source || "unknown");
94
+ const identityDigest = sha256([
95
+ `skill-execution-identity-v${SKILL_EXECUTION_IDENTITY_VERSION}`,
96
+ source,
97
+ skillId,
98
+ rootRealPath,
99
+ ]);
100
+ const contentDigest = sha256([
101
+ `skill-execution-content-v${SKILL_EXECUTION_IDENTITY_VERSION}`,
102
+ "SKILL.md",
103
+ skillMd.digest,
104
+ "handler.js",
105
+ handler?.digest || "absent",
106
+ ]);
107
+
108
+ return Object.freeze({
109
+ schemaVersion: SKILL_EXECUTION_IDENTITY_VERSION,
110
+ identityDigest,
111
+ contentDigest,
112
+ rootRealPath,
113
+ handlerPresent: handler !== null,
114
+ skillFileBytes: skillMd.size,
115
+ componentDigests: Object.freeze({
116
+ "SKILL.md": skillMd.digest,
117
+ "handler.js": handler?.digest || null,
118
+ }),
119
+ // Kept only in the short-lived verification snapshot. Callers must store
120
+ // executionIdentityMetadata(snapshot), never this content-bearing object.
121
+ skillMdContent: skillMd.bytes.toString("utf8"),
122
+ });
123
+ }
124
+
125
+ /** Produce the content-free descriptor safe to retain in loader caches. */
126
+ export function executionIdentityMetadata(snapshot) {
127
+ return Object.freeze({
128
+ schemaVersion: snapshot.schemaVersion,
129
+ identityDigest: snapshot.identityDigest,
130
+ contentDigest: snapshot.contentDigest,
131
+ rootRealPath: snapshot.rootRealPath,
132
+ handlerPresent: snapshot.handlerPresent,
133
+ componentDigests: Object.freeze({ ...snapshot.componentDigests }),
134
+ });
135
+ }
136
+
137
+ export function describeSkillExecutionAuthority(skill = {}) {
138
+ const hasHandler = skill.hasHandler === true;
139
+ const isolated = skill.isolation === true;
140
+ return Object.freeze({
141
+ schemaVersion: SKILL_EXECUTION_IDENTITY_VERSION,
142
+ mode: !hasHandler
143
+ ? "instructions-only"
144
+ : isolated
145
+ ? "controlled-agent-tools"
146
+ : "blocked-direct-handler",
147
+ directHandlerAllowed: false,
148
+ controlledToolEntryRequired: hasHandler,
149
+ });
150
+ }
151
+
152
+ export function isSkillExecutionContext(context = {}) {
153
+ return (
154
+ context.forExecution === true ||
155
+ EXECUTION_REASONS.has(String(context.loadedBecause || ""))
156
+ );
157
+ }
158
+
159
+ /**
160
+ * The only currently mediated handler-skill route is agent-core's explicit
161
+ * isolated-skill branch. It executes an agent loop whose tool calls re-enter
162
+ * host policy; it never imports handler.js. Every direct-handler route is
163
+ * denied until a restricted worker/RPC transport exists.
164
+ */
165
+ export function assertControlledSkillExecution(skill, context = {}) {
166
+ if (!isSkillExecutionContext(context) || skill?.hasHandler !== true) {
167
+ return describeSkillExecutionAuthority(skill);
168
+ }
169
+
170
+ const reason = String(context.loadedBecause || "");
171
+ if (reason === "run_skill" && skill.isolation === true) {
172
+ return describeSkillExecutionAuthority(skill);
173
+ }
174
+
175
+ throw securityError(
176
+ "CC_SKILL_DIRECT_HANDLER_BLOCKED",
177
+ `Skill "${skill.id || "unknown"}" cannot execute handler.js directly. ` +
178
+ "Use an isolated agent/tool route so every external call re-enters host policy.",
179
+ { skillId: skill.id },
180
+ );
181
+ }
182
+
183
+ export function skillDigestDriftError(skill, previousDigest, currentDigest) {
184
+ return securityError(
185
+ "CC_SKILL_DIGEST_DRIFT",
186
+ `Skill "${skill.id || "unknown"}" changed after discovery and was not reauthorized.`,
187
+ {
188
+ skillId: skill.id,
189
+ previousDigest,
190
+ currentDigest,
191
+ },
192
+ );
193
+ }
194
+
195
+ export function skillIdentityChangedError(skill) {
196
+ return securityError(
197
+ "CC_SKILL_IDENTITY_CHANGED",
198
+ `Skill "${skill.id || "unknown"}" changed identity after discovery; reload the skill registry before use.`,
199
+ { skillId: skill.id },
200
+ );
201
+ }
202
+
203
+ export function skillReauthorizationError(skill, cause) {
204
+ return securityError(
205
+ "CC_SKILL_REAUTHORIZE_FAILED",
206
+ `Skill "${skill.id || "unknown"}" digest reauthorization failed.`,
207
+ { skillId: skill.id, cause },
208
+ );
209
+ }
210
+
211
+ export function skillTrustRequiredError(skill) {
212
+ return securityError(
213
+ "CC_SKILL_TRUST_REQUIRED",
214
+ `Skill "${skill.id || "unknown"}" requires host authorization for its current source and content digest before first execution.`,
215
+ { skillId: skill.id },
216
+ );
217
+ }