chainlesschain 0.162.170 → 0.162.172

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 (186) hide show
  1. package/bin/chainlesschain.js +8 -0
  2. package/package.json +6 -1
  3. package/src/assets/web-panel/assets/{AIOps-BTXN24I3.js → AIOps-oKCWU-LK.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-BBB1VF4j.js → ActionButton-4CBfc5E4.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-BVCXq0k6.js → Analytics-BEmR-k_b.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-C3EOo2s5.js → AppLayout-D6a4ZnrC.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-CsJTZSMv.js → Artifacts-BRWIHCPl.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-CP0AllJ_.js → Audit-CzGKlkTc.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-BCAjs08m.js → BackgroundAgents-CmMYN10o.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-BxQI5XH4.js → Backup-CJ6e0ukD.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-Bu-PNzC5.js → BaseInput-BpEvDrNt.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-DjPQynup.js → Chat-wWuwwjKu.js} +4 -4
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CygkRopu.js → ChatBubbleRenderer-CJLyGo_u.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-BxL6xm7Z.js → Checkbox-C6pW60Br.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-CcyB7h_6.js → Codegen-DF-nP22Y.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-8NQiKJJx.js → Col-BuueEwZW.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-B31qy5OS.js → Community-DuE0Yzwr.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-C-5fAsZ4.js → Compact-BrHim8EB.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-BTSccvF0.js → Compliance-DgAet8f_.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-BXctU9IK.js → Cowork-B9wY05lx.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-CxVFX9NG.js → Cron-CvNBxfJX.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-DEF3dq8M.js → Crosschain-BnZRENa0.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-BmKcE9he.js → DID-DiqYLHTI.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-CECBq_wG.js → Dashboard-t3SsRzZL.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-U-iuPB0n.js → Dropdown-BCjMLam9.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-D8BIlSPL.js → EmailListRenderer-D2v9-IHJ.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BzQGfUH-.js → FamilyGuardDashboard-_iQu35qa.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-4_WlOqLZ.js → Federation-Bkty8VqB.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-gtrW-DdF.js → FormItemContext-DdPW81BY.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-BLcvJJB6.js → GenericCardRenderer-DrNYM4Zj.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-Bk0janGD.js → Git-BjF-B2h0.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-CcfyMlV8.js → Governance-DPhGdJ1v.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-CBLrAf4M.js → Inference--PPksOVj.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-ClguhteZ.js → KnowledgeGraph-y5WdV_JV.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-Dp_oeKfJ.js → Logs-B6_x7zba.js} +2 -2
  36. package/src/assets/web-panel/assets/MarkdownRenderer-Bg8zSyF8.js +1 -0
  37. package/src/assets/web-panel/assets/{Marketplace-BHk50smM.js → Marketplace-CHpfMu1A.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-BAY3CV6J.js → McpTools-qqjtX3Cf.js} +5 -5
  39. package/src/assets/web-panel/assets/{Memory-w0pG2AKx.js → Memory-hASSgxbw.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-C0VkDUE3.js → MobileBridge-Dwh7Bhcf.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-BCvQ80I9.js → MobileProjects-D09voh7W.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-DSIl41Tt.js → Mtc-9G1dXeId.js} +5 -5
  43. package/src/assets/web-panel/assets/{MtcAudit-D1mzUlIr.js → MtcAudit-CWtYXj6f.js} +2 -2
  44. package/src/assets/web-panel/assets/{Multisig-CeJz4VSS.js → Multisig-bDI0EnDk.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-_O3aweu8.js → NLProgramming-CTanRaBP.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-Dt7_pO86.js → Notes-BdQENJFv.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-Dhg3Nktv.js → NotificationSettings-JvnQdStO.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-QsAPcTb2.js → OrderTableRenderer-BMGL9RPJ.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-BuiaUPkv.js → Organization-sBZnIb2D.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-C3jb6knl.js → Overflow-CzOhNGE6.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-BOMyrLkb.js → P2P-D_D2yqda.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-UvLStCgS.js → PdhVaultBrowser-D5lKd_Kx.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-B9cN0dJH.js → Permissions-L5s-wENg.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-DNjW5qro.js → PersonalDataHub-iI49x6cH.js} +3 -3
  55. package/src/assets/web-panel/assets/{Pipeline-CFLyZ6Sh.js → Pipeline-DPHqyk09.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-D3w6vOxf.js → Privacy-B-ZL9360.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-cwcVsn8K.js → ProjectInit-f05YzsN2.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-aUoAroc-.js → ProjectSettings-DZLKS6ex.js} +2 -2
  59. package/src/assets/web-panel/assets/{Projects-CrzQv7Zv.js → Projects-ButF3DyM.js} +1 -1
  60. package/src/assets/web-panel/assets/{Providers-jZaPizKR.js → Providers-CFDSXnkR.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-DNzmwcfg.js → QrScannerModal-1N6Sdxdm.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-m-5Gwt70.js → QuickAsk-tEqRwRSR.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-CrrAjNxP.js → Recommend-D4ZVHIwz.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-BDCMjRFe.js → RemoteSession-Cqm32lhm.js} +2 -2
  65. package/src/assets/web-panel/assets/{Reputation-CPCt1Jc8.js → Reputation-BnjVsU_a.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-C-RorxHs.js → Row-DzpHyTuz.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-CnQs4TuY.js → RssFeed-Du5-ouwx.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-B1jkeFZY.js → Search-CYztyf2o.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-CGKI3vvd.js → Security-C1hVxy8Z.js} +3 -3
  70. package/src/assets/web-panel/assets/{Services-DQjesYF8.js → Services-BscEbAZ2.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-C9Ipj0A6.js → Skeleton-B2sMLqKQ.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-D2j54i9O.js → Skills-CoHKax06.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-xhrVjTeb.js → Sla-Bpie5KO6.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-C6KMOUCa.js → SpeechSettings-BX63ijn5.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-CmIPU5wR.js → SyncSettings-Bf72so5A.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-B-T1J42r.js → Tasks-CVB2PZk4.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-Aq669sjw.js → Templates-q0qyclJx.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-BKWUWNXB.js → Tenant-CW-W-i0k.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-DEeAvA8L.js → Terminal-D7QoPiXQ.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-C465ySdn.js → TimelineRenderer-BaRDAbyA.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-BgVqF-bX.js → Tokens-D6U4PRW8.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-BMNHmxwH.js → Trigger-ClBDWdLo.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-B_adk89L.js → Trust-C_M6rWPq.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-Biw38mog.js → UkeySign-bXHx8s4C.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-AC-eaw5k.js → VideoEditing-BcIt_ieI.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-8lQ5_t0X.js → Wallet-Dd-4jcLs.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-JDmH_-DF.js → WebAuthn-B4F6yxQK.js} +5 -5
  88. package/src/assets/web-panel/assets/{WorkflowEditor-DHQAdITG.js → WorkflowEditor-BEHkpfJq.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-C3qauUVv.js → chat-D7hhRpIO.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-DLP70JGe.js → colors-AMRhrRzS.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-DjsoqA5t.js → compact-item-BYpsOET5.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-CfEdl1in.js → createContext-CoUkR4LQ.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-BRylvxzY.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-DWwHHlBG.js → hasIn-CJKJMKki.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-Dfka-vzJ.js → index-8pmZHnQU.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DgQ92xdO.js → index-BBJFiZ9Y.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-VtCz3A64.js → index-BP69Ul3S.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-C8wrUFzY.js → index-BTFHYauX.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-D5VL0NYy.js → index-BUJt2ar4.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-B-rD2rhi.js → index-Bj30Aq6h.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-gu8zBhtp.js → index-BlpuqGt5.js} +1 -1
  102. package/src/assets/web-panel/assets/index-Bzvxvzlk.js +1 -0
  103. package/src/assets/web-panel/assets/{index-CgruUvB3.js → index-C19xZKIP.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DTEcPJGf.js → index-C6bg22vc.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-C4k6JGm_.js → index-CH6XEWdj.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-C0xMzvk8.js → index-CK1Kknpl.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-UEbYl2pu.js → index-CNyLbBGj.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Dmt1HDWZ.js → index-COg__P6M.js} +19 -19
  109. package/src/assets/web-panel/assets/{index-ArZCi1rK.js → index-CRlJOWsf.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BqPuyN4p.js → index-CScG8TAY.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-B4gCFHtB.js → index-CdL9cQIE.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-C47EiQ7d.js → index-Ck35u_0v.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-Dn2rNMmv.js → index-CkLZQtsh.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-T5emAyFT.js → index-DFoujkWD.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DbFnfyKh.js → index-DFwh0R9h.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CsEk9s04.js → index-DStN9E7o.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DTDpF8MS.js → index-DcozYrXV.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-_g5q2hF3.js → index-De5mYp86.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Bp_WNm2_.js → index-DfEVOzNb.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-OfMwkFIo.js → index-Dfna8sKa.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BcDeMCUK.js → index-DjbMaBLf.js} +1 -1
  122. package/src/assets/web-panel/assets/index-Dl6H3dxS.js +1 -0
  123. package/src/assets/web-panel/assets/{index-D-te-S9f.js → index-Dpl_SJuk.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DKsWujXP.js → index-DyF9uYzB.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BydBh7oT.js → index-HF3GvATm.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DAcBi6F-.js → index-OJmXGn8n.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CNeLedtU.js → index-ZPdNPhUq.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Ds1BfT_C.js → index-djikyGz3.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-CbF27GqZ.js → index-gQWWnP3_.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CnhJbWsl.js → index-owVbLJnH.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Lh0e2afo.js → index-tWEDZHzj.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DbjUePgq.js → index-ttTl376q.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-nuZaMsMy.js → index-z5rYvstM.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-C_pMmi75.js → initDefaultProps-B_Uk-wzg.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-BvKgS96o.js → motion-ez7H8y8b.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-C-1U4R1I.js → move-CKWUhhhX.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-D6BC968-.js → mtc-parser-DkNl7ocj.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-DxOZvcGQ.js → omit-C0uA2ytw.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-LpzmHdkw.js → pickAttrs-CySaWMPl.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-Bm--qom1.js → placementArrow-BWL3-3xo.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-CVZZlhJf.js → responsiveObserve-BRy_wJog.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-DD1xINGx.js → slide-DmmvSaBD.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-LrjHAy63.js → statusUtils-C_7SYY0K.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-BqknYxTe.js → styleChecker-DYgBJGDh.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-Dljy3diT.js → useFlexGapSupport-nPkoZkT6.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-OedUtPLc.js → useFs-CzpsfP4_.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-Cz-kxbP_.js → usePersonalDataHub-Bo2vvMWl.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-C8ZuTk8W.js → vnode-D-hXAnHb.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-CjbgJYXQ.js → zoom-DW7seTGG.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/commands/agent.js +39 -14
  152. package/src/commands/background-session.js +12 -1
  153. package/src/commands/permissions.js +24 -1
  154. package/src/gateways/ws/ws-agent-handler.js +26 -1
  155. package/src/gateways/ws/ws-approval-gate.js +131 -0
  156. package/src/index.js +63 -845
  157. package/src/lib/agent-ipc-bus.js +331 -0
  158. package/src/lib/agent-worktree.js +173 -5
  159. package/src/lib/background-agent-supervisor.js +193 -4
  160. package/src/lib/context-source-ledger.js +164 -0
  161. package/src/lib/execution-trace/index.js +10 -0
  162. package/src/lib/execution-trace/metrics-collector.js +218 -0
  163. package/src/lib/execution-trace/trace-context.js +182 -0
  164. package/src/lib/hook-manager.js +17 -0
  165. package/src/lib/hooks-v2-runtime.js +278 -0
  166. package/src/lib/interaction-adapter.js +26 -5
  167. package/src/lib/metrics-collector.js +127 -0
  168. package/src/lib/observability/index.js +33 -0
  169. package/src/lib/observability/otlp-exporter.js +260 -0
  170. package/src/lib/otlp-exporter.js +45 -0
  171. package/src/lib/process-execution-broker/SPAWN_AUDIT_REPORT.md +117 -0
  172. package/src/lib/process-execution-broker/index.js +450 -0
  173. package/src/lib/process-execution-broker/patch-child-process.js +50 -0
  174. package/src/lib/process-execution-broker/spawn-audit.json +3814 -0
  175. package/src/lib/repl-rewind.js +62 -14
  176. package/src/lib/runtime-provenance-ledger.js +190 -0
  177. package/src/lib/session-hooks.js +41 -0
  178. package/src/lib/turn-binding.js +134 -0
  179. package/src/program-base.js +4 -1
  180. package/src/repl/agent-repl.js +77 -3
  181. package/src/repl/repl-turn-binding.js +91 -0
  182. package/src/runtime/headless-runner.js +59 -0
  183. package/src/assets/web-panel/assets/MarkdownRenderer-RQ1HbTY5.js +0 -1
  184. package/src/assets/web-panel/assets/devWarning-Cwuuqc_f.js +0 -1
  185. package/src/assets/web-panel/assets/index-BkTk-zJK.js +0 -1
  186. package/src/assets/web-panel/assets/index-C-BSTEhe.js +0 -1
@@ -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 };
@@ -187,7 +187,7 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
187
187
  });
188
188
  }
189
189
 
190
- _ask(questionType, question, extra = {}) {
190
+ _ask(questionType, question, extra = {}, options = {}) {
191
191
  return this._request(
192
192
  {
193
193
  type: "question",
@@ -195,7 +195,12 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
195
195
  question,
196
196
  ...extra,
197
197
  },
198
- { kind: "question" },
198
+ {
199
+ kind: "question",
200
+ // Approval binding pass-through: a permission-gate producer supplies
201
+ // it; plain questions never carry one (message stays byte-identical).
202
+ ...(options.binding ? { binding: options.binding } : {}),
203
+ },
199
204
  );
200
205
  }
201
206
 
@@ -207,10 +212,26 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
207
212
  return this._ask("select", question, { choices });
208
213
  }
209
214
 
215
+ /**
216
+ * @param {string} question
217
+ * @param {boolean|object} [defaultVal] — boolean (legacy, byte-identical) or
218
+ * an options object `{ default, binding, ...extra }`: `binding` rides out
219
+ * on the request so the client must echo it back on approve (verified in
220
+ * _resolvePending, mismatched approve → deny); any other keys merge into
221
+ * the question message (e.g. structured `approval` context for UIs).
222
+ */
210
223
  async askConfirm(question, defaultVal = true) {
211
- const answer = await this._ask("confirm", question, {
212
- default: defaultVal,
213
- });
224
+ const opts =
225
+ defaultVal !== null && typeof defaultVal === "object"
226
+ ? defaultVal
227
+ : { default: defaultVal };
228
+ const { binding = null, default: dflt = true, ...extra } = opts;
229
+ const answer = await this._ask(
230
+ "confirm",
231
+ question,
232
+ { default: dflt, ...extra },
233
+ binding ? { binding } : {},
234
+ );
214
235
  // Normalize to boolean
215
236
  if (typeof answer === "boolean") return answer;
216
237
  return answer === "true" || answer === "yes" || answer === "y";
@@ -0,0 +1,127 @@
1
+ /**
2
+ * MetricsCollector - CLI runtime metrics collection (M3)
3
+ *
4
+ * Collects counters, gauges, histograms for performance monitoring
5
+ * with OTLP export support (M8 integration)
6
+ */
7
+
8
+ export class MetricsCollector {
9
+ constructor() {
10
+ this._counters = new Map();
11
+ this._gauges = new Map();
12
+ this._histograms = new Map();
13
+ }
14
+
15
+ /**
16
+ * Increment a counter metric
17
+ * @param {string} name - Metric name
18
+ * @param {number} value - Increment amount (default 1)
19
+ * @param {object} labels - Metric labels
20
+ */
21
+ counter(name, value = 1, labels = {}) {
22
+ const key = this._key(name, labels);
23
+ if (!this._counters.has(key)) {
24
+ this._counters.set(key, { name, value: 0, labels });
25
+ }
26
+ this._counters.get(key).value += value;
27
+ }
28
+
29
+ /**
30
+ * Set a gauge metric
31
+ * @param {string} name - Metric name
32
+ * @param {number} value - Gauge value
33
+ * @param {object} labels - Metric labels
34
+ */
35
+ gauge(name, value, labels = {}) {
36
+ const key = this._key(name, labels);
37
+ this._gauges.set(key, { name, value, labels, timestamp: Date.now() });
38
+ }
39
+
40
+ /**
41
+ * Record a histogram observation
42
+ * @param {string} name - Metric name
43
+ * @param {number} value - Observed value
44
+ * @param {object} labels - Metric labels
45
+ */
46
+ histogram(name, value, labels = {}) {
47
+ const key = this._key(name, labels);
48
+ if (!this._histograms.has(key)) {
49
+ this._histograms.set(key, {
50
+ name,
51
+ count: 0,
52
+ sum: 0,
53
+ min: Infinity,
54
+ max: -Infinity,
55
+ labels,
56
+ values: [],
57
+ });
58
+ }
59
+ const h = this._histograms.get(key);
60
+ h.count++;
61
+ h.sum += value;
62
+ h.min = Math.min(h.min, value);
63
+ h.max = Math.max(h.max, value);
64
+ // Keep last 1000 values for percentile calculation
65
+ if (h.values.length < 1000) {
66
+ h.values.push(value);
67
+ } else {
68
+ h.values[h.count % 1000] = value;
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Time a function execution and record duration
74
+ * @param {string} name - Metric name
75
+ * @param {Function} fn - Function to time
76
+ * @param {object} labels - Metric labels
77
+ * @returns {*} Function result
78
+ */
79
+ async timer(name, fn, labels = {}) {
80
+ const start = performance.now();
81
+ try {
82
+ return await fn();
83
+ } finally {
84
+ const duration = performance.now() - start;
85
+ this.histogram(name, duration, labels);
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Get all collected metrics
91
+ * @returns {object} All metrics
92
+ */
93
+ snapshot() {
94
+ return {
95
+ counters: Array.from(this._counters.values()),
96
+ gauges: Array.from(this._gauges.values()),
97
+ histograms: Array.from(this._histograms.values()).map((h) => ({
98
+ name: h.name,
99
+ count: h.count,
100
+ sum: h.sum,
101
+ min: h.min,
102
+ max: h.max,
103
+ avg: h.sum / h.count,
104
+ labels: h.labels,
105
+ })),
106
+ };
107
+ }
108
+
109
+ /**
110
+ * Reset all metrics
111
+ */
112
+ reset() {
113
+ this._counters.clear();
114
+ this._gauges.clear();
115
+ this._histograms.clear();
116
+ }
117
+
118
+ _key(name, labels) {
119
+ const labelStr = Object.entries(labels)
120
+ .sort(([a], [b]) => a.localeCompare(b))
121
+ .map(([k, v]) => `${k}=${v}`)
122
+ .join(",");
123
+ return labelStr ? `${name}{${labelStr}}` : name;
124
+ }
125
+ }
126
+
127
+ export const metricsCollector = new MetricsCollector();
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Observability - 可观测性模块统一导出
3
+ * M3 阶段模块:包含分布式追踪 + 性能指标收集
4
+ */
5
+
6
+ export {
7
+ traceContext,
8
+ TraceContext,
9
+ } from "../execution-trace/trace-context.js";
10
+ export {
11
+ metricsCollector,
12
+ MetricsCollector,
13
+ } from "../execution-trace/metrics-collector.js";
14
+
15
+ /**
16
+ * 初始化可观测性模块
17
+ * @param {Object} [options={}]
18
+ * @param {boolean} [options.tracingEnabled=true] - 是否启用追踪
19
+ * @param {boolean} [options.metricsEnabled=true] - 是否启用指标收集
20
+ */
21
+ export function initObservability(options = {}) {
22
+ const { tracingEnabled = true, metricsEnabled = true } = options;
23
+
24
+ // 可观测性模块初始化逻辑
25
+ return {
26
+ tracingEnabled,
27
+ metricsEnabled,
28
+ traceContext,
29
+ metricsCollector,
30
+ };
31
+ }
32
+
33
+ export * from "../execution-trace/index.js";