chainlesschain 0.162.171 → 0.162.173

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 (176) hide show
  1. package/bin/chainlesschain.js +8 -0
  2. package/package.json +6 -1
  3. package/src/assets/web-panel/assets/{AIOps-Cf8yb18C.js → AIOps-228_yS1K.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-CsFT6FMt.js → ActionButton-qEKhWWk_.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-DQe_hXMA.js → Analytics-Drma7Pkx.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-Cl9Pp7jk.js → AppLayout-B-gexhEy.js} +4 -4
  7. package/src/assets/web-panel/assets/{Artifacts-CBEzLVjF.js → Artifacts-CWNSO5Af.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-BS2Un14C.js → Audit-DY3j9Ltk.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-DmcDH8OK.js → BackgroundAgents-Bz2pcyfS.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-DvzjTkkn.js → Backup-Bg5aAkWT.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-DnbpuyME.js → BaseInput-35_LrETp.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-BJRRCm2P.js → Chat-CWvrCIuL.js} +5 -5
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-Bgpxyqd_.js → ChatBubbleRenderer-7iAWWEmJ.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-DFOrWmvm.js → Checkbox-B4qv17qH.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-BIQ2kU6Q.js → Codegen-Co18wV4m.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-BI3R-N4I.js → Col-D0RjQKek.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-CPiAwsHT.js → Community-C5r80sMV.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-Bv4cslSK.js → Compact-Cnwsi_GQ.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-CSlDG1NZ.js → Compliance-EFmGHrSw.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-CFcRumXf.js → Cowork-7Ix8iqrx.js} +4 -4
  21. package/src/assets/web-panel/assets/{Cron-DKYKMmOn.js → Cron-Dpvn36K7.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-CxPMByp2.js → Crosschain-DgwE0dXI.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-DJqiYw1C.js → DID-79Xkd_Iy.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-D2dLMxqy.js → Dashboard-BX-kQk9j.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-BnJc384A.js → Dropdown-B2hIzIKh.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-DctFvm-J.js → EmailListRenderer-CwgczLkA.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-J_xg-Qop.js → FamilyGuardDashboard-D1dpW73p.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-BckL07Uw.js → Federation-CzGSfm-g.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-B8s5ccSO.js → FormItemContext-Bdgq6Ctr.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-hPMBK2No.js → GenericCardRenderer-BdiR-AVP.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-CfMpYLo7.js → Git-CyFl_ZOb.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-Bt3OcrC7.js → Governance-CIJfns5M.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-BlKc336N.js → Inference-U2SL3a9n.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-B6p7og2c.js → KnowledgeGraph-B8TRMic6.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-uv5Re6YR.js → Logs-CN3aA59h.js} +2 -2
  36. package/src/assets/web-panel/assets/{MarkdownRenderer-CId5JWjX.js → MarkdownRenderer-Op_hHJCw.js} +1 -1
  37. package/src/assets/web-panel/assets/{Marketplace-CfNbntHt.js → Marketplace-CIu4bo4n.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-YRXt74Yk.js → McpTools-dMtEtLGH.js} +5 -5
  39. package/src/assets/web-panel/assets/{Memory-BfQQs-Jd.js → Memory-B2a1qG3t.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-BuGC-4S2.js → MobileBridge-Ci8N7KT8.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-Czieqw1m.js → MobileProjects-CnJwGBSZ.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-DHWHOVCO.js → Mtc-B_yNoA93.js} +5 -5
  43. package/src/assets/web-panel/assets/{MtcAudit-DWSEbMW-.js → MtcAudit-DLYUJLFa.js} +2 -2
  44. package/src/assets/web-panel/assets/{Multisig-DrhEv1vq.js → Multisig-lGvE7Ulk.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-D8wKCu7E.js → NLProgramming-CSl7-p0U.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-AFeqq0I_.js → Notes-CRzhFyCr.js} +4 -4
  47. package/src/assets/web-panel/assets/{NotificationSettings-D6qenYUo.js → NotificationSettings-D8vIFpxx.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-CF0X4fyB.js → OrderTableRenderer-BK07A_0l.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-DdfbNqf6.js → Organization-5CnL1jaB.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-BFEvnLfd.js → Overflow-B4QvQ7ku.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-DtL6wbkz.js → P2P-IwrXGm2f.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-CQPriTud.js → PdhVaultBrowser-CNr6Ocb1.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-Bj25ANmR.js → Permissions-CcKqZlw6.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-BNj2Oux0.js → PersonalDataHub-zUZb-JzZ.js} +3 -3
  55. package/src/assets/web-panel/assets/{Pipeline-Dyj8UEaG.js → Pipeline-mMelf_X6.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-BBUrWRFz.js → Privacy-BaA6CMRz.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-BdX7uQn6.js → ProjectInit-CI8OJYpf.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-BghtW1zr.js → ProjectSettings-C6ZJ3hQv.js} +2 -2
  59. package/src/assets/web-panel/assets/{Projects-9VTquZCz.js → Projects-BVljPeGz.js} +1 -1
  60. package/src/assets/web-panel/assets/{Providers-D-0K_Eza.js → Providers-D_bjZHj6.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-DDaN30_D.js → QrScannerModal-TgVSKKTP.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-DfHlifOj.js → QuickAsk-CnnleZmK.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-CgLIvYE2.js → Recommend-zqJL4tgH.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-DpOPrwE4.js → RemoteSession-bBFpdwjH.js} +2 -2
  65. package/src/assets/web-panel/assets/{Reputation-wMexlbCE.js → Reputation-tKkKrza-.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-D9aD_nrc.js → Row-DgQaPsSR.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-Drg7l6zu.js → RssFeed-B3PJQQ_a.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-BKO1nrwN.js → Search-BX2HUESa.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-G3Kyk-TG.js → Security-aqzxU6JQ.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-xJReTOna.js → Services-BiehYAcJ.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-ldVDVTPG.js → Skeleton-aWL9v64n.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-emwNYV0j.js → Skills-DnLhre12.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-CZYwGp1K.js → Sla-C2ZJiegm.js} +1 -1
  74. package/src/assets/web-panel/assets/SpeechSettings-BpQdJ1IM.js +1 -0
  75. package/src/assets/web-panel/assets/{SyncSettings-Dcs5Hhj6.js → SyncSettings-C93cxqz8.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-CerFAo26.js → Tasks-oSM3jeQI.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-BdZUbOg3.js → Templates-DJa_a4iY.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-B4c_7Bsw.js → Tenant-B7p9ktEF.js} +1 -1
  79. package/src/assets/web-panel/assets/Terminal-aljUKGFD.js +3 -0
  80. package/src/assets/web-panel/assets/{TimelineRenderer-tc6sp0TV.js → TimelineRenderer-CDcFH-4e.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-Bw_vkMJq.js → Tokens-KISm6N5n.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-DkbJnpvz.js → Trigger-BBYrtPba.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-CIf9kqN1.js → Trust-BMuSnufM.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-Cjwllnea.js → UkeySign-BqZbe27i.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-kgfkY7AN.js → VideoEditing-C-21zOQc.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-CYWXt4u9.js → Wallet-EwfAuGhE.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-QgPwyWCO.js → WebAuthn-D__2NkcW.js} +5 -5
  88. package/src/assets/web-panel/assets/{WorkflowEditor-Co0lha18.js → WorkflowEditor-C7pTi9eg.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-CI__Ox-r.js → chat-DGJsLa46.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-Csv0eYYd.js → colors-DLGee_hV.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-e53UCdHy.js → compact-item-uXOmbkDm.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-BMPGRDhV.js → createContext-CsPfwwcp.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-CVrl2cXX.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-Dz68qIAq.js → hasIn-BHvO8oYD.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-CoGSbW5J.js → index-477LYji2.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-53ljQo_x.js → index-9F6z582g.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-ajz0E0pK.js → index-B2NtdqkO.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-ygfUVVFv.js → index-B5XTuu1V.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-wcCouSNq.js → index-BDV08Lfd.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-t6f80uqL.js → index-BOXMd0h7.js} +17 -17
  101. package/src/assets/web-panel/assets/index-BPY_5R3R.js +1 -0
  102. package/src/assets/web-panel/assets/{index-BHkDRNA5.js → index-BZa2DYkz.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DCl4Xb4N.js → index-Bb8I5bJW.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BW2dImbg.js → index-By5mviLz.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-Dk9Gi8xd.js → index-C0mLGe0N.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CXuON9OG.js → index-C0w_0UmL.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-B1s1B8Iy.js → index-CN3eksmo.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DJqQL6so.js → index-CNCYZBCQ.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BT3CV4Nh.js → index-Cc_spyrU.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-CNtZMPKV.js → index-CeJ_IuUy.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-C-NbcAbP.js → index-Ckb7veFD.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-K5E_wjut.js → index-ClWReh9U.js} +1 -1
  113. package/src/assets/web-panel/assets/index-CrRvYSFJ.js +1 -0
  114. package/src/assets/web-panel/assets/{index-5iicv5af.js → index-D3UkkZps.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CrsoSnQF.js → index-D73CnO2G.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-HbhQRrM2.js → index-D7EKxUXQ.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DyqcHiL1.js → index-DA8wNocR.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-Dtjm1K1a.js → index-DEOm1Go8.js} +1 -1
  119. package/src/assets/web-panel/assets/{index--7tHEadk.js → index-DHMZKkRS.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-DnXm3Qsh.js → index-DJBB-U5Z.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DVCd2aMX.js → index-DJkVI1UW.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CpTzqJ0Z.js → index-DbkMc0Qq.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DctYrVMq.js → index-DjX8mK9d.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-_LmPlyeV.js → index-DmcFSHuA.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-CvLBQk_M.js → index-DqNI4xlm.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-C53o-MdJ.js → index-DvQrYrw_.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BOpz2qS1.js → index-Gqs5qts7.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-N9DkR1i7.js → index-MAaNHDU0.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-CYUxs6J1.js → index-YslvEzZs.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-D0bg74e1.js → index-gTQZVYbs.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-C5hLtxVz.js → index-hzI1TGEs.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-B4lKPJy1.js → index-vWJiZGAS.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-CyLUaP2i.js → index-wnZd4y25.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-DVCeQJrT.js → initDefaultProps-oK6Ac1vm.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-chBCR_8v.js → motion-BmETDqwI.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-BziPlrh6.js → move-0DfUhr7q.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-Cenk0OD7.js → mtc-parser-BDG-x4aO.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-D-AiRsei.js → omit-C_n1NOjZ.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-CHw3Fvqt.js → pickAttrs-j5w-2Trf.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-g8I-rCad.js → placementArrow-DDVTNAah.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-BWffAr9k.js → responsiveObserve-DM30qzcv.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-BmUQqhkb.js → slide-BcVzNlnc.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-B89gCO-y.js → statusUtils-VQh4j7zt.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-x1bnCF73.js → styleChecker-DcHl95y_.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-B-k1_Ggw.js → useFlexGapSupport-C5bRw-Km.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-Bc3PUqQk.js → useFs-IcE9exrQ.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-D8qFDX1I.js → usePersonalDataHub-BGv3NgE4.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-UaL5-WGg.js → vnode-B9pXxNhd.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-Dv7bsbLs.js → zoom-Bba0fIkh.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/commands/permissions.js +24 -1
  152. package/src/index.js +63 -845
  153. package/src/lib/agent-ipc-bus.js +331 -0
  154. package/src/lib/context-source-ledger.js +164 -0
  155. package/src/lib/execution-trace/index.js +10 -0
  156. package/src/lib/execution-trace/metrics-collector.js +218 -0
  157. package/src/lib/execution-trace/trace-context.js +182 -0
  158. package/src/lib/hook-manager.js +17 -0
  159. package/src/lib/hooks-v2-runtime.js +278 -0
  160. package/src/lib/metrics-collector.js +127 -0
  161. package/src/lib/observability/index.js +35 -0
  162. package/src/lib/observability/otlp-exporter.js +260 -0
  163. package/src/lib/otlp-exporter.js +45 -0
  164. package/src/lib/process-execution-broker/SPAWN_AUDIT_REPORT.md +117 -0
  165. package/src/lib/process-execution-broker/index.js +450 -0
  166. package/src/lib/process-execution-broker/patch-child-process.js +50 -0
  167. package/src/lib/process-execution-broker/spawn-audit.json +3814 -0
  168. package/src/lib/runtime-provenance-ledger.js +190 -0
  169. package/src/lib/session-hooks.js +41 -0
  170. package/src/program-base.js +4 -1
  171. package/src/repl/agent-repl.js +2 -0
  172. package/src/assets/web-panel/assets/SpeechSettings-CyaPrzOF.js +0 -1
  173. package/src/assets/web-panel/assets/Terminal-VVFLS3Ol.js +0 -3
  174. package/src/assets/web-panel/assets/devWarning-BIulobq7.js +0 -1
  175. package/src/assets/web-panel/assets/index-BGkiYnET.js +0 -1
  176. package/src/assets/web-panel/assets/index-Eyhrr_3u.js +0 -1
@@ -0,0 +1,218 @@
1
+ /**
2
+ * MetricsCollector - M3 轻量级指标收集器
3
+ *
4
+ * 收集CLI运行时的性能指标:
5
+ * - 执行计数器
6
+ * - 延迟直方图
7
+ * - 标签化指标
8
+ * - 自动与traceId关联
9
+ */
10
+
11
+ import { AsyncLocalStorage } from "node:async_hooks";
12
+ import { createHash, randomBytes } from "node:crypto";
13
+ import { traceContext } from "./trace-context.js";
14
+
15
+ class MetricsCollector {
16
+ constructor() {
17
+ this._counters = new Map();
18
+ this._histograms = new Map();
19
+ this._gauges = new Map();
20
+ this._flushedAt = Date.now();
21
+ }
22
+
23
+ /**
24
+ * Increment a counter metric
25
+ * @param {string} name - Metric name
26
+ * @param {number} value - Value to increment by (default: 1)
27
+ * @param {Object} labels - Key-value labels
28
+ */
29
+ increment(name, value = 1, labels = {}) {
30
+ const key = this._metricKey(name, labels);
31
+ const current = this._counters.get(key) || 0;
32
+ this._counters.set(key, current + value);
33
+ }
34
+
35
+ /**
36
+ * Record a value in a histogram (latency, sizes, etc.)
37
+ * @param {string} name - Metric name
38
+ * @param {number} value - Value to record
39
+ * @param {Object} labels - Key-value labels
40
+ */
41
+ observe(name, value, labels = {}) {
42
+ const key = this._metricKey(name, labels);
43
+ const data = this._histograms.get(key) || {
44
+ count: 0,
45
+ sum: 0,
46
+ min: Infinity,
47
+ max: -Infinity,
48
+ values: [],
49
+ };
50
+ data.count += 1;
51
+ data.sum += value;
52
+ data.min = Math.min(data.min, value);
53
+ data.max = Math.max(data.max, value);
54
+ // Keep last 1000 values for percentile calculation
55
+ if (data.values.length > 1000) {
56
+ data.values.shift();
57
+ }
58
+ data.values.push(value);
59
+ this._histograms.set(key, data);
60
+ }
61
+
62
+ /**
63
+ * Set a gauge value
64
+ * @param {string} name - Metric name
65
+ * @param {number} value - Gauge value
66
+ * @param {Object} labels - Key-value labels
67
+ */
68
+ setGauge(name, value, labels = {}) {
69
+ const key = this._metricKey(name, labels);
70
+ this._gauges.set(key, value);
71
+ }
72
+
73
+ /**
74
+ * Time an async function and record latency
75
+ * @param {string} name - Metric name
76
+ * @param {Function} fn - Async function to time
77
+ * @param {Object} labels - Key-value labels
78
+ * @returns {Promise<*>} Function result
79
+ */
80
+ async time(name, fn, labels = {}) {
81
+ const start = performance.now();
82
+ try {
83
+ const result = await fn();
84
+ this.observe(name, performance.now() - start, {
85
+ ...labels,
86
+ status: "success",
87
+ });
88
+ this.increment(`${name}_total`, 1, { ...labels, status: "success" });
89
+ return result;
90
+ } catch (err) {
91
+ this.observe(name, performance.now() - start, {
92
+ ...labels,
93
+ status: "error",
94
+ });
95
+ this.increment(`${name}_total`, 1, {
96
+ ...labels,
97
+ status: "error",
98
+ errorType: err.name,
99
+ });
100
+ throw err;
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Get all collected metrics as OTLP-compatible format
106
+ * @returns {Object} OTLP metrics data
107
+ */
108
+ collect() {
109
+ const metrics = [];
110
+
111
+ // Convert counters
112
+ for (const [key, value] of this._counters) {
113
+ const { name, labels } = this._parseKey(key);
114
+ metrics.push({
115
+ name,
116
+ type: "counter",
117
+ value,
118
+ labels,
119
+ timestamp: Date.now(),
120
+ });
121
+ }
122
+
123
+ // Convert histograms
124
+ for (const [key, data] of this._histograms) {
125
+ const { name, labels } = this._parseKey(key);
126
+ data.values.sort((a, b) => a - b);
127
+ const p50 = data.values[Math.floor(data.values.length * 0.5)];
128
+ const p95 = data.values[Math.floor(data.values.length * 0.95)];
129
+ const p99 = data.values[Math.floor(data.values.length * 0.99)];
130
+ metrics.push({
131
+ name,
132
+ type: "histogram",
133
+ count: data.count,
134
+ sum: data.sum,
135
+ min: data.min,
136
+ max: data.max,
137
+ avg: data.sum / data.count,
138
+ p50,
139
+ p95,
140
+ p99,
141
+ labels,
142
+ timestamp: Date.now(),
143
+ });
144
+ }
145
+
146
+ // Convert gauges
147
+ for (const [key, value] of this._gauges) {
148
+ const { name, labels } = this._parseKey(key);
149
+ metrics.push({
150
+ name,
151
+ type: "gauge",
152
+ value,
153
+ labels,
154
+ timestamp: Date.now(),
155
+ });
156
+ }
157
+
158
+ return {
159
+ resourceMetrics: [
160
+ {
161
+ resource: {
162
+ attributes: [
163
+ {
164
+ key: "service.name",
165
+ value: { stringValue: "chainlesschain-cli" },
166
+ },
167
+ {
168
+ key: "service.version",
169
+ value: { stringValue: "0.10.0-alpha.74" },
170
+ },
171
+ ],
172
+ },
173
+ scopeMetrics: [
174
+ {
175
+ scope: { name: "chainlesschain.cli" },
176
+ metrics,
177
+ },
178
+ ],
179
+ },
180
+ ],
181
+ };
182
+ }
183
+
184
+ /**
185
+ * Reset all metrics
186
+ */
187
+ reset() {
188
+ this._counters.clear();
189
+ this._histograms.clear();
190
+ this._gauges.clear();
191
+ this._flushedAt = Date.now();
192
+ }
193
+
194
+ _metricKey(name, labels) {
195
+ const labelStr = Object.entries(labels)
196
+ .sort(([a], [b]) => a.localeCompare(b))
197
+ .map(([k, v]) => `${k}=${v}`)
198
+ .join(",");
199
+ return labelStr ? `${name}{${labelStr}}` : name;
200
+ }
201
+
202
+ _parseKey(key) {
203
+ const match = key.match(/^([^{]+)(?:\{([^}]+)\})?$/);
204
+ if (!match) return { name: key, labels: {} };
205
+ const [, name, labelStr] = match;
206
+ if (!labelStr) return { name, labels: {} };
207
+ const labels = {};
208
+ for (const pair of labelStr.split(",")) {
209
+ const [k, v] = pair.split("=");
210
+ if (k) labels[k] = v;
211
+ }
212
+ return { name, labels };
213
+ }
214
+ }
215
+
216
+ export { MetricsCollector };
217
+ export const metricsCollector = new MetricsCollector();
218
+ export default metricsCollector;
@@ -0,0 +1,182 @@
1
+ /**
2
+ * TraceContext - W3C Trace Context 兼容的分布式追踪上下文
3
+ *
4
+ * 支持:
5
+ * - traceparent 头格式: {version}-{traceId}-{parentId}-{traceFlags}
6
+ * - tracestate 头传播
7
+ * - AsyncLocalStorage 上下文传播
8
+ * - Span 创建与管理
9
+ * - Baggage 透传
10
+ */
11
+
12
+ import { AsyncLocalStorage } from "node:async_hooks";
13
+ import { randomBytes } from "node:crypto";
14
+
15
+ class TraceContext {
16
+ constructor() {
17
+ this._asyncLocalStorage = new AsyncLocalStorage();
18
+ this._spans = new Map();
19
+ this._listeners = new Set();
20
+ }
21
+
22
+ generateTraceId() {
23
+ return randomBytes(16).toString("hex");
24
+ }
25
+
26
+ generateSpanId() {
27
+ return randomBytes(8).toString("hex");
28
+ }
29
+
30
+ parseTraceparent(traceparent) {
31
+ if (!traceparent) return null;
32
+ const parts = traceparent.split("-");
33
+ if (parts.length !== 4) return null;
34
+ const [version, traceId, parentId, traceFlags] = parts;
35
+ if (
36
+ version.length !== 2 ||
37
+ traceId.length !== 32 ||
38
+ parentId.length !== 16 ||
39
+ traceFlags.length !== 2
40
+ ) {
41
+ return null;
42
+ }
43
+ return { version, traceId, parentId, traceFlags: parseInt(traceFlags, 16) };
44
+ }
45
+
46
+ formatTraceparent(traceId, spanId, traceFlags = 0x01) {
47
+ return `00-${traceId}-${spanId}-${traceFlags.toString(16).padStart(2, "0")}`;
48
+ }
49
+
50
+ getCurrentContext() {
51
+ return this._asyncLocalStorage.getStore();
52
+ }
53
+
54
+ startRootSpan(name, attributes = {}) {
55
+ const traceId = this.generateTraceId();
56
+ const spanId = this.generateSpanId();
57
+ const context = {
58
+ traceId,
59
+ spanId,
60
+ parentSpanId: null,
61
+ name,
62
+ attributes,
63
+ startTime: Date.now(),
64
+ tracestate: "",
65
+ baggage: {},
66
+ };
67
+ this._spans.set(spanId, context);
68
+ this._emit("span:start", context);
69
+ return context;
70
+ }
71
+
72
+ startSpan(name, attributes = {}) {
73
+ const parent = this.getCurrentContext();
74
+ if (!parent) {
75
+ return this.startRootSpan(name, attributes);
76
+ }
77
+ const spanId = this.generateSpanId();
78
+ const context = {
79
+ traceId: parent.traceId,
80
+ spanId,
81
+ parentSpanId: parent.spanId,
82
+ name,
83
+ attributes: { ...attributes },
84
+ startTime: Date.now(),
85
+ tracestate: parent.tracestate || "",
86
+ baggage: { ...(parent.baggage || {}) },
87
+ };
88
+ this._spans.set(spanId, context);
89
+ this._emit("span:start", context);
90
+ return context;
91
+ }
92
+
93
+ endSpan(span, status = { code: "OK" }) {
94
+ if (!span || !this._spans.has(span.spanId)) return;
95
+ span.endTime = Date.now();
96
+ span.duration = span.endTime - span.startTime;
97
+ span.status = status;
98
+ this._emit("span:end", span);
99
+ this._spans.delete(span.spanId);
100
+ }
101
+
102
+ async runInContext(context, fn) {
103
+ return this._asyncLocalStorage.run(context, fn);
104
+ }
105
+
106
+ getPropagationEnv() {
107
+ const ctx = this.getCurrentContext();
108
+ if (!ctx) return {};
109
+ const env = {
110
+ TRACEPARENT: this.formatTraceparent(ctx.traceId, ctx.spanId),
111
+ };
112
+ if (ctx.tracestate) {
113
+ env.TRACESTATE = ctx.tracestate;
114
+ }
115
+ if (ctx.baggage && Object.keys(ctx.baggage).length > 0) {
116
+ env.BAGGAGE = Object.entries(ctx.baggage)
117
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
118
+ .join(",");
119
+ }
120
+ return env;
121
+ }
122
+
123
+ extractFromEnv(env = process.env) {
124
+ const traceparent = env.TRACEPARENT || env.traceparent;
125
+ if (!traceparent) return null;
126
+ const parsed = this.parseTraceparent(traceparent);
127
+ if (!parsed) return null;
128
+ const context = {
129
+ traceId: parsed.traceId,
130
+ spanId: parsed.parentId,
131
+ parentSpanId: null,
132
+ name: "inherited",
133
+ attributes: {},
134
+ startTime: Date.now(),
135
+ tracestate: env.TRACESTATE || env.tracestate || "",
136
+ baggage: this._parseBaggage(env.BAGGAGE || env.baggage),
137
+ };
138
+ return context;
139
+ }
140
+
141
+ on(event, listener) {
142
+ this._listeners.add({ event, listener });
143
+ }
144
+
145
+ off(event, listener) {
146
+ for (const entry of this._listeners) {
147
+ if (entry.event === event && entry.listener === listener) {
148
+ this._listeners.delete(entry);
149
+ break;
150
+ }
151
+ }
152
+ }
153
+
154
+ _emit(event, data) {
155
+ for (const { event: ev, listener } of this._listeners) {
156
+ if (ev === event) {
157
+ try {
158
+ listener(data);
159
+ } catch (e) {
160
+ // Silently ignore listener errors
161
+ }
162
+ }
163
+ }
164
+ }
165
+
166
+ _parseBaggage(baggage) {
167
+ if (!baggage) return {};
168
+ const result = {};
169
+ for (const pair of baggage.split(",")) {
170
+ const eqIdx = pair.indexOf("=");
171
+ if (eqIdx === -1) continue;
172
+ const key = decodeURIComponent(pair.slice(0, eqIdx).trim());
173
+ const value = decodeURIComponent(pair.slice(eqIdx + 1).trim());
174
+ result[key] = value;
175
+ }
176
+ return result;
177
+ }
178
+ }
179
+
180
+ export { TraceContext };
181
+ export const traceContext = new TraceContext();
182
+ export default traceContext;
@@ -5,6 +5,7 @@
5
5
 
6
6
  import crypto from "crypto";
7
7
  import { execSync } from "child_process";
8
+ import broker from "./process-execution-broker/index.js";
8
9
 
9
10
  /**
10
11
  * Hook priority levels — lower values run first.
@@ -62,6 +63,13 @@ export const HookEvents = {
62
63
  CIFailure: "CIFailure",
63
64
  IterationWarning: "IterationWarning",
64
65
  IterationBudgetExhausted: "IterationBudgetExhausted",
66
+ /**
67
+ * Stop: Fired at the END of every agent turn/loop iteration, BEFORE waiting
68
+ * for the next user input. Aligns with Claude Code hook spec.
69
+ * Fires regardless of outcome (success, error, max-iterations, stop).
70
+ * Does NOT fire on final process exit (use SessionEnd/Shutdown for that).
71
+ */
72
+ Stop: "Stop",
65
73
  };
66
74
 
67
75
  /**
@@ -282,6 +290,15 @@ export async function executeHook(hook, context = {}) {
282
290
  HOOK_EVENT: hook.event,
283
291
  HOOK_CONTEXT: JSON.stringify(context),
284
292
  };
293
+ // M1: Record hook command execution in broker audit log
294
+ broker.auditLog.push({
295
+ pid: process.pid,
296
+ origin: "hook",
297
+ command: cmd,
298
+ args: [],
299
+ startedAt: Date.now(),
300
+ sessionId: context?.sessionId,
301
+ });
285
302
  const output = execSync(cmd, {
286
303
  encoding: "utf-8",
287
304
  timeout: hook.timeout || 5000,
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Hooks v2 System — M3-1: 完整18事件schema + 5种executor类型
3
+ * 对应文档 §2.3
4
+ *
5
+ * 支持的18种生命周期事件:
6
+ * Session: PreToolUse, PostToolUse, Notification, Stop, SubagentStop
7
+ * Auth: PreCommit, PostCommit
8
+ * Skill: UserPromptSubmit, SessionStart, SessionEnd
9
+ * Model: PreCompact, ModelSelection
10
+ * Config: ConfigChange, PermissionAllow, PermissionDeny
11
+ * Timeline: TimelineEntry
12
+ * MCP: McpRequest, McpResponse
13
+ *
14
+ * 支持的executor类型:
15
+ * 1. command (shell command, current hooks.json only supports this)
16
+ * 2. http (webhook)
17
+ * 3. prompt (inline prompt template)
18
+ * 4. agent (dispatch to cc agent/skill)
19
+ * 5. js (inline JS function via vm sandbox)
20
+ */
21
+
22
+ import { EventEmitter } from "node:events";
23
+ import crypto from "node:crypto";
24
+ import fs from "node:fs/promises";
25
+ import path from "node:path";
26
+ import broker from "./process-execution-broker/index.js";
27
+
28
+ const VALID_HOOK_EVENTS = new Set([
29
+ // Session
30
+ "PreToolUse", "PostToolUse", "Notification", "Stop", "SubagentStop",
31
+ // Auth
32
+ "PreCommit", "PostCommit",
33
+ // Skill
34
+ "UserPromptSubmit", "SessionStart", "SessionEnd",
35
+ // Model
36
+ "PreCompact", "ModelSelection",
37
+ // Config
38
+ "ConfigChange", "PermissionAllow", "PermissionDeny",
39
+ // Timeline
40
+ "TimelineEntry",
41
+ // MCP
42
+ "McpRequest", "McpResponse",
43
+ ]);
44
+
45
+ const VALID_EXECUTOR_TYPES = new Set(["command", "http", "prompt", "agent", "js"]);
46
+
47
+ class HooksV2Runtime extends EventEmitter {
48
+ constructor(configDir) {
49
+ super();
50
+ this.configDir = configDir;
51
+ this.hooks = new Map(); // eventName -> HookDefinition[]
52
+ this.executionLog = [];
53
+ this._loaded = false;
54
+ }
55
+
56
+ /**
57
+ * @typedef {Object} HookDefinition
58
+ * @property {string} id
59
+ * @property {string} event
60
+ * @property {'command'|'http'|'prompt'|'agent'|'js'} type
61
+ * @property {string} [command] - for type=command
62
+ * @property {string[]} [args]
63
+ * @property {string} [url] - for type=http
64
+ * @property {string} [method] - GET/POST
65
+ * @property {Object} [headers]
66
+ * @property {string} [template] - for type=prompt
67
+ * @property {string} [agentName] - for type=agent
68
+ * @property {string} [skillName] - for type=agent
69
+ * @property {string} [code] - for type=js
70
+ * @property {number} [timeoutMs]
71
+ * @property {boolean} [blocking] - default false
72
+ * @property {string[]} [if] - conditional matchers
73
+ * @property {string} [description]
74
+ */
75
+
76
+ async loadHooks(hooksPath) {
77
+ try {
78
+ const content = await fs.readFile(hooksPath, "utf8");
79
+ const config = JSON.parse(content);
80
+ this.hooks.clear();
81
+
82
+ const hookDefs = Array.isArray(config) ? config : (config.hooks || []);
83
+ for (const def of hookDefs) {
84
+ if (!VALID_HOOK_EVENTS.has(def.event)) {
85
+ process.emitWarning(`[hooks-v2] Unknown event type: ${def.event}, skipping`);
86
+ continue;
87
+ }
88
+ if (!VALID_EXECUTOR_TYPES.has(def.type)) {
89
+ process.emitWarning(`[hooks-v2] Unknown executor type: ${def.type} for ${def.event}, skipping`);
90
+ continue;
91
+ }
92
+ const id = def.id || crypto.randomUUID();
93
+ if (!this.hooks.has(def.event)) this.hooks.set(def.event, []);
94
+ this.hooks.get(def.event).push({ id, ...def });
95
+ }
96
+ this._loaded = true;
97
+ this.emit("loaded", { count: hookDefs.length, events: Array.from(this.hooks.keys()) });
98
+ } catch (e) {
99
+ if (e.code !== "ENOENT") {
100
+ this.emit("load:error", e);
101
+ }
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Register a hook programmatically
107
+ */
108
+ registerHook(def) {
109
+ if (!VALID_HOOK_EVENTS.has(def.event)) throw new Error(`Invalid event: ${def.event}`);
110
+ if (!VALID_EXECUTOR_TYPES.has(def.type)) throw new Error(`Invalid executor type: ${def.type}`);
111
+ const id = def.id || crypto.randomUUID();
112
+ const full = { id, blocking: false, timeoutMs: 30000, ...def };
113
+ if (!this.hooks.has(def.event)) this.hooks.set(def.event, []);
114
+ this.hooks.get(def.event).push(full);
115
+ return id;
116
+ }
117
+
118
+ unregisterHook(id) {
119
+ for (const [event, hooks] of this.hooks.entries()) {
120
+ const idx = hooks.findIndex(h => h.id === id);
121
+ if (idx >= 0) {
122
+ hooks.splice(idx, 1);
123
+ return true;
124
+ }
125
+ }
126
+ return false;
127
+ }
128
+
129
+ /**
130
+ * Fire an event - executes all registered hooks
131
+ * @param {string} eventName
132
+ * @param {Object} context - event context (tool_name, tool_input, session_id, etc.)
133
+ * @returns {Promise<{results: Array, blocked: boolean, blockingResult?: any}>}
134
+ */
135
+ async emitEvent(eventName, context = {}) {
136
+ if (!VALID_HOOK_EVENTS.has(eventName)) {
137
+ throw new Error(`Invalid hook event: ${eventName}`);
138
+ }
139
+
140
+ const hooks = this.hooks.get(eventName) || [];
141
+ const results = [];
142
+ let blocked = false;
143
+ let blockingResult = null;
144
+
145
+ for (const hook of hooks) {
146
+ const execId = crypto.randomUUID();
147
+ const start = Date.now();
148
+ const record = { execId, hookId: hook.id, event: eventName, type: hook.type, startedAt: new Date() };
149
+
150
+ try {
151
+ let result;
152
+ switch (hook.type) {
153
+ case "command":
154
+ result = await this._execCommand(hook, context);
155
+ break;
156
+ case "http":
157
+ result = await this._execHttp(hook, context);
158
+ break;
159
+ case "prompt":
160
+ result = await this._execPrompt(hook, context);
161
+ break;
162
+ case "agent":
163
+ result = await this._execAgent(hook, context);
164
+ break;
165
+ case "js":
166
+ result = await this._execJs(hook, context);
167
+ break;
168
+ }
169
+
170
+ record.durationMs = Date.now() - start;
171
+ record.status = "success";
172
+ record.result = result;
173
+ results.push(record);
174
+
175
+ // Check for blocking decision
176
+ if (hook.blocking && result && result.decision === "block") {
177
+ blocked = true;
178
+ blockingResult = result;
179
+ record.blocked = true;
180
+ }
181
+
182
+ this.emit("hook:success", record);
183
+ } catch (err) {
184
+ record.durationMs = Date.now() - start;
185
+ record.status = "error";
186
+ record.error = err.message;
187
+ results.push(record);
188
+ this.emit("hook:error", record);
189
+ }
190
+
191
+ this.executionLog.push(record);
192
+ }
193
+
194
+ return { results, blocked, blockingResult };
195
+ }
196
+
197
+ async _execCommand(hook, context) {
198
+ const child = await broker.spawn(
199
+ hook.command, hook.args || [],
200
+ {
201
+ env: { ...process.env, CC_HOOK_EVENT: hook.event, CC_HOOK_CONTEXT: JSON.stringify(context) },
202
+ stdio: "pipe",
203
+ timeout: hook.timeoutMs,
204
+ },
205
+ { origin: "hook", hookName: hook.id, timeout: hook.timeoutMs },
206
+ );
207
+ return new Promise((resolve, reject) => {
208
+ let stdout = "", stderr = "";
209
+ child.stdout.on("data", d => stdout += d);
210
+ child.stderr.on("data", d => stderr += d);
211
+ child.on("exit", (code) => {
212
+ if (code === 0) {
213
+ let parsed = {};
214
+ try { parsed = JSON.parse(stdout); } catch { parsed = { raw: stdout }; }
215
+ resolve({ ...parsed, exitCode: code, stderr });
216
+ } else {
217
+ reject(new Error(`Hook command failed with exit ${code}: ${stderr}`));
218
+ }
219
+ });
220
+ });
221
+ }
222
+
223
+ async _execHttp(hook, context) {
224
+ // Simple HTTP webhook executor
225
+ const method = hook.method || "POST";
226
+ const controller = new AbortController();
227
+ const timer = setTimeout(() => controller.abort(), hook.timeoutMs || 30000);
228
+ try {
229
+ const res = await fetch(hook.url, {
230
+ method,
231
+ headers: { "Content-Type": "application/json", ...(hook.headers || {}) },
232
+ body: method !== "GET" ? JSON.stringify({ event: hook.event, context }) : undefined,
233
+ signal: controller.signal,
234
+ });
235
+ clearTimeout(timer);
236
+ return { status: res.status, body: await res.text().catch(() => "") };
237
+ } finally {
238
+ clearTimeout(timer);
239
+ }
240
+ }
241
+
242
+ async _execPrompt(hook, context) {
243
+ // Prompt template execution - returns expanded prompt for agent prepend
244
+ const vars = { ...context };
245
+ let expanded = hook.template || "";
246
+ expanded = expanded.replace(/\$\{(\w+)\}/g, (_, k) => vars[k] ?? "");
247
+ return { decision: "augment", prompt: expanded };
248
+ }
249
+
250
+ async _execAgent(hook, context) {
251
+ // Dispatch to agent/skill - stub for full integration
252
+ return { decision: "delegate", agentName: hook.agentName, skillName: hook.skillName, context };
253
+ }
254
+
255
+ async _execJs(hook, context) {
256
+ // In-process JS execution via vm (sandboxed) - stub for full vm2/isolated-vm integration
257
+ return { decision: "noop", note: "JS executor stub - context received", contextKeys: Object.keys(context) };
258
+ }
259
+
260
+ /** Get all registered hooks */
261
+ getHookRegistry() {
262
+ const registry = {};
263
+ for (const [event, hooks] of this.hooks.entries()) {
264
+ registry[event] = hooks.map(h => ({ id: h.id, type: h.type, description: h.description, blocking: h.blocking }));
265
+ }
266
+ return registry;
267
+ }
268
+
269
+ /** Get recent execution log */
270
+ getExecutionLog(limit = 50) {
271
+ return this.executionLog.slice(-limit);
272
+ }
273
+ }
274
+
275
+ // Singleton instance
276
+ const hooksRuntime = new HooksV2Runtime();
277
+ export default hooksRuntime;
278
+ export { HooksV2Runtime, VALID_HOOK_EVENTS, VALID_EXECUTOR_TYPES };