harnery 0.34.1 → 0.36.0

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 (692) hide show
  1. package/dist/commander.d.ts +30 -5
  2. package/dist/commander.d.ts.map +1 -1
  3. package/dist/commander.js +124 -94
  4. package/dist/commands/agents.d.ts +37 -6
  5. package/dist/commands/agents.d.ts.map +1 -1
  6. package/dist/commands/agents.js +466 -371
  7. package/dist/commands/backup.d.ts.map +1 -1
  8. package/dist/commands/backup.js +10 -10
  9. package/dist/commands/browse-session.d.ts.map +1 -1
  10. package/dist/commands/browse-session.js +12 -0
  11. package/dist/commands/browse.d.ts +1 -1
  12. package/dist/commands/browse.d.ts.map +1 -1
  13. package/dist/commands/browse.js +31 -6
  14. package/dist/commands/conversations.d.ts +10 -0
  15. package/dist/commands/conversations.d.ts.map +1 -0
  16. package/dist/commands/conversations.js +201 -0
  17. package/dist/commands/decision.d.ts.map +1 -1
  18. package/dist/commands/decision.js +2 -2
  19. package/dist/commands/deinit.d.ts.map +1 -1
  20. package/dist/commands/deinit.js +5 -0
  21. package/dist/commands/docs.d.ts.map +1 -1
  22. package/dist/commands/docs.js +13 -2
  23. package/dist/commands/doctor.d.ts +5 -0
  24. package/dist/commands/doctor.d.ts.map +1 -1
  25. package/dist/commands/doctor.js +51 -7
  26. package/dist/commands/events.d.ts.map +1 -1
  27. package/dist/commands/events.js +18 -1
  28. package/dist/commands/fetch.js +6 -5
  29. package/dist/commands/files.d.ts +22 -0
  30. package/dist/commands/files.d.ts.map +1 -0
  31. package/dist/commands/files.js +113 -0
  32. package/dist/commands/governor.js +14 -12
  33. package/dist/commands/inbox.d.ts +5 -0
  34. package/dist/commands/inbox.d.ts.map +1 -0
  35. package/dist/commands/inbox.js +57 -0
  36. package/dist/commands/init.d.ts +4 -5
  37. package/dist/commands/init.d.ts.map +1 -1
  38. package/dist/commands/init.js +63 -13
  39. package/dist/commands/ledger-v3.d.ts.map +1 -1
  40. package/dist/commands/ledger-v3.js +347 -1
  41. package/dist/commands/logs.d.ts +4 -0
  42. package/dist/commands/logs.d.ts.map +1 -0
  43. package/dist/commands/logs.js +169 -0
  44. package/dist/commands/messages.d.ts +5 -0
  45. package/dist/commands/messages.d.ts.map +1 -0
  46. package/dist/commands/messages.js +45 -0
  47. package/dist/commands/outline.d.ts +1 -1
  48. package/dist/commands/outline.d.ts.map +1 -1
  49. package/dist/commands/outline.js +2 -2
  50. package/dist/commands/presence.d.ts.map +1 -1
  51. package/dist/commands/presence.js +2 -2
  52. package/dist/commands/read.d.ts +1 -1
  53. package/dist/commands/read.d.ts.map +1 -1
  54. package/dist/commands/read.js +2 -2
  55. package/dist/commands/semantic.d.ts +4 -0
  56. package/dist/commands/semantic.d.ts.map +1 -0
  57. package/dist/commands/semantic.js +199 -0
  58. package/dist/commands/storage.d.ts +4 -0
  59. package/dist/commands/storage.d.ts.map +1 -0
  60. package/dist/commands/storage.js +238 -0
  61. package/dist/commands/tunnel.d.ts +5 -1
  62. package/dist/commands/tunnel.d.ts.map +1 -1
  63. package/dist/commands/tunnel.js +44 -31
  64. package/dist/commands/web.d.ts +3 -0
  65. package/dist/commands/web.d.ts.map +1 -1
  66. package/dist/commands/web.js +84 -7
  67. package/dist/commands/work.js +3 -3
  68. package/dist/commands/workflow.js +13 -13
  69. package/dist/core/adapters/profiles.d.ts +1 -1
  70. package/dist/core/agents/canonical-emit.d.ts +3 -0
  71. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  72. package/dist/core/agents/canonical-emit.js +12 -0
  73. package/dist/core/agents/claim-path.d.ts +11 -0
  74. package/dist/core/agents/claim-path.d.ts.map +1 -0
  75. package/dist/core/agents/claim-path.js +22 -0
  76. package/dist/core/agents/cli.js +209 -39
  77. package/dist/core/agents/coord-client.d.ts +29 -3
  78. package/dist/core/agents/coord-client.d.ts.map +1 -1
  79. package/dist/core/agents/coord-client.js +88 -9
  80. package/dist/core/agents/live-authority-v3.d.ts +47 -1
  81. package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
  82. package/dist/core/agents/live-authority-v3.js +245 -13
  83. package/dist/core/agents/live-lifecycle-v3.js +9 -4
  84. package/dist/core/agents/live-observation-v3.d.ts.map +1 -1
  85. package/dist/core/agents/live-observation-v3.js +8 -3
  86. package/dist/core/agents/render/prompt-context.d.ts +9 -3
  87. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  88. package/dist/core/agents/render/prompt-context.js +36 -17
  89. package/dist/core/agents/rules/stop-hook.d.ts +2 -0
  90. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  91. package/dist/core/agents/rules/stop-hook.js +115 -22
  92. package/dist/core/agents/rules/verdict.d.ts +1 -0
  93. package/dist/core/agents/rules/verdict.d.ts.map +1 -1
  94. package/dist/core/agents/session-events.d.ts.map +1 -1
  95. package/dist/core/agents/session-events.js +4 -0
  96. package/dist/core/agents/session-finalization-state-v3.js +1 -1
  97. package/dist/core/agents/session-finalizer-v3.js +5 -1
  98. package/dist/core/agents/session-name-display.d.ts +1 -0
  99. package/dist/core/agents/session-name-display.d.ts.map +1 -1
  100. package/dist/core/agents/session-name-display.js +8 -1
  101. package/dist/core/agents/state/activity-log.d.ts +3 -0
  102. package/dist/core/agents/state/activity-log.d.ts.map +1 -1
  103. package/dist/core/agents/state/activity-log.js +6 -3
  104. package/dist/core/agents/state/heartbeat-reader.d.ts +46 -0
  105. package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -0
  106. package/dist/core/agents/state/heartbeat-reader.js +25 -0
  107. package/dist/core/agents/state/heartbeat-writer.d.ts +9 -48
  108. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  109. package/dist/core/agents/state/heartbeat-writer.js +34 -34
  110. package/dist/core/agents/state/live-coordination-view.d.ts +6 -8
  111. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  112. package/dist/core/agents/state/live-coordination-view.js +16 -67
  113. package/dist/core/agents/state/live-coordination-writer.d.ts +12 -0
  114. package/dist/core/agents/state/live-coordination-writer.d.ts.map +1 -0
  115. package/dist/core/agents/state/live-coordination-writer.js +92 -0
  116. package/dist/core/agents/state/names.d.ts +9 -1
  117. package/dist/core/agents/state/names.d.ts.map +1 -1
  118. package/dist/core/agents/state/names.js +190 -182
  119. package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
  120. package/dist/core/agents/state/stale-sweep.js +23 -5
  121. package/dist/core/artifacts/constants.d.ts +5 -0
  122. package/dist/core/artifacts/constants.d.ts.map +1 -0
  123. package/dist/core/artifacts/constants.js +4 -0
  124. package/dist/core/artifacts/index.d.ts +24 -3
  125. package/dist/core/artifacts/index.d.ts.map +1 -1
  126. package/dist/core/artifacts/index.js +96 -8
  127. package/dist/core/config.d.ts +62 -4
  128. package/dist/core/config.d.ts.map +1 -1
  129. package/dist/core/config.js +98 -4
  130. package/dist/core/conversations/archive.d.ts +49 -0
  131. package/dist/core/conversations/archive.d.ts.map +1 -0
  132. package/dist/core/conversations/archive.js +136 -0
  133. package/dist/core/conversations/catalog.d.ts +10 -0
  134. package/dist/core/conversations/catalog.d.ts.map +1 -0
  135. package/dist/core/conversations/catalog.js +72 -0
  136. package/dist/core/conversations/context-pack.d.ts +6 -0
  137. package/dist/core/conversations/context-pack.d.ts.map +1 -0
  138. package/dist/core/conversations/context-pack.js +60 -0
  139. package/dist/core/conversations/contract.d.ts +155 -0
  140. package/dist/core/conversations/contract.d.ts.map +1 -0
  141. package/dist/core/conversations/contract.js +1 -0
  142. package/dist/core/conversations/evaluation.d.ts +16 -0
  143. package/dist/core/conversations/evaluation.d.ts.map +1 -0
  144. package/dist/core/conversations/evaluation.js +9 -0
  145. package/dist/core/conversations/index.d.ts +10 -0
  146. package/dist/core/conversations/index.d.ts.map +1 -0
  147. package/dist/core/conversations/index.js +9 -0
  148. package/dist/core/conversations/lifecycle.d.ts +28 -0
  149. package/dist/core/conversations/lifecycle.d.ts.map +1 -0
  150. package/dist/core/conversations/lifecycle.js +29 -0
  151. package/dist/core/conversations/normalize.d.ts +14 -0
  152. package/dist/core/conversations/normalize.d.ts.map +1 -0
  153. package/dist/core/conversations/normalize.js +82 -0
  154. package/dist/core/conversations/query.d.ts +8 -0
  155. package/dist/core/conversations/query.d.ts.map +1 -0
  156. package/dist/core/conversations/query.js +280 -0
  157. package/dist/core/conversations/search-index.d.ts +9 -0
  158. package/dist/core/conversations/search-index.d.ts.map +1 -0
  159. package/dist/core/conversations/search-index.js +29 -0
  160. package/dist/core/events/legacy-storage/canary.d.ts +18 -0
  161. package/dist/core/events/legacy-storage/canary.d.ts.map +1 -0
  162. package/dist/core/events/legacy-storage/canary.js +150 -0
  163. package/dist/core/events/legacy-storage/fence.d.ts +15 -0
  164. package/dist/core/events/legacy-storage/fence.d.ts.map +1 -0
  165. package/dist/core/events/legacy-storage/fence.js +115 -0
  166. package/dist/core/events/legacy-storage/index.d.ts +6 -0
  167. package/dist/core/events/legacy-storage/index.d.ts.map +1 -0
  168. package/dist/core/events/legacy-storage/index.js +5 -0
  169. package/dist/core/events/legacy-storage/inventory.d.ts +10 -0
  170. package/dist/core/events/legacy-storage/inventory.d.ts.map +1 -0
  171. package/dist/core/events/legacy-storage/inventory.js +40 -0
  172. package/dist/core/events/legacy-storage/manifest.d.ts +23 -0
  173. package/dist/core/events/legacy-storage/manifest.d.ts.map +1 -0
  174. package/dist/core/events/legacy-storage/manifest.js +108 -0
  175. package/dist/core/events/legacy-storage/reader.d.ts +15 -0
  176. package/dist/core/events/legacy-storage/reader.d.ts.map +1 -0
  177. package/dist/core/events/legacy-storage/reader.js +154 -0
  178. package/dist/core/events/v3/authority-outbox.d.ts +7 -2
  179. package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
  180. package/dist/core/events/v3/authority-outbox.js +16 -3
  181. package/dist/core/events/v3/base-contract.d.ts +851 -16
  182. package/dist/core/events/v3/base-contract.d.ts.map +1 -1
  183. package/dist/core/events/v3/base-contract.js +50 -7
  184. package/dist/core/events/v3/bootstrap.d.ts +39 -0
  185. package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
  186. package/dist/core/events/v3/bootstrap.js +167 -3
  187. package/dist/core/events/v3/capabilities.d.ts +11 -0
  188. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  189. package/dist/core/events/v3/capabilities.js +26 -3
  190. package/dist/core/events/v3/control-witness.d.ts +44 -0
  191. package/dist/core/events/v3/control-witness.d.ts.map +1 -0
  192. package/dist/core/events/v3/control-witness.js +233 -0
  193. package/dist/core/events/v3/control-writer.d.ts +4 -0
  194. package/dist/core/events/v3/control-writer.d.ts.map +1 -0
  195. package/dist/core/events/v3/control-writer.js +16 -0
  196. package/dist/core/events/v3/control.d.ts +8 -2
  197. package/dist/core/events/v3/control.d.ts.map +1 -1
  198. package/dist/core/events/v3/control.js +46 -18
  199. package/dist/core/events/v3/coordination-transaction-recovery.d.ts +42 -0
  200. package/dist/core/events/v3/coordination-transaction-recovery.d.ts.map +1 -0
  201. package/dist/core/events/v3/coordination-transaction-recovery.js +342 -0
  202. package/dist/core/events/v3/coordination-view.d.ts.map +1 -1
  203. package/dist/core/events/v3/coordination-view.js +16 -1
  204. package/dist/core/events/v3/generated.d.ts +1 -1
  205. package/dist/core/events/v3/generated.js +1 -1
  206. package/dist/core/events/v3/index.d.ts +8 -5
  207. package/dist/core/events/v3/index.d.ts.map +1 -1
  208. package/dist/core/events/v3/index.js +7 -4
  209. package/dist/core/events/v3/latency.d.ts +31 -1
  210. package/dist/core/events/v3/latency.d.ts.map +1 -1
  211. package/dist/core/events/v3/latency.js +127 -3
  212. package/dist/core/events/v3/live-route-observer.d.ts +31 -0
  213. package/dist/core/events/v3/live-route-observer.d.ts.map +1 -0
  214. package/dist/core/events/v3/live-route-observer.js +58 -0
  215. package/dist/core/events/v3/live-routing.d.ts +42 -20
  216. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  217. package/dist/core/events/v3/live-routing.js +153 -41
  218. package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
  219. package/dist/core/events/v3/producers/command-recorder.js +10 -1
  220. package/dist/core/events/v3/producers/coordination-recorder.d.ts +11 -1
  221. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  222. package/dist/core/events/v3/producers/coordination-recorder.js +90 -13
  223. package/dist/core/events/v3/producers/diagnostic-summaries.d.ts +129 -0
  224. package/dist/core/events/v3/producers/diagnostic-summaries.d.ts.map +1 -0
  225. package/dist/core/events/v3/producers/diagnostic-summaries.js +499 -0
  226. package/dist/core/events/v3/producers/hook-base.d.ts +17 -1
  227. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  228. package/dist/core/events/v3/producers/hook-base.js +83 -2
  229. package/dist/core/events/v3/producers/intake.d.ts +13 -0
  230. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  231. package/dist/core/events/v3/producers/intake.js +36 -2
  232. package/dist/core/events/v3/producers/producer-state-observer.d.ts +8 -0
  233. package/dist/core/events/v3/producers/producer-state-observer.d.ts.map +1 -0
  234. package/dist/core/events/v3/producers/producer-state-observer.js +45 -0
  235. package/dist/core/events/v3/producers/recorder.d.ts +117 -1
  236. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  237. package/dist/core/events/v3/producers/recorder.js +992 -27
  238. package/dist/core/events/v3/reader.d.ts +51 -0
  239. package/dist/core/events/v3/reader.d.ts.map +1 -1
  240. package/dist/core/events/v3/reader.js +181 -1
  241. package/dist/core/events/v3/rotation-config.d.ts +9 -0
  242. package/dist/core/events/v3/rotation-config.d.ts.map +1 -0
  243. package/dist/core/events/v3/rotation-config.js +91 -0
  244. package/dist/core/events/v3/runtime-build.d.ts +11 -0
  245. package/dist/core/events/v3/runtime-build.d.ts.map +1 -0
  246. package/dist/core/events/v3/runtime-build.js +39 -0
  247. package/dist/core/events/v3/runtime-identity.d.ts +5 -0
  248. package/dist/core/events/v3/runtime-identity.d.ts.map +1 -0
  249. package/dist/core/events/v3/runtime-identity.js +18 -0
  250. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +52 -0
  251. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -0
  252. package/dist/core/events/v3/runtime-telemetry-capabilities.js +54 -0
  253. package/dist/core/events/v3/support-storage/classify.d.ts +46 -0
  254. package/dist/core/events/v3/support-storage/classify.d.ts.map +1 -0
  255. package/dist/core/events/v3/support-storage/classify.js +149 -0
  256. package/dist/core/events/v3/support-storage/eligibility.d.ts +29 -0
  257. package/dist/core/events/v3/support-storage/eligibility.d.ts.map +1 -0
  258. package/dist/core/events/v3/support-storage/eligibility.js +35 -0
  259. package/dist/core/events/v3/support-storage/index.d.ts +10 -0
  260. package/dist/core/events/v3/support-storage/index.d.ts.map +1 -0
  261. package/dist/core/events/v3/support-storage/index.js +9 -0
  262. package/dist/core/events/v3/support-storage/inventory.d.ts +30 -0
  263. package/dist/core/events/v3/support-storage/inventory.d.ts.map +1 -0
  264. package/dist/core/events/v3/support-storage/inventory.js +94 -0
  265. package/dist/core/events/v3/support-storage/logical-authority.d.ts +14 -0
  266. package/dist/core/events/v3/support-storage/logical-authority.d.ts.map +1 -0
  267. package/dist/core/events/v3/support-storage/logical-authority.js +104 -0
  268. package/dist/core/events/v3/support-storage/maintenance.d.ts +98 -0
  269. package/dist/core/events/v3/support-storage/maintenance.d.ts.map +1 -0
  270. package/dist/core/events/v3/support-storage/maintenance.js +352 -0
  271. package/dist/core/events/v3/support-storage/pack-contract.d.ts +59 -0
  272. package/dist/core/events/v3/support-storage/pack-contract.d.ts.map +1 -0
  273. package/dist/core/events/v3/support-storage/pack-contract.js +249 -0
  274. package/dist/core/events/v3/support-storage/pack-reader.d.ts +34 -0
  275. package/dist/core/events/v3/support-storage/pack-reader.d.ts.map +1 -0
  276. package/dist/core/events/v3/support-storage/pack-reader.js +258 -0
  277. package/dist/core/events/v3/support-storage/pack-writer.d.ts +30 -0
  278. package/dist/core/events/v3/support-storage/pack-writer.d.ts.map +1 -0
  279. package/dist/core/events/v3/support-storage/pack-writer.js +268 -0
  280. package/dist/core/events/v3/support-storage/recovery.d.ts +15 -0
  281. package/dist/core/events/v3/support-storage/recovery.d.ts.map +1 -0
  282. package/dist/core/events/v3/support-storage/recovery.js +22 -0
  283. package/dist/core/events/v3/turn-telemetry.d.ts +21 -6
  284. package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
  285. package/dist/core/events/v3/turn-telemetry.js +32 -2
  286. package/dist/core/events/v3/writer.d.ts +13 -1
  287. package/dist/core/events/v3/writer.d.ts.map +1 -1
  288. package/dist/core/events/v3/writer.js +126 -12
  289. package/dist/core/governor/plan-read.d.ts.map +1 -1
  290. package/dist/core/governor/plan-read.js +5 -21
  291. package/dist/core/governor/planning.js +6 -8
  292. package/dist/core/governor/service-read.d.ts +12 -0
  293. package/dist/core/governor/service-read.d.ts.map +1 -1
  294. package/dist/core/governor/service-read.js +266 -2
  295. package/dist/core/governor/service.d.ts +1 -0
  296. package/dist/core/governor/service.d.ts.map +1 -1
  297. package/dist/core/governor/service.js +53 -18
  298. package/dist/core/guard/evidence-v3.d.ts.map +1 -1
  299. package/dist/core/guard/evidence-v3.js +2 -0
  300. package/dist/core/hooks/adapter/events.d.ts.map +1 -1
  301. package/dist/core/hooks/adapter/events.js +1 -0
  302. package/dist/core/hooks/adapter/output.d.ts +4 -2
  303. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  304. package/dist/core/hooks/adapter/output.js +13 -5
  305. package/dist/core/hooks/adapter/parse.d.ts +3 -0
  306. package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
  307. package/dist/core/hooks/adapter/parse.js +14 -0
  308. package/dist/core/hooks/adapter/runtime-telemetry.d.ts +142 -0
  309. package/dist/core/hooks/adapter/runtime-telemetry.d.ts.map +1 -0
  310. package/dist/core/hooks/adapter/runtime-telemetry.js +869 -0
  311. package/dist/core/hooks/cli.js +318 -61
  312. package/dist/core/hooks/effects/image-capture.d.ts +1 -1
  313. package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
  314. package/dist/core/hooks/effects/image-capture.js +4 -2
  315. package/dist/core/hooks/remediation-cap.d.ts +39 -0
  316. package/dist/core/hooks/remediation-cap.d.ts.map +1 -0
  317. package/dist/core/hooks/remediation-cap.js +63 -0
  318. package/dist/core/hooks/resolve/coord-root.d.ts +22 -9
  319. package/dist/core/hooks/resolve/coord-root.d.ts.map +1 -1
  320. package/dist/core/hooks/resolve/coord-root.js +92 -11
  321. package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
  322. package/dist/core/hooks/resolve/owner.js +5 -0
  323. package/dist/core/hooks/resolve/transcript.d.ts +33 -9
  324. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  325. package/dist/core/hooks/resolve/transcript.js +33 -10
  326. package/dist/core/inbox/contract.d.ts +64 -0
  327. package/dist/core/inbox/contract.d.ts.map +1 -0
  328. package/dist/core/inbox/contract.js +13 -0
  329. package/dist/core/inbox/index.d.ts +5 -0
  330. package/dist/core/inbox/index.d.ts.map +1 -0
  331. package/dist/core/inbox/index.js +4 -0
  332. package/dist/core/inbox/lifecycle.d.ts +22 -0
  333. package/dist/core/inbox/lifecycle.d.ts.map +1 -0
  334. package/dist/core/inbox/lifecycle.js +41 -0
  335. package/dist/core/inbox/service.d.ts +36 -0
  336. package/dist/core/inbox/service.d.ts.map +1 -0
  337. package/dist/core/inbox/service.js +210 -0
  338. package/dist/core/inbox/watcher.d.ts +7 -0
  339. package/dist/core/inbox/watcher.d.ts.map +1 -0
  340. package/dist/core/inbox/watcher.js +26 -0
  341. package/dist/core/presence/codec-digest.d.ts.map +1 -1
  342. package/dist/core/presence/codec-digest.js +14 -3
  343. package/dist/core/presence/relay-client.d.ts +1 -0
  344. package/dist/core/presence/relay-client.d.ts.map +1 -1
  345. package/dist/core/presence/relay-client.js +52 -8
  346. package/dist/core/semantic/adapters.d.ts +37 -0
  347. package/dist/core/semantic/adapters.d.ts.map +1 -0
  348. package/dist/core/semantic/adapters.js +360 -0
  349. package/dist/core/semantic/contract.d.ts +1072 -0
  350. package/dist/core/semantic/contract.d.ts.map +1 -0
  351. package/dist/core/semantic/contract.js +331 -0
  352. package/dist/core/semantic/evidence.d.ts +11 -0
  353. package/dist/core/semantic/evidence.d.ts.map +1 -0
  354. package/dist/core/semantic/evidence.js +262 -0
  355. package/dist/core/semantic/index.d.ts +14 -0
  356. package/dist/core/semantic/index.d.ts.map +1 -0
  357. package/dist/core/semantic/index.js +13 -0
  358. package/dist/core/semantic/once.d.ts +38 -0
  359. package/dist/core/semantic/once.d.ts.map +1 -0
  360. package/dist/core/semantic/once.js +364 -0
  361. package/dist/core/semantic/prompt.d.ts +12 -0
  362. package/dist/core/semantic/prompt.d.ts.map +1 -0
  363. package/dist/core/semantic/prompt.js +83 -0
  364. package/dist/core/semantic/review.d.ts +144 -0
  365. package/dist/core/semantic/review.d.ts.map +1 -0
  366. package/dist/core/semantic/review.js +544 -0
  367. package/dist/core/semantic/routes.d.ts +10 -0
  368. package/dist/core/semantic/routes.d.ts.map +1 -0
  369. package/dist/core/semantic/routes.js +21 -0
  370. package/dist/core/semantic/scheduler.d.ts +27 -0
  371. package/dist/core/semantic/scheduler.d.ts.map +1 -0
  372. package/dist/core/semantic/scheduler.js +91 -0
  373. package/dist/core/semantic/service-status.d.ts +51 -0
  374. package/dist/core/semantic/service-status.d.ts.map +1 -0
  375. package/dist/core/semantic/service-status.js +140 -0
  376. package/dist/core/semantic/service.d.ts +52 -0
  377. package/dist/core/semantic/service.d.ts.map +1 -0
  378. package/dist/core/semantic/service.js +559 -0
  379. package/dist/core/semantic/soak.d.ts +75 -0
  380. package/dist/core/semantic/soak.d.ts.map +1 -0
  381. package/dist/core/semantic/soak.js +476 -0
  382. package/dist/core/semantic/storage.d.ts +81 -0
  383. package/dist/core/semantic/storage.d.ts.map +1 -0
  384. package/dist/core/semantic/storage.js +180 -0
  385. package/dist/core/semantic/usage.d.ts +43 -0
  386. package/dist/core/semantic/usage.d.ts.map +1 -0
  387. package/dist/core/semantic/usage.js +193 -0
  388. package/dist/core/semantic/validate.d.ts +18 -0
  389. package/dist/core/semantic/validate.d.ts.map +1 -0
  390. package/dist/core/semantic/validate.js +207 -0
  391. package/dist/core/storage/buffer.d.ts +28 -0
  392. package/dist/core/storage/buffer.d.ts.map +1 -0
  393. package/dist/core/storage/buffer.js +101 -0
  394. package/dist/core/storage/builtins.d.ts +3 -0
  395. package/dist/core/storage/builtins.d.ts.map +1 -0
  396. package/dist/core/storage/builtins.js +683 -0
  397. package/dist/core/storage/catalog.d.ts +19 -0
  398. package/dist/core/storage/catalog.d.ts.map +1 -0
  399. package/dist/core/storage/catalog.js +365 -0
  400. package/dist/core/storage/config.d.ts +16 -0
  401. package/dist/core/storage/config.d.ts.map +1 -0
  402. package/dist/core/storage/config.js +311 -0
  403. package/dist/core/storage/contract.d.ts +275 -0
  404. package/dist/core/storage/contract.d.ts.map +1 -0
  405. package/dist/core/storage/contract.js +3 -0
  406. package/dist/core/storage/durable-history.d.ts +36 -0
  407. package/dist/core/storage/durable-history.d.ts.map +1 -0
  408. package/dist/core/storage/durable-history.js +606 -0
  409. package/dist/core/storage/health.d.ts +4 -0
  410. package/dist/core/storage/health.d.ts.map +1 -0
  411. package/dist/core/storage/health.js +65 -0
  412. package/dist/core/storage/index.d.ts +16 -0
  413. package/dist/core/storage/index.d.ts.map +1 -0
  414. package/dist/core/storage/index.js +15 -0
  415. package/dist/core/storage/inventory.d.ts +25 -0
  416. package/dist/core/storage/inventory.d.ts.map +1 -0
  417. package/dist/core/storage/inventory.js +666 -0
  418. package/dist/core/storage/jsonl.d.ts +52 -0
  419. package/dist/core/storage/jsonl.d.ts.map +1 -0
  420. package/dist/core/storage/jsonl.js +156 -0
  421. package/dist/core/storage/log-retention.d.ts +52 -0
  422. package/dist/core/storage/log-retention.d.ts.map +1 -0
  423. package/dist/core/storage/log-retention.js +419 -0
  424. package/dist/core/storage/logger.d.ts +82 -0
  425. package/dist/core/storage/logger.d.ts.map +1 -0
  426. package/dist/core/storage/logger.js +411 -0
  427. package/dist/core/storage/maintenance-providers.d.ts +26 -0
  428. package/dist/core/storage/maintenance-providers.d.ts.map +1 -0
  429. package/dist/core/storage/maintenance-providers.js +141 -0
  430. package/dist/core/storage/maintenance.d.ts +125 -0
  431. package/dist/core/storage/maintenance.d.ts.map +1 -0
  432. package/dist/core/storage/maintenance.js +609 -0
  433. package/dist/core/storage/metrics.d.ts +60 -0
  434. package/dist/core/storage/metrics.d.ts.map +1 -0
  435. package/dist/core/storage/metrics.js +134 -0
  436. package/dist/core/storage/policy.d.ts +7 -0
  437. package/dist/core/storage/policy.d.ts.map +1 -0
  438. package/dist/core/storage/policy.js +110 -0
  439. package/dist/core/storage/process-log.d.ts +38 -0
  440. package/dist/core/storage/process-log.d.ts.map +1 -0
  441. package/dist/core/storage/process-log.js +165 -0
  442. package/dist/core/storage/query.d.ts +34 -0
  443. package/dist/core/storage/query.d.ts.map +1 -0
  444. package/dist/core/storage/query.js +295 -0
  445. package/dist/core/storage/receipts.d.ts +23 -0
  446. package/dist/core/storage/receipts.d.ts.map +1 -0
  447. package/dist/core/storage/receipts.js +117 -0
  448. package/dist/core/storage/segments.d.ts +84 -0
  449. package/dist/core/storage/segments.d.ts.map +1 -0
  450. package/dist/core/storage/segments.js +542 -0
  451. package/dist/core/storage/sink-graph.d.ts +65 -0
  452. package/dist/core/storage/sink-graph.d.ts.map +1 -0
  453. package/dist/core/storage/sink-graph.js +213 -0
  454. package/dist/core/storage/storm-control.d.ts +23 -0
  455. package/dist/core/storage/storm-control.d.ts.map +1 -0
  456. package/dist/core/storage/storm-control.js +59 -0
  457. package/dist/core/work/state.d.ts.map +1 -1
  458. package/dist/core/work/state.js +10 -14
  459. package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
  460. package/dist/core/workflow/live-session-v3.js +2 -1
  461. package/dist/index.d.ts +2 -0
  462. package/dist/index.d.ts.map +1 -1
  463. package/dist/index.js +2 -0
  464. package/dist/lazy-commands.d.ts +26 -0
  465. package/dist/lazy-commands.d.ts.map +1 -0
  466. package/dist/lazy-commands.js +210 -0
  467. package/dist/lib/browser/client.d.ts +11 -0
  468. package/dist/lib/browser/client.d.ts.map +1 -1
  469. package/dist/lib/browser/client.js +13 -0
  470. package/dist/lib/browser/index.d.ts +1 -0
  471. package/dist/lib/browser/index.d.ts.map +1 -1
  472. package/dist/lib/browser/standalone-html.d.ts +25 -0
  473. package/dist/lib/browser/standalone-html.d.ts.map +1 -0
  474. package/dist/lib/browser/standalone-html.js +284 -0
  475. package/dist/lib/docs-lint.d.ts +2 -0
  476. package/dist/lib/docs-lint.d.ts.map +1 -1
  477. package/dist/lib/docs-lint.js +45 -80
  478. package/dist/lib/docs-metadata-audit.d.ts +3 -0
  479. package/dist/lib/docs-metadata-audit.d.ts.map +1 -1
  480. package/dist/lib/docs-metadata-audit.js +13 -23
  481. package/dist/lib/docs-metadata-sync.d.ts +1 -0
  482. package/dist/lib/docs-metadata-sync.d.ts.map +1 -1
  483. package/dist/lib/docs-metadata-sync.js +28 -10
  484. package/dist/lib/docs-repository-view.d.ts +22 -0
  485. package/dist/lib/docs-repository-view.d.ts.map +1 -0
  486. package/dist/lib/docs-repository-view.js +185 -0
  487. package/dist/lib/http/client.d.ts +11 -5
  488. package/dist/lib/http/client.d.ts.map +1 -1
  489. package/dist/lib/http/client.js +22 -4
  490. package/dist/lib/http/index.d.ts +1 -1
  491. package/dist/lib/http/index.d.ts.map +1 -1
  492. package/dist/lib/http/index.js +1 -1
  493. package/dist/lib/indexer-exclusions.d.ts +27 -0
  494. package/dist/lib/indexer-exclusions.d.ts.map +1 -0
  495. package/dist/lib/indexer-exclusions.js +176 -0
  496. package/dist/lib/instructions/apply.d.ts.map +1 -1
  497. package/dist/lib/instructions/apply.js +1 -0
  498. package/dist/lib/instructions/templates.d.ts +2 -0
  499. package/dist/lib/instructions/templates.d.ts.map +1 -1
  500. package/dist/lib/instructions/templates.js +149 -4
  501. package/dist/lib/local-file-url.d.ts +9 -0
  502. package/dist/lib/local-file-url.d.ts.map +1 -0
  503. package/dist/lib/local-file-url.js +20 -0
  504. package/dist/lib/web-performance.d.ts +118 -0
  505. package/dist/lib/web-performance.d.ts.map +1 -0
  506. package/dist/lib/web-performance.js +192 -0
  507. package/package.json +34 -2
  508. package/schemas/config.schema.json +58 -0
  509. package/schemas/event-v3.schema.json +3073 -581
  510. package/src/commander.ts +462 -93
  511. package/src/commands/agents.ts +617 -355
  512. package/src/commands/backup.ts +18 -14
  513. package/src/commands/browse-session.ts +12 -0
  514. package/src/commands/browse.ts +31 -9
  515. package/src/commands/conversations.ts +279 -0
  516. package/src/commands/decision.ts +8 -2
  517. package/src/commands/deinit.ts +6 -0
  518. package/src/commands/docs.ts +25 -6
  519. package/src/commands/doctor.ts +75 -9
  520. package/src/commands/events.ts +21 -1
  521. package/src/commands/fetch.ts +7 -6
  522. package/src/commands/files.ts +143 -0
  523. package/src/commands/governor.ts +13 -12
  524. package/src/commands/inbox.ts +61 -0
  525. package/src/commands/init.ts +78 -16
  526. package/src/commands/ledger-v3.ts +421 -1
  527. package/src/commands/logs.ts +224 -0
  528. package/src/commands/messages.ts +61 -0
  529. package/src/commands/outline.ts +6 -2
  530. package/src/commands/presence.ts +7 -2
  531. package/src/commands/read.ts +6 -2
  532. package/src/commands/semantic.ts +244 -0
  533. package/src/commands/storage.ts +310 -0
  534. package/src/commands/tunnel.ts +66 -52
  535. package/src/commands/web.ts +92 -7
  536. package/src/commands/work.ts +3 -3
  537. package/src/commands/workflow.ts +13 -13
  538. package/src/core/agents/canonical-emit.ts +15 -0
  539. package/src/core/agents/claim-path.ts +23 -0
  540. package/src/core/agents/cli.ts +259 -53
  541. package/src/core/agents/coord-client.ts +92 -8
  542. package/src/core/agents/live-authority-v3.ts +342 -14
  543. package/src/core/agents/live-lifecycle-v3.ts +14 -4
  544. package/src/core/agents/live-observation-v3.ts +13 -3
  545. package/src/core/agents/render/prompt-context.ts +40 -16
  546. package/src/core/agents/rules/stop-hook.ts +129 -25
  547. package/src/core/agents/rules/verdict.ts +1 -0
  548. package/src/core/agents/session-events.ts +4 -0
  549. package/src/core/agents/session-finalization-state-v3.ts +1 -1
  550. package/src/core/agents/session-finalizer-v3.ts +4 -1
  551. package/src/core/agents/session-name-display.ts +9 -1
  552. package/src/core/agents/state/activity-log.ts +7 -2
  553. package/src/core/agents/state/heartbeat-reader.ts +69 -0
  554. package/src/core/agents/state/heartbeat-writer.ts +47 -84
  555. package/src/core/agents/state/live-coordination-view.ts +17 -81
  556. package/src/core/agents/state/live-coordination-writer.ts +141 -0
  557. package/src/core/agents/state/names.ts +190 -182
  558. package/src/core/agents/state/stale-sweep.ts +25 -5
  559. package/src/core/artifacts/constants.ts +4 -0
  560. package/src/core/artifacts/index.ts +113 -8
  561. package/src/core/config.ts +126 -5
  562. package/src/core/conversations/archive.ts +237 -0
  563. package/src/core/conversations/catalog.ts +79 -0
  564. package/src/core/conversations/context-pack.ts +72 -0
  565. package/src/core/conversations/contract.ts +178 -0
  566. package/src/core/conversations/evaluation.ts +30 -0
  567. package/src/core/conversations/index.ts +9 -0
  568. package/src/core/conversations/lifecycle.ts +63 -0
  569. package/src/core/conversations/normalize.ts +105 -0
  570. package/src/core/conversations/query.ts +318 -0
  571. package/src/core/conversations/search-index.ts +48 -0
  572. package/src/core/events/legacy-storage/canary.ts +177 -0
  573. package/src/core/events/legacy-storage/fence.ts +129 -0
  574. package/src/core/events/legacy-storage/index.ts +5 -0
  575. package/src/core/events/legacy-storage/inventory.ts +51 -0
  576. package/src/core/events/legacy-storage/manifest.ts +136 -0
  577. package/src/core/events/legacy-storage/reader.ts +178 -0
  578. package/src/core/events/v3/authority-outbox.ts +22 -1
  579. package/src/core/events/v3/base-contract.ts +56 -7
  580. package/src/core/events/v3/bootstrap.ts +195 -2
  581. package/src/core/events/v3/capabilities.ts +37 -3
  582. package/src/core/events/v3/control-witness.ts +339 -0
  583. package/src/core/events/v3/control-writer.ts +16 -0
  584. package/src/core/events/v3/control.ts +54 -18
  585. package/src/core/events/v3/coordination-transaction-recovery.ts +477 -0
  586. package/src/core/events/v3/coordination-view.ts +17 -1
  587. package/src/core/events/v3/generated.ts +1 -1
  588. package/src/core/events/v3/index.ts +26 -2
  589. package/src/core/events/v3/latency.ts +213 -2
  590. package/src/core/events/v3/live-route-observer.ts +80 -0
  591. package/src/core/events/v3/live-routing.ts +182 -45
  592. package/src/core/events/v3/producers/command-recorder.ts +10 -1
  593. package/src/core/events/v3/producers/coordination-recorder.ts +112 -15
  594. package/src/core/events/v3/producers/diagnostic-summaries.ts +593 -0
  595. package/src/core/events/v3/producers/hook-base.ts +116 -2
  596. package/src/core/events/v3/producers/intake.ts +48 -2
  597. package/src/core/events/v3/producers/producer-state-observer.ts +52 -0
  598. package/src/core/events/v3/producers/recorder.ts +1403 -30
  599. package/src/core/events/v3/reader.ts +243 -2
  600. package/src/core/events/v3/rotation-config.ts +98 -0
  601. package/src/core/events/v3/runtime-build.ts +41 -0
  602. package/src/core/events/v3/runtime-identity.ts +16 -0
  603. package/src/core/events/v3/runtime-telemetry-capabilities.ts +143 -0
  604. package/src/core/events/v3/support-storage/classify.ts +209 -0
  605. package/src/core/events/v3/support-storage/eligibility.ts +58 -0
  606. package/src/core/events/v3/support-storage/index.ts +9 -0
  607. package/src/core/events/v3/support-storage/inventory.ts +135 -0
  608. package/src/core/events/v3/support-storage/logical-authority.ts +117 -0
  609. package/src/core/events/v3/support-storage/maintenance.ts +501 -0
  610. package/src/core/events/v3/support-storage/pack-contract.ts +337 -0
  611. package/src/core/events/v3/support-storage/pack-reader.ts +346 -0
  612. package/src/core/events/v3/support-storage/pack-writer.ts +352 -0
  613. package/src/core/events/v3/support-storage/recovery.ts +43 -0
  614. package/src/core/events/v3/turn-telemetry.ts +66 -5
  615. package/src/core/events/v3/writer.ts +168 -16
  616. package/src/core/governor/plan-read.ts +5 -18
  617. package/src/core/governor/planning.ts +5 -8
  618. package/src/core/governor/service-read.ts +320 -2
  619. package/src/core/governor/service.ts +49 -22
  620. package/src/core/guard/evidence-v3.ts +1 -0
  621. package/src/core/hooks/adapter/events.ts +1 -0
  622. package/src/core/hooks/adapter/output.ts +12 -5
  623. package/src/core/hooks/adapter/parse.ts +16 -0
  624. package/src/core/hooks/adapter/runtime-telemetry.ts +1200 -0
  625. package/src/core/hooks/cli.ts +342 -64
  626. package/src/core/hooks/effects/image-capture.ts +4 -1
  627. package/src/core/hooks/remediation-cap.ts +83 -0
  628. package/src/core/hooks/resolve/coord-root.ts +91 -11
  629. package/src/core/hooks/resolve/owner.ts +4 -0
  630. package/src/core/hooks/resolve/transcript.ts +55 -11
  631. package/src/core/inbox/contract.ts +81 -0
  632. package/src/core/inbox/index.ts +4 -0
  633. package/src/core/inbox/lifecycle.ts +104 -0
  634. package/src/core/inbox/service.ts +305 -0
  635. package/src/core/inbox/watcher.ts +36 -0
  636. package/src/core/presence/codec-digest.ts +15 -9
  637. package/src/core/presence/relay-client.ts +55 -7
  638. package/src/core/semantic/adapters.ts +452 -0
  639. package/src/core/semantic/contract.ts +430 -0
  640. package/src/core/semantic/evidence.ts +336 -0
  641. package/src/core/semantic/index.ts +201 -0
  642. package/src/core/semantic/once.ts +496 -0
  643. package/src/core/semantic/prompt.ts +96 -0
  644. package/src/core/semantic/review.ts +803 -0
  645. package/src/core/semantic/routes.ts +30 -0
  646. package/src/core/semantic/scheduler.ts +151 -0
  647. package/src/core/semantic/service-status.ts +212 -0
  648. package/src/core/semantic/service.ts +681 -0
  649. package/src/core/semantic/soak.ts +638 -0
  650. package/src/core/semantic/storage.ts +300 -0
  651. package/src/core/semantic/usage.ts +272 -0
  652. package/src/core/semantic/validate.ts +243 -0
  653. package/src/core/storage/buffer.ts +124 -0
  654. package/src/core/storage/builtins.ts +916 -0
  655. package/src/core/storage/catalog.ts +467 -0
  656. package/src/core/storage/config.ts +423 -0
  657. package/src/core/storage/contract.ts +342 -0
  658. package/src/core/storage/durable-history.ts +738 -0
  659. package/src/core/storage/health.ts +76 -0
  660. package/src/core/storage/index.ts +15 -0
  661. package/src/core/storage/inventory.ts +859 -0
  662. package/src/core/storage/jsonl.ts +213 -0
  663. package/src/core/storage/log-retention.ts +555 -0
  664. package/src/core/storage/logger.ts +546 -0
  665. package/src/core/storage/maintenance-providers.ts +200 -0
  666. package/src/core/storage/maintenance.ts +929 -0
  667. package/src/core/storage/metrics.ts +199 -0
  668. package/src/core/storage/policy.ts +141 -0
  669. package/src/core/storage/process-log.ts +203 -0
  670. package/src/core/storage/query.ts +360 -0
  671. package/src/core/storage/receipts.ts +162 -0
  672. package/src/core/storage/segments.ts +721 -0
  673. package/src/core/storage/sink-graph.ts +343 -0
  674. package/src/core/storage/storm-control.ts +91 -0
  675. package/src/core/work/state.ts +12 -21
  676. package/src/core/workflow/live-session-v3.ts +2 -4
  677. package/src/index.ts +2 -0
  678. package/src/lazy-commands.ts +294 -0
  679. package/src/lib/browser/client.ts +21 -0
  680. package/src/lib/browser/index.ts +4 -0
  681. package/src/lib/browser/standalone-html.ts +312 -0
  682. package/src/lib/docs-lint.ts +58 -77
  683. package/src/lib/docs-metadata-audit.ts +26 -21
  684. package/src/lib/docs-metadata-sync.ts +32 -9
  685. package/src/lib/docs-repository-view.ts +220 -0
  686. package/src/lib/http/client.ts +44 -8
  687. package/src/lib/http/index.ts +6 -1
  688. package/src/lib/indexer-exclusions.ts +173 -0
  689. package/src/lib/instructions/apply.ts +1 -0
  690. package/src/lib/instructions/templates.ts +154 -4
  691. package/src/lib/local-file-url.ts +31 -0
  692. package/src/lib/web-performance.ts +335 -0
@@ -0,0 +1,1200 @@
1
+ import { createHash } from "node:crypto";
2
+ import { closeSync, existsSync, openSync, readdirSync, readSync, statSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { basename, join, resolve } from "node:path";
5
+
6
+ import type { Adapter } from "../../adapter.ts";
7
+ import { transcriptPathCandidates } from "../resolve/transcript.ts";
8
+
9
+ const DEFAULT_TAIL_BYTES = 256 * 1024;
10
+ /**
11
+ * An active turn can accumulate enough tool traffic to push its native turn
12
+ * ancestor beyond the ordinary status tail. Keep attribution bounded while
13
+ * giving long-running interactive turns a larger matching window.
14
+ */
15
+ const ACTIVE_TURN_TAIL_BYTES = 4 * 1024 * 1024;
16
+ const DEFAULT_MAX_SAMPLE_AGE_MS = 30_000;
17
+ const DEFAULT_MAX_CURSOR_DATABASES = 8;
18
+ const SESSION_CACHE_LIMIT = 128;
19
+
20
+ export type RuntimeContextTelemetry =
21
+ | {
22
+ state: "observed";
23
+ used_tokens: number;
24
+ limit_tokens: number;
25
+ measured_at: string;
26
+ method: "codex_transcript_token_count" | "claude_transcript_usage_model_capability";
27
+ source_event: string;
28
+ source_witness: string;
29
+ attestation: "derived" | "inferred";
30
+ confidence: "exact" | "high" | "medium";
31
+ bytes_read: number;
32
+ io_duration_ms: number;
33
+ }
34
+ | {
35
+ state: "observed";
36
+ used_percent: number;
37
+ measured_at: string;
38
+ method: "cursor_composer_context_percent";
39
+ source_event: string;
40
+ source_witness: string;
41
+ attestation: "derived";
42
+ confidence: "high";
43
+ runtime_version?: string;
44
+ bytes_read: number;
45
+ io_duration_ms: number;
46
+ }
47
+ | {
48
+ state: "partial";
49
+ reason: RuntimeContextMissingReason;
50
+ used_tokens?: number;
51
+ measured_at?: string;
52
+ bytes_read: number;
53
+ io_duration_ms: number;
54
+ }
55
+ | {
56
+ state: "unsupported";
57
+ reason: RuntimeContextUnsupportedReason;
58
+ bytes_read: 0;
59
+ io_duration_ms: number;
60
+ };
61
+
62
+ export type RuntimeContextMissingReason =
63
+ | "codex_transcript_ambiguous"
64
+ | "codex_transcript_session_mismatch"
65
+ | "codex_transcript_unreadable"
66
+ | "codex_transcript_turn_not_found"
67
+ | "codex_transcript_turn_not_terminal"
68
+ | "codex_transcript_token_count_missing"
69
+ | "codex_transcript_sample_stale"
70
+ | "context_used_tokens_not_reported"
71
+ | "context_limit_tokens_not_reported"
72
+ | "context_limit_tokens_invalid"
73
+ | "claude_context_limit_tokens_not_reported"
74
+ | "claude_transcript_sample_stale"
75
+ | "claude_transcript_session_mismatch"
76
+ | "claude_transcript_turn_not_found"
77
+ | "claude_transcript_unreadable"
78
+ | "cursor_context_database_unavailable"
79
+ | "cursor_context_database_unreadable"
80
+ | "cursor_context_session_not_found"
81
+ | "cursor_context_sample_ambiguous"
82
+ | "cursor_context_sample_stale"
83
+ | "cursor_context_sample_time_not_reported"
84
+ | "cursor_context_usage_invalid";
85
+
86
+ export type RuntimeContextUnsupportedReason =
87
+ | "runtime_context_telemetry_unavailable"
88
+ | "runtime_session_id_not_reported"
89
+ | "runtime_turn_id_not_reported"
90
+ | "runtime_adapter_not_supported";
91
+
92
+ export interface RuntimeContextRequest {
93
+ adapter: Adapter;
94
+ session_id?: string;
95
+ turn_id?: string;
96
+ /** Canonical producer turn boundary used when task_started has left the bounded tail. */
97
+ turn_started_at?: string;
98
+ transcript_path?: string;
99
+ observed_at?: string;
100
+ /**
101
+ * Status reads the newest session sample without turn attribution. Active
102
+ * turn reads require a matching task_started boundary but not task_complete.
103
+ */
104
+ mode: "turn" | "active_turn" | "status";
105
+ }
106
+
107
+ export interface RuntimeTelemetryOptions {
108
+ codexRoots?: string[];
109
+ cursorRoots?: string[];
110
+ maxCursorDatabases?: number;
111
+ maxTailBytes?: number;
112
+ maxSampleAgeMs?: number;
113
+ /** Recorder-only cadence override used by deterministic tests. */
114
+ activeContextProbeIntervalMs?: number;
115
+ }
116
+
117
+ interface TailRead {
118
+ text: string;
119
+ bytes: number;
120
+ }
121
+
122
+ interface ParsedRuntimeRow {
123
+ timestamp?: string;
124
+ ordinal?: number;
125
+ type?: string;
126
+ uuid?: string;
127
+ parent_uuid?: string;
128
+ prompt_id?: string;
129
+ session_id?: string;
130
+ /** CC stamps the effective effort level at the row's top level. */
131
+ effort?: string;
132
+ payload?: Record<string, unknown>;
133
+ }
134
+
135
+ interface CodexTokenSample {
136
+ used_tokens?: number;
137
+ limit_tokens?: number;
138
+ measured_at?: string;
139
+ ordinal?: number;
140
+ }
141
+
142
+ const codexTranscriptCache = new Map<string, string>();
143
+ const cursorDatabaseCache = new Map<string, string>();
144
+
145
+ /**
146
+ * Read privacy-safe context telemetry from a local runtime transcript.
147
+ *
148
+ * The returned union contains only numeric measurements, timestamps, bounded
149
+ * I/O counters, and a privacy-safe witness. Transcript bodies and paths never
150
+ * cross this interface.
151
+ */
152
+ export function readRuntimeContextTelemetry(
153
+ request: RuntimeContextRequest,
154
+ options: RuntimeTelemetryOptions = {},
155
+ ): RuntimeContextTelemetry {
156
+ const startedAt = performance.now();
157
+ if (!request.session_id) return unsupported("runtime_session_id_not_reported", startedAt);
158
+ if (request.mode !== "status" && !request.turn_id && request.adapter !== "cursor") {
159
+ return unsupported("runtime_turn_id_not_reported", startedAt);
160
+ }
161
+ if (request.adapter === "codex") return readCodexContext(request, options, startedAt);
162
+ if (request.adapter === "claude-code") return readClaudeContext(request, options, startedAt);
163
+ if (request.adapter === "cursor") return readCursorContext(request, options, startedAt);
164
+ return unsupported("runtime_adapter_not_supported", startedAt);
165
+ }
166
+
167
+ /**
168
+ * Locate a Codex rollout transcript for a session when the hook payload
169
+ * carries no transcript_path. Codex omits the path on its hook events, which
170
+ * leaves transcript-backed evidence unavailable unless Harnery resolves the
171
+ * rollout itself. Discovery reuses the telemetry scanner's roots (native
172
+ * ~/.codex plus WSL-mounted Windows homes) and its process cache, and returns
173
+ * undefined on zero or ambiguous matches.
174
+ *
175
+ * Callers on repeated hook paths must retain the verified result in their
176
+ * owner-only session state. The process cache bounds repeated reads inside one
177
+ * process, but hook processes are intentionally short-lived.
178
+ */
179
+ export function discoverCodexSessionTranscript(
180
+ sessionId: string | undefined,
181
+ transcriptPath?: string,
182
+ options: RuntimeTelemetryOptions = {},
183
+ ): string | undefined {
184
+ if (!sessionId || !/^[0-9a-f][0-9a-f-]{14,62}[0-9a-f]$/i.test(sessionId)) return undefined;
185
+ const resolution = resolveCodexTranscript(
186
+ { adapter: "codex", session_id: sessionId, transcript_path: transcriptPath, mode: "status" },
187
+ options,
188
+ );
189
+ return resolution.state === "found" ? resolution.path : undefined;
190
+ }
191
+
192
+ /** Status compatibility wrapper: exact pairs render; partial values do not. */
193
+ export function readRuntimeContextUsage(
194
+ adapter: Adapter,
195
+ sessionId: string,
196
+ options: RuntimeTelemetryOptions = {},
197
+ ): { used: number; window: number } | null {
198
+ const result = readRuntimeContextTelemetry(
199
+ { adapter, session_id: sessionId, mode: "status" },
200
+ options,
201
+ );
202
+ return result.state === "observed" && "used_tokens" in result
203
+ ? { used: result.used_tokens, window: result.limit_tokens }
204
+ : null;
205
+ }
206
+
207
+ export function clearRuntimeTelemetryCachesForTest(): void {
208
+ codexTranscriptCache.clear();
209
+ cursorDatabaseCache.clear();
210
+ }
211
+
212
+ export type RuntimeTuningMissingReason =
213
+ | "codex_transcript_ambiguous"
214
+ | "codex_transcript_session_mismatch"
215
+ | "codex_transcript_unreadable"
216
+ | "codex_transcript_turn_context_missing"
217
+ | "claude_transcript_unreadable"
218
+ | "claude_transcript_assistant_row_missing";
219
+
220
+ /**
221
+ * Privacy-safe tuning identity read from a local runtime transcript.
222
+ *
223
+ * `observed` means the newest identity-bearing row was read: a Codex
224
+ * `turn_context` row or a CC assistant row with a real model id. An observed
225
+ * result with NO `effort` is itself evidence — CC omits the field exactly when
226
+ * the model has no effort dial — so callers must distinguish it from
227
+ * `partial`/`unsupported`, where nothing was established.
228
+ */
229
+ export type RuntimeTuningTelemetry =
230
+ | {
231
+ state: "observed";
232
+ model?: string;
233
+ effort?: string;
234
+ speed?: string;
235
+ measured_at?: string;
236
+ method: "codex_transcript_turn_context" | "claude_transcript_assistant_row";
237
+ source_event: string;
238
+ bytes_read: number;
239
+ io_duration_ms: number;
240
+ }
241
+ | {
242
+ state: "partial";
243
+ reason: RuntimeTuningMissingReason;
244
+ bytes_read: number;
245
+ io_duration_ms: number;
246
+ }
247
+ | {
248
+ state: "unsupported";
249
+ reason: RuntimeContextUnsupportedReason;
250
+ bytes_read: 0;
251
+ io_duration_ms: number;
252
+ };
253
+
254
+ export interface RuntimeTuningRequest {
255
+ adapter: Adapter;
256
+ session_id?: string;
257
+ transcript_path?: string;
258
+ }
259
+
260
+ /**
261
+ * Read the newest observed tuning (effort, and speed where reported) for a
262
+ * session from its local runtime transcript.
263
+ *
264
+ * Codex: the newest `turn_context` row carries the EFFECTIVE per-turn effort,
265
+ * including `-c model_reasoning_effort` overrides (the config default is
266
+ * deliberately not consulted — it is the default, not the effective value).
267
+ * CC: the newest assistant row carries effort at the row's top level and
268
+ * speed inside `message.usage`; model, effort, and speed are read from the
269
+ * SAME row so a mid-session model swap cannot blend two rows' values.
270
+ *
271
+ * Same bounded tail-read and privacy posture as `readRuntimeContextTelemetry`:
272
+ * only tokens, timestamps, and I/O counters cross this interface.
273
+ */
274
+ export function readRuntimeTuning(
275
+ request: RuntimeTuningRequest,
276
+ options: RuntimeTelemetryOptions = {},
277
+ ): RuntimeTuningTelemetry {
278
+ const startedAt = performance.now();
279
+ if (request.adapter === "codex") {
280
+ if (!request.session_id) return unsupported("runtime_session_id_not_reported", startedAt);
281
+ return readCodexTuning(request, options, startedAt);
282
+ }
283
+ if (request.adapter === "claude-code") return readClaudeTuning(request, options, startedAt);
284
+ return unsupported("runtime_adapter_not_supported", startedAt);
285
+ }
286
+
287
+ function readCodexTuning(
288
+ request: RuntimeTuningRequest,
289
+ options: RuntimeTelemetryOptions,
290
+ startedAt: number,
291
+ ): RuntimeTuningTelemetry {
292
+ const resolved = resolveCodexTranscript(
293
+ {
294
+ adapter: "codex",
295
+ session_id: request.session_id,
296
+ transcript_path: request.transcript_path,
297
+ mode: "status",
298
+ },
299
+ options,
300
+ );
301
+ if (resolved.state === "missing") {
302
+ return unsupported("runtime_context_telemetry_unavailable", startedAt);
303
+ }
304
+ if (resolved.state === "ambiguous") {
305
+ return tuningPartial("codex_transcript_ambiguous", 0, startedAt);
306
+ }
307
+ if (resolved.state === "mismatch") {
308
+ return tuningPartial("codex_transcript_session_mismatch", 0, startedAt);
309
+ }
310
+ const tail = readTail(resolved.path, options.maxTailBytes ?? DEFAULT_TAIL_BYTES);
311
+ if (!tail) return tuningPartial("codex_transcript_unreadable", 0, startedAt);
312
+ const fromTail = newestTurnContextTuning(parseRuntimeRows(tail.text), tail.bytes, startedAt);
313
+ if (fromTail) return fromTail;
314
+ // `turn_context` is written at the START of a turn, so one long turn pushes
315
+ // it past the bounded tail. The front of the file is then the reliable
316
+ // place, but not a fixed-size head: a real interactive rollout opens with
317
+ // hundreds of KB of session_meta, instruction, and world_state rows before
318
+ // the first turn_context (observed live: 272KB in a desktop session). Scan
319
+ // forward in bounded chunks and keep the LAST match inside the cap; rows
320
+ // between the cap and the tail window stay unscanned, and the stop-time
321
+ // re-read heals any staleness that gap could cause.
322
+ const forward = scanForwardTurnContext(resolved.path, TUNING_FORWARD_SCAN_MAX_BYTES);
323
+ if (forward.row) {
324
+ const fromForward = newestTurnContextTuning(
325
+ [forward.row],
326
+ tail.bytes + forward.bytes,
327
+ startedAt,
328
+ );
329
+ if (fromForward) return fromForward;
330
+ }
331
+ return tuningPartial(
332
+ "codex_transcript_turn_context_missing",
333
+ tail.bytes + forward.bytes,
334
+ startedAt,
335
+ );
336
+ }
337
+
338
+ /** Forward-scan budget for the first turn_context; generous against
339
+ * instruction/world_state bloat while still bounding a runaway file. */
340
+ const TUNING_FORWARD_SCAN_MAX_BYTES = 4 * 1024 * 1024;
341
+ const TUNING_FORWARD_CHUNK_BYTES = 256 * 1024;
342
+
343
+ /** Stream the file from the start in bounded chunks, returning the last
344
+ * parseable `turn_context` row inside the budget and the bytes read. */
345
+ function scanForwardTurnContext(
346
+ path: string,
347
+ maxBytes: number,
348
+ ): { row?: ParsedRuntimeRow; bytes: number } {
349
+ let fd: number | undefined;
350
+ let bytesRead = 0;
351
+ let remainder = "";
352
+ let match: ParsedRuntimeRow | undefined;
353
+ try {
354
+ fd = openSync(path, "r");
355
+ const buffer = Buffer.alloc(TUNING_FORWARD_CHUNK_BYTES);
356
+ while (bytesRead < maxBytes) {
357
+ const read = readSync(fd, buffer, 0, buffer.length, bytesRead);
358
+ if (read <= 0) break;
359
+ bytesRead += read;
360
+ const text = remainder + buffer.subarray(0, read).toString("utf8");
361
+ const lines = text.split("\n");
362
+ remainder = lines.pop() ?? "";
363
+ for (const line of lines) {
364
+ if (!line.includes('"turn_context"')) continue;
365
+ const rows = parseRuntimeRows(line);
366
+ const row = rows.find((candidate) => candidate.type === "turn_context");
367
+ if (row) match = row;
368
+ }
369
+ if (read < buffer.length) break;
370
+ }
371
+ return { row: match, bytes: bytesRead };
372
+ } catch {
373
+ return { row: match, bytes: bytesRead };
374
+ } finally {
375
+ if (fd !== undefined) closeSync(fd);
376
+ }
377
+ }
378
+
379
+ function newestTurnContextTuning(
380
+ rows: ParsedRuntimeRow[],
381
+ bytesRead: number,
382
+ startedAt: number,
383
+ ): RuntimeTuningTelemetry | undefined {
384
+ for (let index = rows.length - 1; index >= 0; index--) {
385
+ const row = rows[index]!;
386
+ if (row.type !== "turn_context") continue;
387
+ const effort = row.payload?.effort;
388
+ const model = row.payload?.model;
389
+ if (typeof effort !== "string" || effort.length === 0) continue;
390
+ return {
391
+ state: "observed",
392
+ effort,
393
+ ...(typeof model === "string" && model.length > 0 ? { model } : {}),
394
+ ...(row.timestamp ? { measured_at: row.timestamp } : {}),
395
+ method: "codex_transcript_turn_context",
396
+ source_event: "codex.rollout_turn_context",
397
+ bytes_read: bytesRead,
398
+ io_duration_ms: elapsed(startedAt),
399
+ };
400
+ }
401
+ return undefined;
402
+ }
403
+
404
+ function readClaudeTuning(
405
+ request: RuntimeTuningRequest,
406
+ options: RuntimeTelemetryOptions,
407
+ startedAt: number,
408
+ ): RuntimeTuningTelemetry {
409
+ const readablePath = transcriptPathCandidates(request.transcript_path).find((candidate) =>
410
+ existsSync(candidate),
411
+ );
412
+ if (!readablePath) return unsupported("runtime_context_telemetry_unavailable", startedAt);
413
+ const tail = readTail(readablePath, options.maxTailBytes ?? DEFAULT_TAIL_BYTES);
414
+ if (!tail) return tuningPartial("claude_transcript_unreadable", 0, startedAt);
415
+ const rows = parseRuntimeRows(tail.text);
416
+ for (let index = rows.length - 1; index >= 0; index--) {
417
+ const row = rows[index]!;
418
+ if (row.type !== "assistant") continue;
419
+ const model = row.payload?.model;
420
+ if (typeof model !== "string" || model.length === 0 || model.startsWith("<")) continue;
421
+ const usage = objectValue(row.payload?.usage);
422
+ const speed = usage?.speed;
423
+ return {
424
+ state: "observed",
425
+ model,
426
+ ...(row.effort ? { effort: row.effort } : {}),
427
+ ...(typeof speed === "string" && speed.length > 0 ? { speed } : {}),
428
+ ...(row.timestamp ? { measured_at: row.timestamp } : {}),
429
+ method: "claude_transcript_assistant_row",
430
+ source_event: "claude-code.transcript_assistant_row",
431
+ bytes_read: tail.bytes,
432
+ io_duration_ms: elapsed(startedAt),
433
+ };
434
+ }
435
+ return tuningPartial("claude_transcript_assistant_row_missing", tail.bytes, startedAt);
436
+ }
437
+
438
+ function tuningPartial(
439
+ reason: RuntimeTuningMissingReason,
440
+ bytesRead: number,
441
+ startedAt: number,
442
+ ): RuntimeTuningTelemetry {
443
+ return {
444
+ state: "partial",
445
+ reason,
446
+ bytes_read: bytesRead,
447
+ io_duration_ms: elapsed(startedAt),
448
+ };
449
+ }
450
+
451
+ function readCodexContext(
452
+ request: RuntimeContextRequest,
453
+ options: RuntimeTelemetryOptions,
454
+ startedAt: number,
455
+ ): RuntimeContextTelemetry {
456
+ const resolved = resolveCodexTranscript(request, options);
457
+ if (resolved.state === "missing") {
458
+ return unsupported("runtime_context_telemetry_unavailable", startedAt);
459
+ }
460
+ if (resolved.state === "ambiguous") {
461
+ return partial("codex_transcript_ambiguous", 0, startedAt);
462
+ }
463
+ if (resolved.state === "mismatch") {
464
+ return partial("codex_transcript_session_mismatch", 0, startedAt);
465
+ }
466
+
467
+ const tail = readTail(
468
+ resolved.path,
469
+ options.maxTailBytes ??
470
+ (request.mode === "active_turn" ? ACTIVE_TURN_TAIL_BYTES : DEFAULT_TAIL_BYTES),
471
+ );
472
+ if (!tail) return partial("codex_transcript_unreadable", 0, startedAt);
473
+ const rows = parseRuntimeRows(tail.text);
474
+ if (request.mode === "status") {
475
+ const token = newestCodexToken(rows);
476
+ return codexObservation(request, token, undefined, tail.bytes, options, startedAt);
477
+ }
478
+
479
+ if (request.mode === "active_turn") {
480
+ const active = tokenWithinActiveTurn(rows, request.turn_id!);
481
+ const token =
482
+ active.state === "found" ? active.token : tokenAtOrAfter(rows, request.turn_started_at);
483
+ if (active.state === "turn_missing" && !token) {
484
+ return partial("codex_transcript_turn_not_found", tail.bytes, startedAt);
485
+ }
486
+ return codexObservation(request, token, undefined, tail.bytes, options, startedAt);
487
+ }
488
+
489
+ const turnId = request.turn_id!;
490
+ const terminalIndex = findCodexTurnTerminal(rows, turnId);
491
+ if (terminalIndex < 0) {
492
+ const sawStart = rows.some(
493
+ (row) =>
494
+ row.type === "event_msg" &&
495
+ row.payload?.type === "task_started" &&
496
+ row.payload.turn_id === turnId,
497
+ );
498
+ return partial(
499
+ sawStart ? "codex_transcript_turn_not_terminal" : "codex_transcript_turn_not_found",
500
+ tail.bytes,
501
+ startedAt,
502
+ );
503
+ }
504
+
505
+ const terminal = rows[terminalIndex]!;
506
+ const token = tokenBeforeTerminal(rows, terminalIndex);
507
+ return codexObservation(request, token, terminal, tail.bytes, options, startedAt);
508
+ }
509
+
510
+ function codexObservation(
511
+ request: RuntimeContextRequest,
512
+ token: CodexTokenSample | undefined,
513
+ terminal: ParsedRuntimeRow | undefined,
514
+ bytesRead: number,
515
+ options: RuntimeTelemetryOptions,
516
+ startedAt: number,
517
+ ): RuntimeContextTelemetry {
518
+ if (!token) return partial("codex_transcript_token_count_missing", bytesRead, startedAt);
519
+ if (token.used_tokens === undefined) {
520
+ return partial("context_used_tokens_not_reported", bytesRead, startedAt);
521
+ }
522
+ if (token.limit_tokens === undefined) {
523
+ return partial("context_limit_tokens_not_reported", bytesRead, startedAt, token);
524
+ }
525
+ if (token.limit_tokens <= 0) {
526
+ return partial("context_limit_tokens_invalid", bytesRead, startedAt, token);
527
+ }
528
+ if (!token.measured_at || !Number.isFinite(Date.parse(token.measured_at))) {
529
+ return partial("codex_transcript_token_count_missing", bytesRead, startedAt);
530
+ }
531
+ if (terminal?.timestamp) {
532
+ const age = Date.parse(terminal.timestamp) - Date.parse(token.measured_at);
533
+ if (age < 0 || age > (options.maxSampleAgeMs ?? DEFAULT_MAX_SAMPLE_AGE_MS)) {
534
+ return partial("codex_transcript_sample_stale", bytesRead, startedAt, token);
535
+ }
536
+ }
537
+ if (request.mode === "active_turn" && request.observed_at) {
538
+ const age = Date.parse(request.observed_at) - Date.parse(token.measured_at);
539
+ if (
540
+ !Number.isFinite(age) ||
541
+ age < -5_000 ||
542
+ age > (options.maxSampleAgeMs ?? DEFAULT_MAX_SAMPLE_AGE_MS)
543
+ ) {
544
+ return partial("codex_transcript_sample_stale", bytesRead, startedAt, token);
545
+ }
546
+ }
547
+ const witness = [
548
+ request.session_id,
549
+ request.turn_id ?? "status",
550
+ token.ordinal ?? "unknown",
551
+ token.measured_at,
552
+ token.used_tokens,
553
+ token.limit_tokens,
554
+ ].join("\0");
555
+ return {
556
+ state: "observed",
557
+ used_tokens: token.used_tokens,
558
+ limit_tokens: token.limit_tokens,
559
+ measured_at: token.measured_at,
560
+ method: "codex_transcript_token_count",
561
+ source_event: "codex.rollout_token_count",
562
+ source_witness: createHash("sha256").update(witness).digest("hex"),
563
+ attestation: "derived",
564
+ confidence: "exact",
565
+ bytes_read: bytesRead,
566
+ io_duration_ms: elapsed(startedAt),
567
+ };
568
+ }
569
+
570
+ function readClaudeContext(
571
+ request: RuntimeContextRequest,
572
+ options: RuntimeTelemetryOptions,
573
+ startedAt: number,
574
+ ): RuntimeContextTelemetry {
575
+ const readablePath = transcriptPathCandidates(request.transcript_path).find((candidate) =>
576
+ existsSync(candidate),
577
+ );
578
+ if (!readablePath) return unsupported("runtime_context_telemetry_unavailable", startedAt);
579
+ const tail = readTail(
580
+ readablePath,
581
+ options.maxTailBytes ??
582
+ (request.mode === "active_turn" ? ACTIVE_TURN_TAIL_BYTES : DEFAULT_TAIL_BYTES),
583
+ );
584
+ if (!tail) return partial("claude_transcript_unreadable", 0, startedAt);
585
+ const rows = parseRuntimeRows(tail.text);
586
+ const sessionRows = rows.filter(
587
+ (row) => row.session_id === undefined || row.session_id === request.session_id,
588
+ );
589
+ if (rows.some((row) => row.session_id !== undefined) && sessionRows.length === 0) {
590
+ return partial("claude_transcript_session_mismatch", tail.bytes, startedAt);
591
+ }
592
+ const turnAttributed = request.mode === "turn" || request.mode === "active_turn";
593
+ const candidateRows = turnAttributed
594
+ ? claudeAssistantRowsForTurn(sessionRows, request.turn_id!)
595
+ : sessionRows.filter((row) => row.type === "assistant");
596
+ if (turnAttributed && candidateRows.length === 0) {
597
+ return partial("claude_transcript_turn_not_found", tail.bytes, startedAt);
598
+ }
599
+ for (let index = candidateRows.length - 1; index >= 0; index--) {
600
+ const row = candidateRows[index]!;
601
+ if (row.type !== "assistant") continue;
602
+ const message = row.payload;
603
+ const usage = objectValue(message?.usage);
604
+ if (!usage) continue;
605
+ const used = sumNumbers(
606
+ usage.input_tokens,
607
+ usage.cache_creation_input_tokens,
608
+ usage.cache_read_input_tokens,
609
+ );
610
+ if (used === undefined) {
611
+ return partial("context_used_tokens_not_reported", tail.bytes, startedAt);
612
+ }
613
+ const model = stringValue(message?.model);
614
+ const capability = model ? claudeModelContextCapability(model) : undefined;
615
+ if (capability && row.timestamp) {
616
+ if (request.mode === "active_turn" && request.observed_at) {
617
+ const age = Date.parse(request.observed_at) - Date.parse(row.timestamp);
618
+ if (
619
+ !Number.isFinite(age) ||
620
+ age < -5_000 ||
621
+ age > (options.maxSampleAgeMs ?? DEFAULT_MAX_SAMPLE_AGE_MS)
622
+ ) {
623
+ return partial("claude_transcript_sample_stale", tail.bytes, startedAt, {
624
+ used_tokens: used,
625
+ measured_at: row.timestamp,
626
+ });
627
+ }
628
+ }
629
+ const witness = [
630
+ request.session_id,
631
+ request.turn_id ?? "status",
632
+ row.timestamp,
633
+ used,
634
+ model,
635
+ capability.limit_tokens,
636
+ capability.authority,
637
+ ].join("\0");
638
+ return {
639
+ state: "observed",
640
+ used_tokens: used,
641
+ limit_tokens: capability.limit_tokens,
642
+ measured_at: row.timestamp,
643
+ method: "claude_transcript_usage_model_capability",
644
+ source_event: "claude.transcript_usage_model_capability",
645
+ source_witness: createHash("sha256").update(witness).digest("hex"),
646
+ attestation: "inferred",
647
+ confidence: "high",
648
+ bytes_read: tail.bytes,
649
+ io_duration_ms: elapsed(startedAt),
650
+ };
651
+ }
652
+ return partial("claude_context_limit_tokens_not_reported", tail.bytes, startedAt, {
653
+ used_tokens: used,
654
+ measured_at: row.timestamp,
655
+ });
656
+ }
657
+ return partial("context_used_tokens_not_reported", tail.bytes, startedAt);
658
+ }
659
+
660
+ interface ClaudeModelContextCapability {
661
+ limit_tokens: number;
662
+ authority: string;
663
+ }
664
+
665
+ /**
666
+ * Versioned exact-name families from Anthropic's published model capability
667
+ * table. Unknown aliases deliberately stay missing: matching a product label
668
+ * or guessing from a family name would turn an estimate into fake precision.
669
+ */
670
+ function claudeModelContextCapability(model: string): ClaudeModelContextCapability | undefined {
671
+ const normalized = model.toLowerCase();
672
+ const oneMillionTokenModels = new Set([
673
+ "claude-fable-5",
674
+ "claude-opus-5",
675
+ "claude-sonnet-5",
676
+ "claude-opus-4-8",
677
+ "claude-opus-4-7",
678
+ "claude-opus-4-6",
679
+ "claude-sonnet-4-6",
680
+ ]);
681
+ if (oneMillionTokenModels.has(normalized)) {
682
+ return { limit_tokens: 1_000_000, authority: "anthropic_model_capabilities_2026_08" };
683
+ }
684
+ if (normalized === "claude-haiku-4-5" || normalized === "claude-haiku-4-5-20251001") {
685
+ return { limit_tokens: 200_000, authority: "anthropic_model_capabilities_2026_08" };
686
+ }
687
+ return undefined;
688
+ }
689
+
690
+ interface CursorContextSample {
691
+ used_percent: number;
692
+ measured_at: string;
693
+ bytes_read: number;
694
+ database_path: string;
695
+ }
696
+
697
+ function readCursorContext(
698
+ request: RuntimeContextRequest,
699
+ options: RuntimeTelemetryOptions,
700
+ startedAt: number,
701
+ ): RuntimeContextTelemetry {
702
+ const cached = cursorDatabaseCache.get(request.session_id!);
703
+ if (cached && existsSync(cached)) {
704
+ const sample = readCursorDatabase(cached, request.session_id!);
705
+ if (sample.state === "found") {
706
+ return cursorObservation(request, sample.sample, options, startedAt);
707
+ }
708
+ cursorDatabaseCache.delete(request.session_id!);
709
+ }
710
+
711
+ const databases = cursorDatabasePaths(options);
712
+ if (databases.length === 0) {
713
+ return partial("cursor_context_database_unavailable", 0, startedAt);
714
+ }
715
+ const matches: CursorContextSample[] = [];
716
+ let bytesRead = 0;
717
+ let unreadable = 0;
718
+ for (const databasePath of databases) {
719
+ const result = readCursorDatabase(databasePath, request.session_id!);
720
+ bytesRead += result.state === "found" ? result.sample.bytes_read : result.bytes_read;
721
+ if (result.state === "unreadable") unreadable += 1;
722
+ if (result.state !== "found") continue;
723
+ matches.push(result.sample);
724
+ }
725
+ if (matches.length === 0) {
726
+ return partial(
727
+ unreadable === databases.length
728
+ ? "cursor_context_database_unreadable"
729
+ : "cursor_context_session_not_found",
730
+ bytesRead,
731
+ startedAt,
732
+ );
733
+ }
734
+ matches.sort((left, right) => Date.parse(right.measured_at) - Date.parse(left.measured_at));
735
+ const newest = matches[0]!;
736
+ const tied = matches.filter((sample) => sample.measured_at === newest.measured_at);
737
+ if (tied.some((sample) => sample.used_percent !== newest.used_percent)) {
738
+ return partial("cursor_context_sample_ambiguous", bytesRead, startedAt);
739
+ }
740
+ cacheCursorDatabase(request.session_id!, newest.database_path);
741
+ return cursorObservation(request, newest, options, startedAt);
742
+ }
743
+
744
+ function cursorObservation(
745
+ request: RuntimeContextRequest,
746
+ sample: CursorContextSample,
747
+ options: RuntimeTelemetryOptions,
748
+ startedAt: number,
749
+ ): RuntimeContextTelemetry {
750
+ if (
751
+ !Number.isFinite(sample.used_percent) ||
752
+ sample.used_percent < 0 ||
753
+ sample.used_percent > 100
754
+ ) {
755
+ return partial("cursor_context_usage_invalid", sample.bytes_read, startedAt);
756
+ }
757
+ const sampleMs = Date.parse(sample.measured_at);
758
+ if (!Number.isFinite(sampleMs)) {
759
+ return partial("cursor_context_sample_time_not_reported", sample.bytes_read, startedAt);
760
+ }
761
+ if ((request.mode === "turn" || request.mode === "active_turn") && request.observed_at) {
762
+ const observedMs = Date.parse(request.observed_at);
763
+ const age = observedMs - sampleMs;
764
+ if (
765
+ !Number.isFinite(observedMs) ||
766
+ age < -5_000 ||
767
+ age > (options.maxSampleAgeMs ?? DEFAULT_MAX_SAMPLE_AGE_MS)
768
+ ) {
769
+ return partial("cursor_context_sample_stale", sample.bytes_read, startedAt);
770
+ }
771
+ }
772
+ const witness = [request.session_id, sample.measured_at, sample.used_percent].join("\0");
773
+ return {
774
+ state: "observed",
775
+ used_percent: sample.used_percent,
776
+ measured_at: sample.measured_at,
777
+ method: "cursor_composer_context_percent",
778
+ source_event: "cursor.composer_context_percent",
779
+ source_witness: createHash("sha256").update(witness).digest("hex"),
780
+ attestation: "derived",
781
+ confidence: "high",
782
+ bytes_read: sample.bytes_read,
783
+ io_duration_ms: elapsed(startedAt),
784
+ };
785
+ }
786
+
787
+ type CursorDatabaseResult =
788
+ | { state: "found"; sample: CursorContextSample }
789
+ | { state: "missing"; bytes_read: number }
790
+ | { state: "unreadable"; bytes_read: number };
791
+
792
+ function readCursorDatabase(databasePath: string, sessionId: string): CursorDatabaseResult {
793
+ try {
794
+ // Bun is the primary hook runtime. Node fallback processes fail closed here
795
+ // instead of importing a Bun-only module at startup.
796
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
797
+ const { Database } = require("bun:sqlite") as {
798
+ Database: new (
799
+ path: string,
800
+ options: { readonly: boolean },
801
+ ) => {
802
+ query(sql: string): { get(): { value: string | Uint8Array } | null };
803
+ close(): void;
804
+ };
805
+ };
806
+ const database = new Database(databasePath, { readonly: true });
807
+ const row = database
808
+ .query("SELECT value FROM ItemTable WHERE key = 'composer.composerData'")
809
+ .get();
810
+ database.close();
811
+ if (!row?.value) return { state: "missing", bytes_read: 0 };
812
+ const text =
813
+ typeof row.value === "string" ? row.value : Buffer.from(row.value).toString("utf8");
814
+ const bytesRead = Buffer.byteLength(text);
815
+ const parsed = objectValue(JSON.parse(text));
816
+ const composers = Array.isArray(parsed?.allComposers) ? parsed.allComposers : [];
817
+ for (const candidate of composers) {
818
+ const composer = objectValue(candidate);
819
+ if (stringValue(composer?.composerId) !== sessionId) continue;
820
+ const usedPercent = numberValue(composer?.contextUsagePercent);
821
+ if (usedPercent === undefined) return { state: "missing", bytes_read: bytesRead };
822
+ const measuredAt = cursorMeasuredAt(composer?.lastUpdatedAt);
823
+ if (!measuredAt) return { state: "missing", bytes_read: bytesRead };
824
+ return {
825
+ state: "found",
826
+ sample: {
827
+ used_percent: usedPercent,
828
+ measured_at: measuredAt,
829
+ bytes_read: bytesRead,
830
+ database_path: databasePath,
831
+ },
832
+ };
833
+ }
834
+ return { state: "missing", bytes_read: bytesRead };
835
+ } catch {
836
+ return { state: "unreadable", bytes_read: 0 };
837
+ }
838
+ }
839
+
840
+ function cursorMeasuredAt(value: unknown): string | undefined {
841
+ if (typeof value === "string" && Number.isFinite(Date.parse(value))) {
842
+ return new Date(value).toISOString();
843
+ }
844
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return undefined;
845
+ const milliseconds = value < 10_000_000_000 ? value * 1_000 : value;
846
+ const date = new Date(milliseconds);
847
+ return Number.isFinite(date.getTime()) ? date.toISOString() : undefined;
848
+ }
849
+
850
+ function cursorDatabasePaths(options: RuntimeTelemetryOptions): string[] {
851
+ const roots = options.cursorRoots ?? defaultCursorRoots();
852
+ const limit = Math.max(1, Math.floor(options.maxCursorDatabases ?? DEFAULT_MAX_CURSOR_DATABASES));
853
+ const candidates: Array<{ path: string; modified_ms: number }> = [];
854
+ for (const root of roots) {
855
+ let names: string[];
856
+ try {
857
+ names = readdirSync(root).sort();
858
+ } catch {
859
+ continue;
860
+ }
861
+ for (const name of names) {
862
+ const databasePath = join(root, name, "state.vscdb");
863
+ try {
864
+ candidates.push({ path: databasePath, modified_ms: statSync(databasePath).mtimeMs });
865
+ } catch {
866
+ // Removed or unreadable workspaces are not candidates.
867
+ }
868
+ }
869
+ }
870
+ return candidates
871
+ .sort((left, right) => right.modified_ms - left.modified_ms)
872
+ .slice(0, limit)
873
+ .map((candidate) => candidate.path);
874
+ }
875
+
876
+ function defaultCursorRoots(): string[] {
877
+ const roots = [resolve(homedir(), ".config", "Cursor", "User", "workspaceStorage")];
878
+ try {
879
+ if (existsSync("/mnt/c/Users")) {
880
+ for (const user of readdirSync("/mnt/c/Users")) {
881
+ roots.push(`/mnt/c/Users/${user}/AppData/Roaming/Cursor/User/workspaceStorage`);
882
+ }
883
+ }
884
+ } catch {
885
+ // Non-WSL hosts do not expose this mount.
886
+ }
887
+ return roots;
888
+ }
889
+
890
+ function cacheCursorDatabase(sessionId: string, databasePath: string): void {
891
+ cursorDatabaseCache.delete(sessionId);
892
+ cursorDatabaseCache.set(sessionId, databasePath);
893
+ while (cursorDatabaseCache.size > SESSION_CACHE_LIMIT) {
894
+ cursorDatabaseCache.delete(cursorDatabaseCache.keys().next().value!);
895
+ }
896
+ }
897
+
898
+ /** Join assistant rows to the native CC prompt id through the transcript's
899
+ * parent UUID chain. No UUID or prompt value crosses the reader boundary. */
900
+ function claudeAssistantRowsForTurn(rows: ParsedRuntimeRow[], turnId: string): ParsedRuntimeRow[] {
901
+ const byUuid = new Map(rows.filter((row) => row.uuid).map((row) => [row.uuid!, row] as const));
902
+ return rows.filter((row) => {
903
+ if (row.type !== "assistant") return false;
904
+ let parentUuid = row.parent_uuid;
905
+ const seen = new Set<string>();
906
+ for (let depth = 0; parentUuid && depth < 64 && !seen.has(parentUuid); depth += 1) {
907
+ seen.add(parentUuid);
908
+ const parent = byUuid.get(parentUuid);
909
+ if (!parent) return false;
910
+ if (parent.type === "user" && parent.prompt_id) return parent.prompt_id === turnId;
911
+ parentUuid = parent.parent_uuid;
912
+ }
913
+ return false;
914
+ });
915
+ }
916
+
917
+ function newestCodexToken(rows: ParsedRuntimeRow[]): CodexTokenSample | undefined {
918
+ for (let index = rows.length - 1; index >= 0; index--) {
919
+ const token = codexToken(rows[index]!);
920
+ if (token) return token;
921
+ }
922
+ return undefined;
923
+ }
924
+
925
+ function tokenWithinActiveTurn(
926
+ rows: ParsedRuntimeRow[],
927
+ turnId: string,
928
+ ): { state: "found"; token?: CodexTokenSample } | { state: "turn_missing" } {
929
+ let startIndex = -1;
930
+ for (let index = rows.length - 1; index >= 0; index -= 1) {
931
+ const row = rows[index]!;
932
+ if (
933
+ row.type === "event_msg" &&
934
+ row.payload?.type === "task_started" &&
935
+ row.payload.turn_id === turnId
936
+ ) {
937
+ startIndex = index;
938
+ break;
939
+ }
940
+ }
941
+ if (startIndex < 0) return { state: "turn_missing" };
942
+
943
+ let token: CodexTokenSample | undefined;
944
+ for (let index = startIndex + 1; index < rows.length; index += 1) {
945
+ const row = rows[index]!;
946
+ if (
947
+ row.type === "event_msg" &&
948
+ (row.payload?.type === "task_started" || row.payload?.type === "task_complete")
949
+ ) {
950
+ break;
951
+ }
952
+ token = codexToken(row) ?? token;
953
+ }
954
+ return { state: "found", token };
955
+ }
956
+
957
+ function tokenAtOrAfter(
958
+ rows: ParsedRuntimeRow[],
959
+ turnStartedAt: string | undefined,
960
+ ): CodexTokenSample | undefined {
961
+ if (!turnStartedAt || !Number.isFinite(Date.parse(turnStartedAt))) return undefined;
962
+ const token = newestCodexToken(rows);
963
+ if (!token?.measured_at) return undefined;
964
+ return Date.parse(token.measured_at) >= Date.parse(turnStartedAt) ? token : undefined;
965
+ }
966
+
967
+ function tokenBeforeTerminal(
968
+ rows: ParsedRuntimeRow[],
969
+ terminalIndex: number,
970
+ ): CodexTokenSample | undefined {
971
+ for (let index = terminalIndex - 1; index >= 0; index--) {
972
+ const row = rows[index]!;
973
+ const type = row.payload?.type;
974
+ if (type === "task_started" || type === "task_complete") break;
975
+ const token = codexToken(row);
976
+ if (token) return token;
977
+ }
978
+ return undefined;
979
+ }
980
+
981
+ function codexToken(row: ParsedRuntimeRow): CodexTokenSample | undefined {
982
+ if (row.type !== "event_msg" || row.payload?.type !== "token_count") return undefined;
983
+ const info = objectValue(row.payload.info);
984
+ const usage = objectValue(info?.last_token_usage);
985
+ return {
986
+ used_tokens: safeInteger(usage?.input_tokens),
987
+ limit_tokens: safeInteger(info?.model_context_window),
988
+ measured_at: timestamp(row.timestamp),
989
+ ordinal: safeInteger(row.ordinal),
990
+ };
991
+ }
992
+
993
+ function findCodexTurnTerminal(rows: ParsedRuntimeRow[], turnId: string): number {
994
+ for (let index = rows.length - 1; index >= 0; index--) {
995
+ const row = rows[index]!;
996
+ if (
997
+ row.type === "event_msg" &&
998
+ row.payload?.type === "task_complete" &&
999
+ row.payload.turn_id === turnId
1000
+ ) {
1001
+ return index;
1002
+ }
1003
+ }
1004
+ return -1;
1005
+ }
1006
+
1007
+ function parseRuntimeRows(text: string): ParsedRuntimeRow[] {
1008
+ const rows: ParsedRuntimeRow[] = [];
1009
+ for (const line of text.split("\n")) {
1010
+ if (!line.trim()) continue;
1011
+ try {
1012
+ const value = JSON.parse(line) as unknown;
1013
+ const row = objectValue(value);
1014
+ if (!row) continue;
1015
+ rows.push({
1016
+ timestamp: timestamp(row.timestamp),
1017
+ ordinal: safeInteger(row.ordinal),
1018
+ type: typeof row.type === "string" ? row.type : undefined,
1019
+ uuid: stringValue(row.uuid),
1020
+ parent_uuid: stringValue(row.parentUuid),
1021
+ prompt_id: stringValue(row.promptId) ?? stringValue(row.prompt_id),
1022
+ session_id: stringValue(row.sessionId) ?? stringValue(row.session_id),
1023
+ ...(typeof row.effort === "string" && row.effort.length > 0 ? { effort: row.effort } : {}),
1024
+ payload: objectValue(row.payload) ?? objectValue(row.message) ?? undefined,
1025
+ });
1026
+ } catch {
1027
+ // The first line may be cut by the bounded tail or a writer may be mid-flush.
1028
+ }
1029
+ }
1030
+ return rows;
1031
+ }
1032
+
1033
+ function stringValue(value: unknown): string | undefined {
1034
+ return typeof value === "string" && value.length > 0 ? value : undefined;
1035
+ }
1036
+
1037
+ function numberValue(value: unknown): number | undefined {
1038
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
1039
+ }
1040
+
1041
+ function readTail(path: string, maxBytes: number): TailRead | undefined {
1042
+ let fd: number | undefined;
1043
+ try {
1044
+ const size = statSync(path).size;
1045
+ const bytes = Math.max(0, Math.min(size, Math.max(1, Math.floor(maxBytes))));
1046
+ const start = size - bytes;
1047
+ fd = openSync(path, "r");
1048
+ const buffer = Buffer.alloc(bytes);
1049
+ const read = readSync(fd, buffer, 0, bytes, start);
1050
+ const text = buffer.subarray(0, read).toString("utf8");
1051
+ return {
1052
+ text: start > 0 ? text.slice(Math.max(0, text.indexOf("\n") + 1)) : text,
1053
+ bytes: read,
1054
+ };
1055
+ } catch {
1056
+ return undefined;
1057
+ } finally {
1058
+ if (fd !== undefined) closeSync(fd);
1059
+ }
1060
+ }
1061
+
1062
+ type TranscriptResolution =
1063
+ | { state: "found"; path: string }
1064
+ | { state: "missing" }
1065
+ | { state: "ambiguous" }
1066
+ | { state: "mismatch" };
1067
+
1068
+ function resolveCodexTranscript(
1069
+ request: RuntimeContextRequest,
1070
+ options: RuntimeTelemetryOptions,
1071
+ ): TranscriptResolution {
1072
+ const sessionId = request.session_id!;
1073
+ const cached = codexTranscriptCache.get(sessionId);
1074
+ if (cached && existsSync(cached)) return { state: "found", path: cached };
1075
+
1076
+ const supplied = transcriptPathCandidates(request.transcript_path).filter((candidate) =>
1077
+ existsSync(candidate),
1078
+ );
1079
+ const verifiedSupplied = supplied.filter((candidate) => transcriptMatches(candidate, sessionId));
1080
+ if (verifiedSupplied.length === 1) return cacheTranscript(sessionId, verifiedSupplied[0]!);
1081
+ if (verifiedSupplied.length > 1) return { state: "ambiguous" };
1082
+ if (supplied.length > 0) return { state: "mismatch" };
1083
+
1084
+ const matches = codexRoots(options)
1085
+ .flatMap((root) => findTranscriptMatches(root, sessionId))
1086
+ .filter((path, index, values) => values.indexOf(path) === index);
1087
+ if (matches.length === 1) return cacheTranscript(sessionId, matches[0]!);
1088
+ if (matches.length > 1) return { state: "ambiguous" };
1089
+ return { state: "missing" };
1090
+ }
1091
+
1092
+ function cacheTranscript(sessionId: string, path: string): TranscriptResolution {
1093
+ codexTranscriptCache.delete(sessionId);
1094
+ codexTranscriptCache.set(sessionId, path);
1095
+ while (codexTranscriptCache.size > SESSION_CACHE_LIMIT) {
1096
+ codexTranscriptCache.delete(codexTranscriptCache.keys().next().value!);
1097
+ }
1098
+ return { state: "found", path };
1099
+ }
1100
+
1101
+ function codexRoots(options: RuntimeTelemetryOptions): string[] {
1102
+ if (options.codexRoots) return options.codexRoots;
1103
+ const roots = [resolve(homedir(), ".codex", "sessions")];
1104
+ try {
1105
+ if (existsSync("/mnt/c/Users")) {
1106
+ for (const user of readdirSync("/mnt/c/Users")) {
1107
+ roots.push(`/mnt/c/Users/${user}/.codex/sessions`);
1108
+ }
1109
+ }
1110
+ } catch {
1111
+ // Non-WSL hosts do not expose this mount.
1112
+ }
1113
+ return roots;
1114
+ }
1115
+
1116
+ function findTranscriptMatches(root: string, sessionId: string): string[] {
1117
+ if (!existsSync(root)) return [];
1118
+ const matches: string[] = [];
1119
+ const stack: Array<{ path: string; depth: number }> = [{ path: root, depth: 0 }];
1120
+ while (stack.length > 0) {
1121
+ const current = stack.pop()!;
1122
+ if (current.depth > 4) continue;
1123
+ let names: string[];
1124
+ try {
1125
+ names = readdirSync(current.path);
1126
+ } catch {
1127
+ continue;
1128
+ }
1129
+ for (const name of names) {
1130
+ const path = join(current.path, name);
1131
+ try {
1132
+ const stat = statSync(path);
1133
+ if (stat.isDirectory()) stack.push({ path, depth: current.depth + 1 });
1134
+ else if (transcriptMatches(path, sessionId)) matches.push(path);
1135
+ } catch {
1136
+ // A concurrently removed partition is simply unavailable.
1137
+ }
1138
+ }
1139
+ }
1140
+ return matches;
1141
+ }
1142
+
1143
+ function transcriptMatches(path: string, sessionId: string): boolean {
1144
+ return basename(path).endsWith(`-${sessionId}.jsonl`);
1145
+ }
1146
+
1147
+ /** Narrow return: this exact shape is a member of both telemetry unions. */
1148
+ function unsupported(
1149
+ reason: RuntimeContextUnsupportedReason,
1150
+ startedAt: number,
1151
+ ): {
1152
+ state: "unsupported";
1153
+ reason: RuntimeContextUnsupportedReason;
1154
+ bytes_read: 0;
1155
+ io_duration_ms: number;
1156
+ } {
1157
+ return { state: "unsupported", reason, bytes_read: 0, io_duration_ms: elapsed(startedAt) };
1158
+ }
1159
+
1160
+ function partial(
1161
+ reason: RuntimeContextMissingReason,
1162
+ bytesRead: number,
1163
+ startedAt: number,
1164
+ sample?: Pick<CodexTokenSample, "used_tokens" | "measured_at">,
1165
+ ): RuntimeContextTelemetry {
1166
+ return {
1167
+ state: "partial",
1168
+ reason,
1169
+ ...(sample?.used_tokens !== undefined ? { used_tokens: sample.used_tokens } : {}),
1170
+ ...(sample?.measured_at ? { measured_at: sample.measured_at } : {}),
1171
+ bytes_read: bytesRead,
1172
+ io_duration_ms: elapsed(startedAt),
1173
+ };
1174
+ }
1175
+
1176
+ function elapsed(startedAt: number): number {
1177
+ return Math.max(0, Math.round((performance.now() - startedAt) * 1000) / 1000);
1178
+ }
1179
+
1180
+ function objectValue(value: unknown): Record<string, unknown> | null {
1181
+ return typeof value === "object" && value !== null && !Array.isArray(value)
1182
+ ? (value as Record<string, unknown>)
1183
+ : null;
1184
+ }
1185
+
1186
+ function safeInteger(value: unknown): number | undefined {
1187
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
1188
+ }
1189
+
1190
+ function timestamp(value: unknown): string | undefined {
1191
+ if (typeof value !== "string" || !Number.isFinite(Date.parse(value))) return undefined;
1192
+ return new Date(value).toISOString();
1193
+ }
1194
+
1195
+ function sumNumbers(...values: unknown[]): number | undefined {
1196
+ const numbers = values.map(safeInteger);
1197
+ return numbers.some((value) => value !== undefined)
1198
+ ? numbers.reduce<number>((total, value) => total + (value ?? 0), 0)
1199
+ : undefined;
1200
+ }