chainlesschain 0.166.9 → 0.166.13

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 (232) hide show
  1. package/README.md +33 -0
  2. package/bin/chainlesschain.js +5 -0
  3. package/package.json +5 -2
  4. package/src/assets/web-panel/assets/{AIOps-DJvpifGx.js → AIOps-BN25cNOD.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-D2UhuF_A.js → ActionButton-Da9IP-m5.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-C9ho9obu.js → Analytics-D7hkEvQm.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-BvRCpFK3.js → AppLayout-CCV4Xnbc.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-jxrySvpk.js → Artifacts-CVSnVJeA.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-ovEw0ZYl.js → Audit-CuYdw5Ag.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-D7H5z6zS.js → BackgroundAgents-DZCnK-Tf.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-BuXob8za.js → Backup-cV9FdpTy.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-CtnszuQ2.js → BaseInput-BRnv6YSp.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-B_mYE8fJ.js → Chat-Bw5w87P4.js} +6 -6
  14. package/src/assets/web-panel/assets/ChatBubbleRenderer-C0GjtUAw.js +1 -0
  15. package/src/assets/web-panel/assets/{Checkbox-ierdtcJD.js → Checkbox-DaoTqcdt.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-3VKPJD_B.js → Codegen-B4dYcEIi.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-1EdMyf5P.js → Col-mAhuOeuD.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-D6H7UA8K.js → Community-BK6KEdBk.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-BBAZvYIm.js → Compact-CCglmNu5.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-CgsTrAoj.js → Compliance-Cm8S4of7.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-tnZgLoTE.js → Cowork-Dhs1QLMe.js} +3 -3
  22. package/src/assets/web-panel/assets/{Cron-CPpZw2Nh.js → Cron-CLlhmXWk.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-BymBcp5z.js → Crosschain-BnHVbaNs.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-DKPxS_K1.js → DID-UzQP9-0O.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-DvJhEmH9.js → Dashboard-CBdlPClz.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-b8iQyQIZ.js → Dropdown-axIRPdq1.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer--0-A-zKb.js → EmailListRenderer-DUalW5rx.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-C12iDN06.js → FamilyGuardDashboard-Bl4W9luY.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-BRhaE2Z8.js → Federation-C1yP-uEu.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-C4dnq7yf.js → FormItemContext-Xh6Ig5q8.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-CGAdbR5n.js → GenericCardRenderer-C2cz3bt2.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-4eA2fYzL.js → Git-C_z63ixg.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-BJuY9Y-9.js → Governance-BYqB33_3.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-DZ5Dy4up.js → Inference-CEULuArm.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-BMTjRs4A.js → KnowledgeGraph-fgMsu-0H.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-BKEeQEfJ.js → Logs-DO9Hdcec.js} +2 -2
  37. package/src/assets/web-panel/assets/MarkdownRenderer-BkrK04xW.js +1 -0
  38. package/src/assets/web-panel/assets/{Marketplace-Dhho4fEg.js → Marketplace-B8zyLiFe.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-BW6xxSlU.js → McpTools-BLAN2mWW.js} +3 -3
  40. package/src/assets/web-panel/assets/{Memory-mPqlpSkq.js → Memory-CrQcFM7u.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-Cb9N_DQI.js → MobileBridge-DVnyiiU-.js} +1 -1
  42. package/src/assets/web-panel/assets/{MobileProjects-BNs8tah_.js → MobileProjects-qjCME5OD.js} +1 -1
  43. package/src/assets/web-panel/assets/{Mtc-CaxBt8tn.js → Mtc-4JE3C3It.js} +2 -2
  44. package/src/assets/web-panel/assets/{MtcAudit-DRPQbp3t.js → MtcAudit-CjBuak9I.js} +5 -5
  45. package/src/assets/web-panel/assets/{Multisig-CRm-d8bK.js → Multisig-BtPcYQcC.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-BCCk3LPs.js → NLProgramming-Cx653_Ba.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-Cv8SN8gN.js → Notes-CkuD3YzS.js} +4 -4
  48. package/src/assets/web-panel/assets/{NotificationSettings-CggIvTh5.js → NotificationSettings-BgNgU7HH.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-BW3_bV12.js → OrderTableRenderer-BTC8W0a-.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-BuRE-VCO.js → Organization-Dmd4Hjxz.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-DBrm1gju.js → Overflow-C_5DA-G0.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-CWVnDYgS.js → P2P-uwslV4XC.js} +2 -2
  53. package/src/assets/web-panel/assets/{PdhVaultBrowser-8RKUIpte.js → PdhVaultBrowser-CuNgwVnX.js} +5 -5
  54. package/src/assets/web-panel/assets/{Permissions-tDUAxogW.js → Permissions-CJayVX9H.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-Dv2-CFis.js → PersonalDataHub-Cb05H5go.js} +4 -4
  56. package/src/assets/web-panel/assets/{Pipeline-DM6kvFni.js → Pipeline-BZlGKapZ.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-DzK-yL0d.js → Privacy-BIzZWYzd.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-B5UrNpkj.js → ProjectInit-vEYYyQXQ.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-CxJD43oW.js → ProjectSettings-MZqTy5CC.js} +2 -2
  60. package/src/assets/web-panel/assets/Projects-CRARUOl8.js +1 -0
  61. package/src/assets/web-panel/assets/{Providers-CYl4jRYK.js → Providers-80VAK8PX.js} +1 -1
  62. package/src/assets/web-panel/assets/{QrScannerModal-DeH2T0fH.js → QrScannerModal-CzRSoIwK.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-Bw9k_kTk.js → QuickAsk-BpwQ2n4C.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-Bl_jGwoi.js → Recommend-BC03TZ79.js} +1 -1
  65. package/src/assets/web-panel/assets/{RemoteSession-d6u01Kq0.js → RemoteSession-DE59-jaa.js} +2 -2
  66. package/src/assets/web-panel/assets/{Reputation-Ds_Dfr-k.js → Reputation-DOHmeWyA.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-BpQUQTNj.js → Row-hc5RZl1D.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-BatpZBGt.js → RssFeed-Cv5uMP7E.js} +3 -3
  69. package/src/assets/web-panel/assets/{Search-D7hOObzi.js → Search-qohu7Ug0.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-dXQ4FKNt.js → Security-drCPFWV5.js} +4 -4
  71. package/src/assets/web-panel/assets/{Services-D8wInGPa.js → Services-BAEgUeRy.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-DXQCoYpM.js → Skeleton-CkJkKBlo.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-D3oLRIVn.js → Skills-bMuKEpez.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-BmP4-LnJ.js → Sla-DxWQVHRC.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-DLj-xzro.js → SpeechSettings-BpS8idmV.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-8KKaaRMr.js → SyncSettings-BPBLlW5v.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-GyK42I7C.js → Tasks-C4SLEeUh.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-n1y_8UBG.js → Templates-r-wfU39U.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-B39nBph8.js → Tenant-C7vjRmLN.js} +1 -1
  80. package/src/assets/web-panel/assets/{Terminal-DCQoOKXe.js → Terminal-DdzeFCV2.js} +2 -2
  81. package/src/assets/web-panel/assets/{TimelineRenderer-BkhbDfXk.js → TimelineRenderer-CYyWN2KD.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-BeHIIU8D.js → Tokens-D8A9osUg.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-BHvWXVOb.js → Trigger-DBvrNlyS.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-y2WaOSto.js → Trust-DBVAGc7o.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-DBFeJBzt.js → UkeySign-C1vQUCRJ.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-BEOWitC-.js → VideoEditing-BKs4dah4.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-BITedTe6.js → Wallet-ByIuj3lD.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-DMwlJVin.js → WebAuthn-DYlAFCm9.js} +3 -3
  89. package/src/assets/web-panel/assets/{WorkflowEditor-CKfGFEu1.js → WorkflowEditor-Dwyadd0c.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-DR6gnBGF.js → chat-Bm2f3s08.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-C_Hw5NCn.js → colors-C8ORSh7V.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-B8IPwsEu.js → compact-item-1iVlnsM-.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-D-u4JVnJ.js → createContext-CmqNyUSL.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-B69RCDDH.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-CZubdS4D.js → hasIn-rUMaX3Ul.js} +1 -1
  96. package/src/assets/web-panel/assets/index-9biMQ-tw.js +1 -0
  97. package/src/assets/web-panel/assets/{index-C25rOz7O.js → index-B53c3diB.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CfniPP5p.js → index-B59OWAs7.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-11ASqx-A.js → index-B8BrB0Ls.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-auyNYjLo.js → index-BC32_0xT.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-Ctje8Vl3.js → index-BC8Wb6cy.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Cg2bCeol.js → index-BCOhTILd.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-D1w96gg9.js → index-BFniLMn9.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-k1Xa5iw1.js → index-BIvM-uAX.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DuOU5apg.js → index-BK-RY0-7.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-D47jt8ET.js → index-BQL9r73Y.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-C2VmtNaQ.js → index-BVtnizyC.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Bizm87cX.js → index-Bf1PlIHp.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Dt-w3xQ7.js → index-Bgw4Y2rU.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-ffe7bvqP.js → index-BgwLNxmr.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Cl5RpreD.js → index-C-J5-pGH.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-idZKyADQ.js → index-C-ZIHi42.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-LvjAKDSl.js → index-C3B1S-mW.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-DmRcgiYT.js → index-C5RfRciU.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-rYBHSDcJ.js → index-CCEyz58d.js} +1 -1
  116. package/src/assets/web-panel/assets/index-COie87kl.js +1 -0
  117. package/src/assets/web-panel/assets/{index-DcFjRT-K.js → index-CTfEmKK0.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-DjRrqooR.js → index-CfiHyVyl.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DpjHpRoq.js → index-CkFvuAex.js} +3 -3
  120. package/src/assets/web-panel/assets/{index-BzoFanEQ.js → index-D98FXb0w.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-Cbm8F0M2.js → index-DDHk911Q.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-BXS6wYJZ.js → index-DJxtPFOh.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DY6MHo9D.js → index-DVJ1uKf4.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CiXkhOkY.js → index-Dcck8QfW.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-mYZJxGH6.js → index-DgUE51Pz.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CqmLw8cs.js → index-Dsve5Gkv.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-xoNssgz_.js → index-DvedhJeM.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DfnzrUxU.js → index-DwMdWKiF.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-Bi21Etg4.js → index-OcbzdRpT.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DJ6pG79m.js → index-fPK6GFEg.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-_nL79NT8.js → index-geQinnns.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DTosx2Wu.js → index-pHWA7bmM.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-cVqbas5C.js → index-reUHhuz8.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-Bv2132PO.js → index-tqTx5wXo.js} +1 -1
  135. package/src/assets/web-panel/assets/{initDefaultProps-lcU_dT2r.js → initDefaultProps-CuA-cpkL.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-Dc7UNXZ1.js → motion-CimmE_9b.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-Cll8ZXaL.js → move-DlGlrltz.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-CAb_yLIM.js → mtc-parser-CK6BJQ07.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-DurYMyTe.js → omit-BKjBfZfB.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-BITQyOlw.js → pickAttrs-B2chVYw9.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-Dg1rH91i.js → placementArrow-BW8aLJJ3.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-D_EWIeac.js → responsiveObserve-dXlPl66S.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-lK4d3zsh.js → slide-hSa89S4G.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-Bflq-Git.js → statusUtils-DM6KLt-s.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-Ccp0I-wt.js → styleChecker-C9MQAK15.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-CYZbByYA.js → useFlexGapSupport-BpQDpP0z.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-B_x0nxFD.js → useFs-C7rtRViA.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-DW55rL85.js → usePersonalDataHub-Dm15xafq.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-Ca6MH3W8.js → vnode-mEiEytw4.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-NdHelOog.js → zoom-DzPxflhY.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/command-help-index.json +5 -5
  153. package/src/commands/agent.js +51 -20
  154. package/src/commands/compact.js +349 -3
  155. package/src/commands/context.js +72 -1
  156. package/src/commands/graph.js +26 -15
  157. package/src/commands/hmemory.js +21 -0
  158. package/src/commands/hook.js +256 -28
  159. package/src/commands/memory.js +209 -42
  160. package/src/commands/promcomp.js +17 -0
  161. package/src/commands/serve.js +94 -10
  162. package/src/commands/session.js +2 -3
  163. package/src/commands/team.js +7 -1
  164. package/src/data/changelog.json +41 -2
  165. package/src/gateways/ws/session-core-protocol.js +62 -3
  166. package/src/gateways/ws/session-protocol.js +123 -15
  167. package/src/gateways/ws/ws-agent-handler.js +157 -9
  168. package/src/gateways/ws/ws-session-gateway.js +204 -30
  169. package/src/generated/cc-agent-protocol.schema.json +2094 -4
  170. package/src/harness/prompt-compressor.js +5 -55
  171. package/src/lib/agent-sandbox.js +14 -4
  172. package/src/lib/agent-team/team-distributed-graph-bridge.js +3 -3
  173. package/src/lib/app-server/context-memory-notifications.js +54 -0
  174. package/src/lib/app-server/rollout-store-factory.js +115 -0
  175. package/src/lib/app-server/rollout-store.js +310 -23
  176. package/src/lib/app-server/server.js +184 -7
  177. package/src/lib/app-server/sqlite-rollout-store.js +59 -16
  178. package/src/lib/auto-mode-config.js +26 -0
  179. package/src/lib/causal-observability.js +13 -1
  180. package/src/lib/context-memory-kernel/authority.js +95 -0
  181. package/src/lib/context-memory-kernel/durable-memory-port.js +296 -0
  182. package/src/lib/context-memory-kernel/index.js +8 -0
  183. package/src/lib/context-memory-kernel/jsonl-session-context-port.js +232 -0
  184. package/src/lib/context-memory-kernel/live-compaction.js +375 -0
  185. package/src/lib/context-memory-kernel/memory-service.js +667 -0
  186. package/src/lib/context-memory-kernel/message-adapter.js +451 -0
  187. package/src/lib/context-memory-kernel/privacy-purge-port.js +244 -0
  188. package/src/lib/context-memory-kernel/provider-context.js +192 -0
  189. package/src/lib/context-memory-kernel/runtime.js +61 -0
  190. package/src/lib/direct-model-usage.js +22 -18
  191. package/src/lib/graph-kernel/cutover-authority-resolver.js +4 -5
  192. package/src/lib/graph-kernel/cutover-ledger.js +2 -2
  193. package/src/lib/graph-kernel/event-store.js +3 -5
  194. package/src/lib/graph-kernel/index.js +2 -0
  195. package/src/lib/graph-kernel/migration-saga.js +2 -2
  196. package/src/lib/graph-kernel/production-cutover-evidence.js +976 -0
  197. package/src/lib/graph-kernel/retirement-evidence.js +12 -4
  198. package/src/lib/hierarchical-memory.js +22 -0
  199. package/src/lib/hook-audit-store.js +170 -0
  200. package/src/lib/hook-event-bus.cjs +0 -0
  201. package/src/lib/hook-manager.js +25 -83
  202. package/src/lib/hook-runtime-adapters.js +233 -0
  203. package/src/lib/hook-runtime-contract.cjs +291 -0
  204. package/src/lib/hook-runtime-contract.js +21 -0
  205. package/src/lib/hook-trust.js +210 -0
  206. package/src/lib/hooks-v2-producers.js +52 -6
  207. package/src/lib/hooks-v2-runtime.js +443 -178
  208. package/src/lib/llm-pricing.js +10 -0
  209. package/src/lib/memory-manager.js +29 -4
  210. package/src/lib/model-context-window.js +52 -0
  211. package/src/lib/permanent-memory.js +17 -0
  212. package/src/lib/plan-mode.js +8 -4
  213. package/src/lib/process-execution-broker/index.js +208 -16
  214. package/src/lib/runtime-usage-ledger.js +20 -0
  215. package/src/lib/session-consolidator.js +59 -0
  216. package/src/lib/session-core-singletons.js +17 -4
  217. package/src/lib/session-hooks.js +29 -2
  218. package/src/lib/session-transcript-migration.js +188 -0
  219. package/src/lib/settings-hook-events.cjs +37 -401
  220. package/src/lib/settings-hook-events.js +210 -8
  221. package/src/lib/settings-hooks.cjs +42 -83
  222. package/src/lib/ws-session-manager.js +4 -1
  223. package/src/repl/agent-repl.js +186 -53
  224. package/src/runtime/agent-core.js +376 -350
  225. package/src/runtime/headless-runner.js +40 -33
  226. package/src/runtime/headless-stream.js +131 -30
  227. package/src/assets/web-panel/assets/ChatBubbleRenderer-DaiA6CsX.js +0 -1
  228. package/src/assets/web-panel/assets/MarkdownRenderer-B05DgASC.js +0 -1
  229. package/src/assets/web-panel/assets/Projects-Z2Orm8Ma.js +0 -1
  230. package/src/assets/web-panel/assets/devWarning-Cq6lSd_q.js +0 -1
  231. package/src/assets/web-panel/assets/index-BQ3213fz.js +0 -1
  232. package/src/assets/web-panel/assets/index-vJagfET2.js +0 -1
@@ -120,6 +120,10 @@ function sameMembers(actual, expected) {
120
120
  );
121
121
  }
122
122
 
123
+ function compareCanonicalText(left, right) {
124
+ return left < right ? -1 : left > right ? 1 : 0;
125
+ }
126
+
123
127
  function clone(value) {
124
128
  return value == null ? value : JSON.parse(JSON.stringify(value));
125
129
  }
@@ -289,7 +293,7 @@ function normalizeMutationProbes(value, contract) {
289
293
  };
290
294
  });
291
295
  normalized.sort((left, right) =>
292
- left.mutationFunction.localeCompare(right.mutationFunction),
296
+ compareCanonicalText(left.mutationFunction, right.mutationFunction),
293
297
  );
294
298
  const actual = normalized.map((entry) => entry.mutationFunction);
295
299
  if (
@@ -347,7 +351,8 @@ function normalizeReplacementJourneys(value, contract, platforms, commitSha) {
347
351
  };
348
352
  });
349
353
  normalized.sort((left, right) =>
350
- `${left.replacementEntryId}:${left.platform}`.localeCompare(
354
+ compareCanonicalText(
355
+ `${left.replacementEntryId}:${left.platform}`,
351
356
  `${right.replacementEntryId}:${right.platform}`,
352
357
  ),
353
358
  );
@@ -408,7 +413,10 @@ function normalizeHistoricalReadProbes(value, contract) {
408
413
  };
409
414
  });
410
415
  normalized.sort((left, right) =>
411
- left.historicalReadFunction.localeCompare(right.historicalReadFunction),
416
+ compareCanonicalText(
417
+ left.historicalReadFunction,
418
+ right.historicalReadFunction,
419
+ ),
412
420
  );
413
421
  const actual = normalized.map((entry) => entry.historicalReadFunction);
414
422
  if (
@@ -524,7 +532,7 @@ export function normalizeGraphLegacyWriterObservation(
524
532
  }))
525
533
  : [];
526
534
  writerObservations.sort((left, right) =>
527
- left.writerFile.localeCompare(right.writerFile),
535
+ compareCanonicalText(left.writerFile, right.writerFile),
528
536
  );
529
537
  const actualWriterFiles = writerObservations.map((entry) => entry.writerFile);
530
538
  if (
@@ -6,6 +6,18 @@
6
6
  */
7
7
 
8
8
  import { escapeLike } from "./sql-like.js";
9
+ import {
10
+ assertLegacyMutationAllowed,
11
+ resolveCliContextMemoryCutover,
12
+ } from "./context-memory-kernel/authority.js";
13
+
14
+ function assertLegacyHierarchicalMemoryMutationAllowed(operation) {
15
+ assertLegacyMutationAllowed(
16
+ resolveCliContextMemoryCutover({
17
+ scopeKey: `cli:legacy-hierarchical-memory:${operation}`,
18
+ }),
19
+ );
20
+ }
9
21
 
10
22
  // ─── Configuration ───────────────────────────────────────────────
11
23
  export const MEMORY_CONFIG = {
@@ -123,6 +135,7 @@ function calcRetention(
123
135
  * Create persistent memory tables for long-term / core / sharing
124
136
  */
125
137
  export function ensureMemoryTables(db) {
138
+ assertLegacyHierarchicalMemoryMutationAllowed("ensure-tables");
126
139
  db.exec(`
127
140
  CREATE TABLE IF NOT EXISTS memory_long_term (
128
141
  id TEXT PRIMARY KEY,
@@ -179,6 +192,7 @@ export function ensureMemoryTables(db) {
179
192
  * @param {string} [options.namespace] - Namespace for in-memory isolation (default: "global")
180
193
  */
181
194
  export function storeMemory(db, content, options = {}) {
195
+ assertLegacyHierarchicalMemoryMutationAllowed("store");
182
196
  if (!content || !content.trim()) {
183
197
  throw new Error("Memory content cannot be empty");
184
198
  }
@@ -258,6 +272,7 @@ export function storeMemory(db, content, options = {}) {
258
272
  * the default "global" namespace (backward compatible).
259
273
  */
260
274
  export function recallMemory(db, query, options = {}) {
275
+ assertLegacyHierarchicalMemoryMutationAllowed("recall");
261
276
  if (!query || !query.trim()) return [];
262
277
 
263
278
  const limit = Math.max(1, parseInt(options.limit) || 20);
@@ -653,6 +668,7 @@ export function applyForgettingCurve(
653
668
  * persisted to the DB — lives alongside the in-memory layer.
654
669
  */
655
670
  export function attachMetadata(memoryId, metadata, namespace = DEFAULT_NS) {
671
+ assertLegacyHierarchicalMemoryMutationAllowed("attach-metadata");
656
672
  if (!memoryId) throw new Error("memoryId is required");
657
673
  if (!metadata || typeof metadata !== "object")
658
674
  throw new Error("metadata must be an object");
@@ -682,6 +698,7 @@ function _locateInMemory(memoryId) {
682
698
  * Promote a memory one layer up: working → short-term → long-term.
683
699
  */
684
700
  export function promoteMemoryV2(db, memoryId) {
701
+ assertLegacyHierarchicalMemoryMutationAllowed("promote");
685
702
  if (!memoryId) throw new Error("memoryId is required");
686
703
  const loc = _locateInMemory(memoryId);
687
704
  if (loc && loc.layer === MEMORY_LAYER.WORKING) {
@@ -728,6 +745,7 @@ export function promoteMemoryV2(db, memoryId) {
728
745
  * (long-term/core demotion requires DB round-trip; not exposed here.)
729
746
  */
730
747
  export function demoteMemoryV2(memoryId) {
748
+ assertLegacyHierarchicalMemoryMutationAllowed("demote");
731
749
  if (!memoryId) throw new Error("memoryId is required");
732
750
  for (const [ns, nsMap] of _shortTermNS) {
733
751
  if (nsMap.has(memoryId)) {
@@ -790,6 +808,7 @@ export function shareMemoryV2(
790
808
  }
791
809
 
792
810
  export function revokeShare(shareId) {
811
+ assertLegacyHierarchicalMemoryMutationAllowed("revoke-share");
793
812
  const record = _v2Shares.find((s) => s.id === shareId);
794
813
  if (!record) throw new Error(`Share not found: ${shareId}`);
795
814
  if (record.revokedAt) throw new Error(`Share already revoked`);
@@ -896,6 +915,7 @@ export function searchSemanticV2(db, options = {}) {
896
915
  * Delegates to existing consolidateMemory() for promotion logic.
897
916
  */
898
917
  export function consolidateV2(db, options = {}) {
918
+ assertLegacyHierarchicalMemoryMutationAllowed("consolidate-v2");
899
919
  const id = `consol-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
900
920
  const record = {
901
921
  id,
@@ -949,6 +969,7 @@ export function listConsolidations(options = {}) {
949
969
  * Prune with per-layer scope + custom threshold.
950
970
  */
951
971
  export function pruneV2(db, options = {}) {
972
+ assertLegacyHierarchicalMemoryMutationAllowed("prune-v2");
952
973
  const { layer, maxAge = 720, threshold } = options;
953
974
  if (layer && !_LAYER_VALUES.has(layer))
954
975
  throw new Error(`Invalid layer: ${layer}`);
@@ -1000,6 +1021,7 @@ export function startConsolidationTimer({
1000
1021
  db,
1001
1022
  onTick,
1002
1023
  } = {}) {
1024
+ assertLegacyHierarchicalMemoryMutationAllowed("start-consolidation-timer");
1003
1025
  if (_consolidationTimer) return _consolidationTimer;
1004
1026
  if (!db) throw new Error("db is required for consolidation timer");
1005
1027
  _consolidationTimer = setInterval(() => {
@@ -0,0 +1,170 @@
1
+ import crypto from "node:crypto";
2
+ import path from "node:path";
3
+ import { getHomeDir } from "./paths.js";
4
+ import {
5
+ mutateSecurityStore,
6
+ readSecurityStore,
7
+ } from "./durable-security-store.js";
8
+ import { stableStringify } from "./hook-runtime-contract.js";
9
+
10
+ export const HOOK_AUDIT_STORE_SCHEMA =
11
+ "chainlesschain.hook-runtime-audit-store/v1";
12
+ export const HOOK_AUDIT_RECORD_SCHEMA = "chainlesschain.hook-runtime-audit/v1";
13
+ export const DEFAULT_MAX_HOOK_AUDIT_RECORDS = 10000;
14
+
15
+ function sha256(label, value) {
16
+ return crypto
17
+ .createHash("sha256")
18
+ .update(`${label}\0`, "utf8")
19
+ .update(String(value), "utf8")
20
+ .digest("hex");
21
+ }
22
+
23
+ function safeToken(value, max = 256) {
24
+ if (value == null) return null;
25
+ const text = String(value);
26
+ return text.length <= max ? text : text.slice(0, max);
27
+ }
28
+
29
+ function digestToken(value) {
30
+ if (value == null || value === "") return null;
31
+ const text = String(value);
32
+ return /^[a-f0-9]{64}$/iu.test(text)
33
+ ? text.toLowerCase()
34
+ : sha256("chainlesschain.hook-audit-token.v1", text);
35
+ }
36
+
37
+ function normalizeRecord(record = {}) {
38
+ return {
39
+ schema: HOOK_AUDIT_RECORD_SCHEMA,
40
+ timestamp: safeToken(record.timestamp || new Date().toISOString(), 64),
41
+ phase: safeToken(record.phase, 32),
42
+ event: safeToken(record.event, 96),
43
+ eventId: digestToken(record.eventId),
44
+ executionId: digestToken(record.executionId),
45
+ hookId: digestToken(record.hookId),
46
+ hookDigest: digestToken(record.hookDigest),
47
+ sourceKind: safeToken(record.sourceKind, 32),
48
+ sourceDigest: digestToken(record.sourceDigest),
49
+ trustStatus: safeToken(record.trustStatus, 64),
50
+ priority: Number.isFinite(Number(record.priority))
51
+ ? Number(record.priority)
52
+ : null,
53
+ executionMode: safeToken(record.executionMode, 32),
54
+ status: safeToken(record.status, 32),
55
+ decision: safeToken(record.decision, 32),
56
+ durationMs: Number.isFinite(Number(record.durationMs))
57
+ ? Math.max(0, Math.floor(Number(record.durationMs)))
58
+ : null,
59
+ errorCode: safeToken(record.errorCode, 96),
60
+ };
61
+ }
62
+
63
+ function hashRecord(prevHash, record) {
64
+ return sha256(
65
+ "chainlesschain.hook-audit-chain.v1",
66
+ `${prevHash || "genesis"}\n${stableStringify(record)}`,
67
+ );
68
+ }
69
+
70
+ function validateStore(store) {
71
+ if (Object.keys(store).length === 0) {
72
+ return {
73
+ schema: HOOK_AUDIT_STORE_SCHEMA,
74
+ anchorHash: null,
75
+ headHash: null,
76
+ records: [],
77
+ };
78
+ }
79
+ if (
80
+ store.schema !== HOOK_AUDIT_STORE_SCHEMA ||
81
+ !Array.isArray(store.records) ||
82
+ (store.anchorHash != null && typeof store.anchorHash !== "string") ||
83
+ (store.headHash != null && typeof store.headHash !== "string")
84
+ ) {
85
+ const error = new Error("Hook audit store has an invalid schema");
86
+ error.code = "CC_HOOK_AUDIT_STORE_INVALID";
87
+ throw error;
88
+ }
89
+ return store;
90
+ }
91
+
92
+ export class HookAuditStore {
93
+ constructor({ filePath, maxRecords, now } = {}) {
94
+ this.filePath =
95
+ filePath ||
96
+ process.env.CC_HOOK_AUDIT_FILE ||
97
+ path.join(getHomeDir(), "audit", "hook-runtime-v1.json");
98
+ this.maxRecords = Math.max(
99
+ 100,
100
+ Math.min(100000, Number(maxRecords) || DEFAULT_MAX_HOOK_AUDIT_RECORDS),
101
+ );
102
+ this.now = typeof now === "function" ? now : () => new Date().toISOString();
103
+ }
104
+
105
+ append(record) {
106
+ const normalized = normalizeRecord({
107
+ ...record,
108
+ timestamp: record?.timestamp || this.now(),
109
+ });
110
+ return mutateSecurityStore(this.filePath, "Hook runtime audit", (draft) => {
111
+ const store = validateStore(draft);
112
+ if (Object.keys(draft).length === 0) Object.assign(draft, store);
113
+ const prevHash = draft.headHash || draft.anchorHash || null;
114
+ const hash = hashRecord(prevHash, normalized);
115
+ draft.records.push({ record: normalized, prevHash, hash });
116
+ draft.headHash = hash;
117
+ if (draft.records.length > this.maxRecords) {
118
+ const removeCount = draft.records.length - this.maxRecords;
119
+ const removed = draft.records.splice(0, removeCount);
120
+ draft.anchorHash =
121
+ removed[removed.length - 1]?.hash || draft.anchorHash;
122
+ }
123
+ return Object.freeze({ ...normalized, prevHash, hash });
124
+ });
125
+ }
126
+
127
+ list({ limit = 100 } = {}) {
128
+ const store = validateStore(
129
+ readSecurityStore(this.filePath, "Hook runtime audit"),
130
+ );
131
+ return store.records.slice(-Math.max(0, Number(limit) || 0));
132
+ }
133
+
134
+ verify() {
135
+ const store = validateStore(
136
+ readSecurityStore(this.filePath, "Hook runtime audit"),
137
+ );
138
+ let prev = store.anchorHash || null;
139
+ for (let index = 0; index < store.records.length; index += 1) {
140
+ const entry = store.records[index];
141
+ if (!entry || entry.prevHash !== prev) {
142
+ return { ok: false, length: store.records.length, brokenAt: index };
143
+ }
144
+ const expected = hashRecord(prev, entry.record);
145
+ if (entry.hash !== expected) {
146
+ return { ok: false, length: store.records.length, brokenAt: index };
147
+ }
148
+ prev = entry.hash;
149
+ }
150
+ return {
151
+ ok: prev === (store.headHash || store.anchorHash || null),
152
+ length: store.records.length,
153
+ brokenAt:
154
+ prev === (store.headHash || store.anchorHash || null)
155
+ ? -1
156
+ : store.records.length,
157
+ headHash: store.headHash || null,
158
+ };
159
+ }
160
+ }
161
+
162
+ let defaultStore;
163
+ export function getDefaultHookAuditStore() {
164
+ if (!defaultStore) defaultStore = new HookAuditStore();
165
+ return defaultStore;
166
+ }
167
+
168
+ export function _resetDefaultHookAuditStore() {
169
+ defaultStore = undefined;
170
+ }
Binary file
@@ -6,19 +6,14 @@
6
6
  import crypto from "crypto";
7
7
  import broker from "./process-execution-broker/index.js";
8
8
  import hookEnvironment from "./hook-environment.cjs";
9
+ import { HOOK_EVENT_TYPES, HOOK_PRIORITY } from "./hook-runtime-contract.js";
9
10
 
10
11
  const { buildManagedHookEnvironment } = hookEnvironment;
11
12
 
12
13
  /**
13
14
  * Hook priority levels — lower values run first.
14
15
  */
15
- export const HookPriority = {
16
- SYSTEM: 0,
17
- HIGH: 100,
18
- NORMAL: 500,
19
- LOW: 900,
20
- MONITOR: 1000,
21
- };
16
+ export const HookPriority = HOOK_PRIORITY;
22
17
 
23
18
  /**
24
19
  * Hook execution types.
@@ -33,47 +28,7 @@ export const HookType = {
33
28
  /**
34
29
  * All supported hook event names.
35
30
  */
36
- export const HookEvents = {
37
- Setup: "Setup",
38
- PreIPCCall: "PreIPCCall",
39
- PostIPCCall: "PostIPCCall",
40
- IPCError: "IPCError",
41
- PreToolUse: "PreToolUse",
42
- PostToolUse: "PostToolUse",
43
- ToolError: "ToolError",
44
- SessionStart: "SessionStart",
45
- SessionEnd: "SessionEnd",
46
- PreCompact: "PreCompact",
47
- PostCompact: "PostCompact",
48
- Notification: "Notification",
49
- UserPromptSubmit: "UserPromptSubmit",
50
- AssistantResponse: "AssistantResponse",
51
- AgentStart: "AgentStart",
52
- AgentStop: "AgentStop",
53
- TaskAssigned: "TaskAssigned",
54
- TaskCompleted: "TaskCompleted",
55
- PreFileAccess: "PreFileAccess",
56
- PostFileAccess: "PostFileAccess",
57
- FileModified: "FileModified",
58
- MemorySave: "MemorySave",
59
- MemoryLoad: "MemoryLoad",
60
- AuditLog: "AuditLog",
61
- ComplianceCheck: "ComplianceCheck",
62
- DataSubjectRequest: "DataSubjectRequest",
63
- PreGitCommit: "PreGitCommit",
64
- PostGitCommit: "PostGitCommit",
65
- PreGitPush: "PreGitPush",
66
- CIFailure: "CIFailure",
67
- IterationWarning: "IterationWarning",
68
- IterationBudgetExhausted: "IterationBudgetExhausted",
69
- /**
70
- * Stop: Fired at the END of every agent turn/loop iteration, BEFORE waiting
71
- * for the next user input. Aligns with Claude Code hook spec.
72
- * Fires regardless of outcome (success, error, max-iterations, stop).
73
- * Does NOT fire on final process exit (use SessionEnd/Shutdown for that).
74
- */
75
- Stop: "Stop",
76
- };
31
+ export const HookEvents = HOOK_EVENT_TYPES;
77
32
 
78
33
  /**
79
34
  * Ensure hooks table exists in the database.
@@ -290,8 +245,7 @@ export async function executeHook(hook, context = {}) {
290
245
  }
291
246
  const env = buildManagedHookEnvironment({
292
247
  managedAllowlist: hook.managedEnvironmentAllowlist,
293
- requestedAllowlist:
294
- hook.environmentAllowlist || hook.envAllowlist,
248
+ requestedAllowlist: hook.environmentAllowlist || hook.envAllowlist,
295
249
  values: {
296
250
  HOOK_EVENT: hook.event,
297
251
  HOOK_CONTEXT: JSON.stringify(context),
@@ -364,39 +318,27 @@ export async function executeHook(hook, context = {}) {
364
318
  * Returns array of { hookId, hookName, success, result, error, executionTime }.
365
319
  */
366
320
  export async function executeHooks(db, eventName, context = {}) {
367
- const hooks = listHooks(db, { event: eventName, enabledOnly: true });
368
- const results = [];
369
-
370
- for (const hook of hooks) {
371
- // Check matcher against context
372
- if (hook.matcher) {
373
- const matchFn = compileMatcher(hook.matcher);
374
- const target =
375
- context.target ||
376
- context.channel ||
377
- context.tool ||
378
- context.file ||
379
- eventName;
380
- if (!matchFn(target)) {
381
- continue;
382
- }
383
- }
384
-
385
- const outcome = await executeHook(hook, context);
386
- results.push({
387
- hookId: hook.id,
388
- hookName: hook.name,
389
- ...outcome,
390
- });
391
-
392
- // Update stats
393
- updateHookStats(db, hook.id, {
394
- executionTime: outcome.executionTime,
395
- success: outcome.success,
396
- });
397
- }
398
-
399
- return results;
321
+ // Compatibility API: SQLite rows are definitions only. All scheduling,
322
+ // timeout, trust, decision and audit semantics belong to Hooks v2.
323
+ const { executeHooksV2Event } = await import("./hooks-v2-producers.js");
324
+ const outcome = await executeHooksV2Event(eventName, context, {
325
+ hookDb: db,
326
+ matchTarget:
327
+ context.target ||
328
+ context.channel ||
329
+ context.tool_name ||
330
+ context.tool ||
331
+ context.file ||
332
+ eventName,
333
+ });
334
+ return (outcome.results || []).map((record) => ({
335
+ hookId: record.sourceHookId || record.hookId,
336
+ hookName: record.hookName || record.hookId,
337
+ success: record.status === "success",
338
+ result: record.result?.raw ?? record.result ?? null,
339
+ error: record.error || null,
340
+ executionTime: record.durationMs || 0,
341
+ }));
400
342
  }
401
343
 
402
344
  /**
@@ -0,0 +1,233 @@
1
+ import crypto from "node:crypto";
2
+ import settingsHookLoader from "./settings-hooks.cjs";
3
+ import {
4
+ HOOK_EXECUTION_MODE,
5
+ HOOK_PRIORITY,
6
+ normalizeHookPriority,
7
+ normalizeHookTimeoutMs,
8
+ stableStringify,
9
+ } from "./hook-runtime-contract.js";
10
+ import { computeHookDefinitionDigest } from "./hook-trust.js";
11
+
12
+ const { collectHooks, compileMatcher } = settingsHookLoader;
13
+
14
+ function adapterId(prefix, value) {
15
+ return `${prefix}:${crypto
16
+ .createHash("sha256")
17
+ .update(stableStringify(value), "utf8")
18
+ .digest("hex")}`;
19
+ }
20
+
21
+ function settingsAuthority(authoritySource = {}) {
22
+ const scope =
23
+ authoritySource.scope ||
24
+ (authoritySource.kind === "plugin"
25
+ ? "plugin"
26
+ : authoritySource.sourceFile
27
+ ? "project"
28
+ : "explicit");
29
+ return Object.freeze({
30
+ kind: authoritySource.kind || "settings",
31
+ sourceFile: authoritySource.sourceFile || null,
32
+ digest: authoritySource.digest || null,
33
+ scope,
34
+ requiresConsent: scope === "project",
35
+ });
36
+ }
37
+
38
+ export function adaptSettingsHookDefinitions(
39
+ settingsHooks,
40
+ event,
41
+ matchTarget = "",
42
+ { cwd = process.cwd(), failureMode = "fail-closed" } = {},
43
+ ) {
44
+ const authorityErrors = settingsHooks?._authorityErrors;
45
+ if (Array.isArray(authorityErrors) && authorityErrors.length > 0) {
46
+ const error = new Error(
47
+ "Settings Hook authority could not be loaded safely",
48
+ );
49
+ error.code = authorityErrors[0]?.code || "CC_HOOK_AUTHORITY_INVALID";
50
+ error.authorityErrors = authorityErrors;
51
+ throw error;
52
+ }
53
+ return collectHooks(settingsHooks, event, matchTarget).map((hook, index) => {
54
+ const authority = settingsAuthority(hook.authoritySource);
55
+ const identity = {
56
+ event,
57
+ command: hook.command,
58
+ shell: hook.shell ?? true,
59
+ authority,
60
+ index,
61
+ };
62
+ const definition = {
63
+ id: adapterId("settings", identity),
64
+ event,
65
+ type: "command",
66
+ command: hook.command,
67
+ shell: hook.shell == null ? true : hook.shell,
68
+ cwd,
69
+ priority: normalizeHookPriority(hook.priority, HOOK_PRIORITY.NORMAL),
70
+ timeoutMs: normalizeHookTimeoutMs(
71
+ hook.timeout == null ? undefined : Number(hook.timeout) * 1000,
72
+ ),
73
+ executionMode:
74
+ hook.async === true
75
+ ? HOOK_EXECUTION_MODE.ASYNC
76
+ : HOOK_EXECUTION_MODE.BLOCKING,
77
+ asyncRewake: hook.asyncRewake === true,
78
+ legacyPayload: true,
79
+ legacyAdapter: true,
80
+ legacyHook: hook,
81
+ origin: hook.origin || "settings",
82
+ authority,
83
+ environmentAllowlist:
84
+ hook.environmentAllowlist || hook.envAllowlist || undefined,
85
+ sandboxPolicy: hook.sandboxPolicy,
86
+ requiredBoundaries: hook.requiredBoundaries,
87
+ pluginId: hook.pluginId || null,
88
+ pluginVersion: hook.pluginVersion || null,
89
+ pluginSource: hook.pluginSource || null,
90
+ failureMode: failureMode === "ignore" ? "ignore" : "fail-closed",
91
+ };
92
+ definition.definitionDigest = computeHookDefinitionDigest(definition);
93
+ return Object.freeze(definition);
94
+ });
95
+ }
96
+
97
+ function databaseMatchTarget(context, event) {
98
+ return (
99
+ context.target ||
100
+ context.channel ||
101
+ context.tool_name ||
102
+ context.tool ||
103
+ context.file ||
104
+ event
105
+ );
106
+ }
107
+
108
+ export function readDatabaseHookRows(db, event) {
109
+ if (!db || typeof db.prepare !== "function") return [];
110
+ return db
111
+ .prepare(
112
+ "SELECT * FROM hooks WHERE event = ? AND enabled = 1 ORDER BY priority ASC, id ASC",
113
+ )
114
+ .all(event);
115
+ }
116
+
117
+ function databaseReadFailureDefinition(event) {
118
+ const authority = Object.freeze({
119
+ kind: "database",
120
+ scope: "explicit",
121
+ subject: "database:hook-observer",
122
+ requiresConsent: false,
123
+ });
124
+ const definition = {
125
+ id: `database:adapter-read-failure:${event}`,
126
+ event,
127
+ type: "js",
128
+ handler() {
129
+ const error = new Error(
130
+ "Database Hook observer source could not be read",
131
+ );
132
+ error.code = "CC_HOOK_DATABASE_READ_FAILED";
133
+ throw error;
134
+ },
135
+ priority: HOOK_PRIORITY.NORMAL,
136
+ timeoutMs: normalizeHookTimeoutMs(),
137
+ executionMode: HOOK_EXECUTION_MODE.BLOCKING,
138
+ origin: "database",
139
+ authority,
140
+ failureMode: "ignore",
141
+ observeOnly: true,
142
+ databaseHookName: "database-hook-observer",
143
+ };
144
+ definition.definitionDigest = computeHookDefinitionDigest(definition);
145
+ return Object.freeze(definition);
146
+ }
147
+
148
+ export function adaptDatabaseHookDefinitions(db, event, context = {}) {
149
+ const target = databaseMatchTarget(context, event);
150
+ const definitions = [];
151
+ let rows;
152
+ try {
153
+ rows = readDatabaseHookRows(db, event);
154
+ } catch {
155
+ // Database hooks are a legacy, observe-only source. A missing table or an
156
+ // unavailable optional database must remain visible in the canonical
157
+ // audit/event stream, but it cannot acquire decision authority merely by
158
+ // failing to load.
159
+ return [databaseReadFailureDefinition(event)];
160
+ }
161
+ for (const row of rows) {
162
+ if (row.matcher && !compileMatcher(row.matcher)(target)) continue;
163
+ const commandBacked = new Set(["command", "script"]).has(row.type);
164
+ const authority = Object.freeze({
165
+ kind: "database",
166
+ scope: "explicit",
167
+ subject: `database:${row.id}`,
168
+ requiresConsent: false,
169
+ });
170
+ const definition = {
171
+ id: `database:${row.id}`,
172
+ event,
173
+ type: commandBacked ? "command" : "js",
174
+ ...(commandBacked
175
+ ? { command: row.handler || "", shell: true }
176
+ : { handler: () => null }),
177
+ priority: normalizeHookPriority(row.priority, HOOK_PRIORITY.NORMAL),
178
+ timeoutMs: normalizeHookTimeoutMs(row.timeout),
179
+ executionMode:
180
+ row.type === "async"
181
+ ? HOOK_EXECUTION_MODE.ASYNC
182
+ : HOOK_EXECUTION_MODE.BLOCKING,
183
+ legacyPayload: true,
184
+ legacyAdapter: true,
185
+ origin: "database",
186
+ authority,
187
+ failureMode: "ignore",
188
+ observeOnly: true,
189
+ databaseHookId: row.id,
190
+ databaseHookName: row.name,
191
+ recordResult(record) {
192
+ const success = record?.status === "success";
193
+ const executionTime = Math.max(0, Number(record?.durationMs) || 0);
194
+ const current = db
195
+ .prepare(
196
+ "SELECT execution_count, error_count, total_execution_time FROM hooks WHERE id = ?",
197
+ )
198
+ .get(row.id);
199
+ if (!current) return;
200
+ db.prepare(
201
+ `UPDATE hooks
202
+ SET execution_count = ?,
203
+ error_count = ?,
204
+ total_execution_time = ?,
205
+ updated_at = datetime('now')
206
+ WHERE id = ?`,
207
+ ).run(
208
+ (current.execution_count || 0) + 1,
209
+ (current.error_count || 0) + (success ? 0 : 1),
210
+ (current.total_execution_time || 0) + executionTime,
211
+ row.id,
212
+ );
213
+ },
214
+ };
215
+ definition.definitionDigest = computeHookDefinitionDigest(definition);
216
+ definitions.push(Object.freeze(definition));
217
+ }
218
+ return definitions;
219
+ }
220
+
221
+ export function collectCanonicalAdapterHooks(
222
+ event,
223
+ context,
224
+ { settingsHooks, hookDb, matchTarget, cwd, settingsFailureMode } = {},
225
+ ) {
226
+ return [
227
+ ...adaptSettingsHookDefinitions(settingsHooks, event, matchTarget, {
228
+ cwd,
229
+ failureMode: settingsFailureMode,
230
+ }),
231
+ ...adaptDatabaseHookDefinitions(hookDb, event, context),
232
+ ];
233
+ }