chainlesschain 0.162.162 → 0.162.164

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 (237) hide show
  1. package/package.json +3 -1
  2. package/src/assets/web-panel/assets/{AIOps-ClI2ALgv.js → AIOps-BqRkaHGb.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-BDjRcJaK.js → ActionButton-DWO7OZLC.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-DikSRsaT.js → Analytics-C5oaVezM.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-9mLhMFmz.js → AppLayout-CsUESDoZ.js} +3 -3
  6. package/src/assets/web-panel/assets/{Artifacts-BSr88BrH.js → Artifacts-Dragqu5k.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-CdvyimOF.js → Audit-CQsaHctY.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-D3_hCedh.js → BackgroundAgents-DdG1jNSM.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-Cyvv9RHf.js → Backup-DN6sjK4z.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-BZM14kt8.js → BaseInput-Cxm_ZTCl.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-DrQSokVz.js → Chat-DVXGmA56.js} +6 -6
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-HwJR-C6B.js → ChatBubbleRenderer-BdaCL_iE.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-bFLYeWMV.js → Checkbox-DEc4vD_A.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-7mN7xJXT.js → Codegen-CKiTcv36.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-DAB5ZWm7.js → Col-Br9UUNN0.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-B_1TymaK.js → Community-NeUH_70T.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-Bq1uSWLJ.js → Compact-BqR-z2Df.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-CyiE1jEe.js → Compliance-DcWB_SgZ.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-Cpk0D7vm.js → Cowork-BfhgcudF.js} +2 -2
  20. package/src/assets/web-panel/assets/{Cron-d_Lv3rdB.js → Cron-LaU29LgD.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-DMqhHjMR.js → Crosschain-B2ZB9uwW.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-Br-oPuBw.js → DID-BuHl38A2.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-CfLW_RaP.js → Dashboard-m627yqvZ.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-DZnTOExV.js → Dropdown-C7bxF8F5.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-DHIUHDv1.js → EmailListRenderer-DPLPQzLp.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-Bw3t3myu.js → FamilyGuardDashboard-cOiH6ike.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-D9cpQPAY.js → Federation-Bvkzg88z.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-Jdczr9Mr.js → FormItemContext-BTsiA7h_.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-BT8ZMpC5.js → GenericCardRenderer-BGnVE5qu.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-DjARip2b.js → Git-DS_j6r25.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-BgWbSRcj.js → Governance-CKRG3Rsl.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-CfouJciM.js → Inference-DW8INoNQ.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-50l7mrAr.js → KnowledgeGraph-BhEYeFhC.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-rq50H84B.js → Logs-wqi0uxuR.js} +2 -2
  35. package/src/assets/web-panel/assets/{MarkdownRenderer-DUPIEdQH.js → MarkdownRenderer-DS8dE8ty.js} +1 -1
  36. package/src/assets/web-panel/assets/{Marketplace-BYgPDmHU.js → Marketplace-CMlTuPLT.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-5DVgcFdx.js → McpTools-CSx4m5JJ.js} +3 -3
  38. package/src/assets/web-panel/assets/{Memory-B70LPk7f.js → Memory-vnQCUy-_.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-De8ssA5Y.js → MobileBridge-BV2NA742.js} +1 -1
  40. package/src/assets/web-panel/assets/MobileProjects-Bw0k8e1B.js +1 -0
  41. package/src/assets/web-panel/assets/{Mtc-RJsOTsIA.js → Mtc-CzK_FPB1.js} +2 -2
  42. package/src/assets/web-panel/assets/{MtcAudit-Crh-6BEK.js → MtcAudit-Cb7G9oL3.js} +5 -5
  43. package/src/assets/web-panel/assets/{Multisig-wuoR5l3x.js → Multisig-qJxlUyzr.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-U2Mji4fZ.js → NLProgramming-DqaBJ7Te.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-CdTZAyDH.js → Notes-CwhTJkRi.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-C-FucWE7.js → NotificationSettings-YDs4Fal4.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-DCYFTeaI.js → OrderTableRenderer-CvEALpq7.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-an3OF85L.js → Organization-CEmQm9n8.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-C-1vmYFe.js → Overflow-zby_P_LA.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-Cwh47xKg.js → P2P-DsmDNFNT.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-Dm38GT0k.js → PdhVaultBrowser-FWwFlZGF.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-DS2Y8awD.js → Permissions-DuzQ6me5.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-BQNziA0I.js → PersonalDataHub-DZbeN613.js} +3 -3
  54. package/src/assets/web-panel/assets/{Pipeline-DF85L1ue.js → Pipeline-CoNSVAUS.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-BuLornF-.js → Privacy-OYJEAaMC.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-C3Y31IwX.js → ProjectInit-CWIapV--.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-BCPiI8aD.js → ProjectSettings-CX8xMxZn.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-BZ6s4k6g.js → Projects-BLCN8YyY.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-D3Wp022X.js → Providers-BV_sxp75.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-CUJfQkH4.js → QrScannerModal-BTnRrHRp.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-UAc0EO8l.js → QuickAsk-D1KZg018.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-BaxKupcs.js → Recommend-COm5cuNg.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-C75NNnXZ.js → RemoteSession-0saWEkYI.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-BVXynZAk.js → Reputation-Dr7iKLS2.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-C5MRZ0bi.js → Row-C1vpPBcr.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-DAKkEYka.js → RssFeed-CxlWrtNj.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-DvWv9YOA.js → Search-BT2V8dPN.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-B5peafW1.js → Security-bm9V3c5k.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-UQmvPEaG.js → Services-CocH1yyX.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-C3bhWpuF.js → Skeleton-DHItlMdd.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-DfkKf9_H.js → Skills-C59sLc4w.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-DqMSjlBM.js → Sla-Crj4BMc8.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-C-WbxWUX.js → SpeechSettings-DX4KFceY.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-CYuHZ4N2.js → SyncSettings-BD_iwQLr.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-CyeAyB9d.js → Tasks-BmCTzYsH.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-BTCeQnpq.js → Templates-BGUaxZYl.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-BifQuA9Y.js → Tenant-BS0tJx2O.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-Bx_9Bocf.js → Terminal--tHSAsld.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-BX0RFCOm.js → TimelineRenderer-D9-MFxS4.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-CGHrCmUS.js → Tokens-CiCB485f.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-DlqaY4SO.js → Trigger-SmCFuW_l.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-DfOmj-ay.js → Trust-DkK3Rqe0.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-B72jH5fE.js → UkeySign-CDM4LGdB.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-BT-63fqv.js → VideoEditing-IDB7DJXt.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-Dsul3sHr.js → Wallet-Bikj5cmt.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-Izkwwdgy.js → WebAuthn-C9abWlAw.js} +2 -2
  87. package/src/assets/web-panel/assets/{WorkflowEditor-D3FHSiH1.js → WorkflowEditor-DrbRKVky.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-CmVz5z3U.js → chat-CccCSDQf.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-CuLgyJBp.js → colors-CXObXLhb.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-Ml1YkXpw.js → compact-item-B5kfYAxC.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-BvjJ48bs.js → createContext-DmiPBfip.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-CvKrADNa.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-DVC0157C.js → hasIn-Q6lYteAc.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-C229ABfy.js → index-25Wlqps4.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-Ck_52dz_.js → index-33U29UNV.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-QXzlT9KD.js → index-4oXBDczR.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-4SBta3d7.js → index-BGYXvMc5.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-B0S8NzO6.js → index-BJCCa0s_.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DJyN28Et.js → index-BJJ5DhKI.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DC_OI9H2.js → index-BLOzViJ6.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-C_XuRgGn.js → index-BRrbUMoG.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-wvb_FtaV.js → index-BUFpT17Q.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-KMqhcF7l.js → index-BkRDiqGc.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-vG4XSJ1d.js → index-BsfvW6my.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DYXHFr4r.js → index-By-kfPED.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DuGszaWY.js → index-BzFTcQsc.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CXkJH-lK.js → index-C2FXdboq.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Dt5KMjwJ.js → index-C5XOlTHN.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-4wcgvPoF.js → index-CLhBDS2w.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-C_H_S-DY.js → index-CMq7UeoT.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BydjdZnl.js → index-CVMTWNKl.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BjHBpRYZ.js → index-Caghi-yL.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-Bzr0rB5T.js → index-CdB6FuSH.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BbPtzB8M.js → index-CoK8-kWQ.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BUt8kTIB.js → index-CsO3GUAY.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-C_vRgTl9.js → index-CwZBa20Z.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DukDVXCv.js → index-D-kASucw.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BbepULSc.js → index-D8eBw7vW.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-BfuKP4qe.js → index-D9wgifk4.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BiC6dQZG.js → index-DAYCTc07.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CmFNvNLZ.js → index-DF6Q8l2h.js} +1 -1
  122. package/src/assets/web-panel/assets/index-DTdFUWc_.js +1 -0
  123. package/src/assets/web-panel/assets/{index-KjgKdZe-.js → index-DgTLApS9.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-BpFJHiTv.js → index-DgxVJ8pg.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-Cw0Rjy87.js → index-DlJvIqoR.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CFYVQMvu.js → index-Dw4eHfsG.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CudmwNBV.js → index-Rh-ytwow.js} +3 -3
  128. package/src/assets/web-panel/assets/{index-DDGaOWBV.js → index-StAEt2pq.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-D3lD5qap.js → index-bzfw951k.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BzG-x9p4.js → index-fSUMbMvv.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-B_EvG_GW.js → index-tFHy5Wol.js} +1 -1
  132. package/src/assets/web-panel/assets/index-zQ0M_kz-.js +1 -0
  133. package/src/assets/web-panel/assets/{initDefaultProps-BDgd2YZ8.js → initDefaultProps-BNq7X72N.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-ErtrXdYe.js → motion-DOf9viTc.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-_GPPNCgs.js → move-CRHTcW4x.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-DRLL-8V2.js → mtc-parser-Cyoozgm2.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-p86sl023.js → omit-6-TjFNru.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-BTu7cMLH.js → pickAttrs-DlUmO1zi.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-BEKz6Isr.js → placementArrow-CFOL8mIR.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-Ck42c9MP.js → responsiveObserve-BtaFK5zd.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-1CEvuPsB.js → slide-BIbc2bur.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-BDfdx1GJ.js → statusUtils-BXX9d6-w.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-B4K46m5w.js → styleChecker-BGv10Bpn.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-DoIVpJNq.js → useFlexGapSupport-bKnKT8tw.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-DdAWi-ln.js → useFs-FY4IL4jn.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-iUu6k8dx.js → usePersonalDataHub-Bwl9TEgu.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-DZz4R6Tw.js → vnode-BM3OHxAT.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-DXlf9sA3.js → zoom-D1fbFiHB.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/commands/agenda.js +320 -32
  151. package/src/commands/agent.js +105 -11
  152. package/src/commands/context.js +125 -14
  153. package/src/commands/doctor.js +85 -1
  154. package/src/commands/hook.js +181 -7
  155. package/src/commands/plugin.js +456 -1
  156. package/src/commands/review.js +363 -2
  157. package/src/commands/session.js +191 -0
  158. package/src/commands/team.js +19 -1
  159. package/src/data/changelog.json +10 -4
  160. package/src/gateways/ws/remote-session-protocol.js +39 -0
  161. package/src/gateways/ws/session-protocol.js +55 -2
  162. package/src/gateways/ws/ws-agent-handler.js +50 -0
  163. package/src/harness/jsonl-session-store.js +60 -0
  164. package/src/harness/worktree-isolator.js +140 -5
  165. package/src/lib/agent-schedule-store.js +318 -10
  166. package/src/lib/agent-team/team-worktree.js +37 -2
  167. package/src/lib/agent-tool-admission.js +125 -0
  168. package/src/lib/app-preview.js +360 -0
  169. package/src/lib/async-hook-supervisor.cjs +54 -0
  170. package/src/lib/capability-manifest.js +319 -0
  171. package/src/lib/capability-negotiation.js +23 -12
  172. package/src/lib/channels/channel-manager.js +54 -2
  173. package/src/lib/cli-context-engineering.js +9 -2
  174. package/src/lib/context-breakdown.js +116 -0
  175. package/src/lib/diagnostic-bundle.js +230 -0
  176. package/src/lib/doctor-checkup.js +275 -4
  177. package/src/lib/execution-location.js +286 -0
  178. package/src/lib/headless-manifest.js +13 -40
  179. package/src/lib/hook-event-log.cjs +193 -0
  180. package/src/lib/hook-stats-store.cjs +197 -0
  181. package/src/lib/idempotency.js +109 -0
  182. package/src/lib/interaction-adapter.js +34 -4
  183. package/src/lib/json-schema-output.js +46 -12
  184. package/src/lib/json-schema-validate.js +143 -3
  185. package/src/lib/jsonl-session-store.js +1 -0
  186. package/src/lib/lsp/__tests__/lsp-manager.test.js +58 -0
  187. package/src/lib/lsp/lsp-manager.js +56 -0
  188. package/src/lib/monitor-event.js +290 -0
  189. package/src/lib/operation-fingerprint.js +217 -0
  190. package/src/lib/plugin-runtime/bin.js +37 -0
  191. package/src/lib/plugin-runtime/capabilities.js +19 -0
  192. package/src/lib/plugin-runtime/capability-consent.js +203 -0
  193. package/src/lib/plugin-runtime/hooks.js +37 -0
  194. package/src/lib/plugin-runtime/lsp.js +38 -0
  195. package/src/lib/plugin-runtime/mcp.js +40 -0
  196. package/src/lib/plugin-runtime/monitors.js +37 -0
  197. package/src/lib/plugin-runtime/plugin-options.js +151 -0
  198. package/src/lib/plugin-runtime/policy.js +62 -0
  199. package/src/lib/plugin-runtime/scopes.js +20 -4
  200. package/src/lib/pr-automation-policy.js +224 -0
  201. package/src/lib/project-instructions.js +128 -0
  202. package/src/lib/remote-approval-bridge.js +66 -13
  203. package/src/lib/repl-goal.js +132 -0
  204. package/src/lib/repl-rewind.js +153 -0
  205. package/src/lib/review-comment-anchor.js +241 -0
  206. package/src/lib/review-pipeline.js +46 -7
  207. package/src/lib/runtime-checkup.js +221 -0
  208. package/src/lib/schedule-planner.js +17 -1
  209. package/src/lib/secret-scan.js +409 -0
  210. package/src/lib/session-branch.js +0 -0
  211. package/src/lib/settings-hook-events.cjs +13 -0
  212. package/src/lib/settings-loader.cjs +42 -0
  213. package/src/lib/side-effect-ledger-store.js +88 -0
  214. package/src/lib/side-effect-ledger.js +401 -0
  215. package/src/lib/skill-loader.js +32 -0
  216. package/src/lib/skill-path-scope.js +63 -0
  217. package/src/lib/sub-agent-context.js +110 -9
  218. package/src/lib/sub-agent-registry.js +19 -0
  219. package/src/lib/subagent-inheritance.js +112 -0
  220. package/src/lib/telemetry/span-recorder.js +17 -4
  221. package/src/lib/terminal-context.js +195 -0
  222. package/src/lib/turn-binding-store.js +119 -0
  223. package/src/lib/unattended-action-policy.js +182 -0
  224. package/src/lib/worktree-cleanup-safety.js +138 -0
  225. package/src/lib/worktree-isolator.js +8 -0
  226. package/src/lib/worktree-sparse.js +131 -0
  227. package/src/repl/agent-repl.js +280 -30
  228. package/src/repl/permission-tier.js +28 -0
  229. package/src/runtime/agent-core.js +565 -21
  230. package/src/runtime/coding-agent-contract-shared.cjs +60 -1
  231. package/src/runtime/diagnostics.js +60 -0
  232. package/src/runtime/headless-runner.js +393 -1
  233. package/src/runtime/headless-stream.js +60 -1
  234. package/src/assets/web-panel/assets/MobileProjects-D10VISps.js +0 -1
  235. package/src/assets/web-panel/assets/devWarning-DhiGrbsh.js +0 -1
  236. package/src/assets/web-panel/assets/index-B7a1TrU6.js +0 -1
  237. package/src/assets/web-panel/assets/index-C2B1KRja.js +0 -1
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Execution-location model — the "任务在哪执行是 Session 一等属性" core of P1-7
3
+ * (Local / SSH / Cloud / Remote Control 统一模型) of
4
+ * CLAUDE_CODE_IDE_INCREMENTAL_GAP_ANALYSIS_2026-07-13.md.
5
+ *
6
+ * [[execution-backend.js]] is the runtime EXECUTOR (Local / Docker / SSH backends
7
+ * that actually run a command). It is NOT a session-level, displayable, policy
8
+ * layer: it has no notion of "show the user where this runs, with what
9
+ * permissions, whose credentials (source+scope only) and how results return",
10
+ * and no fail-closed default for an UNKNOWN location.
11
+ *
12
+ * This module is that pure descriptor + policy. The P1-7 table requires every
13
+ * session to surface: Execution Location, Source, Permissions, Credentials
14
+ * (source & scope only — never a value), Lifecycle, Cost and Return Path. This
15
+ * module normalizes those, and enforces the two invariants that give it teeth:
16
+ *
17
+ * 1. Credentials NEVER carry values — only {name, source, scope} survive, so a
18
+ * descriptor can be rendered/logged/shipped without leaking a secret.
19
+ * 2. An UNKNOWN or unrecognized location fails CLOSED to the most-restrictive
20
+ * permission profile (read-only, no shell/network/mcp/external), because we
21
+ * must not grant a remote/unknown environment ambient power by default.
22
+ *
23
+ * PURE: no fs / clock / RNG / process. A caller feeds observed session facts and
24
+ * reads back a safe descriptor plus a list of policy violations.
25
+ */
26
+
27
+ /** Canonical execution locations. UNKNOWN is the fail-closed sink. */
28
+ export const EXECUTION_LOCATION = Object.freeze({
29
+ LOCAL: "local",
30
+ WSL: "wsl",
31
+ SSH: "ssh",
32
+ CONTAINER: "container",
33
+ CLOUD: "cloud",
34
+ UNKNOWN: "unknown",
35
+ });
36
+
37
+ const LOCATION_ALIASES = new Map([
38
+ ["local", EXECUTION_LOCATION.LOCAL],
39
+ ["localhost", EXECUTION_LOCATION.LOCAL],
40
+ ["wsl", EXECUTION_LOCATION.WSL],
41
+ ["wsl2", EXECUTION_LOCATION.WSL],
42
+ ["ssh", EXECUTION_LOCATION.SSH],
43
+ ["remote-ssh", EXECUTION_LOCATION.SSH],
44
+ ["remote_ssh", EXECUTION_LOCATION.SSH],
45
+ ["container", EXECUTION_LOCATION.CONTAINER],
46
+ ["docker", EXECUTION_LOCATION.CONTAINER],
47
+ ["devcontainer", EXECUTION_LOCATION.CONTAINER],
48
+ ["dev-container", EXECUTION_LOCATION.CONTAINER],
49
+ ["cloud", EXECUTION_LOCATION.CLOUD],
50
+ ["codespaces", EXECUTION_LOCATION.CLOUD],
51
+ ["codespace", EXECUTION_LOCATION.CLOUD],
52
+ ["sandbox", EXECUTION_LOCATION.CLOUD],
53
+ ]);
54
+
55
+ /** Locations that are NOT the user's own trusted machine. */
56
+ const REMOTE_LOCATIONS = new Set([
57
+ EXECUTION_LOCATION.SSH,
58
+ EXECUTION_LOCATION.CONTAINER,
59
+ EXECUTION_LOCATION.CLOUD,
60
+ ]);
61
+
62
+ /** Normalize any location label to a canonical value; unrecognized → UNKNOWN. */
63
+ export function normalizeExecutionLocation(value) {
64
+ if (typeof value !== "string") return EXECUTION_LOCATION.UNKNOWN;
65
+ return (
66
+ LOCATION_ALIASES.get(value.trim().toLowerCase()) ||
67
+ EXECUTION_LOCATION.UNKNOWN
68
+ );
69
+ }
70
+
71
+ export function isRemoteLocation(location) {
72
+ return REMOTE_LOCATIONS.has(normalizeExecutionLocation(location));
73
+ }
74
+
75
+ /**
76
+ * Detect the ambient execution location from process signals. PURE: the caller
77
+ * supplies `env` (process.env) and `dockerEnvFileExists` (existsSync('/.dockerenv'))
78
+ * so this stays fs/process-free and unit-testable. Ordered most-specific-first,
79
+ * so a Codespace (which is also a container) reports CLOUD, and an SSH login
80
+ * outranks a bare WSL marker.
81
+ *
82
+ * @param {{env?:object, dockerEnvFileExists?:boolean}} [signals]
83
+ * @returns {string} a canonical EXECUTION_LOCATION value
84
+ */
85
+ export function detectAmbientLocation({ env = {}, dockerEnvFileExists } = {}) {
86
+ const e = env && typeof env === "object" ? env : {};
87
+ const has = (k) => typeof e[k] === "string" && e[k].trim() !== "";
88
+
89
+ // Cloud dev environments (GitHub Codespaces) — most specific.
90
+ if (e.CODESPACES === "true" || has("GITHUB_CODESPACE_TOKEN")) {
91
+ return EXECUTION_LOCATION.CLOUD;
92
+ }
93
+ // An interactive SSH login carries these — a remote shell, not the box's own tty.
94
+ if (has("SSH_CONNECTION") || has("SSH_CLIENT") || has("SSH_TTY")) {
95
+ return EXECUTION_LOCATION.SSH;
96
+ }
97
+ // Containers: the classic /.dockerenv marker, an explicit `container` env, or k8s.
98
+ if (
99
+ dockerEnvFileExists === true ||
100
+ has("container") ||
101
+ has("KUBERNETES_SERVICE_HOST")
102
+ ) {
103
+ return EXECUTION_LOCATION.CONTAINER;
104
+ }
105
+ // WSL exports these into every shell.
106
+ if (has("WSL_DISTRO_NAME") || has("WSL_INTEROP")) {
107
+ return EXECUTION_LOCATION.WSL;
108
+ }
109
+ return EXECUTION_LOCATION.LOCAL;
110
+ }
111
+
112
+ /** The most-restrictive permission profile — the fail-closed floor. */
113
+ function lockedDownPermissions() {
114
+ return Object.freeze({
115
+ file: "read", // read-only
116
+ shell: false,
117
+ network: false,
118
+ mcp: false,
119
+ externalSystems: false,
120
+ });
121
+ }
122
+
123
+ function normalizeFileAccess(v) {
124
+ const s = String(v || "").toLowerCase();
125
+ if (s === "write" || s === "readwrite" || s === "read-write") return "write";
126
+ if (s === "none") return "none";
127
+ return "read";
128
+ }
129
+
130
+ /**
131
+ * Clamp a requested permission set to what a location may grant. Every ambient
132
+ * power (shell / network / mcp / external) requires an EXPLICIT `true` — an
133
+ * unspecified or truthy-but-not-true power stays off. File access defaults to
134
+ * read; only a write-class request ("write" / "readwrite") grants write. An
135
+ * UNKNOWN location ignores the request entirely and returns the locked-down
136
+ * floor — the fail-closed core.
137
+ */
138
+ export function clampPermissionsForLocation(location, requested = {}) {
139
+ const loc = normalizeExecutionLocation(location);
140
+ if (loc === EXECUTION_LOCATION.UNKNOWN) return lockedDownPermissions();
141
+
142
+ const req = requested && typeof requested === "object" ? requested : {};
143
+ const grant = (key) => req[key] === true;
144
+
145
+ return {
146
+ file: normalizeFileAccess(req.file),
147
+ shell: grant("shell"),
148
+ network: grant("network"),
149
+ mcp: grant("mcp"),
150
+ externalSystems: grant("externalSystems"),
151
+ };
152
+ }
153
+
154
+ /**
155
+ * Strip credential references down to what may be displayed: name, source and
156
+ * scope only. Any `value` / `token` / `secret` field is dropped — this is the
157
+ * enforcement point behind "Credentials 只显示来源和作用域,不显示值".
158
+ */
159
+ export function redactCredentialRefs(creds) {
160
+ const list = Array.isArray(creds) ? creds : [];
161
+ return list
162
+ .filter((c) => c && typeof c === "object")
163
+ .map((c) => ({
164
+ name: c.name == null ? null : String(c.name),
165
+ source: c.source == null ? null : String(c.source),
166
+ scope: c.scope == null ? null : String(c.scope),
167
+ }));
168
+ }
169
+
170
+ const RETURN_PATHS = new Set([
171
+ "commit",
172
+ "pr",
173
+ "patch",
174
+ "artifact",
175
+ "report",
176
+ "none",
177
+ ]);
178
+
179
+ function normalizeReturnPath(v) {
180
+ const s = String(v || "").toLowerCase();
181
+ return RETURN_PATHS.has(s) ? s : "none";
182
+ }
183
+
184
+ /**
185
+ * Build the safe, displayable execution-context descriptor for a session.
186
+ *
187
+ * @param {object} input
188
+ * @param {string} input.location raw location label
189
+ * @param {object} [input.source] {dir, repo, commit, repos?}
190
+ * @param {object} [input.permissions] requested permissions (clamped)
191
+ * @param {Array} [input.credentials] credential refs (values stripped)
192
+ * @param {object} [input.lifecycle] {foreground?, onDisconnect?, onSleep?}
193
+ * @param {object} [input.cost] {model?, tokenBudget?, remote?}
194
+ * @param {string} [input.returnPath] commit|pr|patch|artifact|report|none
195
+ * @returns {object} normalized descriptor (safe to render/log/ship)
196
+ */
197
+ export function describeExecutionContext(input = {}) {
198
+ const location = normalizeExecutionLocation(input.location);
199
+ const permissions = clampPermissionsForLocation(location, input.permissions);
200
+ const src =
201
+ input.source && typeof input.source === "object" ? input.source : {};
202
+ return {
203
+ location,
204
+ remote: REMOTE_LOCATIONS.has(location),
205
+ source: {
206
+ dir: src.dir == null ? null : String(src.dir),
207
+ repo: src.repo == null ? null : String(src.repo),
208
+ commit: src.commit == null ? null : String(src.commit),
209
+ repos: Array.isArray(src.repos) ? src.repos.map((r) => String(r)) : [],
210
+ },
211
+ permissions,
212
+ credentials: redactCredentialRefs(input.credentials),
213
+ lifecycle: {
214
+ foreground: input.lifecycle?.foreground !== false,
215
+ onDisconnect: input.lifecycle?.onDisconnect
216
+ ? String(input.lifecycle.onDisconnect)
217
+ : "pause",
218
+ onSleep: input.lifecycle?.onSleep
219
+ ? String(input.lifecycle.onSleep)
220
+ : "pause",
221
+ },
222
+ cost: {
223
+ model: input.cost?.model ? String(input.cost.model) : null,
224
+ tokenBudget: Number.isFinite(Number(input.cost?.tokenBudget))
225
+ ? Number(input.cost.tokenBudget)
226
+ : null,
227
+ remote: input.cost?.remote === true,
228
+ },
229
+ returnPath: normalizeReturnPath(input.returnPath),
230
+ };
231
+ }
232
+
233
+ /** Keys that must never appear on a credential ref (a value leak). */
234
+ const CREDENTIAL_VALUE_KEYS = ["value", "token", "secret", "password", "key"];
235
+
236
+ /**
237
+ * Validate a raw execution-context input for policy compliance. EXHAUSTIVE:
238
+ * collects every violation. Fail-closed reads:
239
+ * - a credential ref carrying a value/token/secret/password/key → leak
240
+ * - location UNKNOWN → the session runs somewhere we cannot vouch for
241
+ * - a remote location with no return path → results have nowhere safe to go
242
+ * - a remote session granted network / external egress → surfaced as
243
+ * `remote-egress-granted` so it must be explicitly acknowledged, not ambient
244
+ *
245
+ * @returns {{ok:boolean, violations:string[], descriptor:object}}
246
+ */
247
+ export function validateExecutionContext(input = {}) {
248
+ const violations = [];
249
+ const rawCreds = Array.isArray(input.credentials) ? input.credentials : [];
250
+ for (const c of rawCreds) {
251
+ if (c && typeof c === "object") {
252
+ for (const k of CREDENTIAL_VALUE_KEYS) {
253
+ if (c[k] != null) {
254
+ violations.push("credential-value-present");
255
+ break;
256
+ }
257
+ }
258
+ }
259
+ }
260
+
261
+ const location = normalizeExecutionLocation(input.location);
262
+ if (location === EXECUTION_LOCATION.UNKNOWN) {
263
+ violations.push("unknown-location");
264
+ }
265
+
266
+ const descriptor = describeExecutionContext(input);
267
+
268
+ if (descriptor.remote && descriptor.returnPath === "none") {
269
+ violations.push("remote-without-return-path");
270
+ }
271
+
272
+ // Network / external egress FROM a remote box is the highest-risk grant — it
273
+ // must be an explicit, acknowledged decision, never ambient.
274
+ if (
275
+ descriptor.remote &&
276
+ (descriptor.permissions.network || descriptor.permissions.externalSystems)
277
+ ) {
278
+ violations.push("remote-egress-granted");
279
+ }
280
+
281
+ return {
282
+ ok: violations.length === 0,
283
+ violations,
284
+ descriptor,
285
+ };
286
+ }
@@ -17,6 +17,10 @@
17
17
  import crypto from "node:crypto";
18
18
  import { createRequire } from "node:module";
19
19
  import { PROTOCOL_MIN_VERSION } from "./capability-negotiation.js";
20
+ import {
21
+ CAPABILITY_MANIFEST,
22
+ toAgentFeatureFlags,
23
+ } from "./capability-manifest.js";
20
24
 
21
25
  export const STREAM_PROTOCOL_VERSION = 1;
22
26
 
@@ -143,46 +147,15 @@ export function buildAgentCapabilities() {
143
147
  // older line shape, so min === current.
144
148
  min_protocol_version: PROTOCOL_MIN_VERSION,
145
149
  agent_tools: contract.listCodingAgentToolNames(),
146
- permission_modes: [
147
- "default",
148
- "manual",
149
- "auto",
150
- "dontAsk",
151
- "plan",
152
- "acceptEdits",
153
- "bypassPermissions",
154
- ],
155
- output_formats: ["text", "json", "stream-json"],
156
- input_formats: ["text", "stream-json"],
150
+ // P1-9: permission modes, formats and the feature flags all project from the
151
+ // single canonical [[capability-manifest.js]] so `cc agent --capabilities`,
152
+ // the negotiator and the docs can no longer drift. Additive protocol-v1
153
+ // stream fields (event_seq / tool_use_id / trace_id) come in via the wire
154
+ // features; the mcp object and sandbox_engines come from the manifest too.
155
+ permission_modes: [...CAPABILITY_MANIFEST.permissionModes],
156
+ output_formats: [...CAPABILITY_MANIFEST.outputFormats],
157
+ input_formats: [...CAPABILITY_MANIFEST.inputFormats],
157
158
  exit_codes: HEADLESS_EXIT_CODES,
158
- features: {
159
- bare: true,
160
- safe_mode: true,
161
- ephemeral: true,
162
- background: true,
163
- worktree: true,
164
- checkpoint: true,
165
- json_schema_output: true,
166
- partial_messages: true,
167
- interactive_approvals: true,
168
- permission_prompt_tool: true,
169
- remote_control: true,
170
- // Additive protocol-v1 stream fields (agent-sdk docs/PROTOCOL.md §1.2.1):
171
- // every stream-json stdout line carries a monotonic `seq` and a
172
- // run-scoped `trace_id`, and tool_use/tool_result lines carry a pairing
173
- // `id` ("tu-<n>"). `trace_id` is caller-injectable (--trace-id /
174
- // CC_TRACE_ID) for end-to-end IDE ↔ CLI correlation.
175
- tool_use_id: true,
176
- event_seq: true,
177
- trace_id: true,
178
- mcp: {
179
- config_file: true,
180
- registry: true,
181
- tool_search: true,
182
- oauth: true,
183
- managed_allowlist: true,
184
- },
185
- sandbox_engines: ["docker", "bubblewrap"],
186
- },
159
+ features: toAgentFeatureFlags(),
187
160
  };
188
161
  }
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * hook-event-log — a persistent, hash-chained, replay-safe log of the hook
5
+ * delivery envelopes produced by the unified event bus ([[hook-event-bus.cjs]]).
6
+ *
7
+ * The event bus already stamps every settings-hook delivery with a stable
8
+ * `event_id` (see [[settings-hook-events.cjs]] `withDeliveryId`), but until now
9
+ * the full envelope was discarded — so there was nothing to look up when a user
10
+ * wants `cc hook replay <event-id>`. This store persists each envelope to a
11
+ * tamper-evident JSONL log so the replay command has a real source.
12
+ *
13
+ * Design:
14
+ * - OPT-IN: recording only happens when `CC_HOOK_EVENT_LOG` is enabled, so the
15
+ * default hook-firing path is byte-for-byte unchanged (no new IO per turn).
16
+ * - Hash chain: each line is `{envelope, prevHash, hash}` where
17
+ * `hash = sha256(prevHash + stableStringify(envelope))`. Editing / deleting /
18
+ * reordering any recorded line breaks the chain (mirrors the session
19
+ * transcript integrity design), which `verifyHookEventChain` detects.
20
+ * - Size guard: the log rotates to `<file>.1` once it exceeds MAX_LOG_BYTES so
21
+ * an always-on session can't grow it without bound.
22
+ * - Pure over injected IO (`_deps.fs` / `_deps.os`) so it is fully unit-testable
23
+ * without touching the real home directory.
24
+ */
25
+
26
+ const fs = require("fs");
27
+ const os = require("os");
28
+ const path = require("path");
29
+ const crypto = require("crypto");
30
+ const { stableStringify } = require("./hook-event-bus.cjs");
31
+
32
+ const _deps = { fs, os };
33
+
34
+ /** Cap the always-on log at 5 MiB, then rotate to `<file>.1`. */
35
+ const MAX_LOG_BYTES = 5 * 1024 * 1024;
36
+
37
+ /** Default log location: `~/.chainlesschain/hook-events.jsonl`. */
38
+ function hookEventLogPath(homedir) {
39
+ const home = homedir || _deps.os.homedir();
40
+ return path.join(home, ".chainlesschain", "hook-events.jsonl");
41
+ }
42
+
43
+ /** Recording is opt-in — `CC_HOOK_EVENT_LOG=1` (or `true`) turns it on. */
44
+ function isHookEventLogEnabled(env = process.env) {
45
+ const v = String(env.CC_HOOK_EVENT_LOG || "").toLowerCase();
46
+ return v === "1" || v === "true" || v === "yes" || v === "on";
47
+ }
48
+
49
+ /** Hash one envelope against the previous chain hash (deterministic). */
50
+ function computeChainHash(prevHash, envelope) {
51
+ return crypto
52
+ .createHash("sha256")
53
+ .update(`${prevHash || "genesis"}\n${stableStringify(envelope)}`, "utf-8")
54
+ .digest("hex");
55
+ }
56
+
57
+ /** The hash the NEXT record must chain from (last parseable line's `hash`). */
58
+ function latestChainHash(text) {
59
+ const lines = String(text || "").split("\n");
60
+ for (let i = lines.length - 1; i >= 0; i--) {
61
+ if (!lines[i].trim()) continue;
62
+ try {
63
+ const rec = JSON.parse(lines[i]);
64
+ return typeof rec?.hash === "string" ? rec.hash : null;
65
+ } catch {
66
+ // half-written tail line — chain from the previous intact record
67
+ continue;
68
+ }
69
+ }
70
+ return null;
71
+ }
72
+
73
+ /**
74
+ * Append a hook envelope to the chained log. Best-effort: never throws — a
75
+ * failure to record must not break the turn that fired the hook.
76
+ *
77
+ * @param {object} envelope a full envelope from buildHookEnvelope
78
+ * @param {object} [opts] { filePath, homedir }
79
+ * @returns {{ok:boolean, event_id?:string, hash?:string, reason?:string}}
80
+ */
81
+ function appendHookEvent(envelope, { filePath, homedir } = {}) {
82
+ if (!envelope || typeof envelope !== "object" || !envelope.event_id) {
83
+ return { ok: false, reason: "invalid envelope (no event_id)" };
84
+ }
85
+ const f = _deps.fs;
86
+ const fp = filePath || hookEventLogPath(homedir);
87
+ try {
88
+ const dir = path.dirname(fp);
89
+ if (!f.existsSync(dir)) f.mkdirSync(dir, { recursive: true });
90
+ let prevHash = null;
91
+ if (f.existsSync(fp)) {
92
+ let rotated = false;
93
+ try {
94
+ if (f.statSync(fp).size > MAX_LOG_BYTES) {
95
+ f.renameSync(fp, `${fp}.1`);
96
+ rotated = true;
97
+ }
98
+ } catch {
99
+ /* stat/rename best-effort */
100
+ }
101
+ if (!rotated) prevHash = latestChainHash(f.readFileSync(fp, "utf-8"));
102
+ }
103
+ const hash = computeChainHash(prevHash, envelope);
104
+ const line = `${JSON.stringify({ envelope, prevHash, hash })}\n`;
105
+ f.appendFileSync(fp, line, "utf-8");
106
+ return { ok: true, event_id: envelope.event_id, hash };
107
+ } catch (e) {
108
+ return { ok: false, reason: e.message };
109
+ }
110
+ }
111
+
112
+ /** Read every recorded record (skips malformed / half-written lines). */
113
+ function readHookEventRecords({ filePath, homedir } = {}) {
114
+ const f = _deps.fs;
115
+ const fp = filePath || hookEventLogPath(homedir);
116
+ if (!f.existsSync(fp)) return [];
117
+ const out = [];
118
+ for (const line of f.readFileSync(fp, "utf-8").split("\n")) {
119
+ if (!line.trim()) continue;
120
+ try {
121
+ out.push(JSON.parse(line));
122
+ } catch {
123
+ /* skip malformed / partial line */
124
+ }
125
+ }
126
+ return out;
127
+ }
128
+
129
+ /**
130
+ * Look up the envelope for a delivery id. The LATEST matching record wins (an
131
+ * event_id can recur across processes; the most recent delivery is what a user
132
+ * replaying "the last one" means).
133
+ */
134
+ function findHookEvent(eventId, { filePath, homedir } = {}) {
135
+ if (!eventId) return null;
136
+ const records = readHookEventRecords({ filePath, homedir });
137
+ for (let i = records.length - 1; i >= 0; i--) {
138
+ if (records[i]?.envelope?.event_id === eventId) return records[i].envelope;
139
+ }
140
+ return null;
141
+ }
142
+
143
+ /** The most recent `limit` envelopes (newest last), for `cc hook events-log`. */
144
+ function listHookEvents({ limit = 20, filePath, homedir } = {}) {
145
+ const records = readHookEventRecords({ filePath, homedir });
146
+ const n = Math.max(0, Number(limit) || 0);
147
+ return records.slice(n ? -n : 0).map((r) => r.envelope);
148
+ }
149
+
150
+ /**
151
+ * Recompute the chain and report the first break, if any.
152
+ * @returns {{ok:boolean, length:number, brokenAt:number, reason?:string}}
153
+ */
154
+ function verifyHookEventChain({ filePath, homedir } = {}) {
155
+ const records = readHookEventRecords({ filePath, homedir });
156
+ let prev = null;
157
+ for (let i = 0; i < records.length; i++) {
158
+ const { envelope, prevHash, hash } = records[i] || {};
159
+ if ((prevHash ?? null) !== prev) {
160
+ return {
161
+ ok: false,
162
+ length: records.length,
163
+ brokenAt: i,
164
+ reason: "prevHash does not match the previous record's hash",
165
+ };
166
+ }
167
+ const expect = computeChainHash(prev, envelope);
168
+ if (expect !== hash) {
169
+ return {
170
+ ok: false,
171
+ length: records.length,
172
+ brokenAt: i,
173
+ reason: "record hash does not match its envelope (tampered)",
174
+ };
175
+ }
176
+ prev = hash;
177
+ }
178
+ return { ok: true, length: records.length, brokenAt: -1 };
179
+ }
180
+
181
+ module.exports = {
182
+ MAX_LOG_BYTES,
183
+ hookEventLogPath,
184
+ isHookEventLogEnabled,
185
+ computeChainHash,
186
+ latestChainHash,
187
+ appendHookEvent,
188
+ readHookEventRecords,
189
+ findHookEvent,
190
+ listHookEvents,
191
+ verifyHookEventChain,
192
+ _deps,
193
+ };