harnery 0.35.0 → 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 (616) 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 -96
  4. package/dist/commands/agents.d.ts +23 -3
  5. package/dist/commands/agents.d.ts.map +1 -1
  6. package/dist/commands/agents.js +379 -198
  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 +5 -4
  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/deinit.d.ts.map +1 -1
  18. package/dist/commands/deinit.js +5 -0
  19. package/dist/commands/docs.d.ts.map +1 -1
  20. package/dist/commands/docs.js +13 -2
  21. package/dist/commands/doctor.d.ts +5 -0
  22. package/dist/commands/doctor.d.ts.map +1 -1
  23. package/dist/commands/doctor.js +51 -7
  24. package/dist/commands/fetch.js +6 -5
  25. package/dist/commands/files.d.ts +22 -0
  26. package/dist/commands/files.d.ts.map +1 -0
  27. package/dist/commands/files.js +113 -0
  28. package/dist/commands/governor.js +14 -12
  29. package/dist/commands/inbox.d.ts +5 -0
  30. package/dist/commands/inbox.d.ts.map +1 -0
  31. package/dist/commands/inbox.js +57 -0
  32. package/dist/commands/init.d.ts +4 -5
  33. package/dist/commands/init.d.ts.map +1 -1
  34. package/dist/commands/init.js +63 -13
  35. package/dist/commands/ledger-v3.d.ts.map +1 -1
  36. package/dist/commands/ledger-v3.js +347 -1
  37. package/dist/commands/logs.d.ts +4 -0
  38. package/dist/commands/logs.d.ts.map +1 -0
  39. package/dist/commands/logs.js +169 -0
  40. package/dist/commands/messages.d.ts +5 -0
  41. package/dist/commands/messages.d.ts.map +1 -0
  42. package/dist/commands/messages.js +45 -0
  43. package/dist/commands/outline.d.ts +1 -1
  44. package/dist/commands/outline.d.ts.map +1 -1
  45. package/dist/commands/outline.js +2 -2
  46. package/dist/commands/read.d.ts +1 -1
  47. package/dist/commands/read.d.ts.map +1 -1
  48. package/dist/commands/read.js +2 -2
  49. package/dist/commands/semantic.d.ts.map +1 -1
  50. package/dist/commands/semantic.js +54 -2
  51. package/dist/commands/storage.d.ts +4 -0
  52. package/dist/commands/storage.d.ts.map +1 -0
  53. package/dist/commands/storage.js +238 -0
  54. package/dist/commands/tunnel.d.ts +5 -1
  55. package/dist/commands/tunnel.d.ts.map +1 -1
  56. package/dist/commands/tunnel.js +44 -31
  57. package/dist/commands/web.d.ts +3 -0
  58. package/dist/commands/web.d.ts.map +1 -1
  59. package/dist/commands/web.js +67 -7
  60. package/dist/commands/work.js +3 -3
  61. package/dist/commands/workflow.js +13 -13
  62. package/dist/core/adapters/profiles.d.ts +1 -1
  63. package/dist/core/agents/cli.js +209 -39
  64. package/dist/core/agents/live-authority-v3.d.ts +47 -1
  65. package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
  66. package/dist/core/agents/live-authority-v3.js +244 -10
  67. package/dist/core/agents/live-lifecycle-v3.js +6 -1
  68. package/dist/core/agents/live-observation-v3.d.ts.map +1 -1
  69. package/dist/core/agents/live-observation-v3.js +6 -1
  70. package/dist/core/agents/render/prompt-context.d.ts +9 -3
  71. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  72. package/dist/core/agents/render/prompt-context.js +24 -7
  73. package/dist/core/agents/rules/stop-hook.d.ts +2 -0
  74. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  75. package/dist/core/agents/rules/stop-hook.js +94 -13
  76. package/dist/core/agents/rules/verdict.d.ts +1 -0
  77. package/dist/core/agents/rules/verdict.d.ts.map +1 -1
  78. package/dist/core/agents/session-events.d.ts.map +1 -1
  79. package/dist/core/agents/session-events.js +4 -0
  80. package/dist/core/agents/session-finalization-state-v3.js +1 -1
  81. package/dist/core/agents/session-finalizer-v3.js +5 -1
  82. package/dist/core/agents/state/activity-log.d.ts +3 -0
  83. package/dist/core/agents/state/activity-log.d.ts.map +1 -1
  84. package/dist/core/agents/state/activity-log.js +6 -3
  85. package/dist/core/agents/state/heartbeat-writer.d.ts +6 -0
  86. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  87. package/dist/core/agents/state/heartbeat-writer.js +18 -0
  88. package/dist/core/agents/state/live-coordination-view.d.ts +5 -7
  89. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  90. package/dist/core/agents/state/live-coordination-view.js +15 -90
  91. package/dist/core/agents/state/live-coordination-writer.d.ts +12 -0
  92. package/dist/core/agents/state/live-coordination-writer.d.ts.map +1 -0
  93. package/dist/core/agents/state/live-coordination-writer.js +92 -0
  94. package/dist/core/artifacts/index.d.ts +21 -0
  95. package/dist/core/artifacts/index.d.ts.map +1 -1
  96. package/dist/core/artifacts/index.js +46 -1
  97. package/dist/core/config.d.ts +62 -4
  98. package/dist/core/config.d.ts.map +1 -1
  99. package/dist/core/config.js +98 -4
  100. package/dist/core/conversations/archive.d.ts +49 -0
  101. package/dist/core/conversations/archive.d.ts.map +1 -0
  102. package/dist/core/conversations/archive.js +136 -0
  103. package/dist/core/conversations/catalog.d.ts +10 -0
  104. package/dist/core/conversations/catalog.d.ts.map +1 -0
  105. package/dist/core/conversations/catalog.js +72 -0
  106. package/dist/core/conversations/context-pack.d.ts +6 -0
  107. package/dist/core/conversations/context-pack.d.ts.map +1 -0
  108. package/dist/core/conversations/context-pack.js +60 -0
  109. package/dist/core/conversations/contract.d.ts +155 -0
  110. package/dist/core/conversations/contract.d.ts.map +1 -0
  111. package/dist/core/conversations/contract.js +1 -0
  112. package/dist/core/conversations/evaluation.d.ts +16 -0
  113. package/dist/core/conversations/evaluation.d.ts.map +1 -0
  114. package/dist/core/conversations/evaluation.js +9 -0
  115. package/dist/core/conversations/index.d.ts +10 -0
  116. package/dist/core/conversations/index.d.ts.map +1 -0
  117. package/dist/core/conversations/index.js +9 -0
  118. package/dist/core/conversations/lifecycle.d.ts +28 -0
  119. package/dist/core/conversations/lifecycle.d.ts.map +1 -0
  120. package/dist/core/conversations/lifecycle.js +29 -0
  121. package/dist/core/conversations/normalize.d.ts +14 -0
  122. package/dist/core/conversations/normalize.d.ts.map +1 -0
  123. package/dist/core/conversations/normalize.js +82 -0
  124. package/dist/core/conversations/query.d.ts +8 -0
  125. package/dist/core/conversations/query.d.ts.map +1 -0
  126. package/dist/core/conversations/query.js +280 -0
  127. package/dist/core/conversations/search-index.d.ts +9 -0
  128. package/dist/core/conversations/search-index.d.ts.map +1 -0
  129. package/dist/core/conversations/search-index.js +29 -0
  130. package/dist/core/events/legacy-storage/canary.d.ts +18 -0
  131. package/dist/core/events/legacy-storage/canary.d.ts.map +1 -0
  132. package/dist/core/events/legacy-storage/canary.js +150 -0
  133. package/dist/core/events/legacy-storage/fence.d.ts +15 -0
  134. package/dist/core/events/legacy-storage/fence.d.ts.map +1 -0
  135. package/dist/core/events/legacy-storage/fence.js +115 -0
  136. package/dist/core/events/legacy-storage/index.d.ts +6 -0
  137. package/dist/core/events/legacy-storage/index.d.ts.map +1 -0
  138. package/dist/core/events/legacy-storage/index.js +5 -0
  139. package/dist/core/events/legacy-storage/inventory.d.ts +10 -0
  140. package/dist/core/events/legacy-storage/inventory.d.ts.map +1 -0
  141. package/dist/core/events/legacy-storage/inventory.js +40 -0
  142. package/dist/core/events/legacy-storage/manifest.d.ts +23 -0
  143. package/dist/core/events/legacy-storage/manifest.d.ts.map +1 -0
  144. package/dist/core/events/legacy-storage/manifest.js +108 -0
  145. package/dist/core/events/legacy-storage/reader.d.ts +15 -0
  146. package/dist/core/events/legacy-storage/reader.d.ts.map +1 -0
  147. package/dist/core/events/legacy-storage/reader.js +154 -0
  148. package/dist/core/events/v3/authority-outbox.d.ts +7 -2
  149. package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
  150. package/dist/core/events/v3/authority-outbox.js +16 -3
  151. package/dist/core/events/v3/base-contract.d.ts +81 -41
  152. package/dist/core/events/v3/base-contract.d.ts.map +1 -1
  153. package/dist/core/events/v3/base-contract.js +17 -7
  154. package/dist/core/events/v3/bootstrap.d.ts +39 -0
  155. package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
  156. package/dist/core/events/v3/bootstrap.js +167 -3
  157. package/dist/core/events/v3/capabilities.js +3 -3
  158. package/dist/core/events/v3/control-witness.d.ts +44 -0
  159. package/dist/core/events/v3/control-witness.d.ts.map +1 -0
  160. package/dist/core/events/v3/control-witness.js +233 -0
  161. package/dist/core/events/v3/control-writer.d.ts +4 -0
  162. package/dist/core/events/v3/control-writer.d.ts.map +1 -0
  163. package/dist/core/events/v3/control-writer.js +16 -0
  164. package/dist/core/events/v3/control.d.ts +8 -2
  165. package/dist/core/events/v3/control.d.ts.map +1 -1
  166. package/dist/core/events/v3/control.js +46 -18
  167. package/dist/core/events/v3/coordination-transaction-recovery.d.ts +42 -0
  168. package/dist/core/events/v3/coordination-transaction-recovery.d.ts.map +1 -0
  169. package/dist/core/events/v3/coordination-transaction-recovery.js +342 -0
  170. package/dist/core/events/v3/coordination-view.d.ts.map +1 -1
  171. package/dist/core/events/v3/coordination-view.js +16 -1
  172. package/dist/core/events/v3/generated.d.ts +1 -1
  173. package/dist/core/events/v3/generated.js +1 -1
  174. package/dist/core/events/v3/index.d.ts +4 -2
  175. package/dist/core/events/v3/index.d.ts.map +1 -1
  176. package/dist/core/events/v3/index.js +3 -1
  177. package/dist/core/events/v3/live-route-observer.d.ts +31 -0
  178. package/dist/core/events/v3/live-route-observer.d.ts.map +1 -0
  179. package/dist/core/events/v3/live-route-observer.js +58 -0
  180. package/dist/core/events/v3/live-routing.d.ts +13 -21
  181. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  182. package/dist/core/events/v3/live-routing.js +45 -41
  183. package/dist/core/events/v3/producers/coordination-recorder.d.ts +11 -1
  184. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  185. package/dist/core/events/v3/producers/coordination-recorder.js +76 -10
  186. package/dist/core/events/v3/producers/diagnostic-summaries.d.ts +129 -0
  187. package/dist/core/events/v3/producers/diagnostic-summaries.d.ts.map +1 -0
  188. package/dist/core/events/v3/producers/diagnostic-summaries.js +499 -0
  189. package/dist/core/events/v3/producers/hook-base.js +1 -1
  190. package/dist/core/events/v3/producers/intake.d.ts +7 -0
  191. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  192. package/dist/core/events/v3/producers/intake.js +25 -2
  193. package/dist/core/events/v3/producers/producer-state-observer.d.ts +8 -0
  194. package/dist/core/events/v3/producers/producer-state-observer.d.ts.map +1 -0
  195. package/dist/core/events/v3/producers/producer-state-observer.js +45 -0
  196. package/dist/core/events/v3/producers/recorder.d.ts +55 -1
  197. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  198. package/dist/core/events/v3/producers/recorder.js +353 -24
  199. package/dist/core/events/v3/reader.d.ts +51 -0
  200. package/dist/core/events/v3/reader.d.ts.map +1 -1
  201. package/dist/core/events/v3/reader.js +181 -1
  202. package/dist/core/events/v3/rotation-config.d.ts +9 -0
  203. package/dist/core/events/v3/rotation-config.d.ts.map +1 -0
  204. package/dist/core/events/v3/rotation-config.js +91 -0
  205. package/dist/core/events/v3/runtime-build.d.ts +11 -0
  206. package/dist/core/events/v3/runtime-build.d.ts.map +1 -0
  207. package/dist/core/events/v3/runtime-build.js +39 -0
  208. package/dist/core/events/v3/runtime-identity.d.ts +5 -0
  209. package/dist/core/events/v3/runtime-identity.d.ts.map +1 -0
  210. package/dist/core/events/v3/runtime-identity.js +18 -0
  211. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +6 -5
  212. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -1
  213. package/dist/core/events/v3/runtime-telemetry-capabilities.js +1 -1
  214. package/dist/core/events/v3/support-storage/classify.d.ts +46 -0
  215. package/dist/core/events/v3/support-storage/classify.d.ts.map +1 -0
  216. package/dist/core/events/v3/support-storage/classify.js +149 -0
  217. package/dist/core/events/v3/support-storage/eligibility.d.ts +29 -0
  218. package/dist/core/events/v3/support-storage/eligibility.d.ts.map +1 -0
  219. package/dist/core/events/v3/support-storage/eligibility.js +35 -0
  220. package/dist/core/events/v3/support-storage/index.d.ts +10 -0
  221. package/dist/core/events/v3/support-storage/index.d.ts.map +1 -0
  222. package/dist/core/events/v3/support-storage/index.js +9 -0
  223. package/dist/core/events/v3/support-storage/inventory.d.ts +30 -0
  224. package/dist/core/events/v3/support-storage/inventory.d.ts.map +1 -0
  225. package/dist/core/events/v3/support-storage/inventory.js +94 -0
  226. package/dist/core/events/v3/support-storage/logical-authority.d.ts +14 -0
  227. package/dist/core/events/v3/support-storage/logical-authority.d.ts.map +1 -0
  228. package/dist/core/events/v3/support-storage/logical-authority.js +104 -0
  229. package/dist/core/events/v3/support-storage/maintenance.d.ts +98 -0
  230. package/dist/core/events/v3/support-storage/maintenance.d.ts.map +1 -0
  231. package/dist/core/events/v3/support-storage/maintenance.js +352 -0
  232. package/dist/core/events/v3/support-storage/pack-contract.d.ts +59 -0
  233. package/dist/core/events/v3/support-storage/pack-contract.d.ts.map +1 -0
  234. package/dist/core/events/v3/support-storage/pack-contract.js +249 -0
  235. package/dist/core/events/v3/support-storage/pack-reader.d.ts +34 -0
  236. package/dist/core/events/v3/support-storage/pack-reader.d.ts.map +1 -0
  237. package/dist/core/events/v3/support-storage/pack-reader.js +258 -0
  238. package/dist/core/events/v3/support-storage/pack-writer.d.ts +30 -0
  239. package/dist/core/events/v3/support-storage/pack-writer.d.ts.map +1 -0
  240. package/dist/core/events/v3/support-storage/pack-writer.js +268 -0
  241. package/dist/core/events/v3/support-storage/recovery.d.ts +15 -0
  242. package/dist/core/events/v3/support-storage/recovery.d.ts.map +1 -0
  243. package/dist/core/events/v3/support-storage/recovery.js +22 -0
  244. package/dist/core/events/v3/turn-telemetry.d.ts +14 -8
  245. package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
  246. package/dist/core/events/v3/turn-telemetry.js +32 -2
  247. package/dist/core/events/v3/writer.d.ts +13 -1
  248. package/dist/core/events/v3/writer.d.ts.map +1 -1
  249. package/dist/core/events/v3/writer.js +126 -12
  250. package/dist/core/governor/plan-read.d.ts.map +1 -1
  251. package/dist/core/governor/plan-read.js +5 -21
  252. package/dist/core/governor/planning.js +6 -8
  253. package/dist/core/governor/service-read.d.ts +12 -0
  254. package/dist/core/governor/service-read.d.ts.map +1 -1
  255. package/dist/core/governor/service-read.js +266 -2
  256. package/dist/core/governor/service.d.ts +1 -0
  257. package/dist/core/governor/service.d.ts.map +1 -1
  258. package/dist/core/governor/service.js +53 -18
  259. package/dist/core/guard/evidence-v3.d.ts.map +1 -1
  260. package/dist/core/guard/evidence-v3.js +2 -0
  261. package/dist/core/hooks/adapter/events.d.ts.map +1 -1
  262. package/dist/core/hooks/adapter/events.js +1 -0
  263. package/dist/core/hooks/adapter/output.d.ts +4 -2
  264. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  265. package/dist/core/hooks/adapter/output.js +13 -5
  266. package/dist/core/hooks/adapter/runtime-telemetry.d.ts +27 -4
  267. package/dist/core/hooks/adapter/runtime-telemetry.d.ts.map +1 -1
  268. package/dist/core/hooks/adapter/runtime-telemetry.js +307 -6
  269. package/dist/core/hooks/cli.js +212 -30
  270. package/dist/core/hooks/effects/image-capture.d.ts +1 -1
  271. package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
  272. package/dist/core/hooks/effects/image-capture.js +4 -2
  273. package/dist/core/hooks/remediation-cap.d.ts +8 -3
  274. package/dist/core/hooks/remediation-cap.d.ts.map +1 -1
  275. package/dist/core/hooks/remediation-cap.js +3 -11
  276. package/dist/core/hooks/resolve/coord-root.d.ts +22 -9
  277. package/dist/core/hooks/resolve/coord-root.d.ts.map +1 -1
  278. package/dist/core/hooks/resolve/coord-root.js +92 -11
  279. package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
  280. package/dist/core/hooks/resolve/owner.js +5 -0
  281. package/dist/core/hooks/resolve/transcript.d.ts +8 -0
  282. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  283. package/dist/core/hooks/resolve/transcript.js +11 -0
  284. package/dist/core/inbox/contract.d.ts +64 -0
  285. package/dist/core/inbox/contract.d.ts.map +1 -0
  286. package/dist/core/inbox/contract.js +13 -0
  287. package/dist/core/inbox/index.d.ts +5 -0
  288. package/dist/core/inbox/index.d.ts.map +1 -0
  289. package/dist/core/inbox/index.js +4 -0
  290. package/dist/core/inbox/lifecycle.d.ts +22 -0
  291. package/dist/core/inbox/lifecycle.d.ts.map +1 -0
  292. package/dist/core/inbox/lifecycle.js +41 -0
  293. package/dist/core/inbox/service.d.ts +36 -0
  294. package/dist/core/inbox/service.d.ts.map +1 -0
  295. package/dist/core/inbox/service.js +210 -0
  296. package/dist/core/inbox/watcher.d.ts +7 -0
  297. package/dist/core/inbox/watcher.d.ts.map +1 -0
  298. package/dist/core/inbox/watcher.js +26 -0
  299. package/dist/core/presence/codec-digest.d.ts.map +1 -1
  300. package/dist/core/presence/codec-digest.js +14 -3
  301. package/dist/core/presence/relay-client.d.ts +1 -0
  302. package/dist/core/presence/relay-client.d.ts.map +1 -1
  303. package/dist/core/presence/relay-client.js +52 -8
  304. package/dist/core/semantic/adapters.d.ts +11 -8
  305. package/dist/core/semantic/adapters.d.ts.map +1 -1
  306. package/dist/core/semantic/adapters.js +169 -31
  307. package/dist/core/semantic/contract.d.ts +532 -48
  308. package/dist/core/semantic/contract.d.ts.map +1 -1
  309. package/dist/core/semantic/contract.js +104 -3
  310. package/dist/core/semantic/index.d.ts +7 -3
  311. package/dist/core/semantic/index.d.ts.map +1 -1
  312. package/dist/core/semantic/index.js +7 -3
  313. package/dist/core/semantic/once.d.ts +6 -1
  314. package/dist/core/semantic/once.d.ts.map +1 -1
  315. package/dist/core/semantic/once.js +80 -9
  316. package/dist/core/semantic/prompt.d.ts.map +1 -1
  317. package/dist/core/semantic/prompt.js +14 -1
  318. package/dist/core/semantic/review.d.ts +144 -0
  319. package/dist/core/semantic/review.d.ts.map +1 -0
  320. package/dist/core/semantic/review.js +544 -0
  321. package/dist/core/semantic/routes.d.ts +10 -0
  322. package/dist/core/semantic/routes.d.ts.map +1 -0
  323. package/dist/core/semantic/routes.js +21 -0
  324. package/dist/core/semantic/scheduler.d.ts +14 -3
  325. package/dist/core/semantic/scheduler.d.ts.map +1 -1
  326. package/dist/core/semantic/scheduler.js +30 -6
  327. package/dist/core/semantic/service-status.d.ts +20 -0
  328. package/dist/core/semantic/service-status.d.ts.map +1 -1
  329. package/dist/core/semantic/service-status.js +60 -4
  330. package/dist/core/semantic/service.d.ts +1 -0
  331. package/dist/core/semantic/service.d.ts.map +1 -1
  332. package/dist/core/semantic/service.js +104 -15
  333. package/dist/core/semantic/soak.d.ts +75 -0
  334. package/dist/core/semantic/soak.d.ts.map +1 -0
  335. package/dist/core/semantic/soak.js +476 -0
  336. package/dist/core/semantic/storage.d.ts +11 -1
  337. package/dist/core/semantic/storage.d.ts.map +1 -1
  338. package/dist/core/semantic/storage.js +4 -3
  339. package/dist/core/semantic/usage.d.ts +43 -0
  340. package/dist/core/semantic/usage.d.ts.map +1 -0
  341. package/dist/core/semantic/usage.js +193 -0
  342. package/dist/core/semantic/validate.d.ts +3 -1
  343. package/dist/core/semantic/validate.d.ts.map +1 -1
  344. package/dist/core/semantic/validate.js +34 -1
  345. package/dist/core/storage/buffer.d.ts +28 -0
  346. package/dist/core/storage/buffer.d.ts.map +1 -0
  347. package/dist/core/storage/buffer.js +101 -0
  348. package/dist/core/storage/builtins.d.ts +3 -0
  349. package/dist/core/storage/builtins.d.ts.map +1 -0
  350. package/dist/core/storage/builtins.js +683 -0
  351. package/dist/core/storage/catalog.d.ts +19 -0
  352. package/dist/core/storage/catalog.d.ts.map +1 -0
  353. package/dist/core/storage/catalog.js +365 -0
  354. package/dist/core/storage/config.d.ts +16 -0
  355. package/dist/core/storage/config.d.ts.map +1 -0
  356. package/dist/core/storage/config.js +311 -0
  357. package/dist/core/storage/contract.d.ts +275 -0
  358. package/dist/core/storage/contract.d.ts.map +1 -0
  359. package/dist/core/storage/contract.js +3 -0
  360. package/dist/core/storage/durable-history.d.ts +36 -0
  361. package/dist/core/storage/durable-history.d.ts.map +1 -0
  362. package/dist/core/storage/durable-history.js +606 -0
  363. package/dist/core/storage/health.d.ts +4 -0
  364. package/dist/core/storage/health.d.ts.map +1 -0
  365. package/dist/core/storage/health.js +65 -0
  366. package/dist/core/storage/index.d.ts +16 -0
  367. package/dist/core/storage/index.d.ts.map +1 -0
  368. package/dist/core/storage/index.js +15 -0
  369. package/dist/core/storage/inventory.d.ts +25 -0
  370. package/dist/core/storage/inventory.d.ts.map +1 -0
  371. package/dist/core/storage/inventory.js +666 -0
  372. package/dist/core/storage/jsonl.d.ts +52 -0
  373. package/dist/core/storage/jsonl.d.ts.map +1 -0
  374. package/dist/core/storage/jsonl.js +156 -0
  375. package/dist/core/storage/log-retention.d.ts +52 -0
  376. package/dist/core/storage/log-retention.d.ts.map +1 -0
  377. package/dist/core/storage/log-retention.js +419 -0
  378. package/dist/core/storage/logger.d.ts +82 -0
  379. package/dist/core/storage/logger.d.ts.map +1 -0
  380. package/dist/core/storage/logger.js +411 -0
  381. package/dist/core/storage/maintenance-providers.d.ts +26 -0
  382. package/dist/core/storage/maintenance-providers.d.ts.map +1 -0
  383. package/dist/core/storage/maintenance-providers.js +141 -0
  384. package/dist/core/storage/maintenance.d.ts +125 -0
  385. package/dist/core/storage/maintenance.d.ts.map +1 -0
  386. package/dist/core/storage/maintenance.js +609 -0
  387. package/dist/core/storage/metrics.d.ts +60 -0
  388. package/dist/core/storage/metrics.d.ts.map +1 -0
  389. package/dist/core/storage/metrics.js +134 -0
  390. package/dist/core/storage/policy.d.ts +7 -0
  391. package/dist/core/storage/policy.d.ts.map +1 -0
  392. package/dist/core/storage/policy.js +110 -0
  393. package/dist/core/storage/process-log.d.ts +38 -0
  394. package/dist/core/storage/process-log.d.ts.map +1 -0
  395. package/dist/core/storage/process-log.js +165 -0
  396. package/dist/core/storage/query.d.ts +34 -0
  397. package/dist/core/storage/query.d.ts.map +1 -0
  398. package/dist/core/storage/query.js +295 -0
  399. package/dist/core/storage/receipts.d.ts +23 -0
  400. package/dist/core/storage/receipts.d.ts.map +1 -0
  401. package/dist/core/storage/receipts.js +117 -0
  402. package/dist/core/storage/segments.d.ts +84 -0
  403. package/dist/core/storage/segments.d.ts.map +1 -0
  404. package/dist/core/storage/segments.js +542 -0
  405. package/dist/core/storage/sink-graph.d.ts +65 -0
  406. package/dist/core/storage/sink-graph.d.ts.map +1 -0
  407. package/dist/core/storage/sink-graph.js +213 -0
  408. package/dist/core/storage/storm-control.d.ts +23 -0
  409. package/dist/core/storage/storm-control.d.ts.map +1 -0
  410. package/dist/core/storage/storm-control.js +59 -0
  411. package/dist/core/work/state.d.ts.map +1 -1
  412. package/dist/core/work/state.js +10 -14
  413. package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
  414. package/dist/core/workflow/live-session-v3.js +2 -1
  415. package/dist/index.d.ts +2 -0
  416. package/dist/index.d.ts.map +1 -1
  417. package/dist/index.js +2 -0
  418. package/dist/lazy-commands.d.ts +26 -0
  419. package/dist/lazy-commands.d.ts.map +1 -0
  420. package/dist/lazy-commands.js +210 -0
  421. package/dist/lib/docs-lint.d.ts +2 -0
  422. package/dist/lib/docs-lint.d.ts.map +1 -1
  423. package/dist/lib/docs-lint.js +45 -80
  424. package/dist/lib/docs-metadata-audit.d.ts +3 -0
  425. package/dist/lib/docs-metadata-audit.d.ts.map +1 -1
  426. package/dist/lib/docs-metadata-audit.js +13 -23
  427. package/dist/lib/docs-metadata-sync.d.ts +1 -0
  428. package/dist/lib/docs-metadata-sync.d.ts.map +1 -1
  429. package/dist/lib/docs-metadata-sync.js +28 -10
  430. package/dist/lib/docs-repository-view.d.ts +22 -0
  431. package/dist/lib/docs-repository-view.d.ts.map +1 -0
  432. package/dist/lib/docs-repository-view.js +185 -0
  433. package/dist/lib/http/client.d.ts +11 -5
  434. package/dist/lib/http/client.d.ts.map +1 -1
  435. package/dist/lib/http/client.js +22 -4
  436. package/dist/lib/http/index.d.ts +1 -1
  437. package/dist/lib/http/index.d.ts.map +1 -1
  438. package/dist/lib/http/index.js +1 -1
  439. package/dist/lib/indexer-exclusions.d.ts +27 -0
  440. package/dist/lib/indexer-exclusions.d.ts.map +1 -0
  441. package/dist/lib/indexer-exclusions.js +176 -0
  442. package/dist/lib/instructions/templates.d.ts.map +1 -1
  443. package/dist/lib/instructions/templates.js +5 -0
  444. package/dist/lib/local-file-url.d.ts +9 -0
  445. package/dist/lib/local-file-url.d.ts.map +1 -0
  446. package/dist/lib/local-file-url.js +20 -0
  447. package/dist/lib/web-performance.d.ts +118 -0
  448. package/dist/lib/web-performance.d.ts.map +1 -0
  449. package/dist/lib/web-performance.js +192 -0
  450. package/package.json +29 -2
  451. package/schemas/config.schema.json +58 -0
  452. package/schemas/event-v3.schema.json +324 -112
  453. package/src/commander.ts +462 -95
  454. package/src/commands/agents.ts +517 -190
  455. package/src/commands/backup.ts +18 -14
  456. package/src/commands/browse-session.ts +12 -0
  457. package/src/commands/browse.ts +6 -7
  458. package/src/commands/conversations.ts +279 -0
  459. package/src/commands/deinit.ts +6 -0
  460. package/src/commands/docs.ts +25 -6
  461. package/src/commands/doctor.ts +75 -9
  462. package/src/commands/fetch.ts +7 -6
  463. package/src/commands/files.ts +143 -0
  464. package/src/commands/governor.ts +13 -12
  465. package/src/commands/inbox.ts +61 -0
  466. package/src/commands/init.ts +78 -16
  467. package/src/commands/ledger-v3.ts +421 -1
  468. package/src/commands/logs.ts +224 -0
  469. package/src/commands/messages.ts +61 -0
  470. package/src/commands/outline.ts +6 -2
  471. package/src/commands/read.ts +6 -2
  472. package/src/commands/semantic.ts +66 -1
  473. package/src/commands/storage.ts +310 -0
  474. package/src/commands/tunnel.ts +66 -52
  475. package/src/commands/web.ts +77 -7
  476. package/src/commands/work.ts +3 -3
  477. package/src/commands/workflow.ts +13 -13
  478. package/src/core/agents/cli.ts +259 -53
  479. package/src/core/agents/live-authority-v3.ts +341 -10
  480. package/src/core/agents/live-lifecycle-v3.ts +6 -1
  481. package/src/core/agents/live-observation-v3.ts +6 -1
  482. package/src/core/agents/render/prompt-context.ts +27 -6
  483. package/src/core/agents/rules/stop-hook.ts +107 -16
  484. package/src/core/agents/rules/verdict.ts +1 -0
  485. package/src/core/agents/session-events.ts +4 -0
  486. package/src/core/agents/session-finalization-state-v3.ts +1 -1
  487. package/src/core/agents/session-finalizer-v3.ts +4 -1
  488. package/src/core/agents/state/activity-log.ts +7 -2
  489. package/src/core/agents/state/heartbeat-writer.ts +27 -0
  490. package/src/core/agents/state/live-coordination-view.ts +16 -105
  491. package/src/core/agents/state/live-coordination-writer.ts +141 -0
  492. package/src/core/artifacts/index.ts +64 -1
  493. package/src/core/config.ts +126 -5
  494. package/src/core/conversations/archive.ts +237 -0
  495. package/src/core/conversations/catalog.ts +79 -0
  496. package/src/core/conversations/context-pack.ts +72 -0
  497. package/src/core/conversations/contract.ts +178 -0
  498. package/src/core/conversations/evaluation.ts +30 -0
  499. package/src/core/conversations/index.ts +9 -0
  500. package/src/core/conversations/lifecycle.ts +63 -0
  501. package/src/core/conversations/normalize.ts +105 -0
  502. package/src/core/conversations/query.ts +318 -0
  503. package/src/core/conversations/search-index.ts +48 -0
  504. package/src/core/events/legacy-storage/canary.ts +177 -0
  505. package/src/core/events/legacy-storage/fence.ts +129 -0
  506. package/src/core/events/legacy-storage/index.ts +5 -0
  507. package/src/core/events/legacy-storage/inventory.ts +51 -0
  508. package/src/core/events/legacy-storage/manifest.ts +136 -0
  509. package/src/core/events/legacy-storage/reader.ts +178 -0
  510. package/src/core/events/v3/authority-outbox.ts +22 -1
  511. package/src/core/events/v3/base-contract.ts +17 -7
  512. package/src/core/events/v3/bootstrap.ts +195 -2
  513. package/src/core/events/v3/capabilities.ts +3 -3
  514. package/src/core/events/v3/control-witness.ts +339 -0
  515. package/src/core/events/v3/control-writer.ts +16 -0
  516. package/src/core/events/v3/control.ts +54 -18
  517. package/src/core/events/v3/coordination-transaction-recovery.ts +477 -0
  518. package/src/core/events/v3/coordination-view.ts +17 -1
  519. package/src/core/events/v3/generated.ts +1 -1
  520. package/src/core/events/v3/index.ts +5 -2
  521. package/src/core/events/v3/live-route-observer.ts +80 -0
  522. package/src/core/events/v3/live-routing.ts +64 -46
  523. package/src/core/events/v3/producers/coordination-recorder.ts +95 -10
  524. package/src/core/events/v3/producers/diagnostic-summaries.ts +593 -0
  525. package/src/core/events/v3/producers/hook-base.ts +1 -1
  526. package/src/core/events/v3/producers/intake.ts +30 -2
  527. package/src/core/events/v3/producers/producer-state-observer.ts +52 -0
  528. package/src/core/events/v3/producers/recorder.ts +571 -33
  529. package/src/core/events/v3/reader.ts +243 -2
  530. package/src/core/events/v3/rotation-config.ts +98 -0
  531. package/src/core/events/v3/runtime-build.ts +41 -0
  532. package/src/core/events/v3/runtime-identity.ts +16 -0
  533. package/src/core/events/v3/runtime-telemetry-capabilities.ts +14 -8
  534. package/src/core/events/v3/support-storage/classify.ts +209 -0
  535. package/src/core/events/v3/support-storage/eligibility.ts +58 -0
  536. package/src/core/events/v3/support-storage/index.ts +9 -0
  537. package/src/core/events/v3/support-storage/inventory.ts +135 -0
  538. package/src/core/events/v3/support-storage/logical-authority.ts +117 -0
  539. package/src/core/events/v3/support-storage/maintenance.ts +501 -0
  540. package/src/core/events/v3/support-storage/pack-contract.ts +337 -0
  541. package/src/core/events/v3/support-storage/pack-reader.ts +346 -0
  542. package/src/core/events/v3/support-storage/pack-writer.ts +352 -0
  543. package/src/core/events/v3/support-storage/recovery.ts +43 -0
  544. package/src/core/events/v3/turn-telemetry.ts +58 -7
  545. package/src/core/events/v3/writer.ts +168 -16
  546. package/src/core/governor/plan-read.ts +5 -18
  547. package/src/core/governor/planning.ts +5 -8
  548. package/src/core/governor/service-read.ts +320 -2
  549. package/src/core/governor/service.ts +49 -22
  550. package/src/core/guard/evidence-v3.ts +1 -0
  551. package/src/core/hooks/adapter/events.ts +1 -0
  552. package/src/core/hooks/adapter/output.ts +12 -5
  553. package/src/core/hooks/adapter/runtime-telemetry.ts +408 -13
  554. package/src/core/hooks/cli.ts +226 -32
  555. package/src/core/hooks/effects/image-capture.ts +4 -1
  556. package/src/core/hooks/remediation-cap.ts +12 -6
  557. package/src/core/hooks/resolve/coord-root.ts +91 -11
  558. package/src/core/hooks/resolve/owner.ts +4 -0
  559. package/src/core/hooks/resolve/transcript.ts +18 -0
  560. package/src/core/inbox/contract.ts +81 -0
  561. package/src/core/inbox/index.ts +4 -0
  562. package/src/core/inbox/lifecycle.ts +104 -0
  563. package/src/core/inbox/service.ts +305 -0
  564. package/src/core/inbox/watcher.ts +36 -0
  565. package/src/core/presence/codec-digest.ts +15 -9
  566. package/src/core/presence/relay-client.ts +55 -7
  567. package/src/core/semantic/adapters.ts +200 -41
  568. package/src/core/semantic/contract.ts +135 -3
  569. package/src/core/semantic/index.ts +76 -2
  570. package/src/core/semantic/once.ts +93 -7
  571. package/src/core/semantic/prompt.ts +13 -1
  572. package/src/core/semantic/review.ts +803 -0
  573. package/src/core/semantic/routes.ts +30 -0
  574. package/src/core/semantic/scheduler.ts +49 -5
  575. package/src/core/semantic/service-status.ts +99 -5
  576. package/src/core/semantic/service.ts +116 -15
  577. package/src/core/semantic/soak.ts +638 -0
  578. package/src/core/semantic/storage.ts +20 -6
  579. package/src/core/semantic/usage.ts +272 -0
  580. package/src/core/semantic/validate.ts +31 -0
  581. package/src/core/storage/buffer.ts +124 -0
  582. package/src/core/storage/builtins.ts +916 -0
  583. package/src/core/storage/catalog.ts +467 -0
  584. package/src/core/storage/config.ts +423 -0
  585. package/src/core/storage/contract.ts +342 -0
  586. package/src/core/storage/durable-history.ts +738 -0
  587. package/src/core/storage/health.ts +76 -0
  588. package/src/core/storage/index.ts +15 -0
  589. package/src/core/storage/inventory.ts +859 -0
  590. package/src/core/storage/jsonl.ts +213 -0
  591. package/src/core/storage/log-retention.ts +555 -0
  592. package/src/core/storage/logger.ts +546 -0
  593. package/src/core/storage/maintenance-providers.ts +200 -0
  594. package/src/core/storage/maintenance.ts +929 -0
  595. package/src/core/storage/metrics.ts +199 -0
  596. package/src/core/storage/policy.ts +141 -0
  597. package/src/core/storage/process-log.ts +203 -0
  598. package/src/core/storage/query.ts +360 -0
  599. package/src/core/storage/receipts.ts +162 -0
  600. package/src/core/storage/segments.ts +721 -0
  601. package/src/core/storage/sink-graph.ts +343 -0
  602. package/src/core/storage/storm-control.ts +91 -0
  603. package/src/core/work/state.ts +12 -21
  604. package/src/core/workflow/live-session-v3.ts +2 -4
  605. package/src/index.ts +2 -0
  606. package/src/lazy-commands.ts +294 -0
  607. package/src/lib/docs-lint.ts +58 -77
  608. package/src/lib/docs-metadata-audit.ts +26 -21
  609. package/src/lib/docs-metadata-sync.ts +32 -9
  610. package/src/lib/docs-repository-view.ts +220 -0
  611. package/src/lib/http/client.ts +44 -8
  612. package/src/lib/http/index.ts +6 -1
  613. package/src/lib/indexer-exclusions.ts +173 -0
  614. package/src/lib/instructions/templates.ts +5 -0
  615. package/src/lib/local-file-url.ts +31 -0
  616. package/src/lib/web-performance.ts +335 -0
@@ -23,7 +23,7 @@ import {
23
23
  rmSync,
24
24
  writeFileSync,
25
25
  } from "node:fs";
26
- import { homedir, tmpdir } from "node:os";
26
+ import { tmpdir } from "node:os";
27
27
  import { basename, join, resolve } from "node:path";
28
28
  import type { Command } from "commander";
29
29
  import type { EmitContext, HarneryProgramContext } from "../commander.ts";
@@ -44,7 +44,11 @@ import {
44
44
  resolveOwnerWithSource,
45
45
  sessionIdentityFromEnv,
46
46
  } from "../core/agents/index.ts";
47
- import { reopenLiveCoordinationGenerationV3 } from "../core/agents/live-authority-v3.ts";
47
+ import {
48
+ bootstrapLiveCoordinationAuthorityV3,
49
+ LiveCoordinationAuthorityV3Error,
50
+ reopenLiveCoordinationGenerationV3,
51
+ } from "../core/agents/live-authority-v3.ts";
48
52
  import {
49
53
  listSessionFinalizationRequestsV3,
50
54
  observeHostDisappearedV3,
@@ -56,6 +60,7 @@ import {
56
60
  SESSION_NAME_DISPLAY_NOTE,
57
61
  sessionNameDisplayPending,
58
62
  } from "../core/agents/session-name-display.ts";
63
+ import { agentDisplayName } from "../core/agents/state/activity-log.ts";
59
64
  import {
60
65
  buildLifecycleSuggestedName,
61
66
  buildSuggestedName,
@@ -80,6 +85,10 @@ import type { EventTypeV3 } from "../core/events/v3/contract.ts";
80
85
  import { readEventV3ControlState } from "../core/events/v3/control.ts";
81
86
  import { projectCoordinationViewV3 } from "../core/events/v3/coordination-view.ts";
82
87
  import { liveInstanceIdV3 } from "../core/events/v3/live-routing.ts";
88
+ import {
89
+ countSummarizedSinceV3,
90
+ listDiagnosticSummariesV3,
91
+ } from "../core/events/v3/producers/diagnostic-summaries.ts";
83
92
  import {
84
93
  listHookIntakeGroupsV3,
85
94
  listHookIntakeRecordsV3,
@@ -92,7 +101,10 @@ import { readLedgerV3 } from "../core/events/v3/reader.ts";
92
101
  import { EVENT_V3_LEDGER_RELATIVE_ROOT } from "../core/events/v3/writer.ts";
93
102
  import type { RunQualitySnapshot, RunQualityStatus } from "../core/guard/index.ts";
94
103
  import { evaluateRunQualityIfDue } from "../core/guard/index.ts";
95
- import { readRuntimeContextUsage } from "../core/hooks/adapter/runtime-telemetry.ts";
104
+ import {
105
+ readRuntimeContextTelemetry,
106
+ readRuntimeContextUsage,
107
+ } from "../core/hooks/adapter/runtime-telemetry.ts";
96
108
  import { type RemoteMachine, readRemoteMachines } from "../core/presence/index.ts";
97
109
  import { registerContextCommand } from "./context.ts";
98
110
 
@@ -264,6 +276,7 @@ export function registerAgentsCommand(
264
276
  program: Command,
265
277
  emitParam: EmitContext,
266
278
  programContext?: HarneryProgramContext,
279
+ binName = resolveBinName(),
267
280
  ): void {
268
281
  emit = emitParam;
269
282
  const cmd = program
@@ -385,7 +398,7 @@ export function registerAgentsCommand(
385
398
  )
386
399
  .option(
387
400
  "--session-id <id>",
388
- `Set the task on the heartbeat with this session_id directly, bypassing the ppid walk. Mirror of \`status --session-id\`: use it when the ppid walk can't resolve self (e.g. Cursor, whose shell tool calls don't descend from a pid-map-registered anchor). Discover the id via \`${resolveBinName()} agents list --json\`.`,
401
+ `Set the task on the heartbeat with this session_id directly, bypassing the ppid walk. Mirror of \`status --session-id\`: use it when the ppid walk can't resolve self (e.g. Cursor, whose shell tool calls don't descend from a pid-map-registered anchor). Discover the id via \`${binName} agents list --json\`.`,
389
402
  )
390
403
  .action((text: string[], opts: { sessionId?: string }) => {
391
404
  runSetTask(text.join(" "), opts);
@@ -484,7 +497,7 @@ export function registerAgentsCommand(
484
497
  cmd
485
498
  .command("wait <name>")
486
499
  .description(
487
- `Block until a peer agent releases files (their \`files_touched\` becomes empty, OR they exit). Pair with \`${resolveBinName()} agents ping\` to coordinate hand-offs.`,
500
+ `Block until a peer agent releases files (their \`files_touched\` becomes empty, OR they exit). Pair with \`${binName} agents ping\` to coordinate hand-offs.`,
488
501
  )
489
502
  .option(
490
503
  "--file <path>",
@@ -567,12 +580,11 @@ export function registerAgentsCommand(
567
580
  cmd
568
581
  .command("heal")
569
582
  .description(
570
- "Force a coord-layer recovery action on a specific agent. " +
571
- "Kinds: pidmap (repair process attribution) and cache (rebuild the " +
572
- "disposable V3 coordination cache from the authoritative ledger).",
583
+ "Repair the current session's disposable coordination cache from V3. " +
584
+ "Use explicit options to target another generation or repair process attribution.",
573
585
  )
574
- .requiredOption("--owner <id>", "Target agent's instance_id")
575
- .requiredOption("--kind <kind>", "pidmap | cache")
586
+ .option("--owner <id>", "Target agent's instance_id. Defaults to the current session.")
587
+ .option("--kind <kind>", "pidmap | cache. Defaults to cache.")
576
588
  .option(
577
589
  "--session-id <id>",
578
590
  "(--kind cache) native session id used to join the authoritative V3 generation.",
@@ -589,14 +601,26 @@ export function registerAgentsCommand(
589
601
  "when calling from outside Claude Code's Bash tool tree (e.g. " +
590
602
  "from cron or an external script).",
591
603
  )
604
+ .option(
605
+ "--quarantine-transaction <id>",
606
+ "Quarantine one irreconcilable prepared authority transaction after proving its event was never committed.",
607
+ )
608
+ .option(
609
+ "--approval-record-id <id>",
610
+ "Durable identifier for the operator approval authorizing transaction quarantine.",
611
+ )
612
+ .option("--yes", "Confirm the exact prepared transaction may be quarantined.")
592
613
  .option("--json", "JSON envelope output")
593
614
  .action(
594
615
  (opts: {
595
- owner: string;
596
- kind: string;
616
+ owner?: string;
617
+ kind?: string;
597
618
  sessionId?: string;
598
619
  adapter?: string;
599
620
  pid?: string;
621
+ quarantineTransaction?: string;
622
+ approvalRecordId?: string;
623
+ yes?: boolean;
600
624
  json?: boolean;
601
625
  }) => {
602
626
  runHeal(opts);
@@ -935,14 +959,15 @@ function runIdentityAssume(
935
959
  });
936
960
  process.exit(1);
937
961
  }
938
- if (!opts.sessionId) ensureCursorSession(root);
962
+ if (!opts.sessionId) ensureAdapterSession(root);
939
963
  const owner = opts.sessionId ?? resolveOwner();
940
964
  if (!owner) {
941
- emit.error({
942
- code: "no_pidmap_entry",
943
- message:
965
+ emit.error(
966
+ sessionResolutionFailure(
967
+ root,
944
968
  "not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)",
945
- });
969
+ ),
970
+ );
946
971
  process.exit(1);
947
972
  }
948
973
  try {
@@ -1214,14 +1239,13 @@ function runWhoami(opts: { json?: boolean }): void {
1214
1239
  process.exit(1);
1215
1240
  }
1216
1241
 
1217
- ensureCursorSession(root);
1242
+ ensureAdapterSession(root);
1218
1243
  const resolved = resolveOwnerWithSource();
1219
1244
  const myOwner = resolved.owner;
1220
1245
  if (!myOwner) {
1221
- emit.error({
1222
- code: "no_pidmap_entry",
1223
- message: "not in an agent session; ppid walk found no pid-map entry",
1224
- });
1246
+ emit.error(
1247
+ sessionResolutionFailure(root, "not in an agent session; ppid walk found no pid-map entry"),
1248
+ );
1225
1249
  process.exit(1);
1226
1250
  }
1227
1251
 
@@ -1703,49 +1727,96 @@ function cursorEnvSessionId(): string | null {
1703
1727
  return raw.startsWith("bc-") && raw.length > 3 ? raw.slice(3) : raw;
1704
1728
  }
1705
1729
 
1706
- function shouldBootstrapCursorSession(): boolean {
1707
- return process.env.CURSOR_AGENT === "1" && cursorEnvSessionId() !== null;
1730
+ interface CommandSessionBootstrap {
1731
+ adapter: "claude-code" | "cursor" | "codex";
1732
+ sessionId: string;
1733
+ }
1734
+
1735
+ function commandSessionBootstrap(): CommandSessionBootstrap | null {
1736
+ const cursorSessionId = cursorEnvSessionId();
1737
+ if (process.env.CURSOR_AGENT === "1" && cursorSessionId) {
1738
+ return { adapter: "cursor", sessionId: cursorSessionId };
1739
+ }
1740
+ if (process.env.HARNERY_AGENT_COORD_BRIDGE?.trim() === "codex-wsl") {
1741
+ const sessionId = sessionIdentityFromEnv();
1742
+ if (sessionId) return { adapter: "codex", sessionId };
1743
+ }
1744
+ const claudeSessionId = process.env.CLAUDE_CODE_SESSION_ID?.trim();
1745
+ if (claudeSessionId) {
1746
+ return { adapter: "claude-code", sessionId: claudeSessionId };
1747
+ }
1748
+ return null;
1708
1749
  }
1709
1750
 
1710
- function ensureCursorSession(root: string): void {
1711
- if (!shouldBootstrapCursorSession()) return;
1751
+ function ensureAdapterSession(root: string): void {
1752
+ const bootstrap = commandSessionBootstrap();
1753
+ if (!bootstrap) return;
1754
+ // Claude Code owns a reliable native SessionStart hook. Its environment is
1755
+ // accepted by the explicit `agents heal` recovery path, but ordinary
1756
+ // identity and status commands must not impersonate that hook. The heal
1757
+ // bootstrap records derived provenance instead.
1758
+ if (bootstrap.adapter === "claude-code") return;
1712
1759
  // Explicit owner override means the caller already knows who they are.
1713
1760
  // Bootstrapping sessionStart inherits that env into the child hook, which
1714
1761
  // re-projects a fresh heartbeat onto the override owner and can wipe an
1715
1762
  // assumed persona agent_id (seen under Cursor integration fixtures).
1716
- if (process.env.HARNERY_AGENT_COORD_OWNER?.trim()) return;
1763
+ if (bootstrap.adapter === "cursor" && process.env.HARNERY_AGENT_COORD_OWNER?.trim()) return;
1717
1764
  if (resolveOwnerBySessionEnv(root)) return;
1718
1765
 
1719
- const sessionId = cursorEnvSessionId();
1720
- if (!sessionId) return;
1721
1766
  const agentHook = coordBinPath("agent-hook", root);
1722
1767
  if (!agentHook) return;
1723
1768
 
1724
1769
  const payload = JSON.stringify({
1725
- conversation_id: sessionId,
1726
- session_id: sessionId,
1770
+ ...(bootstrap.adapter === "cursor" ? { conversation_id: bootstrap.sessionId } : {}),
1771
+ session_id: bootstrap.sessionId,
1727
1772
  hook_event_name: "sessionStart",
1728
1773
  workspace_roots: [root],
1729
1774
  cwd: root,
1730
- composer_mode: "agent",
1731
- is_background_agent: false,
1775
+ ...(bootstrap.adapter === "cursor"
1776
+ ? { composer_mode: "agent", is_background_agent: false }
1777
+ : { source: "resume" }),
1732
1778
  });
1733
1779
 
1734
- spawnSync("bash", [agentHook, "session-start", "--adapter", "cursor"], {
1780
+ spawnSync("bash", [agentHook, "session-start", "--adapter", bootstrap.adapter], {
1735
1781
  input: payload,
1736
1782
  cwd: root,
1737
1783
  encoding: "utf8",
1738
1784
  timeout: 3000,
1739
1785
  env: {
1740
1786
  ...process.env,
1741
- HARNERY_AGENT_COORD_PLATFORM: "cursor",
1787
+ HARNERY_AGENT_COORD_PLATFORM: bootstrap.adapter,
1742
1788
  HARNERY_COORD_ROOT_OVERRIDE: root,
1743
- CURSOR_SESSION_ID: sessionId,
1744
- CURSOR_CONVERSATION_ID: sessionId,
1789
+ HARNERY_AGENT_COORD_SESSION_ID: bootstrap.sessionId,
1790
+ ...(bootstrap.adapter === "cursor"
1791
+ ? {
1792
+ CURSOR_SESSION_ID: bootstrap.sessionId,
1793
+ CURSOR_CONVERSATION_ID: bootstrap.sessionId,
1794
+ }
1795
+ : { CODEX_THREAD_ID: bootstrap.sessionId }),
1745
1796
  },
1746
1797
  });
1747
1798
  }
1748
1799
 
1800
+ function sessionResolutionFailure(
1801
+ root: string,
1802
+ fallbackMessage: string,
1803
+ ): { code: string; message: string } {
1804
+ if (!sessionIdentityFromEnv()) return { code: "no_pidmap_entry", message: fallbackMessage };
1805
+ const control = readEventV3ControlState(root);
1806
+ if (control.state !== "candidate" && control.state !== "active") {
1807
+ const detail = `${control.state}:${control.reason}`;
1808
+ return {
1809
+ code: "event_v3_control_unavailable",
1810
+ message: `the adapter session identity is present, but the V3 control state cannot accept session onboarding (${detail})`,
1811
+ };
1812
+ }
1813
+ return {
1814
+ code: "session_generation_unavailable",
1815
+ message:
1816
+ "the adapter session identity is present, but no current V3 session generation was available after onboarding",
1817
+ };
1818
+ }
1819
+
1749
1820
  function runReleaseClaim(path: string): void {
1750
1821
  const root = monorepoRoot();
1751
1822
  if (!root) {
@@ -1757,10 +1828,9 @@ function runReleaseClaim(path: string): void {
1757
1828
  }
1758
1829
  const myOwner = resolveOwner();
1759
1830
  if (!myOwner) {
1760
- emit.error({
1761
- code: "no_pidmap_entry",
1762
- message: "not in an agent session; ppid walk found no pid-map entry",
1763
- });
1831
+ emit.error(
1832
+ sessionResolutionFailure(root, "not in an agent session; ppid walk found no pid-map entry"),
1833
+ );
1764
1834
  process.exit(1);
1765
1835
  }
1766
1836
  // Canonicalize: absolute paths under coordRoot get the prefix stripped;
@@ -1801,14 +1871,15 @@ function runSetTask(task: string, opts?: { sessionId?: string }): void {
1801
1871
  // returns null by design, and erroring here orphans the session's first
1802
1872
  // ritual command. The env id carries the same trust as an explicit
1803
1873
  // --session-id, and set-task mints the heartbeat exactly as that path does.
1804
- if (!opts?.sessionId) ensureCursorSession(root);
1874
+ if (!opts?.sessionId) ensureAdapterSession(root);
1805
1875
  const myOwner = opts?.sessionId ?? resolveOwner() ?? sessionIdentityFromEnv();
1806
1876
  if (!myOwner) {
1807
- emit.error({
1808
- code: "no_pidmap_entry",
1809
- message:
1877
+ emit.error(
1878
+ sessionResolutionFailure(
1879
+ root,
1810
1880
  "not in an agent session; no session-id environment identity and the ppid walk found no pid-map entry (pass --session-id to bypass)",
1811
- });
1881
+ ),
1882
+ );
1812
1883
  process.exit(1);
1813
1884
  }
1814
1885
 
@@ -1897,14 +1968,15 @@ function runLifecycle(rawState: string, opts: { reason?: string; sessionId?: str
1897
1968
  process.exitCode = 1;
1898
1969
  return;
1899
1970
  }
1900
- if (!opts.sessionId) ensureCursorSession(root);
1971
+ if (!opts.sessionId) ensureAdapterSession(root);
1901
1972
  const myOwner = opts.sessionId ?? resolveOwner() ?? sessionIdentityFromEnv();
1902
1973
  if (!myOwner) {
1903
- emit.error({
1904
- code: "no_pidmap_entry",
1905
- message:
1974
+ emit.error(
1975
+ sessionResolutionFailure(
1976
+ root,
1906
1977
  "not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)",
1907
- });
1978
+ ),
1979
+ );
1908
1980
  process.exitCode = 1;
1909
1981
  return;
1910
1982
  }
@@ -2079,14 +2151,15 @@ function runSuggestName(
2079
2151
 
2080
2152
  // Identity: prefer explicit --session-id (ppid-walk-free escape hatch, mirrors
2081
2153
  // `status`/`set-task`), fall back to the ppid walk for interactive shell use.
2082
- if (!opts.sessionId) ensureCursorSession(root);
2154
+ if (!opts.sessionId) ensureAdapterSession(root);
2083
2155
  const myOwner = opts.sessionId ?? resolveOwner();
2084
2156
  if (!myOwner) {
2085
- emit.error({
2086
- code: "no_pidmap_entry",
2087
- message:
2157
+ emit.error(
2158
+ sessionResolutionFailure(
2159
+ root,
2088
2160
  "not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)",
2089
- });
2161
+ ),
2162
+ );
2090
2163
  process.exit(1);
2091
2164
  }
2092
2165
 
@@ -2158,14 +2231,15 @@ function runStatus(opts: {
2158
2231
 
2159
2232
  // Identity resolution: prefer explicit --session-id (hook-friendly), fall
2160
2233
  // back to ppid walk for interactive shell usage.
2161
- if (!opts.sessionId) ensureCursorSession(root);
2234
+ if (!opts.sessionId) ensureAdapterSession(root);
2162
2235
  const myOwner = opts.sessionId ?? resolveOwner();
2163
2236
  if (!myOwner) {
2164
- emit.error({
2165
- code: "no_pidmap_entry",
2166
- message:
2237
+ emit.error(
2238
+ sessionResolutionFailure(
2239
+ root,
2167
2240
  "not in an agent session; ppid walk found no pid-map entry (pass --session-id from a hook payload)",
2168
- });
2241
+ ),
2242
+ );
2169
2243
  process.exit(1);
2170
2244
  }
2171
2245
 
@@ -2207,7 +2281,7 @@ function runStatus(opts: {
2207
2281
  }
2208
2282
  }
2209
2283
 
2210
- emitEventV3({
2284
+ const statusEmitted = emitEventV3({
2211
2285
  owner: myOwner,
2212
2286
  session: nativeSessionIdentity(hb, myOwner),
2213
2287
  adapter: normalizeAdapter(hb.platform),
@@ -2216,6 +2290,16 @@ function runStatus(opts: {
2216
2290
  status: opts.endTurn ? "end_turn_checked" : opts.json ? "json_checked" : "box_checked",
2217
2291
  },
2218
2292
  });
2293
+ // The closing box is a success artifact. Never print it when the exact
2294
+ // evidence enforced by the Stop hook did not reach the ledger.
2295
+ if (opts.endTurn && !statusEmitted) {
2296
+ emit.error({
2297
+ code: "status_event_failed",
2298
+ message: `the end-of-turn status event could not be recorded; no status box was issued; rerun \`${resolveBinName(root)} agents status --end-turn\``,
2299
+ });
2300
+ process.exitCode = 1;
2301
+ return;
2302
+ }
2219
2303
 
2220
2304
  let sessionEnd:
2221
2305
  | { state: "queued" | "already_requested"; request_id: string }
@@ -2285,10 +2369,7 @@ function runStatus(opts: {
2285
2369
  if (!ctxUsage) {
2286
2370
  ctxStr = "unavailable";
2287
2371
  } else if (ctxUsage.percentOnly) {
2288
- // Cursor reports percent only; absolutes are estimates against a hard-coded
2289
- // window. Show the percent + window estimate, marked as estimated.
2290
- const pct = Math.round((ctxUsage.used / ctxUsage.window) * 100);
2291
- ctxStr = `~${pct}% (Cursor; ${fmtTokens(ctxUsage.window)} window est.)`;
2372
+ ctxStr = `${Math.round(ctxUsage.usedPercent)}% (Cursor first-party)`;
2292
2373
  } else {
2293
2374
  ctxStr = `${fmtTokens(ctxUsage.used)} / ${fmtTokens(ctxUsage.window)} (${Math.round(
2294
2375
  (ctxUsage.used / ctxUsage.window) * 100,
@@ -2296,7 +2377,7 @@ function runStatus(opts: {
2296
2377
  }
2297
2378
 
2298
2379
  const timeStr = formatLocalTime(new Date());
2299
- const displayName = `agent-${hb.name || "unknown"}`;
2380
+ const displayName = agentDisplayName(hb.instance_id, hb.name);
2300
2381
 
2301
2382
  // Council pending: list of council IDs where this agent is a member of an
2302
2383
  // active council in `open` round_status without a contribution to that round.
@@ -2340,8 +2421,8 @@ function runStatus(opts: {
2340
2421
  })),
2341
2422
  })),
2342
2423
  pending_councils: pendingCouncils,
2343
- context_used: ctxUsage?.used ?? null,
2344
- context_window: ctxUsage?.window ?? null,
2424
+ context_used: ctxUsage && "used" in ctxUsage ? ctxUsage.used : null,
2425
+ context_window: ctxUsage && "window" in ctxUsage ? ctxUsage.window : null,
2345
2426
  timestamp_iso: new Date().toISOString(),
2346
2427
  timestamp_local: timeStr,
2347
2428
  ...(quality ? { quality } : {}),
@@ -2485,15 +2566,17 @@ export function collectStatusPeerHealth(
2485
2566
  root: string,
2486
2567
  myOwner: string,
2487
2568
  nowMs = Date.now(),
2569
+ readRows: (root: string) => StatusPeerHeartbeat[] = readLiveCoordinationRows,
2570
+ freshnessSeconds = freshnessCutoffSecs(),
2488
2571
  ): { livePeers: StatusPeerHeartbeat[]; stale: number } {
2489
2572
  let rows: StatusPeerHeartbeat[] = [];
2490
2573
  try {
2491
- rows = readLiveCoordinationRows(root);
2574
+ rows = readRows(root);
2492
2575
  } catch {
2493
2576
  // V3 authority failures must not resurrect disposable cache rows.
2494
2577
  }
2495
2578
 
2496
- const cutoffMs = nowMs - freshnessCutoffSecs() * 1000;
2579
+ const cutoffMs = nowMs - freshnessSeconds * 1000;
2497
2580
  const livePeers: StatusPeerHeartbeat[] = [];
2498
2581
  let stale = 0;
2499
2582
  for (const peer of rows) {
@@ -2515,85 +2598,28 @@ function fmtTokens(n: number): string {
2515
2598
  function readContextUsage(
2516
2599
  sessionId: string,
2517
2600
  platform?: string | null,
2518
- ): { used: number; window: number; percentOnly?: boolean } | null {
2601
+ ):
2602
+ | { used: number; window: number; percentOnly?: false }
2603
+ | { usedPercent: number; percentOnly: true }
2604
+ | null {
2519
2605
  if (!sessionId) return null;
2520
2606
  // Dispatch by platform: Codex's JSONL shape is different from Claude Code's
2521
2607
  // (event_msg/response_item vs user/assistant), and Codex transcripts live
2522
2608
  // under ~/.codex/sessions/YYYY/MM/DD/ rather than ~/.claude/projects/.
2523
- // Cursor doesn't surface token counts in its transcript JSONL but DOES
2524
- // store `contextUsagePercent` per composer in workspaceStorage's state.vscdb;
2525
- // readCursorContextUsage reads that via bun:sqlite (percent-only).
2609
+ // Cursor stores a first-party percentage in workspaceStorage. The shared
2610
+ // runtime reader returns it without fabricating a token denominator.
2526
2611
  if (platform === "codex") return readRuntimeContextUsage("codex", sessionId);
2527
- if (platform === "cursor") return readCursorContextUsage(sessionId);
2528
- return readRuntimeContextUsage("claude-code", sessionId);
2529
- }
2530
-
2531
- function readCursorContextUsage(
2532
- sessionId: string,
2533
- ): { used: number; window: number; percentOnly: true } | null {
2534
- // Cursor stores per-chat (composer) context usage as a percent in each
2535
- // workspace's state.vscdb at ItemTable.composer.composerData. The value
2536
- // is a JSON blob with .allComposers[].contextUsagePercent. We find the
2537
- // composer matching the agent's session_id (Cursor uses session_id == composerId
2538
- // for parent chats).
2539
- //
2540
- // Roots searched: ~/.config/Cursor/User/workspaceStorage (Linux native install)
2541
- // and /mnt/c/Users/*/AppData/Roaming/Cursor/User/workspaceStorage (WSL).
2542
- // We don't filter by workspace path; we scan every workspace's state.vscdb
2543
- // looking for a composerId match. Cheap enough at status time (~60K per file,
2544
- // <10ms typical). When a match is found, returns synthetic { used, window }
2545
- // pair where the percent is what's real; absolutes are derived as
2546
- // (window * percent / 100). Window hard-coded to a Cursor-typical 200K.
2547
- const roots: string[] = [];
2548
- const linuxRoot = resolve(homedir(), ".config", "Cursor", "User", "workspaceStorage");
2549
- if (existsSync(linuxRoot)) roots.push(linuxRoot);
2550
- try {
2551
- if (existsSync("/mnt/c/Users")) {
2552
- for (const u of readdirSync("/mnt/c/Users")) {
2553
- const p = `/mnt/c/Users/${u}/AppData/Roaming/Cursor/User/workspaceStorage`;
2554
- if (existsSync(p)) roots.push(p);
2555
- }
2556
- }
2557
- } catch {
2558
- // ignore
2559
- }
2560
- for (const root of roots) {
2561
- let workspaces: string[];
2562
- try {
2563
- workspaces = readdirSync(root);
2564
- } catch {
2565
- continue;
2566
- }
2567
- for (const ws of workspaces) {
2568
- const dbPath = `${root}/${ws}/state.vscdb`;
2569
- if (!existsSync(dbPath)) continue;
2570
- try {
2571
- // Lazy-import bun:sqlite so non-Bun runtimes (if any) don't choke at load.
2572
- // eslint-disable-next-line @typescript-eslint/no-require-imports
2573
- const { Database } = require("bun:sqlite");
2574
- const db = new Database(dbPath, { readonly: true });
2575
- const row = db
2576
- .query("SELECT value FROM ItemTable WHERE key = 'composer.composerData'")
2577
- .get() as { value: string | Uint8Array } | null;
2578
- db.close();
2579
- if (!row?.value) continue;
2580
- const text =
2581
- typeof row.value === "string" ? row.value : Buffer.from(row.value).toString("utf8");
2582
- const parsed = JSON.parse(text);
2583
- const composers = Array.isArray(parsed?.allComposers) ? parsed.allComposers : [];
2584
- for (const c of composers) {
2585
- if (c?.composerId === sessionId && typeof c?.contextUsagePercent === "number") {
2586
- const window = 200000; // hard-coded Cursor-typical window; refine when Cursor exposes the actual ceiling
2587
- const used = Math.round((window * c.contextUsagePercent) / 100);
2588
- return { used, window, percentOnly: true };
2589
- }
2590
- }
2591
- } catch {
2592
- // ignore: DB locked, schema drift, etc. Move on to the next workspace.
2593
- }
2594
- }
2612
+ if (platform === "cursor") {
2613
+ const telemetry = readRuntimeContextTelemetry({
2614
+ adapter: "cursor",
2615
+ session_id: sessionId,
2616
+ mode: "status",
2617
+ });
2618
+ return telemetry.state === "observed" && "used_percent" in telemetry
2619
+ ? { usedPercent: telemetry.used_percent, percentOnly: true }
2620
+ : null;
2595
2621
  }
2596
- return null;
2622
+ return readRuntimeContextUsage("claude-code", sessionId);
2597
2623
  }
2598
2624
 
2599
2625
  function formatLocalTime(d: Date): string {
@@ -2993,9 +3019,9 @@ interface HealthReport {
2993
3019
  lines: number;
2994
3020
  cursor_backlog: number;
2995
3021
  };
2996
- // Heartbeats present in active/ but broken: no name, unparseable, or an
2997
- // absurd (epoch-ish) last_heartbeat. These are the `agent-unknown` peer-table
2998
- // ghosts; a positive count means dead files the sweep isn't catching.
3022
+ // Heartbeat cache files present in active/ but stale or malformed. These are
3023
+ // files the sweep is not catching; a parseable old heartbeat is stale, not
3024
+ // evidence of an epoch-like or corrupt timestamp.
2999
3025
  zombies: {
3000
3026
  count: number;
3001
3027
  samples: string[];
@@ -3049,12 +3075,21 @@ export type EventLedgerHealthV3 =
3049
3075
  groups: Array<{ adapter: string; session_hash: string; count: number }>;
3050
3076
  };
3051
3077
  diagnostics_spool: {
3078
+ /** Logical occurrences: loose files plus coalesced summary counts. */
3052
3079
  total: number;
3080
+ /** Physical loose diagnostic files. */
3081
+ loose_total: number;
3082
+ /** Occurrences coalesced into summaries instead of loose files. */
3083
+ summarized_total: number;
3084
+ /** Physical summary files in `diagnostic-summaries/`. */
3085
+ summary_files: number;
3053
3086
  last_24h: number;
3054
3087
  last_1h: number;
3055
3088
  latest_at: string | null;
3056
3089
  by_category: Record<string, { total: number; last_24h: number }>;
3057
3090
  recent_by_category: Record<string, { last_1h: number; latest_at: string | null }>;
3091
+ /** Times the summary gate failed open (loose write proceeded). */
3092
+ mitigation_fail_open: number;
3058
3093
  };
3059
3094
  span_pressure: Array<{ instance_id: string; generation_id: string; span_count: number }>;
3060
3095
  collection_errors: string[];
@@ -3194,6 +3229,47 @@ export function collectEventLedgerHealthV3(root: string, nowMs = Date.now()): Ev
3194
3229
  collectionErrors.push(`diagnostics spool unreadable: ${errorText(error)}`);
3195
3230
  }
3196
3231
 
3232
+ // 4b) Coalesced diagnostic summaries: occurrences the producer bounded into
3233
+ // `diagnostic-summaries/` instead of loose files. Counted into the logical
3234
+ // totals so mitigation can never make an active fault look healthy; the
3235
+ // physical loose file count stays visible separately.
3236
+ let summarizedTotal = 0;
3237
+ let summaryFiles = 0;
3238
+ let mitigationFailOpen = 0;
3239
+ try {
3240
+ const listing = listDiagnosticSummariesV3(root);
3241
+ summaryFiles = listing.file_count;
3242
+ mitigationFailOpen = listing.mitigation_health?.fail_open_count ?? 0;
3243
+ if (listing.unreadable_count > 0) {
3244
+ collectionErrors.push(`${listing.unreadable_count} diagnostic summary file(s) unreadable`);
3245
+ }
3246
+ const dayAgoMs = nowMs - 24 * 60 * 60 * 1000;
3247
+ const hourAgoMs = nowMs - 60 * 60 * 1000;
3248
+ for (const summary of listing.summaries) {
3249
+ summarizedTotal += summary.summarized_count;
3250
+ const entry = byCategory[summary.category] ?? { total: 0, last_24h: 0 };
3251
+ const recent = recentByCategory[summary.category] ?? { last_1h: 0, latest_at: null };
3252
+ byCategory[summary.category] = entry;
3253
+ recentByCategory[summary.category] = recent;
3254
+ entry.total += summary.summarized_count;
3255
+ const day = countSummarizedSinceV3([summary], dayAgoMs, undefined, nowMs);
3256
+ const hour = countSummarizedSinceV3([summary], hourAgoMs, undefined, nowMs);
3257
+ entry.last_24h += day;
3258
+ diagnostics24h += day;
3259
+ recent.last_1h += hour;
3260
+ diagnostics1h += hour;
3261
+ const lastMs = summary.last_summarized_at ? Date.parse(summary.last_summarized_at) : NaN;
3262
+ if (Number.isFinite(lastMs)) {
3263
+ latestDiagnosticMs = Math.max(latestDiagnosticMs, lastMs);
3264
+ if (!recent.latest_at || lastMs > Date.parse(recent.latest_at)) {
3265
+ recent.latest_at = new Date(lastMs).toISOString();
3266
+ }
3267
+ }
3268
+ }
3269
+ } catch (error) {
3270
+ collectionErrors.push(`diagnostic summaries unreadable: ${errorText(error)}`);
3271
+ }
3272
+
3197
3273
  return {
3198
3274
  state: "live",
3199
3275
  mode: control.state,
@@ -3204,7 +3280,10 @@ export function collectEventLedgerHealthV3(root: string, nowMs = Date.now()): Ev
3204
3280
  pending_finalizations: pending,
3205
3281
  intake_spool: { total: intakeTotal, groups: intakeGroups },
3206
3282
  diagnostics_spool: {
3207
- total: diagnosticsTotal,
3283
+ total: diagnosticsTotal + summarizedTotal,
3284
+ loose_total: diagnosticsTotal,
3285
+ summarized_total: summarizedTotal,
3286
+ summary_files: summaryFiles,
3208
3287
  last_24h: diagnostics24h,
3209
3288
  last_1h: diagnostics1h,
3210
3289
  latest_at: Number.isFinite(latestDiagnosticMs)
@@ -3212,6 +3291,7 @@ export function collectEventLedgerHealthV3(root: string, nowMs = Date.now()): Ev
3212
3291
  : null,
3213
3292
  by_category: byCategory,
3214
3293
  recent_by_category: recentByCategory,
3294
+ mitigation_fail_open: mitigationFailOpen,
3215
3295
  },
3216
3296
  span_pressure: spanPressure,
3217
3297
  collection_errors: collectionErrors,
@@ -3717,13 +3797,15 @@ type ActiveHealthHeartbeat = {
3717
3797
  export function collectActiveAgentHealth(
3718
3798
  root: string,
3719
3799
  nowMs = Date.now(),
3800
+ readRows: (root: string) => ActiveHealthHeartbeat[] = readLiveCoordinationRows,
3801
+ freshnessSeconds = freshnessCutoffSecs(),
3720
3802
  ): ActiveAgentHealthSummary {
3721
3803
  const source: ActiveAgentHealthSummary["source"] = "event-ledger-v3";
3722
3804
  let heartbeats: ActiveHealthHeartbeat[] = [];
3723
3805
  try {
3724
3806
  const control = readEventV3ControlState(root);
3725
3807
  if (control.state === "candidate" || control.state === "active") {
3726
- heartbeats = readLiveCoordinationRows(root);
3808
+ heartbeats = readRows(root);
3727
3809
  }
3728
3810
  } catch {
3729
3811
  // The event-ledger section reports the authority read failure. Do not
@@ -3749,7 +3831,7 @@ export function collectActiveAgentHealth(
3749
3831
  const ageMs = Number.isFinite(lastObservedMs)
3750
3832
  ? nowMs - lastObservedMs
3751
3833
  : Number.POSITIVE_INFINITY;
3752
- if (ageMs > freshnessCutoffSecs() * 1000) stale += 1;
3834
+ if (ageMs > freshnessSeconds * 1000) stale += 1;
3753
3835
  }
3754
3836
  return {
3755
3837
  source,
@@ -3761,6 +3843,22 @@ export function collectActiveAgentHealth(
3761
3843
  };
3762
3844
  }
3763
3845
 
3846
+ export type HeartbeatCacheIssue = "no-name" | "invalid-heartbeat" | "stale-age";
3847
+
3848
+ /** Classify a parseable heartbeat cache file without conflating age with corruption. */
3849
+ export function classifyHeartbeatCacheIssue(
3850
+ heartbeat: Pick<Heartbeat, "name" | "last_heartbeat">,
3851
+ nowMs: number,
3852
+ staleAgeMs: number,
3853
+ ): HeartbeatCacheIssue | null {
3854
+ if (!heartbeat.name || heartbeat.name === "unknown") return "no-name";
3855
+ const lastHeartbeatMs = heartbeat.last_heartbeat
3856
+ ? Date.parse(heartbeat.last_heartbeat)
3857
+ : Number.NaN;
3858
+ if (!Number.isFinite(lastHeartbeatMs)) return "invalid-heartbeat";
3859
+ return nowMs - lastHeartbeatMs > staleAgeMs ? "stale-age" : null;
3860
+ }
3861
+
3764
3862
  function runHealth(opts: { since: string; json?: boolean }): void {
3765
3863
  if (opts.json) emit.config({ format: "json" });
3766
3864
 
@@ -3845,12 +3943,12 @@ function runHealth(opts: { since: string; json?: boolean }): void {
3845
3943
  .map(([agent, count]) => ({ agent, count }));
3846
3944
 
3847
3945
  const activeAgents = collectActiveAgentHealth(root, nowMs);
3848
- // Zombies: files in active/ that are broken: unparseable, nameless, or an
3849
- // absurd (epoch-ish) last_heartbeat. These show as `agent-unknown` ghosts and
3850
- // mean dead files the sweep isn't reaping.
3946
+ // Heartbeat cache issues: files in active/ that are unparseable, nameless,
3947
+ // invalidly timestamped, or stale. Old parseable timestamps are ordinary
3948
+ // staleness, not evidence of epoch-like timestamp corruption.
3851
3949
  let zombieCount = 0;
3852
3950
  const zombieSamples: string[] = [];
3853
- const ABSURD_AGE_MS = 24 * 60 * 60 * 1000; // > 1 day = clearly not a live, self-healing agent
3951
+ const STALE_HEARTBEAT_AGE_MS = 24 * 60 * 60 * 1000;
3854
3952
  if (existsSync(activeDir)) {
3855
3953
  for (const file of readdirSync(activeDir)) {
3856
3954
  if (!file.endsWith(".json")) continue;
@@ -3867,15 +3965,11 @@ function runHealth(opts: { since: string; json?: boolean }): void {
3867
3965
  zombieSamples.push(`${idFromFile.slice(0, 12)} (unparseable/no-id)`);
3868
3966
  continue;
3869
3967
  }
3870
- const lastHbMs = hb.last_heartbeat ? Date.parse(hb.last_heartbeat) : Number.NaN;
3871
- const ageMs = Number.isFinite(lastHbMs) ? nowMs - lastHbMs : Number.POSITIVE_INFINITY;
3872
- // Zombie heuristics on a parseable heartbeat: no name, or an age so large
3873
- // it can only be a broken/epoch timestamp (a real agent would have healed).
3874
- if (!hb.name || hb.name === "unknown" || ageMs > ABSURD_AGE_MS) {
3968
+ const cacheIssue = classifyHeartbeatCacheIssue(hb, nowMs, STALE_HEARTBEAT_AGE_MS);
3969
+ if (cacheIssue) {
3875
3970
  zombieCount++;
3876
3971
  if (zombieSamples.length < 5) {
3877
- const why = !hb.name || hb.name === "unknown" ? "no-name" : "epoch-age";
3878
- zombieSamples.push(`${idFromFile.slice(0, 12)} (${why})`);
3972
+ zombieSamples.push(`${idFromFile.slice(0, 12)} (${cacheIssue})`);
3879
3973
  }
3880
3974
  }
3881
3975
  }
@@ -3939,7 +4033,7 @@ function runHealth(opts: { since: string; json?: boolean }): void {
3939
4033
  }
3940
4034
  if (zombieCount > 0) {
3941
4035
  anomalies.push(
3942
- `${zombieCount} zombie heartbeat(s) in active/ (${zombieSamples.join(", ")}); broken files the sweep isn't reaping`,
4036
+ `${zombieCount} heartbeat cache issue(s) in active/ (${zombieSamples.join(", ")}); stale or malformed files the sweep isn't reaping`,
3943
4037
  );
3944
4038
  }
3945
4039
  if (stopRemediation.total > 0) {
@@ -4095,7 +4189,7 @@ function renderHealthBox(report: HealthReport): void {
4095
4189
  `open spans ${ledger.open_spans.total}${orphanGenerations > 0 ? ` (${orphanGenerations} gen turn-closed)` : ""}`,
4096
4190
  `pending ends ${ledger.pending_finalizations.length}${pendingAges ? ` (${pendingAges})` : ""}`,
4097
4191
  `intake ${ledger.intake_spool.total}`,
4098
- `diagnostics ${ledger.diagnostics_spool.total} (${ledger.diagnostics_spool.last_1h} in 1h / ${ledger.diagnostics_spool.last_24h} in 24h)`,
4192
+ `diagnostics ${ledger.diagnostics_spool.total}${ledger.diagnostics_spool.summarized_total > 0 ? ` (${ledger.diagnostics_spool.loose_total} loose + ${ledger.diagnostics_spool.summarized_total} summarized)` : ""} (${ledger.diagnostics_spool.last_1h} in 1h / ${ledger.diagnostics_spool.last_24h} in 24h)`,
4099
4193
  ].join(" · ");
4100
4194
  }
4101
4195
 
@@ -4116,7 +4210,7 @@ function renderHealthBox(report: HealthReport): void {
4116
4210
  ["stream", streamStr],
4117
4211
  ["event ledger", ledgerStr],
4118
4212
  [
4119
- "zombies",
4213
+ "cache issues",
4120
4214
  report.zombies.count === 0
4121
4215
  ? "0"
4122
4216
  : `${report.zombies.count} (${report.zombies.samples.join(", ")})`,
@@ -4552,10 +4646,18 @@ function runPing(name: string, message: string, opts: { json?: boolean }): void
4552
4646
  }
4553
4647
  const myOwner = resolveOwner();
4554
4648
  if (!myOwner) {
4555
- emit.error({
4556
- code: "no_pidmap_entry",
4557
- message: "not in an agent session; ppid walk found no pid-map entry",
4558
- });
4649
+ const root = monorepoRoot();
4650
+ emit.error(
4651
+ root
4652
+ ? sessionResolutionFailure(
4653
+ root,
4654
+ "not in an agent session; ppid walk found no pid-map entry",
4655
+ )
4656
+ : {
4657
+ code: "no_pidmap_entry",
4658
+ message: "not in an agent session; ppid walk found no pid-map entry",
4659
+ },
4660
+ );
4559
4661
  process.exit(1);
4560
4662
  }
4561
4663
  const peerOwner = resolveOwnerByName(name);
@@ -4722,21 +4824,22 @@ function emitWaitResult(
4722
4824
  }
4723
4825
 
4724
4826
  function runHeal(opts: {
4725
- owner: string;
4726
- kind: string;
4827
+ owner?: string;
4828
+ kind?: string;
4727
4829
  sessionId?: string;
4728
4830
  adapter?: string;
4729
4831
  pid?: string;
4832
+ quarantineTransaction?: string;
4833
+ approvalRecordId?: string;
4834
+ yes?: boolean;
4730
4835
  json?: boolean;
4731
4836
  }): void {
4732
4837
  if (opts.json) emit.config({ format: "json" });
4733
4838
 
4734
- const owner = opts.owner.trim();
4735
- const kind = opts.kind.trim();
4736
- if (!owner) {
4737
- emit.error({ code: "missing_owner", message: "--owner is required" });
4738
- process.exit(1);
4739
- }
4839
+ const requestedOwner = opts.owner?.trim() ?? "";
4840
+ const quarantineTransaction = opts.quarantineTransaction?.trim() ?? "";
4841
+ const approvalRecordId = opts.approvalRecordId?.trim() ?? "";
4842
+ const kind = opts.kind?.trim() || "cache";
4740
4843
  if (kind !== "pidmap" && kind !== "cache") {
4741
4844
  emit.error({
4742
4845
  code: "bad_kind",
@@ -4744,6 +4847,30 @@ function runHeal(opts: {
4744
4847
  });
4745
4848
  process.exit(1);
4746
4849
  }
4850
+ if (quarantineTransaction) {
4851
+ if (opts.kind || opts.pid) {
4852
+ emit.error({
4853
+ code: "conflicting_recovery_options",
4854
+ message: "--quarantine-transaction cannot be combined with --kind or --pid",
4855
+ });
4856
+ process.exit(1);
4857
+ }
4858
+ if (!opts.yes || !approvalRecordId) {
4859
+ emit.error({
4860
+ code: "transaction_quarantine_confirmation_required",
4861
+ message:
4862
+ "--quarantine-transaction requires --approval-record-id <id> and --yes; " +
4863
+ "the command abandons one uncommitted authority mutation while preserving its record",
4864
+ });
4865
+ process.exit(1);
4866
+ }
4867
+ } else if (approvalRecordId || opts.yes) {
4868
+ emit.error({
4869
+ code: "transaction_quarantine_target_required",
4870
+ message: "--approval-record-id and --yes require --quarantine-transaction <id>",
4871
+ });
4872
+ process.exit(1);
4873
+ }
4747
4874
  if (
4748
4875
  opts.adapter &&
4749
4876
  opts.adapter !== "claude-code" &&
@@ -4766,7 +4893,52 @@ function runHeal(opts: {
4766
4893
  process.exit(1);
4767
4894
  }
4768
4895
 
4769
- const action = kind === "pidmap" ? "heal-pidmap" : "repair-coordination-cache";
4896
+ const currentSessionRepair =
4897
+ kind === "cache" &&
4898
+ opts.owner === undefined &&
4899
+ opts.sessionId === undefined &&
4900
+ opts.adapter === undefined &&
4901
+ !quarantineTransaction;
4902
+
4903
+ const ownerResolution = resolveOwnerWithSource();
4904
+ const bootstrapIdentity = currentSessionRepair ? commandSessionBootstrap() : null;
4905
+ const resolvedCurrentOwner =
4906
+ bootstrapIdentity &&
4907
+ (ownerResolution.source === "none" || ownerResolution.source === "active_singleton")
4908
+ ? bootstrapIdentity.sessionId
4909
+ : ownerResolution.owner;
4910
+ const owner = requestedOwner || resolvedCurrentOwner || sessionIdentityFromEnv() || "";
4911
+ if (!owner) {
4912
+ emit.error({
4913
+ code: "session_identity_missing",
4914
+ message:
4915
+ `could not resolve the current session; run ${resolveBinName()} doctor, or pass ` +
4916
+ "--owner <instance-id> --session-id <native-session-id> --adapter <adapter>",
4917
+ });
4918
+ process.exit(1);
4919
+ }
4920
+
4921
+ const currentRow = readLiveCoordinationRow(root, owner);
4922
+ const inferredAdapter = normalizeAdapter(
4923
+ opts.adapter?.trim() || currentRow?.platform || commandSessionBootstrap()?.adapter,
4924
+ );
4925
+ const sessionId =
4926
+ opts.sessionId?.trim() ||
4927
+ (currentSessionRepair ? sessionIdentityFromEnv() : null) ||
4928
+ nativeSessionIdentity(currentRow, owner);
4929
+
4930
+ if (kind === "cache") {
4931
+ const refusal = cacheHealAuthorityRefusal(root, owner, sessionId, inferredAdapter, currentRow);
4932
+ if (refusal) {
4933
+ emitHealFailure(refusal.reason, refusal.message);
4934
+ }
4935
+ }
4936
+
4937
+ const action = quarantineTransaction
4938
+ ? "quarantine-authority-transaction"
4939
+ : kind === "pidmap"
4940
+ ? "heal-pidmap"
4941
+ : "repair-coordination-cache";
4770
4942
 
4771
4943
  // Refuse to materialize a V3 cache at a truncated owner id.
4772
4944
  //
@@ -4809,23 +4981,72 @@ function runHeal(opts: {
4809
4981
  // heal-pidmap <instance_id> [<pid>]
4810
4982
  // repair-coordination-cache <instance_id> [<session_id>]
4811
4983
  const helperArgs: string[] = [action, owner];
4812
- if (kind === "pidmap" && opts.pid) helperArgs.push(opts.pid);
4813
- if (kind === "cache" && opts.sessionId) helperArgs.push(opts.sessionId);
4814
- if (kind === "cache" && opts.adapter) helperArgs.push(`--adapter=${opts.adapter}`);
4984
+ if (quarantineTransaction) {
4985
+ helperArgs.push(
4986
+ quarantineTransaction,
4987
+ approvalRecordId,
4988
+ sessionId,
4989
+ `--adapter=${inferredAdapter}`,
4990
+ );
4991
+ } else {
4992
+ if (kind === "pidmap" && opts.pid) helperArgs.push(opts.pid);
4993
+ if (kind === "cache") helperArgs.push(sessionId, `--adapter=${inferredAdapter}`);
4994
+ }
4815
4995
 
4816
4996
  // Both recovery actions are handled by the bundled agent-coord binary.
4817
4997
  const helper = agentCoordOrExit(root);
4818
- const proc = spawnSync(helper, helperArgs, {
4998
+ let proc = spawnSync(helper, helperArgs, {
4819
4999
  encoding: "utf8",
4820
5000
  ...coordHelperOpts(root),
4821
5001
  });
4822
5002
 
4823
- if (proc.status !== 0) {
4824
- emit.error({
4825
- code: "heal_failed",
4826
- message: spawnFailureMessage(proc, `agent-coord ${action}`),
5003
+ let bootstrapState: "created" | "reused" | undefined;
5004
+ if (
5005
+ proc.status !== 0 &&
5006
+ currentSessionRepair &&
5007
+ missingAuthorityForCurrentSessionBootstrap(root, owner, sessionId)
5008
+ ) {
5009
+ const bootstrap = commandSessionBootstrap();
5010
+ if (
5011
+ !bootstrap ||
5012
+ bootstrap.sessionId !== sessionId ||
5013
+ bootstrap.sessionId !== owner ||
5014
+ bootstrap.adapter !== inferredAdapter
5015
+ ) {
5016
+ emitHealFailure(
5017
+ "native_identity_unverified",
5018
+ "the current adapter did not provide one matching native session id and adapter",
5019
+ );
5020
+ }
5021
+ try {
5022
+ const bootstrapped = bootstrapLiveCoordinationAuthorityV3({
5023
+ coordRoot: root,
5024
+ owner,
5025
+ nativeSessionId: bootstrap.sessionId,
5026
+ adapter: bootstrap.adapter,
5027
+ });
5028
+ bootstrapState = bootstrapped.state;
5029
+ } catch (error) {
5030
+ const reason =
5031
+ error instanceof LiveCoordinationAuthorityV3Error
5032
+ ? error.reason
5033
+ : "authority_bootstrap_failed";
5034
+ emitHealFailure(
5035
+ reason,
5036
+ "the current native session could not establish authority; no fallback cache was accepted",
5037
+ );
5038
+ }
5039
+ proc = spawnSync(helper, helperArgs, {
5040
+ encoding: "utf8",
5041
+ ...coordHelperOpts(root),
4827
5042
  });
4828
- process.exit(1);
5043
+ }
5044
+
5045
+ if (proc.status !== 0) {
5046
+ emitHealFailure(
5047
+ healFailureReason(root, owner, sessionId, inferredAdapter),
5048
+ spawnFailureMessage(proc, `agent-coord ${action}`),
5049
+ );
4829
5050
  }
4830
5051
 
4831
5052
  // Read the derived cache to surface post-action state.
@@ -4836,8 +5057,9 @@ function runHeal(opts: {
4836
5057
  after = null;
4837
5058
  }
4838
5059
 
4839
- const outcome =
4840
- kind === "pidmap"
5060
+ const outcome = quarantineTransaction
5061
+ ? "transaction_quarantined"
5062
+ : kind === "pidmap"
4841
5063
  ? proc.status === 0
4842
5064
  ? "ok"
4843
5065
  : "failed"
@@ -4852,10 +5074,15 @@ function runHeal(opts: {
4852
5074
  action,
4853
5075
  outcome,
4854
5076
  after,
5077
+ ...(quarantineTransaction ? { recovery: JSON.parse(proc.stdout.trim()) as unknown } : {}),
4855
5078
  },
4856
5079
  ],
4857
5080
  meta: {
4858
5081
  kind,
5082
+ automatic: currentSessionRepair && !quarantineTransaction,
5083
+ authority: "event-ledger-v3",
5084
+ adapter: kind === "cache" ? inferredAdapter : undefined,
5085
+ bootstrap: bootstrapState,
4859
5086
  // The path actually spawned, not a guess at the layout: the helper is
4860
5087
  // resolved from harnery's own package location, which differs between a
4861
5088
  // submodule, an installed dependency, and a standalone checkout.
@@ -4863,10 +5090,18 @@ function runHeal(opts: {
4863
5090
  },
4864
5091
  });
4865
5092
  if (!opts.json) {
4866
- if (kind === "pidmap") {
5093
+ if (quarantineTransaction) {
5094
+ emit.text(
5095
+ `coordination recovered: ${quarantineTransaction} quarantined with approval ${approvalRecordId}; ` +
5096
+ `cache ${after ? "present" : "absent"} (${inferredAdapter})\n`,
5097
+ );
5098
+ } else if (kind === "pidmap") {
4867
5099
  emit.text(`agent-coord ${action} ok\n`);
4868
5100
  } else {
4869
- emit.text(`agent-coord ${action} ok: cache ${after ? "present" : "absent"} after\n`);
5101
+ emit.text(
5102
+ `coordination repaired: V3 authority live; ${currentSessionRepair ? "current-session " : ""}` +
5103
+ `cache ${after ? "present" : "absent"} (${inferredAdapter})\n`,
5104
+ );
4870
5105
  }
4871
5106
  }
4872
5107
 
@@ -4877,6 +5112,98 @@ function runHeal(opts: {
4877
5112
  // unconditionally on every `harn agents heal`, which over-counted no-op heals.)
4878
5113
  }
4879
5114
 
5115
+ type HealAuthorityRefusal = {
5116
+ reason: "adapter_mismatch" | "owner_mismatch" | "session_mismatch" | "terminal_generation";
5117
+ message: string;
5118
+ };
5119
+
5120
+ function cacheHealAuthorityRefusal(
5121
+ root: string,
5122
+ owner: string,
5123
+ sessionId: string,
5124
+ adapter: "claude-code" | "cursor" | "codex",
5125
+ currentRow: LiveCoordinationRow | null,
5126
+ ): HealAuthorityRefusal | null {
5127
+ if (currentRow && normalizeAdapter(currentRow.platform) !== adapter) {
5128
+ return {
5129
+ reason: "adapter_mismatch",
5130
+ message: `the live generation belongs to adapter ${normalizeAdapter(currentRow.platform)}, not ${adapter}`,
5131
+ };
5132
+ }
5133
+ let producer: ReturnType<typeof readHookProducerStateV3>;
5134
+ try {
5135
+ producer = readHookProducerStateV3(root, adapter, sessionId);
5136
+ } catch {
5137
+ return {
5138
+ reason: "session_mismatch",
5139
+ message: "the native session producer state could not be read safely",
5140
+ };
5141
+ }
5142
+ if (producer?.terminal) {
5143
+ return {
5144
+ reason: "terminal_generation",
5145
+ message: "the matching generation is terminal and cannot be repaired or reopened by heal",
5146
+ };
5147
+ }
5148
+ if (producer && producer.instance_id !== liveInstanceIdV3(owner)) {
5149
+ return {
5150
+ reason: "owner_mismatch",
5151
+ message: "the native session is bound to a different instance owner",
5152
+ };
5153
+ }
5154
+ if (currentRow && (!producer || producer.generation_id !== currentRow.v3_generation_id)) {
5155
+ return {
5156
+ reason: "session_mismatch",
5157
+ message: "the native session does not bind to the requested live generation",
5158
+ };
5159
+ }
5160
+ return null;
5161
+ }
5162
+
5163
+ function missingAuthorityForCurrentSessionBootstrap(
5164
+ root: string,
5165
+ owner: string,
5166
+ sessionId: string,
5167
+ ): boolean {
5168
+ if (readLiveCoordinationRow(root, owner)) return false;
5169
+ try {
5170
+ const nativeSessionHasProducer = (["claude-code", "codex", "cursor"] as const).some(
5171
+ (adapter) => readHookProducerStateV3(root, adapter, sessionId) !== undefined,
5172
+ );
5173
+ if (nativeSessionHasProducer) return false;
5174
+ const instanceId = liveInstanceIdV3(owner);
5175
+ return !listHookProducerStateRecordsV3(root, { includeTerminal: true }).some(
5176
+ ({ state }) => state.instance_id === instanceId,
5177
+ );
5178
+ } catch {
5179
+ return false;
5180
+ }
5181
+ }
5182
+
5183
+ function healFailureReason(
5184
+ root: string,
5185
+ owner: string,
5186
+ sessionId: string,
5187
+ adapter: "claude-code" | "cursor" | "codex",
5188
+ ): string {
5189
+ const refusal = cacheHealAuthorityRefusal(
5190
+ root,
5191
+ owner,
5192
+ sessionId,
5193
+ adapter,
5194
+ readLiveCoordinationRow(root, owner),
5195
+ );
5196
+ return refusal?.reason ?? "authority_missing";
5197
+ }
5198
+
5199
+ function emitHealFailure(reason: string, message: string): never {
5200
+ emit.error({
5201
+ code: "heal_failed",
5202
+ message: `coordination heal refused (reason=${reason}): ${message}`,
5203
+ });
5204
+ process.exit(1);
5205
+ }
5206
+
4880
5207
  /**
4881
5208
  * Emit one V3 council audit transition keyed to the exact durable manifest.
4882
5209
  * Falls through silently when no live session can attest the observation.