@wrongstack/core 0.313.1 → 0.316.2

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 (290) hide show
  1. package/dist/chronicle/index.js +31 -31
  2. package/dist/chronicle/legacy-journal-import.d.ts +0 -6
  3. package/dist/chronicle/metrics-ingest.d.ts +14 -0
  4. package/dist/chronicle/metrics-schema.d.ts +10 -1
  5. package/dist/chronicle/metrics-store.d.ts +20 -2
  6. package/dist/chronicle/project-server.js +39 -31
  7. package/dist/chronicle/sink.d.ts +13 -0
  8. package/dist/chronicle/sqlite-journal.d.ts +20 -2
  9. package/dist/{chunk-WOEZV3Q4.js → chunk-25LSLC3G.js} +2 -1
  10. package/dist/{chunk-AI4LLQ2U.js → chunk-27QIURLN.js} +229 -12
  11. package/dist/{chunk-I45KAW2N.js → chunk-3AGWVSS7.js} +38 -450
  12. package/dist/chunk-3BDV7RL3.js +211 -0
  13. package/dist/{chunk-NFAYHPRH.js → chunk-3ECENVHL.js} +10 -8
  14. package/dist/{chunk-FW5LDDMJ.js → chunk-45WI72ZB.js} +1576 -1156
  15. package/dist/{chunk-AT4V4XGI.js → chunk-4BMVPOHO.js} +539 -313
  16. package/dist/{chunk-YBUJCZ57.js → chunk-4I7HGVVA.js} +17 -5
  17. package/dist/{chunk-JVGPR3TS.js → chunk-4LCZVJVF.js} +7 -55
  18. package/dist/{chunk-4ZHTKJHM.js → chunk-4SJNS7OB.js} +36 -2
  19. package/dist/{chunk-AD7ZFZCS.js → chunk-5BMIE7QG.js} +3 -3
  20. package/dist/{chunk-IQ35HMQL.js → chunk-5YPSXQXM.js} +71 -24
  21. package/dist/chunk-6FHWXLPT.js +10 -0
  22. package/dist/{chunk-FIV4IJL7.js → chunk-6H5GEOET.js} +163 -20
  23. package/dist/{chunk-VB3H5WWB.js → chunk-6NWEVFEL.js} +2 -2
  24. package/dist/{chunk-E6I5RXVK.js → chunk-AYW5YINX.js} +2 -2
  25. package/dist/{chunk-DEIQMBD2.js → chunk-B7F4WVP4.js} +2 -2
  26. package/dist/{chunk-XQ2XGIBF.js → chunk-BPBKKBUK.js} +6 -7
  27. package/dist/{chunk-K4YUNKU7.js → chunk-BYD345OX.js} +2 -2
  28. package/dist/{chunk-LZDDLNCZ.js → chunk-C27KDLOX.js} +4 -4
  29. package/dist/{chunk-6AKOTGLM.js → chunk-CU546ESW.js} +7 -7
  30. package/dist/{chunk-ZZ4V3WIZ.js → chunk-DLHHXUAM.js} +10 -1
  31. package/dist/{chunk-BAKVJLEV.js → chunk-DOTHQSJ2.js} +28 -16
  32. package/dist/{chunk-KBZGE6LN.js → chunk-DYLPMV4Q.js} +4 -3
  33. package/dist/{chunk-52RTVH4M.js → chunk-F3JWNST7.js} +2 -2
  34. package/dist/{chunk-WEBMSQP2.js → chunk-FC2ZGRF3.js} +21 -4
  35. package/dist/{chunk-FHAMQS7Q.js → chunk-FCBTO76Z.js} +76 -146
  36. package/dist/{chunk-4LJJYBAU.js → chunk-FHZVFYSL.js} +9 -1
  37. package/dist/{chunk-W4A6QA3D.js → chunk-FWNLEZYG.js} +4 -3
  38. package/dist/{chunk-OJZEX73F.js → chunk-GDQ7CZRQ.js} +5 -1
  39. package/dist/{chunk-QVOVMXJR.js → chunk-GJJGJB2R.js} +32 -9
  40. package/dist/{chunk-4XV6IR37.js → chunk-HI3JGZR2.js} +7 -6
  41. package/dist/{chunk-FSWCWSTS.js → chunk-HMLIGAU7.js} +26 -26
  42. package/dist/{chunk-PFXFQQRT.js → chunk-HXKZ7OBQ.js} +7 -43
  43. package/dist/{chunk-2FQL4PDC.js → chunk-I7DALG7J.js} +5 -5
  44. package/dist/{chunk-GM54GJBU.js → chunk-IRUTEHCE.js} +3 -3
  45. package/dist/{chunk-TYW2GI5I.js → chunk-J2WRWR37.js} +40 -13
  46. package/dist/{chunk-ZEHUCJHY.js → chunk-JFPJ6LLQ.js} +2 -2
  47. package/dist/chunk-JMULFFLN.js +9 -0
  48. package/dist/{chunk-RD6DEE36.js → chunk-JO4MGB6Z.js} +94 -8
  49. package/dist/{chunk-5DSMEVA4.js → chunk-K6BXGITA.js} +7 -7
  50. package/dist/{chunk-O74MJHXU.js → chunk-KZMSZV32.js} +2 -2
  51. package/dist/{chunk-GFJOMSHG.js → chunk-LA7CLDRW.js} +6 -2
  52. package/dist/{chunk-M2WF6AXG.js → chunk-LSMMOS2Z.js} +7 -3
  53. package/dist/{chunk-ASX6AW36.js → chunk-LXWCMQNJ.js} +3 -3
  54. package/dist/{chunk-WZO23AWO.js → chunk-M27LIEKV.js} +72 -22
  55. package/dist/{chunk-JTHKOYWU.js → chunk-MJPHJRAL.js} +15 -15
  56. package/dist/{chunk-G5AAKEEZ.js → chunk-MTL4O5YR.js} +5 -5
  57. package/dist/chunk-NHJ75HXY.js +1 -0
  58. package/dist/{chunk-ZYU2YOJ6.js → chunk-NIOAGFPB.js} +29 -15
  59. package/dist/{chunk-Y2GE5TSI.js → chunk-NS52ISWS.js} +2 -2
  60. package/dist/{chunk-UIWONWVG.js → chunk-NSOFPKGT.js} +541 -148
  61. package/dist/{chunk-RCQYT2I4.js → chunk-NVIZG63R.js} +2 -2
  62. package/dist/{chunk-EPC3GZD4.js → chunk-OOYZPOXM.js} +2 -2
  63. package/dist/{chunk-7ZHZE5EO.js → chunk-OSGLYW5J.js} +2 -2
  64. package/dist/{chunk-CE4ZOCOI.js → chunk-PFCMSSUF.js} +9 -9
  65. package/dist/{chunk-GFXZTHNI.js → chunk-PGRVXIMY.js} +5 -5
  66. package/dist/{chunk-JJPMWPB6.js → chunk-PISBFBJN.js} +6 -6
  67. package/dist/chunk-POOOIWE5.js +9 -0
  68. package/dist/{chunk-5RP3QTRL.js → chunk-PQNS3U7Z.js} +20 -3
  69. package/dist/{chunk-3E244UDA.js → chunk-QSTSJOCK.js} +52 -6
  70. package/dist/{chunk-YUPMXOGP.js → chunk-RFQMOKWK.js} +3 -3
  71. package/dist/chunk-RTOTNK3P.js +484 -0
  72. package/dist/{chunk-SN2DQRL6.js → chunk-RXKSDUAU.js} +7 -7
  73. package/dist/{chunk-T3KGZBU5.js → chunk-S45JPKQN.js} +189 -43
  74. package/dist/{chunk-YNCVSFGF.js → chunk-SAFHACFA.js} +4 -1
  75. package/dist/{chunk-KI4L2DUL.js → chunk-TCCHINEF.js} +114 -19
  76. package/dist/{chunk-AWNQ6ED6.js → chunk-THEGTRAG.js} +7 -2
  77. package/dist/{chunk-2KKODIQU.js → chunk-TR4LQE7L.js} +15 -15
  78. package/dist/{chunk-GPQ3NJPR.js → chunk-TWJMGXCI.js} +3 -3
  79. package/dist/{chunk-H72H4XDU.js → chunk-U45AXT5D.js} +9 -9
  80. package/dist/{chunk-62V2AFVG.js → chunk-U4FWBSO3.js} +160 -73
  81. package/dist/{chunk-A455ATZB.js → chunk-UBGDX6FI.js} +8 -1
  82. package/dist/chunk-UJILKYES.js +75 -0
  83. package/dist/{chunk-KSJ5UTP7.js → chunk-ULMAQV3T.js} +84 -4
  84. package/dist/{chunk-CB2HFKTP.js → chunk-VVBP6KGT.js} +1 -1
  85. package/dist/{chunk-RPOA7IAE.js → chunk-W5VITDM2.js} +43 -25
  86. package/dist/{chunk-QRTG4XTI.js → chunk-WAHQVNWT.js} +7 -1
  87. package/dist/{chunk-SQP64RCS.js → chunk-WGGYRBXH.js} +3019 -2976
  88. package/dist/{chunk-K3G6JBUC.js → chunk-WLYKU45P.js} +679 -141
  89. package/dist/chunk-WP7BVANJ.js +53 -0
  90. package/dist/{chunk-GAZEWQEZ.js → chunk-XF4VUMKW.js} +2 -2
  91. package/dist/{chunk-PAAWLLZX.js → chunk-Y5YXDM7D.js} +2 -2
  92. package/dist/{chunk-65RDIOR2.js → chunk-YOPAUVU4.js} +162 -44
  93. package/dist/{chunk-FFSX2QDQ.js → chunk-YPT4A46F.js} +3 -3
  94. package/dist/chunk-YWXT3JNM.js +425 -0
  95. package/dist/{chunk-EFEHDQGY.js → chunk-ZHZ2Y2DH.js} +64 -10
  96. package/dist/{chunk-CQQL4ZOQ.js → chunk-ZT7JNIGX.js} +4 -3
  97. package/dist/coordination/agent-monitor.d.ts +9 -1
  98. package/dist/coordination/agent-subagent-runner.d.ts +1 -1
  99. package/dist/coordination/agents/agent-prompts.d.ts +8 -0
  100. package/dist/coordination/agents/index.d.ts +33 -1
  101. package/dist/coordination/agents/index.js +52 -22
  102. package/dist/coordination/agents/phase3-wave1-platform.d.ts +1 -3
  103. package/dist/coordination/agents/phase3-wave2-meta.d.ts +1 -3
  104. package/dist/coordination/agents/phase8-wave3-products.d.ts +1 -3
  105. package/dist/coordination/agents/phase9-wave4-platform-meta.d.ts +1 -3
  106. package/dist/coordination/agents/project-agent-identity.d.ts +11 -11
  107. package/dist/coordination/agents/types.d.ts +13 -2
  108. package/dist/coordination/brain-monitor.d.ts +30 -7
  109. package/dist/coordination/collab-debug.d.ts +1 -1
  110. package/dist/coordination/collab-pause.d.ts +1 -1
  111. package/dist/coordination/delegate-tool.d.ts +7 -5
  112. package/dist/coordination/director-kanban-queue-helpers.d.ts +1 -0
  113. package/dist/coordination/director-options.d.ts +7 -0
  114. package/dist/coordination/director-spawn-model.d.ts +17 -0
  115. package/dist/coordination/director-tools.d.ts +2 -2
  116. package/dist/coordination/director.d.ts +12 -0
  117. package/dist/coordination/dispatcher.d.ts +8 -0
  118. package/dist/coordination/fleet-bus.d.ts +35 -4
  119. package/dist/coordination/fleet-supervisor.d.ts +10 -2
  120. package/dist/coordination/fleet.d.ts +16 -7
  121. package/dist/coordination/index.d.ts +4 -0
  122. package/dist/coordination/index.js +86 -49
  123. package/dist/coordination/kanban-dispatch-port.d.ts +2 -2
  124. package/dist/coordination/mailbox-http-router.d.ts +4 -3
  125. package/dist/coordination/mailbox-http-validation.d.ts +1 -1
  126. package/dist/coordination/mailbox-project-server.js +15 -15
  127. package/dist/coordination/mailbox-types.d.ts +24 -6
  128. package/dist/coordination/model-tier-leader.d.ts +122 -0
  129. package/dist/coordination/model-tier.d.ts +122 -0
  130. package/dist/coordination/multi-agent-coordinator.d.ts +24 -0
  131. package/dist/coordination/origin-session.d.ts +16 -0
  132. package/dist/coordination/provider-status-tracker.d.ts +37 -5
  133. package/dist/coordination/session-note-hub.d.ts +44 -0
  134. package/dist/coordination/session-note-tool.d.ts +10 -0
  135. package/dist/core/agent.d.ts +1 -1
  136. package/dist/core/context.d.ts +22 -3
  137. package/dist/core/index.d.ts +2 -0
  138. package/dist/core/index.js +130 -38
  139. package/dist/core/request-conversation-binding.d.ts +37 -0
  140. package/dist/core/session-notes.d.ts +25 -0
  141. package/dist/core/system-prompt-builder.d.ts +11 -2
  142. package/dist/core/system-prompt-variants.d.ts +78 -0
  143. package/dist/design/index.js +3 -3
  144. package/dist/execution/auto-compaction-middleware.d.ts +11 -0
  145. package/dist/execution/autonomy-brain.d.ts +2 -1
  146. package/dist/execution/autonomy-prompt-contributor.d.ts +7 -2
  147. package/dist/execution/compaction-core.d.ts +4 -4
  148. package/dist/execution/eternal-autonomy.d.ts +1 -1
  149. package/dist/execution/index.js +138 -129
  150. package/dist/execution/model-runtime.d.ts +0 -7
  151. package/dist/execution/parallel-eternal-engine.d.ts +7 -7
  152. package/dist/extension/index.js +3 -3
  153. package/dist/goal/index.js +6 -6
  154. package/dist/hooks/index.js +3 -3
  155. package/dist/hq/index.js +14 -12
  156. package/dist/hq/persistence/event-log.d.ts +0 -1
  157. package/dist/hq/persistence.d.ts +4 -4
  158. package/dist/hq/publisher.d.ts +2 -0
  159. package/dist/index.d.ts +14 -11
  160. package/dist/index.js +728 -635
  161. package/dist/infrastructure/index.d.ts +4 -4
  162. package/dist/infrastructure/index.js +281 -260
  163. package/dist/infrastructure/token-counter.d.ts +9 -0
  164. package/dist/kernel/events/agent-events.d.ts +77 -3
  165. package/dist/kernel/events/brain-events.d.ts +12 -0
  166. package/dist/kernel/events/provider-events.d.ts +7 -1
  167. package/dist/kernel/events/session-events.d.ts +14 -0
  168. package/dist/kernel/events/tool-events.d.ts +13 -0
  169. package/dist/kernel/index.js +4 -4
  170. package/dist/mailbox-attach.d.ts +1 -1
  171. package/dist/models/index.js +10 -9
  172. package/dist/observability/event-bridge.d.ts +25 -5
  173. package/dist/observability/index.d.ts +9 -8
  174. package/dist/observability/index.js +459 -351
  175. package/dist/observability/tool-usage-source.d.ts +65 -0
  176. package/dist/plugin/index.d.ts +5 -0
  177. package/dist/plugin/index.js +66 -50
  178. package/dist/plugins/auto-review-plugin.d.ts +3 -2
  179. package/dist/plugins/review-finding-commands.d.ts +0 -8
  180. package/dist/{review-finding-store-DKAV3AS6.js → plugins/review-finding-store.js} +7 -6
  181. package/dist/plugins/review-finding-types.js +19 -0
  182. package/dist/plugins/review-report-integration.js +21 -0
  183. package/dist/{review-report-store-OWY3EC3N.js → plugins/review-report-store.js} +7 -6
  184. package/dist/plugins/review-report-types.js +13 -0
  185. package/dist/prompts/index.js +5 -5
  186. package/dist/registry/index.js +3 -3
  187. package/dist/registry/tool-registry.d.ts +59 -9
  188. package/dist/{registry-R23UBE7H.js → registry-7N4O3E7W.js} +5 -5
  189. package/dist/security/capabilities.d.ts +6 -0
  190. package/dist/security/file-permissions.d.ts +1 -1
  191. package/dist/security/index.js +47 -33
  192. package/dist/security/permission-policy.d.ts +12 -1
  193. package/dist/security/secret-scrubber.d.ts +15 -0
  194. package/dist/session-catalog/index.d.ts +1 -0
  195. package/dist/session-catalog/index.js +19 -14
  196. package/dist/session-catalog/project-server.js +30 -13
  197. package/dist/session-catalog/protocol.d.ts +32 -1
  198. package/dist/session-catalog/registry.d.ts +17 -1
  199. package/dist/session-catalog/session-agents.d.ts +56 -0
  200. package/dist/session-catalog/store-rebuild.d.ts +14 -0
  201. package/dist/session-catalog/store-schema.d.ts +26 -0
  202. package/dist/session-catalog/store.d.ts +27 -1
  203. package/dist/session-note-attach.d.ts +9 -0
  204. package/dist/skills/index.js +5 -5
  205. package/dist/statusline/index.d.ts +43 -0
  206. package/dist/statusline/index.js +102 -0
  207. package/dist/storage/board-store-port.d.ts +2 -2
  208. package/dist/storage/config-loader/in-project-policy.d.ts +29 -0
  209. package/dist/storage/config-loader.d.ts +3 -2
  210. package/dist/storage/file-session-writer.d.ts +4 -2
  211. package/dist/storage/goal-coordination.d.ts +6 -1
  212. package/dist/storage/goal-kanban.d.ts +4 -1
  213. package/dist/storage/index.d.ts +12 -4
  214. package/dist/storage/index.js +76 -61
  215. package/dist/storage/input-history-store.d.ts +2 -4
  216. package/dist/storage/memory-curator.d.ts +133 -0
  217. package/dist/storage/session-agent-attribution.d.ts +39 -0
  218. package/dist/storage/session-doctor.d.ts +109 -0
  219. package/dist/storage/session-event-bridge.d.ts +5 -7
  220. package/dist/storage/session-outcome.d.ts +42 -0
  221. package/dist/storage/session-recovery.d.ts +55 -0
  222. package/dist/storage/session-store/load-session-data.d.ts +11 -0
  223. package/dist/storage/session-store/prune-helpers.d.ts +1 -1
  224. package/dist/storage/session-store/resume-session.d.ts +0 -2
  225. package/dist/storage/session-store/types.d.ts +8 -0
  226. package/dist/storage/session-store.d.ts +3 -3
  227. package/dist/storage/session-summary-tracker.d.ts +8 -1
  228. package/dist/storage/session-write-buffer.d.ts +18 -0
  229. package/dist/storage/session-writer-truncate.d.ts +2 -0
  230. package/dist/tasking/index.js +2 -2
  231. package/dist/tools/fallback-manage-tools.d.ts +6 -4
  232. package/dist/tools/index.js +21 -21
  233. package/dist/tools/model-tier-set-tool.d.ts +66 -0
  234. package/dist/types/agent-bridge.d.ts +2 -1
  235. package/dist/types/config/mcp-features.d.ts +7 -0
  236. package/dist/types/config/model-tiers.d.ts +148 -0
  237. package/dist/types/config/root.d.ts +9 -0
  238. package/dist/types/config/tools.d.ts +73 -0
  239. package/dist/types/config.d.ts +1 -0
  240. package/dist/types/context.d.ts +2 -0
  241. package/dist/types/default-config.d.ts +6 -0
  242. package/dist/types/errors.d.ts +2 -1
  243. package/dist/types/index.d.ts +11 -9
  244. package/dist/types/index.js +25 -15
  245. package/dist/types/multi-agent.d.ts +43 -0
  246. package/dist/types/plugin.d.ts +1 -1
  247. package/dist/types/provider.d.ts +15 -0
  248. package/dist/types/runtime-capability-manifest.d.ts +1 -1
  249. package/dist/types/secret-scrubber.d.ts +15 -0
  250. package/dist/types/session-markers.d.ts +37 -10
  251. package/dist/types/session-markers.js +1 -1
  252. package/dist/types/session-timeline.d.ts +197 -0
  253. package/dist/types/session-timeline.js +12 -0
  254. package/dist/types/session.d.ts +172 -11
  255. package/dist/types/system-prompt.d.ts +27 -0
  256. package/dist/utils/config-backup.d.ts +9 -1
  257. package/dist/utils/heap-watchdog.js +2 -2
  258. package/dist/utils/index.js +50 -48
  259. package/dist/utils/message-invariants.d.ts +4 -1
  260. package/dist/utils/regex-guard.d.ts +1 -1
  261. package/dist/utils/socket-path.d.ts +1 -1
  262. package/dist/utils/token-estimate.d.ts +6 -2
  263. package/dist/utils/wstack-paths.d.ts +2 -0
  264. package/dist/wiring/proxy-rewrite.d.ts +28 -0
  265. package/dist/wiring/proxy-rewrite.js +7 -1
  266. package/dist/worktree/index.js +2 -2
  267. package/instructions/agents/explore-companion.md +45 -18
  268. package/instructions/agents/memory-curator.md +34 -22
  269. package/instructions/coordination/director-preamble.md +12 -7
  270. package/instructions/coordination/subagent-baseline.md +26 -5
  271. package/instructions/leader-after-task.md +4 -1
  272. package/instructions/llm/chimera-review.md +30 -9
  273. package/instructions/llm/memory-curator.md +31 -0
  274. package/instructions/sections/tool/delegation-compact.md +2 -0
  275. package/instructions/sections/tool/delegation-full.md +5 -1
  276. package/instructions/sections/tool/mailbox-compact.md +5 -1
  277. package/instructions/sections/tool/mailbox-full.md +3 -0
  278. package/instructions/sections/tool/session-note-compact.md +3 -0
  279. package/instructions/sections/tool/session-note-full.md +15 -0
  280. package/instructions/system-lite.md +9 -4
  281. package/instructions/system-pro.md +66 -143
  282. package/instructions/system.md +73 -175
  283. package/package.json +33 -5
  284. package/dist/chunk-2BUUIMQB.js +0 -225
  285. package/dist/chunk-FAYRX2AD.js +0 -13
  286. package/dist/chunk-H5E77KUJ.js +0 -15
  287. package/dist/chunk-M7BS2K6U.js +0 -1
  288. package/dist/coordination/agents.d.ts +0 -8
  289. package/dist/coordination/transport.d.ts +0 -2
  290. package/dist/storage/session-writer/session-writer-summary-tracker.d.ts +0 -28
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  SECRET_FILE_MODE
3
- } from "./chunk-H5E77KUJ.js";
3
+ } from "./chunk-6FHWXLPT.js";
4
4
  import {
5
5
  withSqliteExperimentalWarningSuppressed
6
6
  } from "./chunk-LX5QWLBL.js";
7
7
  import {
8
8
  atomicWrite,
9
9
  withFileLock
10
- } from "./chunk-7ZHZE5EO.js";
10
+ } from "./chunk-OSGLYW5J.js";
11
11
 
12
12
  // src/chronicle/identity.ts
13
13
  import { createHash } from "node:crypto";
@@ -27,6 +27,15 @@ function stableId(prefix, value) {
27
27
  return `${prefix}_${createHash("sha256").update(value).digest("hex").slice(0, 24)}`;
28
28
  }
29
29
 
30
+ // src/chronicle/project-server-protocol.ts
31
+ var CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION = 2;
32
+ var CHRONICLE_PROJECT_SERVER_MAX_FRAME_CHARS = 64 * 1024 * 1024;
33
+ var CHRONICLE_MAX_APPEND_BATCH = 1e4;
34
+ function encodeChronicleProjectServerMessage(message) {
35
+ return `${JSON.stringify(message)}
36
+ `;
37
+ }
38
+
30
39
  // src/chronicle/event-hash.ts
31
40
  import { createHash as createHash2 } from "node:crypto";
32
41
  var GENESIS_HASH = "0".repeat(64);
@@ -664,6 +673,217 @@ function errorMessage(error) {
664
673
  return error instanceof Error ? error.message : String(error);
665
674
  }
666
675
 
676
+ // src/chronicle/metrics-schema.ts
677
+ import { loadRuntimeDatabaseSync } from "@wrongstack/persistence";
678
+ var SCHEMA_VERSION = 6;
679
+ var READ_CHUNK_BYTES = 1024 * 1024;
680
+ var SQLITE_SOURCE_PREFIX = "sqlite:";
681
+ var SQLITE_INGEST_BATCH = 2e3;
682
+ var EMPTY_FAMILIES = {
683
+ llm: 0,
684
+ agent: 0,
685
+ tool: 0,
686
+ file: 0,
687
+ memory: 0,
688
+ task: 0,
689
+ decision: 0,
690
+ runtime: 0,
691
+ finding: 0
692
+ };
693
+ var Ctor;
694
+ function loadDatabaseSync() {
695
+ if (Ctor) return Ctor;
696
+ if (Ctor === null) throw new Error("SQLite is unavailable in this runtime");
697
+ try {
698
+ Ctor = withSqliteExperimentalWarningSuppressed(loadRuntimeDatabaseSync);
699
+ return Ctor;
700
+ } catch (error) {
701
+ Ctor = null;
702
+ throw new Error(
703
+ "Chronicle metrics need node:sqlite (Node >= 22.5) or bun:sqlite: " + (error instanceof Error ? error.message : String(error))
704
+ );
705
+ }
706
+ }
707
+ function isChronicleMetricsAvailable() {
708
+ try {
709
+ loadDatabaseSync();
710
+ return true;
711
+ } catch {
712
+ return false;
713
+ }
714
+ }
715
+ function ensureMetricsSchema(db) {
716
+ const version = db.prepare("PRAGMA user_version").get().user_version;
717
+ if (version !== 0 && version !== SCHEMA_VERSION) {
718
+ db.exec(
719
+ "DROP TABLE IF EXISTS ingest_state; DROP TABLE IF EXISTS provider_daily;DROP TABLE IF EXISTS task_outcomes; DROP TABLE IF EXISTS file_lineage;DROP TABLE IF EXISTS token_cost; DROP TABLE IF EXISTS daily_counters;DROP TABLE IF EXISTS family_daily; DROP TABLE IF EXISTS agent_daily;DROP TABLE IF EXISTS logical_request_daily; DROP TABLE IF EXISTS file_seen_daily;DROP TABLE IF EXISTS tool_daily;"
720
+ );
721
+ }
722
+ db.exec(`
723
+ CREATE TABLE IF NOT EXISTS ingest_state (
724
+ file TEXT PRIMARY KEY,
725
+ bytes INTEGER NOT NULL
726
+ );
727
+ CREATE TABLE IF NOT EXISTS provider_daily (
728
+ day TEXT NOT NULL,
729
+ provider_id TEXT NOT NULL,
730
+ model_id TEXT NOT NULL,
731
+ attempts INTEGER NOT NULL DEFAULT 0,
732
+ completed INTEGER NOT NULL DEFAULT 0,
733
+ failed INTEGER NOT NULL DEFAULT 0,
734
+ retries INTEGER NOT NULL DEFAULT 0,
735
+ fallbacks INTEGER NOT NULL DEFAULT 0,
736
+ input_tokens INTEGER NOT NULL DEFAULT 0,
737
+ output_tokens INTEGER NOT NULL DEFAULT 0,
738
+ cache_read_tokens INTEGER NOT NULL DEFAULT 0,
739
+ cache_write_tokens INTEGER NOT NULL DEFAULT 0,
740
+ duration_ms_total REAL NOT NULL DEFAULT 0,
741
+ duration_ms_max REAL NOT NULL DEFAULT 0,
742
+ duration_count INTEGER NOT NULL DEFAULT 0,
743
+ PRIMARY KEY (day, provider_id, model_id)
744
+ );
745
+ CREATE TABLE IF NOT EXISTS task_outcomes (
746
+ task_id TEXT PRIMARY KEY,
747
+ run_id TEXT NOT NULL DEFAULT '',
748
+ board_id TEXT NOT NULL DEFAULT '',
749
+ session_id TEXT NOT NULL DEFAULT '',
750
+ agent_id TEXT NOT NULL DEFAULT '',
751
+ status TEXT NOT NULL DEFAULT 'started',
752
+ started_at TEXT,
753
+ ended_at TEXT,
754
+ duration_ms REAL,
755
+ retries INTEGER NOT NULL DEFAULT 0,
756
+ verification_failures INTEGER NOT NULL DEFAULT 0
757
+ );
758
+ CREATE TABLE IF NOT EXISTS file_lineage (
759
+ event_id TEXT PRIMARY KEY,
760
+ path TEXT NOT NULL,
761
+ path_key TEXT NOT NULL,
762
+ operation TEXT NOT NULL,
763
+ occurred_at TEXT NOT NULL,
764
+ session_id TEXT NOT NULL DEFAULT '',
765
+ agent_id TEXT NOT NULL DEFAULT '',
766
+ task_id TEXT NOT NULL DEFAULT '',
767
+ board_id TEXT NOT NULL DEFAULT '',
768
+ run_id TEXT NOT NULL DEFAULT '',
769
+ tool_name TEXT NOT NULL DEFAULT '',
770
+ provider_id TEXT NOT NULL DEFAULT '',
771
+ model_id TEXT NOT NULL DEFAULT '',
772
+ logical_request_id TEXT NOT NULL DEFAULT '',
773
+ prompt_manifest_id TEXT NOT NULL DEFAULT '',
774
+ provenance_confidence TEXT NOT NULL DEFAULT 'unknown',
775
+ source TEXT NOT NULL DEFAULT ''
776
+ );
777
+ CREATE INDEX IF NOT EXISTS idx_file_lineage_path ON file_lineage(path_key, occurred_at);
778
+ CREATE INDEX IF NOT EXISTS idx_file_lineage_task ON file_lineage(task_id);
779
+ -- Latest cumulative token snapshot per (project, session, agent) scope.
780
+ -- token.accounted carries a running total, so last-write-wins is the
781
+ -- correct reduction; the WHERE guard on ingest keeps it order-independent.
782
+ --
783
+ -- The token columns exist because cost alone was unusable: subscription
784
+ -- providers price at 0, so a table holding only cost reported nothing for
785
+ -- most real sessions while the token counts it was derived from were
786
+ -- discarded. provider/model are recorded for the same reason the session
787
+ -- journal now stamps them on llm_response: a spend row that cannot name
788
+ -- the model it paid for cannot be attributed.
789
+ CREATE TABLE IF NOT EXISTS token_cost (
790
+ scope_key TEXT PRIMARY KEY,
791
+ day TEXT NOT NULL,
792
+ occurred_at TEXT NOT NULL,
793
+ sequence INTEGER NOT NULL,
794
+ cost REAL NOT NULL,
795
+ input_tokens INTEGER NOT NULL DEFAULT 0,
796
+ output_tokens INTEGER NOT NULL DEFAULT 0,
797
+ cache_read_tokens INTEGER NOT NULL DEFAULT 0,
798
+ cache_write_tokens INTEGER NOT NULL DEFAULT 0,
799
+ provider TEXT NOT NULL DEFAULT '',
800
+ model TEXT NOT NULL DEFAULT ''
801
+ );
802
+ CREATE INDEX IF NOT EXISTS idx_token_cost_model ON token_cost(provider, model);
803
+ CREATE TABLE IF NOT EXISTS daily_counters (
804
+ day TEXT PRIMARY KEY,
805
+ tool_calls INTEGER NOT NULL DEFAULT 0,
806
+ completed_tools INTEGER NOT NULL DEFAULT 0,
807
+ failed_tools INTEGER NOT NULL DEFAULT 0,
808
+ tool_duration_ms_total REAL NOT NULL DEFAULT 0,
809
+ tool_duration_ms_max REAL NOT NULL DEFAULT 0,
810
+ tool_duration_count INTEGER NOT NULL DEFAULT 0,
811
+ processes INTEGER NOT NULL DEFAULT 0,
812
+ failed_processes INTEGER NOT NULL DEFAULT 0,
813
+ file_events_all INTEGER NOT NULL DEFAULT 0,
814
+ decisions INTEGER NOT NULL DEFAULT 0,
815
+ escalations INTEGER NOT NULL DEFAULT 0,
816
+ agent_events INTEGER NOT NULL DEFAULT 0,
817
+ failures INTEGER NOT NULL DEFAULT 0,
818
+ cancellations INTEGER NOT NULL DEFAULT 0
819
+ );
820
+ CREATE TABLE IF NOT EXISTS family_daily (
821
+ day TEXT NOT NULL,
822
+ family TEXT NOT NULL,
823
+ count INTEGER NOT NULL DEFAULT 0,
824
+ failure_count INTEGER NOT NULL DEFAULT 0,
825
+ PRIMARY KEY (day, family)
826
+ );
827
+ CREATE TABLE IF NOT EXISTS agent_daily (day TEXT NOT NULL, agent_id TEXT NOT NULL, PRIMARY KEY (day, agent_id));
828
+ CREATE TABLE IF NOT EXISTS logical_request_daily (day TEXT NOT NULL, logical_request_id TEXT NOT NULL, PRIMARY KEY (day, logical_request_id));
829
+ CREATE TABLE IF NOT EXISTS file_seen_daily (day TEXT NOT NULL, path_key TEXT NOT NULL, PRIMARY KEY (day, path_key));
830
+ -- Per-tool daily rollup for the auto-thinning pipeline. Distinct from
831
+ -- daily_counters (which is name-agnostic): this is keyed by tool_name so
832
+ -- underusedTools() can pick candidates without scanning the journal.
833
+ CREATE TABLE IF NOT EXISTS tool_daily (
834
+ day TEXT NOT NULL,
835
+ tool_name TEXT NOT NULL,
836
+ invocations INTEGER NOT NULL DEFAULT 0,
837
+ failures INTEGER NOT NULL DEFAULT 0,
838
+ duration_ms_total REAL NOT NULL DEFAULT 0,
839
+ duration_ms_max REAL NOT NULL DEFAULT 0,
840
+ last_invoked_at INTEGER,
841
+ PRIMARY KEY (day, tool_name)
842
+ );
843
+ CREATE INDEX IF NOT EXISTS idx_tool_daily_name ON tool_daily(tool_name, day);
844
+ PRAGMA user_version = ${SCHEMA_VERSION};
845
+ `);
846
+ }
847
+ function eventDay(event) {
848
+ return (event.occurredAt ?? event.observedAt).slice(0, 10);
849
+ }
850
+ function durationMs(event) {
851
+ const value = Number(event.durationNs ?? 0) / 1e6;
852
+ return Number.isFinite(value) && value > 0 ? value : 0;
853
+ }
854
+ function numberOrDuration(event, attributes) {
855
+ const explicit = attributes.durationMs;
856
+ if (typeof explicit === "number" && Number.isFinite(explicit)) return explicit;
857
+ return durationMs(event);
858
+ }
859
+ function numberAt(event, dotPath) {
860
+ const value = readPath(event.attributes ?? {}, dotPath);
861
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
862
+ }
863
+ function readPath(value, key) {
864
+ return key.split(".").reduce(
865
+ (current, part) => current && typeof current === "object" ? current[part] : void 0,
866
+ value
867
+ );
868
+ }
869
+ function stringAt(record, key) {
870
+ const value = record[key];
871
+ return typeof value === "string" && value.length > 0 ? value : void 0;
872
+ }
873
+ function asString(value) {
874
+ return typeof value === "string" && value.length > 0 ? value : void 0;
875
+ }
876
+ function clampLimit(limit, fallback) {
877
+ if (typeof limit !== "number" || !Number.isFinite(limit) || limit <= 0) return fallback;
878
+ return Math.min(Math.floor(limit), 1e4);
879
+ }
880
+ function normalizeKey(value) {
881
+ return value.replaceAll("\\", "/");
882
+ }
883
+ function normalizePathKey(value) {
884
+ return value.replaceAll("\\", "/").replace(/^\.\//, "").toLowerCase();
885
+ }
886
+
667
887
  // src/chronicle/partition-range-cache.ts
668
888
  import * as fs2 from "node:fs/promises";
669
889
  import * as path4 from "node:path";
@@ -901,13 +1121,15 @@ var ChronicleQueryEngine = class _ChronicleQueryEngine {
901
1121
  events: pageEvents,
902
1122
  total: totalCount,
903
1123
  summary: finalizeSummary(summaryAcc),
904
- ...lastEvent && pageEvents.length < remainingCount ? { nextCursor: encodeCursor({
905
- version: 1,
906
- order,
907
- queryHash,
908
- after: orderKey(lastEvent),
909
- snapshot: snapshotFiles.map(({ id, size }) => ({ id, size }))
910
- }) } : {},
1124
+ ...lastEvent && pageEvents.length < remainingCount ? {
1125
+ nextCursor: encodeCursor({
1126
+ version: 1,
1127
+ order,
1128
+ queryHash,
1129
+ after: orderKey(lastEvent),
1130
+ snapshot: snapshotFiles.map(({ id, size }) => ({ id, size }))
1131
+ })
1132
+ } : {},
911
1133
  scannedEvents,
912
1134
  sourceFiles: snapshotFiles.length,
913
1135
  invalidLines
@@ -975,7 +1197,9 @@ var ChronicleQueryEngine = class _ChronicleQueryEngine {
975
1197
  let frontier = [...selected.values()];
976
1198
  const depthLimit = Math.max(0, Math.min(hops, 10));
977
1199
  for (let depth = 0; depth < depthLimit && frontier.length > 0 && selected.size < nodeLimit; depth++) {
978
- const frontierKeys = new Set(frontier.flatMap((event) => relationKeys(event).map((relation) => relation.key)));
1200
+ const frontierKeys = new Set(
1201
+ frontier.flatMap((event) => relationKeys(event).map((relation) => relation.key))
1202
+ );
979
1203
  const next = [];
980
1204
  for await (const event of streamEvents(this.partitionFiles)) {
981
1205
  if (selected.has(event.eventId)) continue;
@@ -988,22 +1212,30 @@ var ChronicleQueryEngine = class _ChronicleQueryEngine {
988
1212
  }
989
1213
  const nodes = [...selected.values()].sort(compareEvents);
990
1214
  const byKey = /* @__PURE__ */ new Map();
991
- for (const node of nodes) for (const relation of relationKeys(node)) {
992
- const related = byKey.get(relation.key) ?? [];
993
- related.push(node);
994
- byKey.set(relation.key, related);
995
- }
1215
+ for (const node of nodes)
1216
+ for (const relation of relationKeys(node)) {
1217
+ const related = byKey.get(relation.key) ?? [];
1218
+ related.push(node);
1219
+ byKey.set(relation.key, related);
1220
+ }
996
1221
  const edges = [];
997
1222
  const seen = /* @__PURE__ */ new Set();
998
- for (const node of nodes) for (const relation of relationKeys(node)) for (const candidate of byKey.get(relation.key) ?? []) {
999
- if (candidate.eventId === node.eventId) continue;
1000
- const [from, to] = compareEvents(node, candidate) <= 0 ? [node, candidate] : [candidate, node];
1001
- const id = `${from.eventId}:${to.eventId}:${relation.kind}`;
1002
- if (!seen.has(id)) {
1003
- seen.add(id);
1004
- edges.push({ from: from.eventId, to: to.eventId, kind: relation.kind, confidence: relation.confidence });
1005
- }
1006
- }
1223
+ for (const node of nodes)
1224
+ for (const relation of relationKeys(node))
1225
+ for (const candidate of byKey.get(relation.key) ?? []) {
1226
+ if (candidate.eventId === node.eventId) continue;
1227
+ const [from, to] = compareEvents(node, candidate) <= 0 ? [node, candidate] : [candidate, node];
1228
+ const id = `${from.eventId}:${to.eventId}:${relation.kind}`;
1229
+ if (!seen.has(id)) {
1230
+ seen.add(id);
1231
+ edges.push({
1232
+ from: from.eventId,
1233
+ to: to.eventId,
1234
+ kind: relation.kind,
1235
+ confidence: relation.confidence
1236
+ });
1237
+ }
1238
+ }
1007
1239
  return { nodes, edges, truncated: seedCount > nodeLimit || selected.size >= nodeLimit };
1008
1240
  }
1009
1241
  };
@@ -1089,47 +1321,69 @@ function createSummaryAccumulator() {
1089
1321
  escalations: 0,
1090
1322
  failures: 0,
1091
1323
  cancellations: 0,
1092
- families: { llm: 0, agent: 0, tool: 0, file: 0, memory: 0, task: 0, decision: 0, runtime: 0, finding: 0 },
1093
- failuresByFamily: { llm: 0, agent: 0, tool: 0, file: 0, memory: 0, task: 0, decision: 0, runtime: 0, finding: 0 }
1324
+ families: {
1325
+ llm: 0,
1326
+ agent: 0,
1327
+ tool: 0,
1328
+ file: 0,
1329
+ memory: 0,
1330
+ task: 0,
1331
+ decision: 0,
1332
+ runtime: 0,
1333
+ finding: 0
1334
+ },
1335
+ failuresByFamily: {
1336
+ llm: 0,
1337
+ agent: 0,
1338
+ tool: 0,
1339
+ file: 0,
1340
+ memory: 0,
1341
+ task: 0,
1342
+ decision: 0,
1343
+ runtime: 0,
1344
+ finding: 0
1345
+ }
1094
1346
  };
1095
1347
  }
1096
1348
  function updateSummary(acc, event) {
1097
1349
  const family = signalFamily(event);
1098
1350
  acc.families[family]++;
1099
1351
  if (isTerminalFailure(event)) acc.failuresByFamily[family]++;
1100
- if (event.correlation.logicalRequestId) acc.logicalRequestIds.add(event.correlation.logicalRequestId);
1352
+ if (event.correlation.logicalRequestId)
1353
+ acc.logicalRequestIds.add(event.correlation.logicalRequestId);
1101
1354
  if (event.runtime?.providerId) acc.providers.add(event.runtime.providerId);
1102
1355
  if (event.runtime?.modelId) acc.models.add(event.runtime.modelId);
1103
1356
  if (event.eventType === "provider.attempt.started") acc.modelAttempts++;
1104
1357
  else if (event.eventType === "provider.attempt.completed") {
1105
1358
  acc.completedAttempts++;
1106
- acc.inputTokens += numberAt(event, "usage.input");
1107
- acc.outputTokens += numberAt(event, "usage.output");
1108
- acc.cacheReadTokens += numberAt(event, "usage.cacheRead");
1109
- acc.cacheWriteTokens += numberAt(event, "usage.cacheWrite");
1110
- const dur = durationMs(event);
1359
+ acc.inputTokens += numberAt2(event, "usage.input");
1360
+ acc.outputTokens += numberAt2(event, "usage.output");
1361
+ acc.cacheReadTokens += numberAt2(event, "usage.cacheRead");
1362
+ acc.cacheWriteTokens += numberAt2(event, "usage.cacheWrite");
1363
+ const dur = durationMs2(event);
1111
1364
  if (dur > 0) acc.providerDurations.push(dur);
1112
1365
  } else if (event.eventType === "provider.attempt.failed") {
1113
1366
  acc.failedAttempts++;
1114
1367
  if (event.attributes?.retryScheduled === true) acc.scheduledRetries++;
1115
- const dur = durationMs(event);
1368
+ const dur = durationMs2(event);
1116
1369
  if (dur > 0) acc.providerDurations.push(dur);
1117
1370
  } else if (event.eventType === "provider.fallback") acc.fallbacks++;
1118
1371
  else if (event.eventType === "tool.started") acc.toolCalls++;
1119
1372
  else if (event.eventType === "tool.executed") {
1120
1373
  acc.completedTools++;
1121
- const dur = durationMs(event);
1374
+ const dur = durationMs2(event);
1122
1375
  if (dur > 0) acc.toolDurations.push(dur);
1123
1376
  } else if (event.eventType === "tool.failed") {
1124
1377
  acc.failedTools++;
1125
- const dur = durationMs(event);
1378
+ const dur = durationMs2(event);
1126
1379
  if (dur > 0) acc.toolDurations.push(dur);
1127
1380
  } else if (event.eventType === "process.started") acc.processes++;
1128
- else if (event.eventType === "process.completed" && event.outcome === "failure") acc.failedProcesses++;
1381
+ else if (event.eventType === "process.completed" && event.outcome === "failure")
1382
+ acc.failedProcesses++;
1129
1383
  else if (event.eventType === "decision.requested") acc.decisions++;
1130
1384
  else if (event.eventType === "decision.escalated") acc.escalations++;
1131
- if (event.eventType === "token.accounted") {
1132
- const cost = readPath(event.attributes ?? {}, "cost.total");
1385
+ if (event.eventType === "token.accounted" || event.eventType === "subagent.token_accounted") {
1386
+ const cost = readPath2(event.attributes ?? {}, "cost.total");
1133
1387
  if (typeof cost === "number" && Number.isFinite(cost)) {
1134
1388
  const key = scopeKey(event);
1135
1389
  const existing = acc.costByScope.get(key);
@@ -1187,10 +1441,16 @@ function finalizeSummary(acc) {
1187
1441
  }
1188
1442
  Object.defineProperty(ChronicleQueryEngine.prototype, "partitionFiles", {
1189
1443
  get() {
1190
- throw new Error("ChronicleQueryEngine no longer loads events on construction. Use async query().");
1444
+ throw new Error(
1445
+ "ChronicleQueryEngine no longer loads events on construction. Use async query()."
1446
+ );
1191
1447
  },
1192
1448
  set(_val) {
1193
- Object.defineProperty(this, "partitionFiles", { value: _val, writable: false, configurable: false });
1449
+ Object.defineProperty(this, "partitionFiles", {
1450
+ value: _val,
1451
+ writable: false,
1452
+ configurable: false
1453
+ });
1194
1454
  }
1195
1455
  });
1196
1456
  async function findChroniclePartitions(root) {
@@ -1214,11 +1474,11 @@ async function findPartitions(root) {
1214
1474
  await visit(root);
1215
1475
  return result.sort(comparePartitionPaths);
1216
1476
  }
1217
- function numberAt(event, dotPath) {
1218
- const value = readPath(event.attributes ?? {}, dotPath);
1477
+ function numberAt2(event, dotPath) {
1478
+ const value = readPath2(event.attributes ?? {}, dotPath);
1219
1479
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
1220
1480
  }
1221
- function durationMs(event) {
1481
+ function durationMs2(event) {
1222
1482
  const value = Number(event.durationNs ?? 0) / 1e6;
1223
1483
  return Number.isFinite(value) ? value : 0;
1224
1484
  }
@@ -1233,23 +1493,29 @@ function scopeKey(event) {
1233
1493
  }
1234
1494
  function signalFamily(event) {
1235
1495
  if (/^(?:decision|brain|permission)\./.test(event.eventType)) return "decision";
1236
- if (event.resource?.kind === "file" || event.resource?.kind === "symbol" || /^(?:file|worktree)\./.test(event.eventType)) return "file";
1496
+ if (event.resource?.kind === "file" || event.resource?.kind === "symbol" || /^(?:file|worktree)\./.test(event.eventType))
1497
+ return "file";
1237
1498
  if (/^(?:provider|token|context|ctx|compaction)\./.test(event.eventType)) return "llm";
1238
1499
  if (/^(?:agent|subagent|delegate|fleet|concurrency)\./.test(event.eventType)) return "agent";
1239
1500
  if (/^(?:tool|process|mcp|network)\./.test(event.eventType)) return "tool";
1240
1501
  if (/^(?:memory|storage|trust)\./.test(event.eventType)) return "memory";
1241
- if (/^(?:sdd|task|kanban|checkpoint|session|iteration|in_flight)\./.test(event.eventType)) return "task";
1502
+ if (/^(?:sdd|task|kanban|checkpoint|session|iteration|in_flight)\./.test(event.eventType))
1503
+ return "task";
1242
1504
  if (/^(?:finding|review)\./.test(event.eventType)) return "finding";
1243
1505
  return "runtime";
1244
1506
  }
1245
1507
  function isTerminalFailure(event) {
1246
- if (event.eventType === "provider.attempt.failed") return event.attributes?.retryScheduled !== true;
1247
- return event.eventType === "tool.failed" || event.eventType === "process.completed" && event.outcome === "failure" || /^(?:agent\.run\.error|sdd\.task\.failed|compaction\.failed|network\.request\.failed)$/.test(event.eventType);
1508
+ if (event.eventType === "provider.attempt.failed")
1509
+ return event.attributes?.retryScheduled !== true;
1510
+ return event.eventType === "tool.failed" || event.eventType === "process.completed" && event.outcome === "failure" || /^(?:agent\.run\.error|sdd\.task\.failed|compaction\.failed|network\.request\.failed)$/.test(
1511
+ event.eventType
1512
+ );
1248
1513
  }
1249
1514
  function relationKeys(event) {
1250
1515
  const result = [];
1251
1516
  const add = (kind, value, confidence) => {
1252
- if (typeof value === "string" && value) result.push({ key: `${kind}:${value}`, kind, confidence });
1517
+ if (typeof value === "string" && value)
1518
+ result.push({ key: `${kind}:${value}`, kind, confidence });
1253
1519
  };
1254
1520
  add("trace", event.correlation.traceId, "correlated");
1255
1521
  add("tool_call", event.correlation.toolCallId, "explicit");
@@ -1269,7 +1535,8 @@ function relationKeys(event) {
1269
1535
  if (typeof resource?.id === "string") add("resource_lineage", resource.id, "inferred");
1270
1536
  }
1271
1537
  }
1272
- if (event.correlation.parentSpanId) add("parent_span", event.correlation.parentSpanId, "explicit");
1538
+ if (event.correlation.parentSpanId)
1539
+ add("parent_span", event.correlation.parentSpanId, "explicit");
1273
1540
  add("parent_span", event.correlation.spanId, "explicit");
1274
1541
  return result;
1275
1542
  }
@@ -1279,18 +1546,25 @@ function matches(event, query) {
1279
1546
  if (query.outcomes && (!event.outcome || !query.outcomes.includes(event.outcome))) return false;
1280
1547
  const occurredAt = event.occurredAt ?? event.observedAt;
1281
1548
  if (query.from && occurredAt < query.from || query.to && occurredAt > query.to) return false;
1282
- if (!equal(query.projectId, event.scope.projectId) || !equal(query.sessionId, event.scope.sessionId)) return false;
1283
- if (!equal(query.agentId, event.scope.agentId) || !equal(query.taskId, event.scope.taskId)) return false;
1284
- if (!equal(query.providerId, event.runtime?.providerId) || !equal(query.modelId, event.runtime?.modelId)) return false;
1285
- if (!equal(query.traceId, event.correlation.traceId) || !equal(query.logicalRequestId, event.correlation.logicalRequestId)) return false;
1549
+ if (!equal(query.projectId, event.scope.projectId) || !equal(query.sessionId, event.scope.sessionId))
1550
+ return false;
1551
+ if (!equal(query.agentId, event.scope.agentId) || !equal(query.taskId, event.scope.taskId))
1552
+ return false;
1553
+ if (!equal(query.providerId, event.runtime?.providerId) || !equal(query.modelId, event.runtime?.modelId))
1554
+ return false;
1555
+ if (!equal(query.traceId, event.correlation.traceId) || !equal(query.logicalRequestId, event.correlation.logicalRequestId))
1556
+ return false;
1286
1557
  if (!equal(query.promptManifestId, event.correlation.promptManifestId)) return false;
1287
- if (!equal(query.attemptId, event.correlation.attemptId) || !equal(query.toolCallId, event.correlation.toolCallId)) return false;
1288
- if (!equal(query.resourceKind, event.resource?.kind) || !equal(query.resourceId, event.resource?.id)) return false;
1558
+ if (!equal(query.attemptId, event.correlation.attemptId) || !equal(query.toolCallId, event.correlation.toolCallId))
1559
+ return false;
1560
+ if (!equal(query.resourceKind, event.resource?.kind) || !equal(query.resourceId, event.resource?.id))
1561
+ return false;
1289
1562
  if (query.path && normalize(event.resource?.path) !== normalize(query.path)) return false;
1290
1563
  if (query.line !== void 0 && !lineContains(event, query.line)) return false;
1291
1564
  if (query.tags && !objectContains(event.tags, query.tags)) return false;
1292
1565
  if (query.attributes && !objectContains(event.attributes, query.attributes)) return false;
1293
- if (query.text && !JSON.stringify(event).toLocaleLowerCase().includes(query.text.toLocaleLowerCase())) return false;
1566
+ if (query.text && !JSON.stringify(event).toLocaleLowerCase().includes(query.text.toLocaleLowerCase()))
1567
+ return false;
1294
1568
  return true;
1295
1569
  }
1296
1570
  function equal(expected, actual) {
@@ -1305,10 +1579,15 @@ function lineContains(event, line) {
1305
1579
  return start !== void 0 && end !== void 0 && line >= start && line <= end;
1306
1580
  }
1307
1581
  function objectContains(actual, expected) {
1308
- return Boolean(actual && Object.entries(expected).every(([key, value]) => deepEqual(readPath(actual, key), value)));
1582
+ return Boolean(
1583
+ actual && Object.entries(expected).every(([key, value]) => deepEqual(readPath2(actual, key), value))
1584
+ );
1309
1585
  }
1310
- function readPath(value, key) {
1311
- return key.split(".").reduce((current, part) => current && typeof current === "object" ? current[part] : void 0, value);
1586
+ function readPath2(value, key) {
1587
+ return key.split(".").reduce(
1588
+ (current, part) => current && typeof current === "object" ? current[part] : void 0,
1589
+ value
1590
+ );
1312
1591
  }
1313
1592
  function deepEqual(left, right) {
1314
1593
  return JSON.stringify(left) === JSON.stringify(right);
@@ -1354,17 +1633,21 @@ function decodeCursor(encoded, order, queryHash) {
1354
1633
  }
1355
1634
  return parsed;
1356
1635
  } catch (error) {
1357
- throw new Error(`Invalid Chronicle cursor: ${error instanceof Error ? error.message : String(error)}`);
1636
+ throw new Error(
1637
+ `Invalid Chronicle cursor: ${error instanceof Error ? error.message : String(error)}`
1638
+ );
1358
1639
  }
1359
1640
  }
1360
1641
  function isCursor(value) {
1361
1642
  if (!value || typeof value !== "object") return false;
1362
1643
  const cursor = value;
1363
1644
  const after = cursor.after;
1364
- if (cursor.version !== 1 || cursor.order !== "asc" && cursor.order !== "desc" || typeof cursor.queryHash !== "string" || !after || typeof after.occurredAt !== "string" || typeof after.persistedAt !== "string" || !Number.isSafeInteger(after.sequence) || typeof after.eventId !== "string" || !Array.isArray(cursor.snapshot) || cursor.snapshot.length > MAX_CURSOR_SNAPSHOT_ENTRIES) return false;
1645
+ if (cursor.version !== 1 || cursor.order !== "asc" && cursor.order !== "desc" || typeof cursor.queryHash !== "string" || !after || typeof after.occurredAt !== "string" || typeof after.persistedAt !== "string" || !Number.isSafeInteger(after.sequence) || typeof after.eventId !== "string" || !Array.isArray(cursor.snapshot) || cursor.snapshot.length > MAX_CURSOR_SNAPSHOT_ENTRIES)
1646
+ return false;
1365
1647
  const snapshotIds = /* @__PURE__ */ new Set();
1366
1648
  for (const entry of cursor.snapshot) {
1367
- if (!entry || typeof entry.id !== "string" || !entry.id || !Number.isSafeInteger(entry.size) || entry.size < 0 || snapshotIds.has(entry.id)) return false;
1649
+ if (!entry || typeof entry.id !== "string" || !entry.id || !Number.isSafeInteger(entry.size) || entry.size < 0 || snapshotIds.has(entry.id))
1650
+ return false;
1368
1651
  snapshotIds.add(entry.id);
1369
1652
  }
1370
1653
  return true;
@@ -1373,29 +1656,33 @@ async function captureSnapshot(files) {
1373
1656
  if (files.length > MAX_CURSOR_SNAPSHOT_ENTRIES) {
1374
1657
  throw new Error("Chronicle snapshot contains too many partitions");
1375
1658
  }
1376
- return Promise.all(files.map(async (file) => {
1377
- let size = 0;
1378
- try {
1379
- size = (await fs3.stat(file)).size;
1380
- } catch {
1381
- }
1382
- return { file, id: fileId(file), size };
1383
- }));
1659
+ return Promise.all(
1660
+ files.map(async (file) => {
1661
+ let size = 0;
1662
+ try {
1663
+ size = (await fs3.stat(file)).size;
1664
+ } catch {
1665
+ }
1666
+ return { file, id: fileId(file), size };
1667
+ })
1668
+ );
1384
1669
  }
1385
1670
  async function resolveSnapshotFiles(files, snapshot) {
1386
1671
  const currentFiles = new Map(files.map((file) => [fileId(file), file]));
1387
- return Promise.all(snapshot.map(async (entry) => {
1388
- const file = currentFiles.get(entry.id);
1389
- if (!file) throw new Error("Chronicle cursor snapshot has expired");
1390
- let currentSize;
1391
- try {
1392
- currentSize = (await fs3.stat(file)).size;
1393
- } catch {
1394
- throw new Error("Chronicle cursor snapshot has expired");
1395
- }
1396
- if (currentSize < entry.size) throw new Error("Chronicle cursor snapshot has expired");
1397
- return { file, ...entry };
1398
- }));
1672
+ return Promise.all(
1673
+ snapshot.map(async (entry) => {
1674
+ const file = currentFiles.get(entry.id);
1675
+ if (!file) throw new Error("Chronicle cursor snapshot has expired");
1676
+ let currentSize;
1677
+ try {
1678
+ currentSize = (await fs3.stat(file)).size;
1679
+ } catch {
1680
+ throw new Error("Chronicle cursor snapshot has expired");
1681
+ }
1682
+ if (currentSize < entry.size) throw new Error("Chronicle cursor snapshot has expired");
1683
+ return { file, ...entry };
1684
+ })
1685
+ );
1399
1686
  }
1400
1687
  function fileId(file) {
1401
1688
  return createHash3("sha256").update(path5.resolve(file), "utf8").digest("base64url");
@@ -1444,14 +1731,17 @@ function isResource(value) {
1444
1731
  "network",
1445
1732
  "artifact",
1446
1733
  "other"
1447
- ].includes(String(value.kind)) || typeof value.id !== "string") return false;
1734
+ ].includes(String(value.kind)) || typeof value.id !== "string")
1735
+ return false;
1448
1736
  return optionalStrings(value, ["path", "contentHashBefore", "contentHashAfter"]) && optionalFiniteNumbers(value, ["lineStart", "lineEnd"]);
1449
1737
  }
1450
1738
  function optionalStrings(value, keys) {
1451
1739
  return keys.every((key) => value[key] === void 0 || typeof value[key] === "string");
1452
1740
  }
1453
1741
  function optionalFiniteNumbers(value, keys) {
1454
- return keys.every((key) => value[key] === void 0 || typeof value[key] === "number" && Number.isFinite(value[key]));
1742
+ return keys.every(
1743
+ (key) => value[key] === void 0 || typeof value[key] === "number" && Number.isFinite(value[key])
1744
+ );
1455
1745
  }
1456
1746
  function isStringRecord(value) {
1457
1747
  return isRecord(value) && Object.values(value).every((entry) => typeof entry === "string");
@@ -1614,21 +1904,21 @@ import { randomUUID as randomUUID2 } from "node:crypto";
1614
1904
  import * as path6 from "node:path";
1615
1905
 
1616
1906
  // src/chronicle/sqlite-journal-schema.ts
1617
- import { loadRuntimeDatabaseSync } from "@wrongstack/persistence";
1907
+ import { loadRuntimeDatabaseSync as loadRuntimeDatabaseSync2 } from "@wrongstack/persistence";
1618
1908
  var CHRONICLE_SQLITE_FILE = "chronicle.sqlite";
1619
1909
  var LEGACY_JSONL_MIGRATION_KEY = "legacy-jsonl-v1";
1620
1910
  var LEGACY_JSONL_QUARANTINE_KEY = "legacy-jsonl-v1:quarantine";
1621
1911
  var LEGACY_JSONL_BOUNDARY_KEY = "legacy-jsonl-v1:boundary";
1622
- var SCHEMA_VERSION = 3;
1623
- var Ctor;
1624
- function loadDatabaseSync() {
1625
- if (Ctor) return Ctor;
1626
- if (Ctor === null) throw new Error("SQLite is unavailable in this runtime");
1912
+ var SCHEMA_VERSION2 = 3;
1913
+ var Ctor2;
1914
+ function loadDatabaseSync2() {
1915
+ if (Ctor2) return Ctor2;
1916
+ if (Ctor2 === null) throw new Error("SQLite is unavailable in this runtime");
1627
1917
  try {
1628
- Ctor = withSqliteExperimentalWarningSuppressed(loadRuntimeDatabaseSync);
1629
- return Ctor;
1918
+ Ctor2 = withSqliteExperimentalWarningSuppressed(loadRuntimeDatabaseSync2);
1919
+ return Ctor2;
1630
1920
  } catch (error) {
1631
- Ctor = null;
1921
+ Ctor2 = null;
1632
1922
  throw new Error(
1633
1923
  "The Chronicle journal needs node:sqlite (Node >= 22.5) or bun:sqlite: " + (error instanceof Error ? error.message : String(error))
1634
1924
  );
@@ -1702,8 +1992,8 @@ function ensureChronicleSchema(db) {
1702
1992
  db.exec("ALTER TABLE events ADD COLUMN prompt_manifest_id TEXT");
1703
1993
  }
1704
1994
  db.exec("CREATE INDEX IF NOT EXISTS events_prompt_manifest ON events(prompt_manifest_id)");
1705
- if (version !== SCHEMA_VERSION) {
1706
- db.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`);
1995
+ if (version !== SCHEMA_VERSION2) {
1996
+ db.exec(`PRAGMA user_version = ${SCHEMA_VERSION2}`);
1707
1997
  }
1708
1998
  }
1709
1999
 
@@ -2011,10 +2301,12 @@ var ChronicleSqliteJournal = class {
2011
2301
  this.maxEvents = options.maxEvents;
2012
2302
  this.retentionCheckIntervalMs = options.retentionCheckIntervalMs ?? 60 * 60 * 1e3;
2013
2303
  this.trimSlack = this.maxEvents === void 0 ? 0 : Math.min(MAX_TRIM_SLACK_EVENTS, Math.floor(this.maxEvents * TRIM_SLACK_RATIO));
2014
- const Database = loadDatabaseSync();
2304
+ const Database = loadDatabaseSync2();
2015
2305
  this.db = new Database(this.dbPath);
2016
2306
  this.db.exec("PRAGMA journal_mode = WAL");
2017
- this.db.exec("PRAGMA synchronous = FULL");
2307
+ this.db.exec(
2308
+ options.durability === "full" ? "PRAGMA synchronous = FULL" : "PRAGMA synchronous = NORMAL"
2309
+ );
2018
2310
  this.db.exec(`PRAGMA wal_autocheckpoint = ${WAL_AUTOCHECKPOINT_PAGES}`);
2019
2311
  this.db.exec(`PRAGMA journal_size_limit = ${WAL_SIZE_LIMIT_BYTES}`);
2020
2312
  ensureChronicleSchema(this.db);
@@ -2415,186 +2707,6 @@ var ChronicleSqliteJournal = class {
2415
2707
  }
2416
2708
  };
2417
2709
 
2418
- // src/chronicle/metrics-schema.ts
2419
- import { loadRuntimeDatabaseSync as loadRuntimeDatabaseSync2 } from "@wrongstack/persistence";
2420
- var SCHEMA_VERSION2 = 4;
2421
- var READ_CHUNK_BYTES = 1024 * 1024;
2422
- var SQLITE_SOURCE_PREFIX = "sqlite:";
2423
- var SQLITE_INGEST_BATCH = 2e3;
2424
- var EMPTY_FAMILIES = {
2425
- llm: 0,
2426
- agent: 0,
2427
- tool: 0,
2428
- file: 0,
2429
- memory: 0,
2430
- task: 0,
2431
- decision: 0,
2432
- runtime: 0,
2433
- finding: 0
2434
- };
2435
- var Ctor2;
2436
- function loadDatabaseSync2() {
2437
- if (Ctor2) return Ctor2;
2438
- if (Ctor2 === null) throw new Error("SQLite is unavailable in this runtime");
2439
- try {
2440
- Ctor2 = withSqliteExperimentalWarningSuppressed(loadRuntimeDatabaseSync2);
2441
- return Ctor2;
2442
- } catch (error) {
2443
- Ctor2 = null;
2444
- throw new Error(
2445
- "Chronicle metrics need node:sqlite (Node >= 22.5) or bun:sqlite: " + (error instanceof Error ? error.message : String(error))
2446
- );
2447
- }
2448
- }
2449
- function isChronicleMetricsAvailable() {
2450
- try {
2451
- loadDatabaseSync2();
2452
- return true;
2453
- } catch {
2454
- return false;
2455
- }
2456
- }
2457
- function ensureMetricsSchema(db) {
2458
- const version = db.prepare("PRAGMA user_version").get().user_version;
2459
- if (version !== 0 && version !== SCHEMA_VERSION2) {
2460
- db.exec(
2461
- "DROP TABLE IF EXISTS ingest_state; DROP TABLE IF EXISTS provider_daily;DROP TABLE IF EXISTS task_outcomes; DROP TABLE IF EXISTS file_lineage;DROP TABLE IF EXISTS token_cost; DROP TABLE IF EXISTS daily_counters;DROP TABLE IF EXISTS family_daily; DROP TABLE IF EXISTS agent_daily;DROP TABLE IF EXISTS logical_request_daily; DROP TABLE IF EXISTS file_seen_daily;"
2462
- );
2463
- }
2464
- db.exec(`
2465
- CREATE TABLE IF NOT EXISTS ingest_state (
2466
- file TEXT PRIMARY KEY,
2467
- bytes INTEGER NOT NULL
2468
- );
2469
- CREATE TABLE IF NOT EXISTS provider_daily (
2470
- day TEXT NOT NULL,
2471
- provider_id TEXT NOT NULL,
2472
- model_id TEXT NOT NULL,
2473
- attempts INTEGER NOT NULL DEFAULT 0,
2474
- completed INTEGER NOT NULL DEFAULT 0,
2475
- failed INTEGER NOT NULL DEFAULT 0,
2476
- retries INTEGER NOT NULL DEFAULT 0,
2477
- fallbacks INTEGER NOT NULL DEFAULT 0,
2478
- input_tokens INTEGER NOT NULL DEFAULT 0,
2479
- output_tokens INTEGER NOT NULL DEFAULT 0,
2480
- cache_read_tokens INTEGER NOT NULL DEFAULT 0,
2481
- cache_write_tokens INTEGER NOT NULL DEFAULT 0,
2482
- duration_ms_total REAL NOT NULL DEFAULT 0,
2483
- duration_ms_max REAL NOT NULL DEFAULT 0,
2484
- duration_count INTEGER NOT NULL DEFAULT 0,
2485
- PRIMARY KEY (day, provider_id, model_id)
2486
- );
2487
- CREATE TABLE IF NOT EXISTS task_outcomes (
2488
- task_id TEXT PRIMARY KEY,
2489
- run_id TEXT NOT NULL DEFAULT '',
2490
- board_id TEXT NOT NULL DEFAULT '',
2491
- session_id TEXT NOT NULL DEFAULT '',
2492
- agent_id TEXT NOT NULL DEFAULT '',
2493
- status TEXT NOT NULL DEFAULT 'started',
2494
- started_at TEXT,
2495
- ended_at TEXT,
2496
- duration_ms REAL,
2497
- retries INTEGER NOT NULL DEFAULT 0,
2498
- verification_failures INTEGER NOT NULL DEFAULT 0
2499
- );
2500
- CREATE TABLE IF NOT EXISTS file_lineage (
2501
- event_id TEXT PRIMARY KEY,
2502
- path TEXT NOT NULL,
2503
- path_key TEXT NOT NULL,
2504
- operation TEXT NOT NULL,
2505
- occurred_at TEXT NOT NULL,
2506
- session_id TEXT NOT NULL DEFAULT '',
2507
- agent_id TEXT NOT NULL DEFAULT '',
2508
- task_id TEXT NOT NULL DEFAULT '',
2509
- board_id TEXT NOT NULL DEFAULT '',
2510
- run_id TEXT NOT NULL DEFAULT '',
2511
- tool_name TEXT NOT NULL DEFAULT '',
2512
- provider_id TEXT NOT NULL DEFAULT '',
2513
- model_id TEXT NOT NULL DEFAULT '',
2514
- logical_request_id TEXT NOT NULL DEFAULT '',
2515
- prompt_manifest_id TEXT NOT NULL DEFAULT '',
2516
- provenance_confidence TEXT NOT NULL DEFAULT 'unknown',
2517
- source TEXT NOT NULL DEFAULT ''
2518
- );
2519
- CREATE INDEX IF NOT EXISTS idx_file_lineage_path ON file_lineage(path_key, occurred_at);
2520
- CREATE INDEX IF NOT EXISTS idx_file_lineage_task ON file_lineage(task_id);
2521
- CREATE TABLE IF NOT EXISTS token_cost (
2522
- scope_key TEXT PRIMARY KEY,
2523
- day TEXT NOT NULL,
2524
- occurred_at TEXT NOT NULL,
2525
- sequence INTEGER NOT NULL,
2526
- cost REAL NOT NULL
2527
- );
2528
- CREATE TABLE IF NOT EXISTS daily_counters (
2529
- day TEXT PRIMARY KEY,
2530
- tool_calls INTEGER NOT NULL DEFAULT 0,
2531
- completed_tools INTEGER NOT NULL DEFAULT 0,
2532
- failed_tools INTEGER NOT NULL DEFAULT 0,
2533
- tool_duration_ms_total REAL NOT NULL DEFAULT 0,
2534
- tool_duration_ms_max REAL NOT NULL DEFAULT 0,
2535
- tool_duration_count INTEGER NOT NULL DEFAULT 0,
2536
- processes INTEGER NOT NULL DEFAULT 0,
2537
- failed_processes INTEGER NOT NULL DEFAULT 0,
2538
- file_events_all INTEGER NOT NULL DEFAULT 0,
2539
- decisions INTEGER NOT NULL DEFAULT 0,
2540
- escalations INTEGER NOT NULL DEFAULT 0,
2541
- agent_events INTEGER NOT NULL DEFAULT 0,
2542
- failures INTEGER NOT NULL DEFAULT 0,
2543
- cancellations INTEGER NOT NULL DEFAULT 0
2544
- );
2545
- CREATE TABLE IF NOT EXISTS family_daily (
2546
- day TEXT NOT NULL,
2547
- family TEXT NOT NULL,
2548
- count INTEGER NOT NULL DEFAULT 0,
2549
- failure_count INTEGER NOT NULL DEFAULT 0,
2550
- PRIMARY KEY (day, family)
2551
- );
2552
- CREATE TABLE IF NOT EXISTS agent_daily (day TEXT NOT NULL, agent_id TEXT NOT NULL, PRIMARY KEY (day, agent_id));
2553
- CREATE TABLE IF NOT EXISTS logical_request_daily (day TEXT NOT NULL, logical_request_id TEXT NOT NULL, PRIMARY KEY (day, logical_request_id));
2554
- CREATE TABLE IF NOT EXISTS file_seen_daily (day TEXT NOT NULL, path_key TEXT NOT NULL, PRIMARY KEY (day, path_key));
2555
- PRAGMA user_version = ${SCHEMA_VERSION2};
2556
- `);
2557
- }
2558
- function eventDay(event) {
2559
- return (event.occurredAt ?? event.observedAt).slice(0, 10);
2560
- }
2561
- function durationMs2(event) {
2562
- const value = Number(event.durationNs ?? 0) / 1e6;
2563
- return Number.isFinite(value) && value > 0 ? value : 0;
2564
- }
2565
- function numberOrDuration(event, attributes) {
2566
- const explicit = attributes.durationMs;
2567
- if (typeof explicit === "number" && Number.isFinite(explicit)) return explicit;
2568
- return durationMs2(event);
2569
- }
2570
- function numberAt2(event, dotPath) {
2571
- const value = readPath2(event.attributes ?? {}, dotPath);
2572
- return typeof value === "number" && Number.isFinite(value) ? value : 0;
2573
- }
2574
- function readPath2(value, key) {
2575
- return key.split(".").reduce(
2576
- (current, part) => current && typeof current === "object" ? current[part] : void 0,
2577
- value
2578
- );
2579
- }
2580
- function stringAt(record, key) {
2581
- const value = record[key];
2582
- return typeof value === "string" && value.length > 0 ? value : void 0;
2583
- }
2584
- function asString(value) {
2585
- return typeof value === "string" && value.length > 0 ? value : void 0;
2586
- }
2587
- function clampLimit(limit, fallback) {
2588
- if (typeof limit !== "number" || !Number.isFinite(limit) || limit <= 0) return fallback;
2589
- return Math.min(Math.floor(limit), 1e4);
2590
- }
2591
- function normalizeKey(value) {
2592
- return value.replaceAll("\\", "/");
2593
- }
2594
- function normalizePathKey(value) {
2595
- return value.replaceAll("\\", "/").replace(/^\.\//, "").toLowerCase();
2596
- }
2597
-
2598
2710
  // src/chronicle/metrics-store.ts
2599
2711
  import * as path8 from "node:path";
2600
2712
 
@@ -2638,7 +2750,7 @@ var ChronicleMetricsIngester = class {
2638
2750
  const journalPath = path7.join(this.directory, CHRONICLE_SQLITE_FILE);
2639
2751
  let source = null;
2640
2752
  try {
2641
- source = new (loadDatabaseSync2())(journalPath, { readOnly: true });
2753
+ source = new (loadDatabaseSync())(journalPath, { readOnly: true });
2642
2754
  } catch {
2643
2755
  }
2644
2756
  try {
@@ -2731,7 +2843,7 @@ var ChronicleMetricsIngester = class {
2731
2843
  }
2732
2844
  rebuildFromSqliteJournal(source, result) {
2733
2845
  this.db.exec(
2734
- "DELETE FROM ingest_state; DELETE FROM provider_daily; DELETE FROM task_outcomes; DELETE FROM file_lineage; DELETE FROM token_cost; DELETE FROM daily_counters; DELETE FROM family_daily; DELETE FROM agent_daily; DELETE FROM logical_request_daily; DELETE FROM file_seen_daily;"
2846
+ "DELETE FROM ingest_state; DELETE FROM provider_daily; DELETE FROM task_outcomes; DELETE FROM file_lineage; DELETE FROM token_cost; DELETE FROM daily_counters; DELETE FROM family_daily; DELETE FROM agent_daily; DELETE FROM logical_request_daily; DELETE FROM file_seen_daily; DELETE FROM tool_daily;"
2735
2847
  );
2736
2848
  this.ingestSqliteJournal(source, /* @__PURE__ */ new Map(), result, true);
2737
2849
  this.ensureRebuildMarker();
@@ -2867,7 +2979,7 @@ var ChronicleMetricsIngester = class {
2867
2979
  const type = event.eventType;
2868
2980
  if (type.startsWith("provider.attempt.") || type === "provider.fallback") {
2869
2981
  this.ingestProvider(event);
2870
- } else if (type === "token.accounted") {
2982
+ } else if (type === "token.accounted" || type === "subagent.token_accounted") {
2871
2983
  this.ingestTokenCost(event);
2872
2984
  } else if (/^(?:sdd|subagent|kanban)\.task[._]/.test(type)) {
2873
2985
  this.ingestTask(event);
@@ -2903,17 +3015,29 @@ var ChronicleMetricsIngester = class {
2903
3015
  const type = event.eventType;
2904
3016
  if (type === "decision.requested") bump("decisions = decisions + 1");
2905
3017
  else if (type === "decision.escalated") bump("escalations = escalations + 1");
2906
- else if (type === "tool.started") bump("tool_calls = tool_calls + 1");
2907
- else if (type === "tool.executed" || type === "tool.failed") {
2908
- const dur = durationMs2(event);
3018
+ else if (type === "tool.started") {
3019
+ bump("tool_calls = tool_calls + 1");
3020
+ this.ingestToolDaily(event, day, "invocation", 0);
3021
+ } else if (type === "tool.executed") {
3022
+ const dur = durationMs(event);
3023
+ const durationCount = dur > 0 ? 1 : 0;
3024
+ bump(
3025
+ "completed_tools = completed_tools + 1, tool_duration_ms_total = tool_duration_ms_total + ?, tool_duration_ms_max = MAX(tool_duration_ms_max, ?), tool_duration_count = tool_duration_count + ?",
3026
+ dur,
3027
+ dur,
3028
+ durationCount
3029
+ );
3030
+ this.ingestToolDaily(event, day, "invocation", dur);
3031
+ } else if (type === "tool.failed") {
3032
+ const dur = durationMs(event);
2909
3033
  const durationCount = dur > 0 ? 1 : 0;
2910
3034
  bump(
2911
- `${type === "tool.executed" ? "completed_tools" : "failed_tools"} = ${type === "tool.executed" ? "completed_tools" : "failed_tools"} + 1,
2912
- tool_duration_ms_total = tool_duration_ms_total + ?, tool_duration_ms_max = MAX(tool_duration_ms_max, ?), tool_duration_count = tool_duration_count + ?`,
3035
+ "failed_tools = failed_tools + 1, tool_duration_ms_total = tool_duration_ms_total + ?, tool_duration_ms_max = MAX(tool_duration_ms_max, ?), tool_duration_count = tool_duration_count + ?",
2913
3036
  dur,
2914
3037
  dur,
2915
3038
  durationCount
2916
3039
  );
3040
+ this.ingestToolDaily(event, day, "failure", dur);
2917
3041
  } else if (type === "process.started") bump("processes = processes + 1");
2918
3042
  else if (type === "process.completed" && event.outcome === "failure")
2919
3043
  bump("failed_processes = failed_processes + 1");
@@ -2927,10 +3051,41 @@ var ChronicleMetricsIngester = class {
2927
3051
  }
2928
3052
  }
2929
3053
  }
3054
+ /**
3055
+ * Per-tool fold used by the auto-thinning pipeline. Distinct from
3056
+ * `daily_counters` (which is name-agnostic): keyed by `(day, tool_name)`
3057
+ * so `underusedTools()` can pick candidates without scanning the journal.
3058
+ *
3059
+ * `kind` selects which counter increments:
3060
+ * - `invocation` — `tool.started` and `tool.executed` (success)
3061
+ * - `failure` — `tool.failed` and `tool.executed` with `!ok`
3062
+ *
3063
+ * `lastInvokedAt` is the event's wall-clock at fold time, not the tool's
3064
+ * internal duration; the auto-thinning policy uses it to compute
3065
+ * "days since last use" relative to the request's anchor day.
3066
+ */
3067
+ ingestToolDaily(event, day, kind, durationMs3) {
3068
+ const toolName = stringAt(event.attributes ?? {}, "toolName");
3069
+ if (!toolName) return;
3070
+ const occurredAtMs = Date.parse(event.occurredAt ?? event.observedAt);
3071
+ const lastInvokedAt = Number.isFinite(occurredAtMs) ? occurredAtMs : Date.now();
3072
+ this.stmt("INSERT OR IGNORE INTO tool_daily (day, tool_name) VALUES (?, ?)").run(day, toolName);
3073
+ const invocations = kind === "invocation" ? 1 : 0;
3074
+ const failures = kind === "failure" ? 1 : 0;
3075
+ this.stmt(
3076
+ `UPDATE tool_daily
3077
+ SET invocations = invocations + ?,
3078
+ failures = failures + ?,
3079
+ duration_ms_total = duration_ms_total + ?,
3080
+ duration_ms_max = MAX(duration_ms_max, ?),
3081
+ last_invoked_at = MAX(COALESCE(last_invoked_at, 0), ?)
3082
+ WHERE day = ? AND tool_name = ?`
3083
+ ).run(invocations, failures, durationMs3, durationMs3, lastInvokedAt, day, toolName);
3084
+ }
2930
3085
  ingestProvider(event) {
2931
3086
  const day = eventDay(event);
2932
- const providerId = event.runtime?.providerId ?? asString(readPath2(event.attributes ?? {}, "from.providerId")) ?? "";
2933
- const modelId = event.runtime?.modelId ?? asString(readPath2(event.attributes ?? {}, "from.model")) ?? "";
3087
+ const providerId = event.runtime?.providerId ?? asString(readPath(event.attributes ?? {}, "from.providerId")) ?? "";
3088
+ const modelId = event.runtime?.modelId ?? asString(readPath(event.attributes ?? {}, "from.model")) ?? "";
2934
3089
  if (!providerId && !modelId) return;
2935
3090
  this.stmt(
2936
3091
  "INSERT OR IGNORE INTO provider_daily (day, provider_id, model_id) VALUES (?, ?, ?)"
@@ -2938,7 +3093,7 @@ var ChronicleMetricsIngester = class {
2938
3093
  const update = (sql, ...params) => this.stmt(
2939
3094
  `UPDATE provider_daily SET ${sql} WHERE day = ? AND provider_id = ? AND model_id = ?`
2940
3095
  ).run(...params, day, providerId, modelId);
2941
- const duration = durationMs2(event);
3096
+ const duration = durationMs(event);
2942
3097
  switch (event.eventType) {
2943
3098
  case "provider.attempt.started":
2944
3099
  update("attempts = attempts + 1");
@@ -2946,10 +3101,10 @@ var ChronicleMetricsIngester = class {
2946
3101
  case "provider.attempt.completed":
2947
3102
  update(
2948
3103
  "completed = completed + 1, input_tokens = input_tokens + ?, output_tokens = output_tokens + ?, cache_read_tokens = cache_read_tokens + ?, cache_write_tokens = cache_write_tokens + ?, duration_ms_total = duration_ms_total + ?, duration_ms_max = MAX(duration_ms_max, ?), duration_count = duration_count + ?",
2949
- numberAt2(event, "usage.input"),
2950
- numberAt2(event, "usage.output"),
2951
- numberAt2(event, "usage.cacheRead"),
2952
- numberAt2(event, "usage.cacheWrite"),
3104
+ numberAt(event, "usage.input"),
3105
+ numberAt(event, "usage.output"),
3106
+ numberAt(event, "usage.cacheRead"),
3107
+ numberAt(event, "usage.cacheWrite"),
2953
3108
  duration,
2954
3109
  duration,
2955
3110
  duration > 0 ? 1 : 0
@@ -2972,18 +3127,47 @@ var ChronicleMetricsIngester = class {
2972
3127
  }
2973
3128
  }
2974
3129
  ingestTokenCost(event) {
2975
- const cost = readPath2(event.attributes ?? {}, "cost.total");
2976
- if (typeof cost !== "number" || !Number.isFinite(cost)) return;
3130
+ const attributes = event.attributes ?? {};
3131
+ const cost = readPath(attributes, "cost.total");
3132
+ const usage = {
3133
+ input: numberAt(event, "usage.input"),
3134
+ output: numberAt(event, "usage.output"),
3135
+ cacheRead: numberAt(event, "usage.cacheRead"),
3136
+ cacheWrite: numberAt(event, "usage.cacheWrite")
3137
+ };
3138
+ const finiteCost = typeof cost === "number" && Number.isFinite(cost) ? cost : void 0;
3139
+ const anyTokens = usage.input > 0 || usage.output > 0 || usage.cacheRead > 0 || usage.cacheWrite > 0;
3140
+ if (finiteCost === void 0 && !anyTokens) return;
2977
3141
  const scopeKey2 = `${event.scope.projectId ?? ""}\0${event.scope.sessionId ?? ""}\0${event.scope.agentId ?? ""}`;
2978
3142
  const occurredAt = event.occurredAt ?? event.observedAt;
2979
3143
  this.stmt(
2980
- `INSERT INTO token_cost (scope_key, day, occurred_at, sequence, cost) VALUES (?, ?, ?, ?, ?)
3144
+ `INSERT INTO token_cost (
3145
+ scope_key, day, occurred_at, sequence, cost,
3146
+ input_tokens, output_tokens, cache_read_tokens, cache_write_tokens,
3147
+ provider, model
3148
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2981
3149
  ON CONFLICT(scope_key) DO UPDATE SET
2982
3150
  day = excluded.day, occurred_at = excluded.occurred_at,
2983
- sequence = excluded.sequence, cost = excluded.cost
3151
+ sequence = excluded.sequence, cost = excluded.cost,
3152
+ input_tokens = excluded.input_tokens, output_tokens = excluded.output_tokens,
3153
+ cache_read_tokens = excluded.cache_read_tokens,
3154
+ cache_write_tokens = excluded.cache_write_tokens,
3155
+ provider = excluded.provider, model = excluded.model
2984
3156
  WHERE excluded.occurred_at > token_cost.occurred_at
2985
3157
  OR (excluded.occurred_at = token_cost.occurred_at AND excluded.sequence > token_cost.sequence)`
2986
- ).run(scopeKey2, eventDay(event), occurredAt, event.sequence, cost);
3158
+ ).run(
3159
+ scopeKey2,
3160
+ eventDay(event),
3161
+ occurredAt,
3162
+ event.sequence,
3163
+ finiteCost ?? 0,
3164
+ usage.input,
3165
+ usage.output,
3166
+ usage.cacheRead,
3167
+ usage.cacheWrite,
3168
+ event.runtime?.providerId ?? stringAt(attributes, "provider") ?? "",
3169
+ event.runtime?.modelId ?? stringAt(attributes, "model") ?? ""
3170
+ );
2987
3171
  }
2988
3172
  ingestTask(event) {
2989
3173
  const attributes = event.attributes ?? {};
@@ -3079,9 +3263,11 @@ var ChronicleMetricsStore = class _ChronicleMetricsStore {
3079
3263
  constructor(directory) {
3080
3264
  this.directory = path8.resolve(directory);
3081
3265
  this.dbPath = path8.join(this.directory, "metrics.db");
3082
- const Database = loadDatabaseSync2();
3266
+ const Database = loadDatabaseSync();
3083
3267
  this.db = new Database(this.dbPath);
3084
3268
  this.db.exec("PRAGMA journal_mode = WAL");
3269
+ this.db.exec("PRAGMA synchronous = NORMAL");
3270
+ this.db.exec("PRAGMA busy_timeout = 5000");
3085
3271
  ensureMetricsSchema(this.db);
3086
3272
  this.ingester = new ChronicleMetricsIngester(this.db, this.directory, this.dbPath);
3087
3273
  }
@@ -3251,6 +3437,55 @@ var ChronicleMetricsStore = class _ChronicleMetricsStore {
3251
3437
  estimatedCostUsd: Number(cost.c)
3252
3438
  };
3253
3439
  }
3440
+ /**
3441
+ * Per-tool candidates for the auto-thinning pipeline. Returns one row per
3442
+ * tool that has at least one day in `[fromDay, toDay]` (default: last 30
3443
+ * days), with `invocations` summed across the window and `lastInvokedAt`
3444
+ * taken as the max. The caller is responsible for the "underused" filter
3445
+ * (`invocations <= maxInvocations`, `lastInvokedAt` older than
3446
+ * `toDay - idleDays`) and for excluding tools still active in the window.
3447
+ *
3448
+ * The query intentionally does NOT pre-filter by threshold — the policy
3449
+ * layer owns that decision so the same data feeds both the dry-run
3450
+ * (`/tool autothin candidates`) and the apply path.
3451
+ */
3452
+ underusedTools(options = {}) {
3453
+ const fromDay = options.from?.slice(0, 10);
3454
+ const toDay = options.to?.slice(0, 10);
3455
+ const clauses = [];
3456
+ const params = [];
3457
+ if (fromDay) {
3458
+ clauses.push("day >= ?");
3459
+ params.push(fromDay);
3460
+ }
3461
+ if (toDay) {
3462
+ clauses.push("day <= ?");
3463
+ params.push(toDay);
3464
+ }
3465
+ const where = clauses.length > 0 ? ` WHERE ${clauses.join(" AND ")}` : "";
3466
+ params.push(clampLimit(options.limit, 500));
3467
+ const rows = this.db.prepare(
3468
+ `SELECT tool_name, SUM(invocations) invocations, SUM(failures) failures,
3469
+ SUM(duration_ms_total) duration_total, MAX(last_invoked_at) last_invoked
3470
+ FROM tool_daily${where}
3471
+ GROUP BY tool_name
3472
+ ORDER BY invocations ASC, tool_name ASC
3473
+ LIMIT ?`
3474
+ ).all(...params);
3475
+ const anchorMs = Date.now();
3476
+ return rows.map((row) => {
3477
+ const lastInvokedAt = row.last_invoked === null ? null : Number(row.last_invoked);
3478
+ const daysSinceLastUse = lastInvokedAt === null ? null : Math.max(0, Math.floor((anchorMs - lastInvokedAt) / 864e5));
3479
+ return {
3480
+ toolName: String(row.tool_name),
3481
+ invocations: Number(row.invocations),
3482
+ failures: Number(row.failures),
3483
+ durationMsTotal: Number(row.duration_total),
3484
+ lastInvokedAt,
3485
+ daysSinceLastUse
3486
+ };
3487
+ });
3488
+ }
3254
3489
  /**
3255
3490
  * A `ChronicleSummary` for the default/unfiltered dashboard view — only
3256
3491
  * `from`/`to` (day-precision) narrow it.
@@ -3461,15 +3696,6 @@ async function importLegacyChronicleJournal(journal, directory) {
3461
3696
  };
3462
3697
  }
3463
3698
 
3464
- // src/chronicle/project-server-protocol.ts
3465
- var CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION = 2;
3466
- var CHRONICLE_PROJECT_SERVER_MAX_FRAME_CHARS = 64 * 1024 * 1024;
3467
- var CHRONICLE_MAX_APPEND_BATCH = 1e4;
3468
- function encodeChronicleProjectServerMessage(message) {
3469
- return `${JSON.stringify(message)}
3470
- `;
3471
- }
3472
-
3473
3699
  // src/chronicle/project-server-endpoint.ts
3474
3700
  import { createHash as createHash4 } from "node:crypto";
3475
3701
  import * as os2 from "node:os";
@@ -3499,24 +3725,24 @@ function chronicleProjectServerMetadataPath(projectDir) {
3499
3725
 
3500
3726
  export {
3501
3727
  resolveChronicleRuntimeLocation,
3728
+ CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION,
3729
+ CHRONICLE_PROJECT_SERVER_MAX_FRAME_CHARS,
3730
+ CHRONICLE_MAX_APPEND_BATCH,
3731
+ encodeChronicleProjectServerMessage,
3502
3732
  GENESIS_HASH,
3503
3733
  CHRONICLE_SCHEMA_VERSION,
3504
3734
  ChronicleJournal,
3735
+ isChronicleMetricsAvailable,
3505
3736
  ChroniclePartitionRangeCache,
3506
3737
  CHRONICLE_FACET_FIELDS,
3507
3738
  ChronicleQueryEngine,
3508
3739
  findChroniclePartitions,
3509
3740
  ChronicleStorageQuotaError,
3510
3741
  ChronicleSqliteJournal,
3511
- isChronicleMetricsAvailable,
3512
3742
  ChronicleMetricsStore,
3513
3743
  importLegacyChronicleJournal,
3514
- CHRONICLE_PROJECT_SERVER_PROTOCOL_VERSION,
3515
- CHRONICLE_PROJECT_SERVER_MAX_FRAME_CHARS,
3516
- CHRONICLE_MAX_APPEND_BATCH,
3517
- encodeChronicleProjectServerMessage,
3518
3744
  chronicleProjectServerKey,
3519
3745
  chronicleProjectServerEndpoint,
3520
3746
  chronicleProjectServerMetadataPath
3521
3747
  };
3522
- //# sourceMappingURL=chunk-AT4V4XGI.js.map
3748
+ //# sourceMappingURL=chunk-4BMVPOHO.js.map