harnery 0.35.0 → 0.37.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 (843) hide show
  1. package/dist/commander.d.ts +30 -5
  2. package/dist/commander.d.ts.map +1 -1
  3. package/dist/commander.js +128 -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 +464 -242
  7. package/dist/commands/artifacts.d.ts.map +1 -1
  8. package/dist/commands/artifacts.js +26 -1
  9. package/dist/commands/backup.d.ts.map +1 -1
  10. package/dist/commands/backup.js +10 -10
  11. package/dist/commands/browse-session.d.ts.map +1 -1
  12. package/dist/commands/browse-session.js +12 -0
  13. package/dist/commands/browse.d.ts +1 -1
  14. package/dist/commands/browse.d.ts.map +1 -1
  15. package/dist/commands/browse.js +16 -4
  16. package/dist/commands/conversations.d.ts +10 -0
  17. package/dist/commands/conversations.d.ts.map +1 -0
  18. package/dist/commands/conversations.js +201 -0
  19. package/dist/commands/deinit.d.ts.map +1 -1
  20. package/dist/commands/deinit.js +5 -0
  21. package/dist/commands/diagnostics.d.ts +4 -0
  22. package/dist/commands/diagnostics.d.ts.map +1 -0
  23. package/dist/commands/diagnostics.js +229 -0
  24. package/dist/commands/docs.d.ts.map +1 -1
  25. package/dist/commands/docs.js +13 -2
  26. package/dist/commands/doctor.d.ts +5 -0
  27. package/dist/commands/doctor.d.ts.map +1 -1
  28. package/dist/commands/doctor.js +51 -7
  29. package/dist/commands/fetch.js +6 -5
  30. package/dist/commands/files.d.ts +34 -0
  31. package/dist/commands/files.d.ts.map +1 -0
  32. package/dist/commands/files.js +166 -0
  33. package/dist/commands/governor.d.ts.map +1 -1
  34. package/dist/commands/governor.js +18 -12
  35. package/dist/commands/inbox.d.ts +5 -0
  36. package/dist/commands/inbox.d.ts.map +1 -0
  37. package/dist/commands/inbox.js +57 -0
  38. package/dist/commands/init.d.ts +4 -5
  39. package/dist/commands/init.d.ts.map +1 -1
  40. package/dist/commands/init.js +63 -13
  41. package/dist/commands/ledger-v3.d.ts.map +1 -1
  42. package/dist/commands/ledger-v3.js +417 -2
  43. package/dist/commands/logs.d.ts +4 -0
  44. package/dist/commands/logs.d.ts.map +1 -0
  45. package/dist/commands/logs.js +169 -0
  46. package/dist/commands/messages.d.ts +5 -0
  47. package/dist/commands/messages.d.ts.map +1 -0
  48. package/dist/commands/messages.js +45 -0
  49. package/dist/commands/outline.d.ts +1 -1
  50. package/dist/commands/outline.d.ts.map +1 -1
  51. package/dist/commands/outline.js +2 -2
  52. package/dist/commands/qa-run.d.ts +4 -0
  53. package/dist/commands/qa-run.d.ts.map +1 -0
  54. package/dist/commands/qa-run.js +141 -0
  55. package/dist/commands/read.d.ts +1 -1
  56. package/dist/commands/read.d.ts.map +1 -1
  57. package/dist/commands/read.js +2 -2
  58. package/dist/commands/resources.d.ts +4 -0
  59. package/dist/commands/resources.d.ts.map +1 -0
  60. package/dist/commands/resources.js +29 -0
  61. package/dist/commands/semantic.d.ts.map +1 -1
  62. package/dist/commands/semantic.js +54 -2
  63. package/dist/commands/storage.d.ts +4 -0
  64. package/dist/commands/storage.d.ts.map +1 -0
  65. package/dist/commands/storage.js +238 -0
  66. package/dist/commands/supervisor.d.ts +4 -0
  67. package/dist/commands/supervisor.d.ts.map +1 -0
  68. package/dist/commands/supervisor.js +101 -0
  69. package/dist/commands/tunnel.d.ts +5 -1
  70. package/dist/commands/tunnel.d.ts.map +1 -1
  71. package/dist/commands/tunnel.js +44 -31
  72. package/dist/commands/web.d.ts +3 -0
  73. package/dist/commands/web.d.ts.map +1 -1
  74. package/dist/commands/web.js +84 -7
  75. package/dist/commands/work.js +3 -3
  76. package/dist/commands/workflow.d.ts.map +1 -1
  77. package/dist/commands/workflow.js +17 -13
  78. package/dist/core/adapters/profiles.d.ts +1 -1
  79. package/dist/core/agents/cli.js +215 -41
  80. package/dist/core/agents/health.d.ts +17 -0
  81. package/dist/core/agents/health.d.ts.map +1 -0
  82. package/dist/core/agents/health.js +109 -0
  83. package/dist/core/agents/live-authority-v3.d.ts +47 -1
  84. package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
  85. package/dist/core/agents/live-authority-v3.js +244 -10
  86. package/dist/core/agents/live-lifecycle-v3.js +6 -1
  87. package/dist/core/agents/live-observation-v3.d.ts.map +1 -1
  88. package/dist/core/agents/live-observation-v3.js +6 -1
  89. package/dist/core/agents/mailbox.d.ts +92 -0
  90. package/dist/core/agents/mailbox.d.ts.map +1 -0
  91. package/dist/core/agents/mailbox.js +325 -0
  92. package/dist/core/agents/reconcile-coordination-v3.d.ts +44 -0
  93. package/dist/core/agents/reconcile-coordination-v3.d.ts.map +1 -0
  94. package/dist/core/agents/reconcile-coordination-v3.js +58 -0
  95. package/dist/core/agents/render/prompt-context.d.ts +14 -3
  96. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  97. package/dist/core/agents/render/prompt-context.js +54 -16
  98. package/dist/core/agents/render/session-context.d.ts +8 -0
  99. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  100. package/dist/core/agents/render/session-context.js +34 -3
  101. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
  102. package/dist/core/agents/rules/commit-conflict.js +50 -1
  103. package/dist/core/agents/rules/stop-hook.d.ts +2 -0
  104. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  105. package/dist/core/agents/rules/stop-hook.js +93 -16
  106. package/dist/core/agents/rules/verdict.d.ts +1 -0
  107. package/dist/core/agents/rules/verdict.d.ts.map +1 -1
  108. package/dist/core/agents/session-events.d.ts.map +1 -1
  109. package/dist/core/agents/session-events.js +4 -0
  110. package/dist/core/agents/session-finalization-state-v3.js +1 -1
  111. package/dist/core/agents/session-finalizer-v3.js +9 -2
  112. package/dist/core/agents/state/activity-log.d.ts +3 -0
  113. package/dist/core/agents/state/activity-log.d.ts.map +1 -1
  114. package/dist/core/agents/state/activity-log.js +6 -3
  115. package/dist/core/agents/state/heartbeat-writer.d.ts +6 -0
  116. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  117. package/dist/core/agents/state/heartbeat-writer.js +18 -0
  118. package/dist/core/agents/state/live-coordination-view.d.ts +5 -7
  119. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  120. package/dist/core/agents/state/live-coordination-view.js +15 -90
  121. package/dist/core/agents/state/live-coordination-writer.d.ts +12 -0
  122. package/dist/core/agents/state/live-coordination-writer.d.ts.map +1 -0
  123. package/dist/core/agents/state/live-coordination-writer.js +92 -0
  124. package/dist/core/artifacts/index.d.ts +47 -1
  125. package/dist/core/artifacts/index.d.ts.map +1 -1
  126. package/dist/core/artifacts/index.js +191 -6
  127. package/dist/core/config.d.ts +74 -4
  128. package/dist/core/config.d.ts.map +1 -1
  129. package/dist/core/config.js +141 -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/diagnostics/advice.d.ts +9 -0
  161. package/dist/core/diagnostics/advice.d.ts.map +1 -0
  162. package/dist/core/diagnostics/advice.js +112 -0
  163. package/dist/core/diagnostics/bundle.d.ts +35 -0
  164. package/dist/core/diagnostics/bundle.d.ts.map +1 -0
  165. package/dist/core/diagnostics/bundle.js +874 -0
  166. package/dist/core/diagnostics/comparison.d.ts +5 -0
  167. package/dist/core/diagnostics/comparison.d.ts.map +1 -0
  168. package/dist/core/diagnostics/comparison.js +444 -0
  169. package/dist/core/diagnostics/contract.d.ts +245 -0
  170. package/dist/core/diagnostics/contract.d.ts.map +1 -0
  171. package/dist/core/diagnostics/contract.js +18 -0
  172. package/dist/core/diagnostics/identity.d.ts +3 -0
  173. package/dist/core/diagnostics/identity.d.ts.map +1 -0
  174. package/dist/core/diagnostics/identity.js +10 -0
  175. package/dist/core/diagnostics/index.d.ts +8 -0
  176. package/dist/core/diagnostics/index.d.ts.map +1 -0
  177. package/dist/core/diagnostics/index.js +7 -0
  178. package/dist/core/diagnostics/replay.d.ts +8 -0
  179. package/dist/core/diagnostics/replay.d.ts.map +1 -0
  180. package/dist/core/diagnostics/replay.js +213 -0
  181. package/dist/core/diagnostics/sanitize.d.ts +9 -0
  182. package/dist/core/diagnostics/sanitize.d.ts.map +1 -0
  183. package/dist/core/diagnostics/sanitize.js +84 -0
  184. package/dist/core/events/legacy-storage/canary.d.ts +18 -0
  185. package/dist/core/events/legacy-storage/canary.d.ts.map +1 -0
  186. package/dist/core/events/legacy-storage/canary.js +150 -0
  187. package/dist/core/events/legacy-storage/compression.d.ts +13 -0
  188. package/dist/core/events/legacy-storage/compression.d.ts.map +1 -0
  189. package/dist/core/events/legacy-storage/compression.js +107 -0
  190. package/dist/core/events/legacy-storage/fence.d.ts +15 -0
  191. package/dist/core/events/legacy-storage/fence.d.ts.map +1 -0
  192. package/dist/core/events/legacy-storage/fence.js +115 -0
  193. package/dist/core/events/legacy-storage/index.d.ts +7 -0
  194. package/dist/core/events/legacy-storage/index.d.ts.map +1 -0
  195. package/dist/core/events/legacy-storage/index.js +6 -0
  196. package/dist/core/events/legacy-storage/inventory.d.ts +10 -0
  197. package/dist/core/events/legacy-storage/inventory.d.ts.map +1 -0
  198. package/dist/core/events/legacy-storage/inventory.js +40 -0
  199. package/dist/core/events/legacy-storage/manifest.d.ts +23 -0
  200. package/dist/core/events/legacy-storage/manifest.d.ts.map +1 -0
  201. package/dist/core/events/legacy-storage/manifest.js +108 -0
  202. package/dist/core/events/legacy-storage/reader.d.ts +15 -0
  203. package/dist/core/events/legacy-storage/reader.d.ts.map +1 -0
  204. package/dist/core/events/legacy-storage/reader.js +154 -0
  205. package/dist/core/events/v3/archive-retention.d.ts +33 -0
  206. package/dist/core/events/v3/archive-retention.d.ts.map +1 -0
  207. package/dist/core/events/v3/archive-retention.js +195 -0
  208. package/dist/core/events/v3/authority-outbox.d.ts +7 -2
  209. package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
  210. package/dist/core/events/v3/authority-outbox.js +16 -3
  211. package/dist/core/events/v3/base-contract.d.ts +81 -41
  212. package/dist/core/events/v3/base-contract.d.ts.map +1 -1
  213. package/dist/core/events/v3/base-contract.js +17 -7
  214. package/dist/core/events/v3/bootstrap.d.ts +39 -0
  215. package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
  216. package/dist/core/events/v3/bootstrap.js +167 -3
  217. package/dist/core/events/v3/capabilities.d.ts +1 -1
  218. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  219. package/dist/core/events/v3/capabilities.js +4 -3
  220. package/dist/core/events/v3/control-witness.d.ts +44 -0
  221. package/dist/core/events/v3/control-witness.d.ts.map +1 -0
  222. package/dist/core/events/v3/control-witness.js +233 -0
  223. package/dist/core/events/v3/control-writer.d.ts +4 -0
  224. package/dist/core/events/v3/control-writer.d.ts.map +1 -0
  225. package/dist/core/events/v3/control-writer.js +16 -0
  226. package/dist/core/events/v3/control.d.ts +8 -2
  227. package/dist/core/events/v3/control.d.ts.map +1 -1
  228. package/dist/core/events/v3/control.js +46 -18
  229. package/dist/core/events/v3/coordination-transaction-recovery.d.ts +42 -0
  230. package/dist/core/events/v3/coordination-transaction-recovery.d.ts.map +1 -0
  231. package/dist/core/events/v3/coordination-transaction-recovery.js +342 -0
  232. package/dist/core/events/v3/coordination-view.d.ts.map +1 -1
  233. package/dist/core/events/v3/coordination-view.js +16 -1
  234. package/dist/core/events/v3/generated.d.ts +1 -1
  235. package/dist/core/events/v3/generated.js +1 -1
  236. package/dist/core/events/v3/index.d.ts +5 -2
  237. package/dist/core/events/v3/index.d.ts.map +1 -1
  238. package/dist/core/events/v3/index.js +4 -1
  239. package/dist/core/events/v3/live-route-observer.d.ts +31 -0
  240. package/dist/core/events/v3/live-route-observer.d.ts.map +1 -0
  241. package/dist/core/events/v3/live-route-observer.js +58 -0
  242. package/dist/core/events/v3/live-routing.d.ts +13 -21
  243. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  244. package/dist/core/events/v3/live-routing.js +46 -41
  245. package/dist/core/events/v3/producers/coordination-recorder.d.ts +11 -1
  246. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  247. package/dist/core/events/v3/producers/coordination-recorder.js +76 -10
  248. package/dist/core/events/v3/producers/diagnostic-summaries.d.ts +129 -0
  249. package/dist/core/events/v3/producers/diagnostic-summaries.d.ts.map +1 -0
  250. package/dist/core/events/v3/producers/diagnostic-summaries.js +499 -0
  251. package/dist/core/events/v3/producers/hook-base.d.ts +1 -1
  252. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  253. package/dist/core/events/v3/producers/hook-base.js +14 -3
  254. package/dist/core/events/v3/producers/intake.d.ts +7 -0
  255. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  256. package/dist/core/events/v3/producers/intake.js +26 -2
  257. package/dist/core/events/v3/producers/producer-state-observer.d.ts +8 -0
  258. package/dist/core/events/v3/producers/producer-state-observer.d.ts.map +1 -0
  259. package/dist/core/events/v3/producers/producer-state-observer.js +45 -0
  260. package/dist/core/events/v3/producers/recorder.d.ts +71 -1
  261. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  262. package/dist/core/events/v3/producers/recorder.js +441 -25
  263. package/dist/core/events/v3/reader.d.ts +51 -0
  264. package/dist/core/events/v3/reader.d.ts.map +1 -1
  265. package/dist/core/events/v3/reader.js +181 -1
  266. package/dist/core/events/v3/rotation-config.d.ts +9 -0
  267. package/dist/core/events/v3/rotation-config.d.ts.map +1 -0
  268. package/dist/core/events/v3/rotation-config.js +91 -0
  269. package/dist/core/events/v3/runtime-build.d.ts +11 -0
  270. package/dist/core/events/v3/runtime-build.d.ts.map +1 -0
  271. package/dist/core/events/v3/runtime-build.js +39 -0
  272. package/dist/core/events/v3/runtime-identity.d.ts +5 -0
  273. package/dist/core/events/v3/runtime-identity.d.ts.map +1 -0
  274. package/dist/core/events/v3/runtime-identity.js +18 -0
  275. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +6 -5
  276. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -1
  277. package/dist/core/events/v3/runtime-telemetry-capabilities.js +1 -1
  278. package/dist/core/events/v3/support-storage/classify.d.ts +46 -0
  279. package/dist/core/events/v3/support-storage/classify.d.ts.map +1 -0
  280. package/dist/core/events/v3/support-storage/classify.js +149 -0
  281. package/dist/core/events/v3/support-storage/eligibility.d.ts +29 -0
  282. package/dist/core/events/v3/support-storage/eligibility.d.ts.map +1 -0
  283. package/dist/core/events/v3/support-storage/eligibility.js +35 -0
  284. package/dist/core/events/v3/support-storage/index.d.ts +10 -0
  285. package/dist/core/events/v3/support-storage/index.d.ts.map +1 -0
  286. package/dist/core/events/v3/support-storage/index.js +9 -0
  287. package/dist/core/events/v3/support-storage/inventory.d.ts +30 -0
  288. package/dist/core/events/v3/support-storage/inventory.d.ts.map +1 -0
  289. package/dist/core/events/v3/support-storage/inventory.js +94 -0
  290. package/dist/core/events/v3/support-storage/logical-authority.d.ts +14 -0
  291. package/dist/core/events/v3/support-storage/logical-authority.d.ts.map +1 -0
  292. package/dist/core/events/v3/support-storage/logical-authority.js +104 -0
  293. package/dist/core/events/v3/support-storage/maintenance.d.ts +98 -0
  294. package/dist/core/events/v3/support-storage/maintenance.d.ts.map +1 -0
  295. package/dist/core/events/v3/support-storage/maintenance.js +352 -0
  296. package/dist/core/events/v3/support-storage/pack-contract.d.ts +59 -0
  297. package/dist/core/events/v3/support-storage/pack-contract.d.ts.map +1 -0
  298. package/dist/core/events/v3/support-storage/pack-contract.js +249 -0
  299. package/dist/core/events/v3/support-storage/pack-reader.d.ts +34 -0
  300. package/dist/core/events/v3/support-storage/pack-reader.d.ts.map +1 -0
  301. package/dist/core/events/v3/support-storage/pack-reader.js +258 -0
  302. package/dist/core/events/v3/support-storage/pack-writer.d.ts +30 -0
  303. package/dist/core/events/v3/support-storage/pack-writer.d.ts.map +1 -0
  304. package/dist/core/events/v3/support-storage/pack-writer.js +268 -0
  305. package/dist/core/events/v3/support-storage/recovery.d.ts +15 -0
  306. package/dist/core/events/v3/support-storage/recovery.d.ts.map +1 -0
  307. package/dist/core/events/v3/support-storage/recovery.js +22 -0
  308. package/dist/core/events/v3/turn-telemetry.d.ts +14 -8
  309. package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
  310. package/dist/core/events/v3/turn-telemetry.js +32 -2
  311. package/dist/core/events/v3/writer.d.ts +13 -1
  312. package/dist/core/events/v3/writer.d.ts.map +1 -1
  313. package/dist/core/events/v3/writer.js +126 -12
  314. package/dist/core/governor/plan-read.d.ts.map +1 -1
  315. package/dist/core/governor/plan-read.js +5 -21
  316. package/dist/core/governor/planning.js +6 -8
  317. package/dist/core/governor/service-read.d.ts +12 -0
  318. package/dist/core/governor/service-read.d.ts.map +1 -1
  319. package/dist/core/governor/service-read.js +266 -2
  320. package/dist/core/governor/service.d.ts +1 -0
  321. package/dist/core/governor/service.d.ts.map +1 -1
  322. package/dist/core/governor/service.js +53 -18
  323. package/dist/core/guard/evidence-v3.d.ts.map +1 -1
  324. package/dist/core/guard/evidence-v3.js +2 -0
  325. package/dist/core/hooks/adapter/events.d.ts.map +1 -1
  326. package/dist/core/hooks/adapter/events.js +1 -0
  327. package/dist/core/hooks/adapter/output.d.ts +12 -2
  328. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  329. package/dist/core/hooks/adapter/output.js +23 -5
  330. package/dist/core/hooks/adapter/runtime-telemetry.d.ts +27 -4
  331. package/dist/core/hooks/adapter/runtime-telemetry.d.ts.map +1 -1
  332. package/dist/core/hooks/adapter/runtime-telemetry.js +307 -6
  333. package/dist/core/hooks/cli.js +380 -207
  334. package/dist/core/hooks/effects/image-capture.d.ts +1 -1
  335. package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
  336. package/dist/core/hooks/effects/image-capture.js +4 -2
  337. package/dist/core/hooks/health.d.ts +59 -0
  338. package/dist/core/hooks/health.d.ts.map +1 -0
  339. package/dist/core/hooks/health.js +84 -0
  340. package/dist/core/hooks/remediation-cap.d.ts +8 -3
  341. package/dist/core/hooks/remediation-cap.d.ts.map +1 -1
  342. package/dist/core/hooks/remediation-cap.js +3 -11
  343. package/dist/core/hooks/resolve/coord-root.d.ts +22 -9
  344. package/dist/core/hooks/resolve/coord-root.d.ts.map +1 -1
  345. package/dist/core/hooks/resolve/coord-root.js +92 -11
  346. package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
  347. package/dist/core/hooks/resolve/owner.js +5 -0
  348. package/dist/core/hooks/resolve/transcript.d.ts +8 -0
  349. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  350. package/dist/core/hooks/resolve/transcript.js +11 -0
  351. package/dist/core/inbox/contract.d.ts +64 -0
  352. package/dist/core/inbox/contract.d.ts.map +1 -0
  353. package/dist/core/inbox/contract.js +13 -0
  354. package/dist/core/inbox/index.d.ts +5 -0
  355. package/dist/core/inbox/index.d.ts.map +1 -0
  356. package/dist/core/inbox/index.js +4 -0
  357. package/dist/core/inbox/lifecycle.d.ts +22 -0
  358. package/dist/core/inbox/lifecycle.d.ts.map +1 -0
  359. package/dist/core/inbox/lifecycle.js +41 -0
  360. package/dist/core/inbox/service.d.ts +36 -0
  361. package/dist/core/inbox/service.d.ts.map +1 -0
  362. package/dist/core/inbox/service.js +210 -0
  363. package/dist/core/inbox/watcher.d.ts +7 -0
  364. package/dist/core/inbox/watcher.d.ts.map +1 -0
  365. package/dist/core/inbox/watcher.js +26 -0
  366. package/dist/core/presence/codec-digest.d.ts.map +1 -1
  367. package/dist/core/presence/codec-digest.js +14 -3
  368. package/dist/core/presence/relay-client.d.ts +1 -0
  369. package/dist/core/presence/relay-client.d.ts.map +1 -1
  370. package/dist/core/presence/relay-client.js +52 -8
  371. package/dist/core/resources/contract.d.ts +90 -0
  372. package/dist/core/resources/contract.d.ts.map +1 -0
  373. package/dist/core/resources/contract.js +2 -0
  374. package/dist/core/resources/index.d.ts +6 -0
  375. package/dist/core/resources/index.d.ts.map +1 -0
  376. package/dist/core/resources/index.js +5 -0
  377. package/dist/core/resources/sampler.d.ts +27 -0
  378. package/dist/core/resources/sampler.d.ts.map +1 -0
  379. package/dist/core/resources/sampler.js +357 -0
  380. package/dist/core/resources/service-status.d.ts +3 -0
  381. package/dist/core/resources/service-status.d.ts.map +1 -0
  382. package/dist/core/resources/service-status.js +48 -0
  383. package/dist/core/resources/service.d.ts +26 -0
  384. package/dist/core/resources/service.d.ts.map +1 -0
  385. package/dist/core/resources/service.js +292 -0
  386. package/dist/core/resources/storage.d.ts +13 -0
  387. package/dist/core/resources/storage.d.ts.map +1 -0
  388. package/dist/core/resources/storage.js +30 -0
  389. package/dist/core/semantic/adapters.d.ts +11 -8
  390. package/dist/core/semantic/adapters.d.ts.map +1 -1
  391. package/dist/core/semantic/adapters.js +169 -31
  392. package/dist/core/semantic/contract.d.ts +532 -48
  393. package/dist/core/semantic/contract.d.ts.map +1 -1
  394. package/dist/core/semantic/contract.js +104 -3
  395. package/dist/core/semantic/index.d.ts +7 -3
  396. package/dist/core/semantic/index.d.ts.map +1 -1
  397. package/dist/core/semantic/index.js +7 -3
  398. package/dist/core/semantic/once.d.ts +6 -1
  399. package/dist/core/semantic/once.d.ts.map +1 -1
  400. package/dist/core/semantic/once.js +80 -9
  401. package/dist/core/semantic/prompt.d.ts.map +1 -1
  402. package/dist/core/semantic/prompt.js +14 -1
  403. package/dist/core/semantic/review.d.ts +144 -0
  404. package/dist/core/semantic/review.d.ts.map +1 -0
  405. package/dist/core/semantic/review.js +544 -0
  406. package/dist/core/semantic/routes.d.ts +10 -0
  407. package/dist/core/semantic/routes.d.ts.map +1 -0
  408. package/dist/core/semantic/routes.js +21 -0
  409. package/dist/core/semantic/scheduler.d.ts +14 -3
  410. package/dist/core/semantic/scheduler.d.ts.map +1 -1
  411. package/dist/core/semantic/scheduler.js +30 -6
  412. package/dist/core/semantic/service-status.d.ts +20 -0
  413. package/dist/core/semantic/service-status.d.ts.map +1 -1
  414. package/dist/core/semantic/service-status.js +60 -4
  415. package/dist/core/semantic/service.d.ts +1 -0
  416. package/dist/core/semantic/service.d.ts.map +1 -1
  417. package/dist/core/semantic/service.js +104 -15
  418. package/dist/core/semantic/soak.d.ts +75 -0
  419. package/dist/core/semantic/soak.d.ts.map +1 -0
  420. package/dist/core/semantic/soak.js +476 -0
  421. package/dist/core/semantic/storage.d.ts +11 -1
  422. package/dist/core/semantic/storage.d.ts.map +1 -1
  423. package/dist/core/semantic/storage.js +4 -3
  424. package/dist/core/semantic/usage.d.ts +43 -0
  425. package/dist/core/semantic/usage.d.ts.map +1 -0
  426. package/dist/core/semantic/usage.js +193 -0
  427. package/dist/core/semantic/validate.d.ts +3 -1
  428. package/dist/core/semantic/validate.d.ts.map +1 -1
  429. package/dist/core/semantic/validate.js +34 -1
  430. package/dist/core/storage/atomic-json.d.ts +3 -0
  431. package/dist/core/storage/atomic-json.d.ts.map +1 -0
  432. package/dist/core/storage/atomic-json.js +15 -0
  433. package/dist/core/storage/buffer.d.ts +28 -0
  434. package/dist/core/storage/buffer.d.ts.map +1 -0
  435. package/dist/core/storage/buffer.js +101 -0
  436. package/dist/core/storage/builtins.d.ts +3 -0
  437. package/dist/core/storage/builtins.d.ts.map +1 -0
  438. package/dist/core/storage/builtins.js +722 -0
  439. package/dist/core/storage/catalog.d.ts +19 -0
  440. package/dist/core/storage/catalog.d.ts.map +1 -0
  441. package/dist/core/storage/catalog.js +365 -0
  442. package/dist/core/storage/config.d.ts +16 -0
  443. package/dist/core/storage/config.d.ts.map +1 -0
  444. package/dist/core/storage/config.js +311 -0
  445. package/dist/core/storage/contract.d.ts +275 -0
  446. package/dist/core/storage/contract.d.ts.map +1 -0
  447. package/dist/core/storage/contract.js +3 -0
  448. package/dist/core/storage/durable-history.d.ts +36 -0
  449. package/dist/core/storage/durable-history.d.ts.map +1 -0
  450. package/dist/core/storage/durable-history.js +606 -0
  451. package/dist/core/storage/health.d.ts +4 -0
  452. package/dist/core/storage/health.d.ts.map +1 -0
  453. package/dist/core/storage/health.js +65 -0
  454. package/dist/core/storage/index.d.ts +16 -0
  455. package/dist/core/storage/index.d.ts.map +1 -0
  456. package/dist/core/storage/index.js +15 -0
  457. package/dist/core/storage/inventory.d.ts +25 -0
  458. package/dist/core/storage/inventory.d.ts.map +1 -0
  459. package/dist/core/storage/inventory.js +666 -0
  460. package/dist/core/storage/jsonl.d.ts +52 -0
  461. package/dist/core/storage/jsonl.d.ts.map +1 -0
  462. package/dist/core/storage/jsonl.js +156 -0
  463. package/dist/core/storage/log-retention.d.ts +52 -0
  464. package/dist/core/storage/log-retention.d.ts.map +1 -0
  465. package/dist/core/storage/log-retention.js +419 -0
  466. package/dist/core/storage/logger.d.ts +84 -0
  467. package/dist/core/storage/logger.d.ts.map +1 -0
  468. package/dist/core/storage/logger.js +413 -0
  469. package/dist/core/storage/maintenance-providers.d.ts +26 -0
  470. package/dist/core/storage/maintenance-providers.d.ts.map +1 -0
  471. package/dist/core/storage/maintenance-providers.js +141 -0
  472. package/dist/core/storage/maintenance.d.ts +125 -0
  473. package/dist/core/storage/maintenance.d.ts.map +1 -0
  474. package/dist/core/storage/maintenance.js +609 -0
  475. package/dist/core/storage/metrics.d.ts +60 -0
  476. package/dist/core/storage/metrics.d.ts.map +1 -0
  477. package/dist/core/storage/metrics.js +134 -0
  478. package/dist/core/storage/policy.d.ts +7 -0
  479. package/dist/core/storage/policy.d.ts.map +1 -0
  480. package/dist/core/storage/policy.js +110 -0
  481. package/dist/core/storage/process-log.d.ts +38 -0
  482. package/dist/core/storage/process-log.d.ts.map +1 -0
  483. package/dist/core/storage/process-log.js +165 -0
  484. package/dist/core/storage/query.d.ts +48 -0
  485. package/dist/core/storage/query.d.ts.map +1 -0
  486. package/dist/core/storage/query.js +346 -0
  487. package/dist/core/storage/receipts.d.ts +23 -0
  488. package/dist/core/storage/receipts.d.ts.map +1 -0
  489. package/dist/core/storage/receipts.js +117 -0
  490. package/dist/core/storage/segments.d.ts +84 -0
  491. package/dist/core/storage/segments.d.ts.map +1 -0
  492. package/dist/core/storage/segments.js +542 -0
  493. package/dist/core/storage/sink-graph.d.ts +65 -0
  494. package/dist/core/storage/sink-graph.d.ts.map +1 -0
  495. package/dist/core/storage/sink-graph.js +213 -0
  496. package/dist/core/storage/storm-control.d.ts +23 -0
  497. package/dist/core/storage/storm-control.d.ts.map +1 -0
  498. package/dist/core/storage/storm-control.js +59 -0
  499. package/dist/core/supervisor/activity.d.ts +4 -0
  500. package/dist/core/supervisor/activity.d.ts.map +1 -0
  501. package/dist/core/supervisor/activity.js +141 -0
  502. package/dist/core/supervisor/contract.d.ts +268 -0
  503. package/dist/core/supervisor/contract.d.ts.map +1 -0
  504. package/dist/core/supervisor/contract.js +35 -0
  505. package/dist/core/supervisor/explanations.d.ts +4 -0
  506. package/dist/core/supervisor/explanations.d.ts.map +1 -0
  507. package/dist/core/supervisor/explanations.js +71 -0
  508. package/dist/core/supervisor/findings.d.ts +20 -0
  509. package/dist/core/supervisor/findings.d.ts.map +1 -0
  510. package/dist/core/supervisor/findings.js +399 -0
  511. package/dist/core/supervisor/history.d.ts +9 -0
  512. package/dist/core/supervisor/history.d.ts.map +1 -0
  513. package/dist/core/supervisor/history.js +46 -0
  514. package/dist/core/supervisor/hook-health-alerts.d.ts +14 -0
  515. package/dist/core/supervisor/hook-health-alerts.d.ts.map +1 -0
  516. package/dist/core/supervisor/hook-health-alerts.js +70 -0
  517. package/dist/core/supervisor/hook-health-storage.d.ts +5 -0
  518. package/dist/core/supervisor/hook-health-storage.d.ts.map +1 -0
  519. package/dist/core/supervisor/hook-health-storage.js +24 -0
  520. package/dist/core/supervisor/hook-health.d.ts +72 -0
  521. package/dist/core/supervisor/hook-health.d.ts.map +1 -0
  522. package/dist/core/supervisor/hook-health.js +203 -0
  523. package/dist/core/supervisor/hooks.d.ts +10 -0
  524. package/dist/core/supervisor/hooks.d.ts.map +1 -0
  525. package/dist/core/supervisor/hooks.js +28 -0
  526. package/dist/core/supervisor/index.d.ts +15 -0
  527. package/dist/core/supervisor/index.d.ts.map +1 -0
  528. package/dist/core/supervisor/index.js +14 -0
  529. package/dist/core/supervisor/log-feed.d.ts +9 -0
  530. package/dist/core/supervisor/log-feed.d.ts.map +1 -0
  531. package/dist/core/supervisor/log-feed.js +103 -0
  532. package/dist/core/supervisor/service.d.ts +29 -0
  533. package/dist/core/supervisor/service.d.ts.map +1 -0
  534. package/dist/core/supervisor/service.js +450 -0
  535. package/dist/core/supervisor/services.d.ts +11 -0
  536. package/dist/core/supervisor/services.d.ts.map +1 -0
  537. package/dist/core/supervisor/services.js +155 -0
  538. package/dist/core/supervisor/status.d.ts +3 -0
  539. package/dist/core/supervisor/status.d.ts.map +1 -0
  540. package/dist/core/supervisor/status.js +48 -0
  541. package/dist/core/supervisor/storage.d.ts +30 -0
  542. package/dist/core/supervisor/storage.d.ts.map +1 -0
  543. package/dist/core/supervisor/storage.js +73 -0
  544. package/dist/core/supervisor/timeline.d.ts +3 -0
  545. package/dist/core/supervisor/timeline.d.ts.map +1 -0
  546. package/dist/core/supervisor/timeline.js +87 -0
  547. package/dist/core/work/state.d.ts.map +1 -1
  548. package/dist/core/work/state.js +10 -14
  549. package/dist/core/workflow/admission.d.ts +23 -0
  550. package/dist/core/workflow/admission.d.ts.map +1 -0
  551. package/dist/core/workflow/admission.js +136 -0
  552. package/dist/core/workflow/engine.d.ts.map +1 -1
  553. package/dist/core/workflow/engine.js +77 -2
  554. package/dist/core/workflow/index.d.ts +3 -2
  555. package/dist/core/workflow/index.d.ts.map +1 -1
  556. package/dist/core/workflow/index.js +2 -1
  557. package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
  558. package/dist/core/workflow/live-session-v3.js +2 -1
  559. package/dist/core/workflow/proof.d.ts +2 -1
  560. package/dist/core/workflow/proof.d.ts.map +1 -1
  561. package/dist/core/workflow/proof.js +39 -1
  562. package/dist/core/workflow/run-state.d.ts +3 -2
  563. package/dist/core/workflow/run-state.d.ts.map +1 -1
  564. package/dist/core/workflow/run-state.js +8 -1
  565. package/dist/core/workflow/types.d.ts +33 -1
  566. package/dist/core/workflow/types.d.ts.map +1 -1
  567. package/dist/core/workflow/types.js +2 -1
  568. package/dist/index.d.ts +2 -0
  569. package/dist/index.d.ts.map +1 -1
  570. package/dist/index.js +2 -0
  571. package/dist/lazy-commands.d.ts +26 -0
  572. package/dist/lazy-commands.d.ts.map +1 -0
  573. package/dist/lazy-commands.js +210 -0
  574. package/dist/lib/browser/client.d.ts +5 -0
  575. package/dist/lib/browser/client.d.ts.map +1 -1
  576. package/dist/lib/browser/client.js +1 -0
  577. package/dist/lib/browser/index.d.ts +2 -0
  578. package/dist/lib/browser/index.d.ts.map +1 -1
  579. package/dist/lib/browser/index.js +2 -0
  580. package/dist/lib/browser/qa-run-contracts.d.ts +173 -0
  581. package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -0
  582. package/dist/lib/browser/qa-run-contracts.js +226 -0
  583. package/dist/lib/browser/qa-run.d.ts +51 -0
  584. package/dist/lib/browser/qa-run.d.ts.map +1 -0
  585. package/dist/lib/browser/qa-run.js +684 -0
  586. package/dist/lib/coord-root-id.d.ts +9 -0
  587. package/dist/lib/coord-root-id.d.ts.map +1 -0
  588. package/dist/lib/coord-root-id.js +17 -0
  589. package/dist/lib/docs-lint.d.ts +2 -0
  590. package/dist/lib/docs-lint.d.ts.map +1 -1
  591. package/dist/lib/docs-lint.js +45 -80
  592. package/dist/lib/docs-metadata-audit.d.ts +3 -0
  593. package/dist/lib/docs-metadata-audit.d.ts.map +1 -1
  594. package/dist/lib/docs-metadata-audit.js +13 -23
  595. package/dist/lib/docs-metadata-sync.d.ts +1 -0
  596. package/dist/lib/docs-metadata-sync.d.ts.map +1 -1
  597. package/dist/lib/docs-metadata-sync.js +28 -10
  598. package/dist/lib/docs-repository-view.d.ts +22 -0
  599. package/dist/lib/docs-repository-view.d.ts.map +1 -0
  600. package/dist/lib/docs-repository-view.js +185 -0
  601. package/dist/lib/http/client.d.ts +11 -5
  602. package/dist/lib/http/client.d.ts.map +1 -1
  603. package/dist/lib/http/client.js +22 -4
  604. package/dist/lib/http/index.d.ts +1 -1
  605. package/dist/lib/http/index.d.ts.map +1 -1
  606. package/dist/lib/http/index.js +1 -1
  607. package/dist/lib/indexer-exclusions.d.ts +27 -0
  608. package/dist/lib/indexer-exclusions.d.ts.map +1 -0
  609. package/dist/lib/indexer-exclusions.js +176 -0
  610. package/dist/lib/instructions/apply.d.ts +3 -1
  611. package/dist/lib/instructions/apply.d.ts.map +1 -1
  612. package/dist/lib/instructions/apply.js +74 -3
  613. package/dist/lib/instructions/templates.d.ts.map +1 -1
  614. package/dist/lib/instructions/templates.js +11 -0
  615. package/dist/lib/local-file-url.d.ts +9 -0
  616. package/dist/lib/local-file-url.d.ts.map +1 -0
  617. package/dist/lib/local-file-url.js +20 -0
  618. package/dist/lib/web-performance.d.ts +118 -0
  619. package/dist/lib/web-performance.d.ts.map +1 -0
  620. package/dist/lib/web-performance.js +192 -0
  621. package/package.json +40 -2
  622. package/schemas/config.schema.json +58 -0
  623. package/schemas/event-v3.schema.json +324 -112
  624. package/src/commander.ts +488 -95
  625. package/src/commands/agents.ts +617 -237
  626. package/src/commands/artifacts.ts +40 -2
  627. package/src/commands/backup.ts +18 -14
  628. package/src/commands/browse-session.ts +12 -0
  629. package/src/commands/browse.ts +21 -7
  630. package/src/commands/conversations.ts +279 -0
  631. package/src/commands/deinit.ts +6 -0
  632. package/src/commands/diagnostics.ts +271 -0
  633. package/src/commands/docs.ts +25 -6
  634. package/src/commands/doctor.ts +75 -9
  635. package/src/commands/fetch.ts +7 -6
  636. package/src/commands/files.ts +243 -0
  637. package/src/commands/governor.ts +21 -12
  638. package/src/commands/inbox.ts +61 -0
  639. package/src/commands/init.ts +78 -16
  640. package/src/commands/ledger-v3.ts +503 -1
  641. package/src/commands/logs.ts +224 -0
  642. package/src/commands/messages.ts +61 -0
  643. package/src/commands/outline.ts +6 -2
  644. package/src/commands/qa-run.ts +184 -0
  645. package/src/commands/read.ts +6 -2
  646. package/src/commands/resources.ts +38 -0
  647. package/src/commands/semantic.ts +66 -1
  648. package/src/commands/storage.ts +310 -0
  649. package/src/commands/supervisor.ts +141 -0
  650. package/src/commands/tunnel.ts +66 -52
  651. package/src/commands/web.ts +96 -7
  652. package/src/commands/work.ts +3 -3
  653. package/src/commands/workflow.ts +21 -13
  654. package/src/core/agents/cli.ts +265 -55
  655. package/src/core/agents/health.ts +142 -0
  656. package/src/core/agents/live-authority-v3.ts +341 -10
  657. package/src/core/agents/live-lifecycle-v3.ts +6 -1
  658. package/src/core/agents/live-observation-v3.ts +6 -1
  659. package/src/core/agents/mailbox.ts +373 -0
  660. package/src/core/agents/reconcile-coordination-v3.ts +77 -0
  661. package/src/core/agents/render/prompt-context.ts +66 -15
  662. package/src/core/agents/render/session-context.ts +37 -3
  663. package/src/core/agents/rules/commit-conflict.ts +58 -1
  664. package/src/core/agents/rules/stop-hook.ts +105 -20
  665. package/src/core/agents/rules/verdict.ts +1 -0
  666. package/src/core/agents/session-events.ts +4 -0
  667. package/src/core/agents/session-finalization-state-v3.ts +1 -1
  668. package/src/core/agents/session-finalizer-v3.ts +8 -2
  669. package/src/core/agents/state/activity-log.ts +7 -2
  670. package/src/core/agents/state/heartbeat-writer.ts +27 -0
  671. package/src/core/agents/state/live-coordination-view.ts +16 -105
  672. package/src/core/agents/state/live-coordination-writer.ts +141 -0
  673. package/src/core/artifacts/index.ts +260 -11
  674. package/src/core/config.ts +235 -5
  675. package/src/core/conversations/archive.ts +237 -0
  676. package/src/core/conversations/catalog.ts +79 -0
  677. package/src/core/conversations/context-pack.ts +72 -0
  678. package/src/core/conversations/contract.ts +178 -0
  679. package/src/core/conversations/evaluation.ts +30 -0
  680. package/src/core/conversations/index.ts +9 -0
  681. package/src/core/conversations/lifecycle.ts +63 -0
  682. package/src/core/conversations/normalize.ts +105 -0
  683. package/src/core/conversations/query.ts +318 -0
  684. package/src/core/conversations/search-index.ts +48 -0
  685. package/src/core/diagnostics/advice.ts +147 -0
  686. package/src/core/diagnostics/bundle.ts +1142 -0
  687. package/src/core/diagnostics/comparison.ts +565 -0
  688. package/src/core/diagnostics/contract.ts +311 -0
  689. package/src/core/diagnostics/identity.ts +11 -0
  690. package/src/core/diagnostics/index.ts +7 -0
  691. package/src/core/diagnostics/replay.ts +314 -0
  692. package/src/core/diagnostics/sanitize.ts +97 -0
  693. package/src/core/events/legacy-storage/canary.ts +177 -0
  694. package/src/core/events/legacy-storage/compression.ts +130 -0
  695. package/src/core/events/legacy-storage/fence.ts +129 -0
  696. package/src/core/events/legacy-storage/index.ts +6 -0
  697. package/src/core/events/legacy-storage/inventory.ts +51 -0
  698. package/src/core/events/legacy-storage/manifest.ts +136 -0
  699. package/src/core/events/legacy-storage/reader.ts +178 -0
  700. package/src/core/events/v3/archive-retention.ts +251 -0
  701. package/src/core/events/v3/authority-outbox.ts +22 -1
  702. package/src/core/events/v3/base-contract.ts +17 -7
  703. package/src/core/events/v3/bootstrap.ts +195 -2
  704. package/src/core/events/v3/capabilities.ts +5 -3
  705. package/src/core/events/v3/control-witness.ts +339 -0
  706. package/src/core/events/v3/control-writer.ts +16 -0
  707. package/src/core/events/v3/control.ts +54 -18
  708. package/src/core/events/v3/coordination-transaction-recovery.ts +477 -0
  709. package/src/core/events/v3/coordination-view.ts +17 -1
  710. package/src/core/events/v3/generated.ts +1 -1
  711. package/src/core/events/v3/index.ts +14 -2
  712. package/src/core/events/v3/live-route-observer.ts +80 -0
  713. package/src/core/events/v3/live-routing.ts +65 -46
  714. package/src/core/events/v3/producers/coordination-recorder.ts +95 -10
  715. package/src/core/events/v3/producers/diagnostic-summaries.ts +593 -0
  716. package/src/core/events/v3/producers/hook-base.ts +15 -3
  717. package/src/core/events/v3/producers/intake.ts +31 -2
  718. package/src/core/events/v3/producers/producer-state-observer.ts +52 -0
  719. package/src/core/events/v3/producers/recorder.ts +681 -34
  720. package/src/core/events/v3/reader.ts +243 -2
  721. package/src/core/events/v3/rotation-config.ts +98 -0
  722. package/src/core/events/v3/runtime-build.ts +41 -0
  723. package/src/core/events/v3/runtime-identity.ts +16 -0
  724. package/src/core/events/v3/runtime-telemetry-capabilities.ts +14 -8
  725. package/src/core/events/v3/support-storage/classify.ts +209 -0
  726. package/src/core/events/v3/support-storage/eligibility.ts +58 -0
  727. package/src/core/events/v3/support-storage/index.ts +9 -0
  728. package/src/core/events/v3/support-storage/inventory.ts +135 -0
  729. package/src/core/events/v3/support-storage/logical-authority.ts +117 -0
  730. package/src/core/events/v3/support-storage/maintenance.ts +501 -0
  731. package/src/core/events/v3/support-storage/pack-contract.ts +337 -0
  732. package/src/core/events/v3/support-storage/pack-reader.ts +346 -0
  733. package/src/core/events/v3/support-storage/pack-writer.ts +352 -0
  734. package/src/core/events/v3/support-storage/recovery.ts +43 -0
  735. package/src/core/events/v3/turn-telemetry.ts +58 -7
  736. package/src/core/events/v3/writer.ts +168 -16
  737. package/src/core/governor/plan-read.ts +5 -18
  738. package/src/core/governor/planning.ts +5 -8
  739. package/src/core/governor/service-read.ts +320 -2
  740. package/src/core/governor/service.ts +49 -22
  741. package/src/core/guard/evidence-v3.ts +1 -0
  742. package/src/core/hooks/adapter/events.ts +1 -0
  743. package/src/core/hooks/adapter/output.ts +23 -5
  744. package/src/core/hooks/adapter/runtime-telemetry.ts +408 -13
  745. package/src/core/hooks/cli.ts +404 -233
  746. package/src/core/hooks/effects/image-capture.ts +4 -1
  747. package/src/core/hooks/health.ts +146 -0
  748. package/src/core/hooks/remediation-cap.ts +12 -6
  749. package/src/core/hooks/resolve/coord-root.ts +91 -11
  750. package/src/core/hooks/resolve/owner.ts +4 -0
  751. package/src/core/hooks/resolve/transcript.ts +18 -0
  752. package/src/core/inbox/contract.ts +81 -0
  753. package/src/core/inbox/index.ts +4 -0
  754. package/src/core/inbox/lifecycle.ts +104 -0
  755. package/src/core/inbox/service.ts +305 -0
  756. package/src/core/inbox/watcher.ts +36 -0
  757. package/src/core/presence/codec-digest.ts +15 -9
  758. package/src/core/presence/relay-client.ts +55 -7
  759. package/src/core/resources/contract.ts +98 -0
  760. package/src/core/resources/index.ts +5 -0
  761. package/src/core/resources/sampler.ts +458 -0
  762. package/src/core/resources/service-status.ts +62 -0
  763. package/src/core/resources/service.ts +337 -0
  764. package/src/core/resources/storage.ts +44 -0
  765. package/src/core/semantic/adapters.ts +200 -41
  766. package/src/core/semantic/contract.ts +135 -3
  767. package/src/core/semantic/index.ts +76 -2
  768. package/src/core/semantic/once.ts +93 -7
  769. package/src/core/semantic/prompt.ts +13 -1
  770. package/src/core/semantic/review.ts +803 -0
  771. package/src/core/semantic/routes.ts +30 -0
  772. package/src/core/semantic/scheduler.ts +49 -5
  773. package/src/core/semantic/service-status.ts +99 -5
  774. package/src/core/semantic/service.ts +116 -15
  775. package/src/core/semantic/soak.ts +638 -0
  776. package/src/core/semantic/storage.ts +20 -6
  777. package/src/core/semantic/usage.ts +272 -0
  778. package/src/core/semantic/validate.ts +31 -0
  779. package/src/core/storage/atomic-json.ts +15 -0
  780. package/src/core/storage/buffer.ts +124 -0
  781. package/src/core/storage/builtins.ts +972 -0
  782. package/src/core/storage/catalog.ts +467 -0
  783. package/src/core/storage/config.ts +423 -0
  784. package/src/core/storage/contract.ts +342 -0
  785. package/src/core/storage/durable-history.ts +738 -0
  786. package/src/core/storage/health.ts +76 -0
  787. package/src/core/storage/index.ts +15 -0
  788. package/src/core/storage/inventory.ts +859 -0
  789. package/src/core/storage/jsonl.ts +213 -0
  790. package/src/core/storage/log-retention.ts +555 -0
  791. package/src/core/storage/logger.ts +548 -0
  792. package/src/core/storage/maintenance-providers.ts +200 -0
  793. package/src/core/storage/maintenance.ts +929 -0
  794. package/src/core/storage/metrics.ts +199 -0
  795. package/src/core/storage/policy.ts +141 -0
  796. package/src/core/storage/process-log.ts +203 -0
  797. package/src/core/storage/query.ts +418 -0
  798. package/src/core/storage/receipts.ts +162 -0
  799. package/src/core/storage/segments.ts +721 -0
  800. package/src/core/storage/sink-graph.ts +343 -0
  801. package/src/core/storage/storm-control.ts +91 -0
  802. package/src/core/supervisor/activity.ts +193 -0
  803. package/src/core/supervisor/contract.ts +312 -0
  804. package/src/core/supervisor/explanations.ts +104 -0
  805. package/src/core/supervisor/findings.ts +788 -0
  806. package/src/core/supervisor/history.ts +61 -0
  807. package/src/core/supervisor/hook-health-alerts.ts +108 -0
  808. package/src/core/supervisor/hook-health-storage.ts +25 -0
  809. package/src/core/supervisor/hook-health.ts +301 -0
  810. package/src/core/supervisor/hooks.ts +35 -0
  811. package/src/core/supervisor/index.ts +14 -0
  812. package/src/core/supervisor/log-feed.ts +131 -0
  813. package/src/core/supervisor/service.ts +511 -0
  814. package/src/core/supervisor/services.ts +203 -0
  815. package/src/core/supervisor/status.ts +59 -0
  816. package/src/core/supervisor/storage.ts +126 -0
  817. package/src/core/supervisor/timeline.ts +133 -0
  818. package/src/core/work/state.ts +12 -21
  819. package/src/core/workflow/admission.ts +215 -0
  820. package/src/core/workflow/engine.ts +93 -1
  821. package/src/core/workflow/index.ts +10 -0
  822. package/src/core/workflow/live-session-v3.ts +2 -4
  823. package/src/core/workflow/proof.ts +54 -1
  824. package/src/core/workflow/run-state.ts +13 -1
  825. package/src/core/workflow/types.ts +39 -1
  826. package/src/index.ts +2 -0
  827. package/src/lazy-commands.ts +294 -0
  828. package/src/lib/browser/client.ts +6 -0
  829. package/src/lib/browser/index.ts +29 -0
  830. package/src/lib/browser/qa-run-contracts.ts +380 -0
  831. package/src/lib/browser/qa-run.ts +784 -0
  832. package/src/lib/coord-root-id.ts +23 -0
  833. package/src/lib/docs-lint.ts +58 -77
  834. package/src/lib/docs-metadata-audit.ts +26 -21
  835. package/src/lib/docs-metadata-sync.ts +32 -9
  836. package/src/lib/docs-repository-view.ts +220 -0
  837. package/src/lib/http/client.ts +44 -8
  838. package/src/lib/http/index.ts +6 -1
  839. package/src/lib/indexer-exclusions.ts +173 -0
  840. package/src/lib/instructions/apply.ts +81 -2
  841. package/src/lib/instructions/templates.ts +11 -0
  842. package/src/lib/local-file-url.ts +31 -0
  843. 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,19 @@ 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";
52
+ import {
53
+ isAddressableName,
54
+ MailboxCapacityError,
55
+ type QueueResult,
56
+ queueMailboxMessage,
57
+ suggestNames,
58
+ } from "../core/agents/mailbox.ts";
59
+ import { reconcileCoordinationV3 } from "../core/agents/reconcile-coordination-v3.ts";
48
60
  import {
49
61
  listSessionFinalizationRequestsV3,
50
62
  observeHostDisappearedV3,
@@ -56,6 +68,7 @@ import {
56
68
  SESSION_NAME_DISPLAY_NOTE,
57
69
  sessionNameDisplayPending,
58
70
  } from "../core/agents/session-name-display.ts";
71
+ import { agentDisplayName } from "../core/agents/state/activity-log.ts";
59
72
  import {
60
73
  buildLifecycleSuggestedName,
61
74
  buildSuggestedName,
@@ -80,6 +93,10 @@ import type { EventTypeV3 } from "../core/events/v3/contract.ts";
80
93
  import { readEventV3ControlState } from "../core/events/v3/control.ts";
81
94
  import { projectCoordinationViewV3 } from "../core/events/v3/coordination-view.ts";
82
95
  import { liveInstanceIdV3 } from "../core/events/v3/live-routing.ts";
96
+ import {
97
+ countSummarizedSinceV3,
98
+ listDiagnosticSummariesV3,
99
+ } from "../core/events/v3/producers/diagnostic-summaries.ts";
83
100
  import {
84
101
  listHookIntakeGroupsV3,
85
102
  listHookIntakeRecordsV3,
@@ -92,7 +109,10 @@ import { readLedgerV3 } from "../core/events/v3/reader.ts";
92
109
  import { EVENT_V3_LEDGER_RELATIVE_ROOT } from "../core/events/v3/writer.ts";
93
110
  import type { RunQualitySnapshot, RunQualityStatus } from "../core/guard/index.ts";
94
111
  import { evaluateRunQualityIfDue } from "../core/guard/index.ts";
95
- import { readRuntimeContextUsage } from "../core/hooks/adapter/runtime-telemetry.ts";
112
+ import {
113
+ readRuntimeContextTelemetry,
114
+ readRuntimeContextUsage,
115
+ } from "../core/hooks/adapter/runtime-telemetry.ts";
96
116
  import { type RemoteMachine, readRemoteMachines } from "../core/presence/index.ts";
97
117
  import { registerContextCommand } from "./context.ts";
98
118
 
@@ -264,6 +284,7 @@ export function registerAgentsCommand(
264
284
  program: Command,
265
285
  emitParam: EmitContext,
266
286
  programContext?: HarneryProgramContext,
287
+ binName = resolveBinName(),
267
288
  ): void {
268
289
  emit = emitParam;
269
290
  const cmd = program
@@ -385,7 +406,7 @@ export function registerAgentsCommand(
385
406
  )
386
407
  .option(
387
408
  "--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\`.`,
409
+ `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
410
  )
390
411
  .action((text: string[], opts: { sessionId?: string }) => {
391
412
  runSetTask(text.join(" "), opts);
@@ -422,7 +443,8 @@ export function registerAgentsCommand(
422
443
  cmd
423
444
  .command("reconcile")
424
445
  .description(
425
- "Reconcile archive, idle, parent/run completion, stale, superseded, and host lifecycle signals into V3 session finalization.",
446
+ "Sweep the stale coordination cache, then reconcile archive, idle, parent/run " +
447
+ "completion, stale, superseded, and host lifecycle signals into V3 session finalization.",
426
448
  )
427
449
  .option("--watch", "Keep reconciling until interrupted")
428
450
  .option("--interval-seconds <n>", "Watch interval in seconds")
@@ -472,9 +494,10 @@ export function registerAgentsCommand(
472
494
  cmd
473
495
  .command("ping <name> <message...>")
474
496
  .description(
475
- "Append a 'handoff' entry to a peer agent's journal. Body prefixed with " +
476
- "`from agent-<me>:`. Use to leave actionable coordination notes for peers " +
477
- "currently holding files you need.",
497
+ "Send a message to another agent by name. Works whether or not that agent " +
498
+ "is running: a live peer sees it on their next prompt, and a name with no " +
499
+ "live session gets it queued until a session of that name next starts. " +
500
+ "Only an unknown name is refused.",
478
501
  )
479
502
  .option("--json", "JSON output")
480
503
  .action((name: string, message: string[], opts: { json?: boolean }) => {
@@ -484,7 +507,7 @@ export function registerAgentsCommand(
484
507
  cmd
485
508
  .command("wait <name>")
486
509
  .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.`,
510
+ `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
511
  )
489
512
  .option(
490
513
  "--file <path>",
@@ -533,7 +556,7 @@ export function registerAgentsCommand(
533
556
  .command("health")
534
557
  .description(
535
558
  "One-screen coord-layer health rollup: heal events, council activity, " +
536
- "zombie detection, and anomalies. Designed for " +
559
+ "heartbeat cache issues, and findings. Designed for " +
537
560
  "daily glance + dashboard ingestion. Reads .harnery/.",
538
561
  )
539
562
  .option("--since <window>", "Window (Nh | Nd). Default: 24h.", "24h")
@@ -567,12 +590,11 @@ export function registerAgentsCommand(
567
590
  cmd
568
591
  .command("heal")
569
592
  .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).",
593
+ "Repair the current session's disposable coordination cache from V3. " +
594
+ "Use explicit options to target another generation or repair process attribution.",
573
595
  )
574
- .requiredOption("--owner <id>", "Target agent's instance_id")
575
- .requiredOption("--kind <kind>", "pidmap | cache")
596
+ .option("--owner <id>", "Target agent's instance_id. Defaults to the current session.")
597
+ .option("--kind <kind>", "pidmap | cache. Defaults to cache.")
576
598
  .option(
577
599
  "--session-id <id>",
578
600
  "(--kind cache) native session id used to join the authoritative V3 generation.",
@@ -589,14 +611,26 @@ export function registerAgentsCommand(
589
611
  "when calling from outside Claude Code's Bash tool tree (e.g. " +
590
612
  "from cron or an external script).",
591
613
  )
614
+ .option(
615
+ "--quarantine-transaction <id>",
616
+ "Quarantine one irreconcilable prepared authority transaction after proving its event was never committed.",
617
+ )
618
+ .option(
619
+ "--approval-record-id <id>",
620
+ "Durable identifier for the operator approval authorizing transaction quarantine.",
621
+ )
622
+ .option("--yes", "Confirm the exact prepared transaction may be quarantined.")
592
623
  .option("--json", "JSON envelope output")
593
624
  .action(
594
625
  (opts: {
595
- owner: string;
596
- kind: string;
626
+ owner?: string;
627
+ kind?: string;
597
628
  sessionId?: string;
598
629
  adapter?: string;
599
630
  pid?: string;
631
+ quarantineTransaction?: string;
632
+ approvalRecordId?: string;
633
+ yes?: boolean;
600
634
  json?: boolean;
601
635
  }) => {
602
636
  runHeal(opts);
@@ -723,7 +757,7 @@ async function runSessionReconcile(opts: {
723
757
  }
724
758
  let stopped = false;
725
759
  do {
726
- emit.data(reconcileSessionFinalizationV3(root));
760
+ emit.data(reconcileCoordinationV3(root));
727
761
  if (!opts.watch || stopped) return;
728
762
  await new Promise<void>((resolvePromise) => {
729
763
  const timer = setTimeout(resolvePromise, interval * 1_000);
@@ -935,14 +969,15 @@ function runIdentityAssume(
935
969
  });
936
970
  process.exit(1);
937
971
  }
938
- if (!opts.sessionId) ensureCursorSession(root);
972
+ if (!opts.sessionId) ensureAdapterSession(root);
939
973
  const owner = opts.sessionId ?? resolveOwner();
940
974
  if (!owner) {
941
- emit.error({
942
- code: "no_pidmap_entry",
943
- message:
975
+ emit.error(
976
+ sessionResolutionFailure(
977
+ root,
944
978
  "not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)",
945
- });
979
+ ),
980
+ );
946
981
  process.exit(1);
947
982
  }
948
983
  try {
@@ -1214,14 +1249,13 @@ function runWhoami(opts: { json?: boolean }): void {
1214
1249
  process.exit(1);
1215
1250
  }
1216
1251
 
1217
- ensureCursorSession(root);
1252
+ ensureAdapterSession(root);
1218
1253
  const resolved = resolveOwnerWithSource();
1219
1254
  const myOwner = resolved.owner;
1220
1255
  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
- });
1256
+ emit.error(
1257
+ sessionResolutionFailure(root, "not in an agent session; ppid walk found no pid-map entry"),
1258
+ );
1225
1259
  process.exit(1);
1226
1260
  }
1227
1261
 
@@ -1703,49 +1737,96 @@ function cursorEnvSessionId(): string | null {
1703
1737
  return raw.startsWith("bc-") && raw.length > 3 ? raw.slice(3) : raw;
1704
1738
  }
1705
1739
 
1706
- function shouldBootstrapCursorSession(): boolean {
1707
- return process.env.CURSOR_AGENT === "1" && cursorEnvSessionId() !== null;
1740
+ interface CommandSessionBootstrap {
1741
+ adapter: "claude-code" | "cursor" | "codex";
1742
+ sessionId: string;
1708
1743
  }
1709
1744
 
1710
- function ensureCursorSession(root: string): void {
1711
- if (!shouldBootstrapCursorSession()) return;
1745
+ function commandSessionBootstrap(): CommandSessionBootstrap | null {
1746
+ const cursorSessionId = cursorEnvSessionId();
1747
+ if (process.env.CURSOR_AGENT === "1" && cursorSessionId) {
1748
+ return { adapter: "cursor", sessionId: cursorSessionId };
1749
+ }
1750
+ if (process.env.HARNERY_AGENT_COORD_BRIDGE?.trim() === "codex-wsl") {
1751
+ const sessionId = sessionIdentityFromEnv();
1752
+ if (sessionId) return { adapter: "codex", sessionId };
1753
+ }
1754
+ const claudeSessionId = process.env.CLAUDE_CODE_SESSION_ID?.trim();
1755
+ if (claudeSessionId) {
1756
+ return { adapter: "claude-code", sessionId: claudeSessionId };
1757
+ }
1758
+ return null;
1759
+ }
1760
+
1761
+ function ensureAdapterSession(root: string): void {
1762
+ const bootstrap = commandSessionBootstrap();
1763
+ if (!bootstrap) return;
1764
+ // Claude Code owns a reliable native SessionStart hook. Its environment is
1765
+ // accepted by the explicit `agents heal` recovery path, but ordinary
1766
+ // identity and status commands must not impersonate that hook. The heal
1767
+ // bootstrap records derived provenance instead.
1768
+ if (bootstrap.adapter === "claude-code") return;
1712
1769
  // Explicit owner override means the caller already knows who they are.
1713
1770
  // Bootstrapping sessionStart inherits that env into the child hook, which
1714
1771
  // re-projects a fresh heartbeat onto the override owner and can wipe an
1715
1772
  // assumed persona agent_id (seen under Cursor integration fixtures).
1716
- if (process.env.HARNERY_AGENT_COORD_OWNER?.trim()) return;
1773
+ if (bootstrap.adapter === "cursor" && process.env.HARNERY_AGENT_COORD_OWNER?.trim()) return;
1717
1774
  if (resolveOwnerBySessionEnv(root)) return;
1718
1775
 
1719
- const sessionId = cursorEnvSessionId();
1720
- if (!sessionId) return;
1721
1776
  const agentHook = coordBinPath("agent-hook", root);
1722
1777
  if (!agentHook) return;
1723
1778
 
1724
1779
  const payload = JSON.stringify({
1725
- conversation_id: sessionId,
1726
- session_id: sessionId,
1780
+ ...(bootstrap.adapter === "cursor" ? { conversation_id: bootstrap.sessionId } : {}),
1781
+ session_id: bootstrap.sessionId,
1727
1782
  hook_event_name: "sessionStart",
1728
1783
  workspace_roots: [root],
1729
1784
  cwd: root,
1730
- composer_mode: "agent",
1731
- is_background_agent: false,
1785
+ ...(bootstrap.adapter === "cursor"
1786
+ ? { composer_mode: "agent", is_background_agent: false }
1787
+ : { source: "resume" }),
1732
1788
  });
1733
1789
 
1734
- spawnSync("bash", [agentHook, "session-start", "--adapter", "cursor"], {
1790
+ spawnSync("bash", [agentHook, "session-start", "--adapter", bootstrap.adapter], {
1735
1791
  input: payload,
1736
1792
  cwd: root,
1737
1793
  encoding: "utf8",
1738
1794
  timeout: 3000,
1739
1795
  env: {
1740
1796
  ...process.env,
1741
- HARNERY_AGENT_COORD_PLATFORM: "cursor",
1797
+ HARNERY_AGENT_COORD_PLATFORM: bootstrap.adapter,
1742
1798
  HARNERY_COORD_ROOT_OVERRIDE: root,
1743
- CURSOR_SESSION_ID: sessionId,
1744
- CURSOR_CONVERSATION_ID: sessionId,
1799
+ HARNERY_AGENT_COORD_SESSION_ID: bootstrap.sessionId,
1800
+ ...(bootstrap.adapter === "cursor"
1801
+ ? {
1802
+ CURSOR_SESSION_ID: bootstrap.sessionId,
1803
+ CURSOR_CONVERSATION_ID: bootstrap.sessionId,
1804
+ }
1805
+ : { CODEX_THREAD_ID: bootstrap.sessionId }),
1745
1806
  },
1746
1807
  });
1747
1808
  }
1748
1809
 
1810
+ function sessionResolutionFailure(
1811
+ root: string,
1812
+ fallbackMessage: string,
1813
+ ): { code: string; message: string } {
1814
+ if (!sessionIdentityFromEnv()) return { code: "no_pidmap_entry", message: fallbackMessage };
1815
+ const control = readEventV3ControlState(root);
1816
+ if (control.state !== "candidate" && control.state !== "active") {
1817
+ const detail = `${control.state}:${control.reason}`;
1818
+ return {
1819
+ code: "event_v3_control_unavailable",
1820
+ message: `the adapter session identity is present, but the V3 control state cannot accept session onboarding (${detail})`,
1821
+ };
1822
+ }
1823
+ return {
1824
+ code: "session_generation_unavailable",
1825
+ message:
1826
+ "the adapter session identity is present, but no current V3 session generation was available after onboarding",
1827
+ };
1828
+ }
1829
+
1749
1830
  function runReleaseClaim(path: string): void {
1750
1831
  const root = monorepoRoot();
1751
1832
  if (!root) {
@@ -1757,10 +1838,9 @@ function runReleaseClaim(path: string): void {
1757
1838
  }
1758
1839
  const myOwner = resolveOwner();
1759
1840
  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
- });
1841
+ emit.error(
1842
+ sessionResolutionFailure(root, "not in an agent session; ppid walk found no pid-map entry"),
1843
+ );
1764
1844
  process.exit(1);
1765
1845
  }
1766
1846
  // Canonicalize: absolute paths under coordRoot get the prefix stripped;
@@ -1801,14 +1881,15 @@ function runSetTask(task: string, opts?: { sessionId?: string }): void {
1801
1881
  // returns null by design, and erroring here orphans the session's first
1802
1882
  // ritual command. The env id carries the same trust as an explicit
1803
1883
  // --session-id, and set-task mints the heartbeat exactly as that path does.
1804
- if (!opts?.sessionId) ensureCursorSession(root);
1884
+ if (!opts?.sessionId) ensureAdapterSession(root);
1805
1885
  const myOwner = opts?.sessionId ?? resolveOwner() ?? sessionIdentityFromEnv();
1806
1886
  if (!myOwner) {
1807
- emit.error({
1808
- code: "no_pidmap_entry",
1809
- message:
1887
+ emit.error(
1888
+ sessionResolutionFailure(
1889
+ root,
1810
1890
  "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
- });
1891
+ ),
1892
+ );
1812
1893
  process.exit(1);
1813
1894
  }
1814
1895
 
@@ -1897,14 +1978,15 @@ function runLifecycle(rawState: string, opts: { reason?: string; sessionId?: str
1897
1978
  process.exitCode = 1;
1898
1979
  return;
1899
1980
  }
1900
- if (!opts.sessionId) ensureCursorSession(root);
1981
+ if (!opts.sessionId) ensureAdapterSession(root);
1901
1982
  const myOwner = opts.sessionId ?? resolveOwner() ?? sessionIdentityFromEnv();
1902
1983
  if (!myOwner) {
1903
- emit.error({
1904
- code: "no_pidmap_entry",
1905
- message:
1984
+ emit.error(
1985
+ sessionResolutionFailure(
1986
+ root,
1906
1987
  "not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)",
1907
- });
1988
+ ),
1989
+ );
1908
1990
  process.exitCode = 1;
1909
1991
  return;
1910
1992
  }
@@ -2079,14 +2161,15 @@ function runSuggestName(
2079
2161
 
2080
2162
  // Identity: prefer explicit --session-id (ppid-walk-free escape hatch, mirrors
2081
2163
  // `status`/`set-task`), fall back to the ppid walk for interactive shell use.
2082
- if (!opts.sessionId) ensureCursorSession(root);
2164
+ if (!opts.sessionId) ensureAdapterSession(root);
2083
2165
  const myOwner = opts.sessionId ?? resolveOwner();
2084
2166
  if (!myOwner) {
2085
- emit.error({
2086
- code: "no_pidmap_entry",
2087
- message:
2167
+ emit.error(
2168
+ sessionResolutionFailure(
2169
+ root,
2088
2170
  "not in an agent session; ppid walk found no pid-map entry (pass --session-id to bypass)",
2089
- });
2171
+ ),
2172
+ );
2090
2173
  process.exit(1);
2091
2174
  }
2092
2175
 
@@ -2158,14 +2241,15 @@ function runStatus(opts: {
2158
2241
 
2159
2242
  // Identity resolution: prefer explicit --session-id (hook-friendly), fall
2160
2243
  // back to ppid walk for interactive shell usage.
2161
- if (!opts.sessionId) ensureCursorSession(root);
2244
+ if (!opts.sessionId) ensureAdapterSession(root);
2162
2245
  const myOwner = opts.sessionId ?? resolveOwner();
2163
2246
  if (!myOwner) {
2164
- emit.error({
2165
- code: "no_pidmap_entry",
2166
- message:
2247
+ emit.error(
2248
+ sessionResolutionFailure(
2249
+ root,
2167
2250
  "not in an agent session; ppid walk found no pid-map entry (pass --session-id from a hook payload)",
2168
- });
2251
+ ),
2252
+ );
2169
2253
  process.exit(1);
2170
2254
  }
2171
2255
 
@@ -2207,7 +2291,7 @@ function runStatus(opts: {
2207
2291
  }
2208
2292
  }
2209
2293
 
2210
- emitEventV3({
2294
+ const statusEmitted = emitEventV3({
2211
2295
  owner: myOwner,
2212
2296
  session: nativeSessionIdentity(hb, myOwner),
2213
2297
  adapter: normalizeAdapter(hb.platform),
@@ -2216,6 +2300,16 @@ function runStatus(opts: {
2216
2300
  status: opts.endTurn ? "end_turn_checked" : opts.json ? "json_checked" : "box_checked",
2217
2301
  },
2218
2302
  });
2303
+ // The closing box is a success artifact. Never print it when the exact
2304
+ // evidence enforced by the Stop hook did not reach the ledger.
2305
+ if (opts.endTurn && !statusEmitted) {
2306
+ emit.error({
2307
+ code: "status_event_failed",
2308
+ message: `the end-of-turn status event could not be recorded; no status box was issued; rerun \`${resolveBinName(root)} agents status --end-turn\``,
2309
+ });
2310
+ process.exitCode = 1;
2311
+ return;
2312
+ }
2219
2313
 
2220
2314
  let sessionEnd:
2221
2315
  | { state: "queued" | "already_requested"; request_id: string }
@@ -2285,10 +2379,7 @@ function runStatus(opts: {
2285
2379
  if (!ctxUsage) {
2286
2380
  ctxStr = "unavailable";
2287
2381
  } 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.)`;
2382
+ ctxStr = `${Math.round(ctxUsage.usedPercent)}% (Cursor first-party)`;
2292
2383
  } else {
2293
2384
  ctxStr = `${fmtTokens(ctxUsage.used)} / ${fmtTokens(ctxUsage.window)} (${Math.round(
2294
2385
  (ctxUsage.used / ctxUsage.window) * 100,
@@ -2296,7 +2387,7 @@ function runStatus(opts: {
2296
2387
  }
2297
2388
 
2298
2389
  const timeStr = formatLocalTime(new Date());
2299
- const displayName = `agent-${hb.name || "unknown"}`;
2390
+ const displayName = agentDisplayName(hb.instance_id, hb.name);
2300
2391
 
2301
2392
  // Council pending: list of council IDs where this agent is a member of an
2302
2393
  // active council in `open` round_status without a contribution to that round.
@@ -2340,8 +2431,8 @@ function runStatus(opts: {
2340
2431
  })),
2341
2432
  })),
2342
2433
  pending_councils: pendingCouncils,
2343
- context_used: ctxUsage?.used ?? null,
2344
- context_window: ctxUsage?.window ?? null,
2434
+ context_used: ctxUsage && "used" in ctxUsage ? ctxUsage.used : null,
2435
+ context_window: ctxUsage && "window" in ctxUsage ? ctxUsage.window : null,
2345
2436
  timestamp_iso: new Date().toISOString(),
2346
2437
  timestamp_local: timeStr,
2347
2438
  ...(quality ? { quality } : {}),
@@ -2485,15 +2576,17 @@ export function collectStatusPeerHealth(
2485
2576
  root: string,
2486
2577
  myOwner: string,
2487
2578
  nowMs = Date.now(),
2579
+ readRows: (root: string) => StatusPeerHeartbeat[] = readLiveCoordinationRows,
2580
+ freshnessSeconds = freshnessCutoffSecs(),
2488
2581
  ): { livePeers: StatusPeerHeartbeat[]; stale: number } {
2489
2582
  let rows: StatusPeerHeartbeat[] = [];
2490
2583
  try {
2491
- rows = readLiveCoordinationRows(root);
2584
+ rows = readRows(root);
2492
2585
  } catch {
2493
2586
  // V3 authority failures must not resurrect disposable cache rows.
2494
2587
  }
2495
2588
 
2496
- const cutoffMs = nowMs - freshnessCutoffSecs() * 1000;
2589
+ const cutoffMs = nowMs - freshnessSeconds * 1000;
2497
2590
  const livePeers: StatusPeerHeartbeat[] = [];
2498
2591
  let stale = 0;
2499
2592
  for (const peer of rows) {
@@ -2515,85 +2608,28 @@ function fmtTokens(n: number): string {
2515
2608
  function readContextUsage(
2516
2609
  sessionId: string,
2517
2610
  platform?: string | null,
2518
- ): { used: number; window: number; percentOnly?: boolean } | null {
2611
+ ):
2612
+ | { used: number; window: number; percentOnly?: false }
2613
+ | { usedPercent: number; percentOnly: true }
2614
+ | null {
2519
2615
  if (!sessionId) return null;
2520
2616
  // Dispatch by platform: Codex's JSONL shape is different from Claude Code's
2521
2617
  // (event_msg/response_item vs user/assistant), and Codex transcripts live
2522
2618
  // 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).
2619
+ // Cursor stores a first-party percentage in workspaceStorage. The shared
2620
+ // runtime reader returns it without fabricating a token denominator.
2526
2621
  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
- }
2622
+ if (platform === "cursor") {
2623
+ const telemetry = readRuntimeContextTelemetry({
2624
+ adapter: "cursor",
2625
+ session_id: sessionId,
2626
+ mode: "status",
2627
+ });
2628
+ return telemetry.state === "observed" && "used_percent" in telemetry
2629
+ ? { usedPercent: telemetry.used_percent, percentOnly: true }
2630
+ : null;
2595
2631
  }
2596
- return null;
2632
+ return readRuntimeContextUsage("claude-code", sessionId);
2597
2633
  }
2598
2634
 
2599
2635
  function formatLocalTime(d: Date): string {
@@ -2993,10 +3029,10 @@ interface HealthReport {
2993
3029
  lines: number;
2994
3030
  cursor_backlog: number;
2995
3031
  };
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.
2999
- zombies: {
3032
+ // Heartbeat cache files present in active/ but stale or malformed. These are
3033
+ // files the sweep is not catching; a parseable old heartbeat is stale, not
3034
+ // evidence of an epoch-like or corrupt timestamp.
3035
+ heartbeat_cache_issues: {
3000
3036
  count: number;
3001
3037
  samples: string[];
3002
3038
  };
@@ -3012,7 +3048,7 @@ interface HealthReport {
3012
3048
  latest_at: string | null;
3013
3049
  sessions: string[];
3014
3050
  };
3015
- anomalies: string[];
3051
+ findings: string[];
3016
3052
  }
3017
3053
 
3018
3054
  /** Open-span soft watermark per producer state. The producer-state reader
@@ -3049,12 +3085,21 @@ export type EventLedgerHealthV3 =
3049
3085
  groups: Array<{ adapter: string; session_hash: string; count: number }>;
3050
3086
  };
3051
3087
  diagnostics_spool: {
3088
+ /** Logical occurrences: loose files plus coalesced summary counts. */
3052
3089
  total: number;
3090
+ /** Physical loose diagnostic files. */
3091
+ loose_total: number;
3092
+ /** Occurrences coalesced into summaries instead of loose files. */
3093
+ summarized_total: number;
3094
+ /** Physical summary files in `diagnostic-summaries/`. */
3095
+ summary_files: number;
3053
3096
  last_24h: number;
3054
3097
  last_1h: number;
3055
3098
  latest_at: string | null;
3056
3099
  by_category: Record<string, { total: number; last_24h: number }>;
3057
3100
  recent_by_category: Record<string, { last_1h: number; latest_at: string | null }>;
3101
+ /** Times the summary gate failed open (loose write proceeded). */
3102
+ mitigation_fail_open: number;
3058
3103
  };
3059
3104
  span_pressure: Array<{ instance_id: string; generation_id: string; span_count: number }>;
3060
3105
  collection_errors: string[];
@@ -3194,6 +3239,47 @@ export function collectEventLedgerHealthV3(root: string, nowMs = Date.now()): Ev
3194
3239
  collectionErrors.push(`diagnostics spool unreadable: ${errorText(error)}`);
3195
3240
  }
3196
3241
 
3242
+ // 4b) Coalesced diagnostic summaries: occurrences the producer bounded into
3243
+ // `diagnostic-summaries/` instead of loose files. Counted into the logical
3244
+ // totals so mitigation can never make an active fault look healthy; the
3245
+ // physical loose file count stays visible separately.
3246
+ let summarizedTotal = 0;
3247
+ let summaryFiles = 0;
3248
+ let mitigationFailOpen = 0;
3249
+ try {
3250
+ const listing = listDiagnosticSummariesV3(root);
3251
+ summaryFiles = listing.file_count;
3252
+ mitigationFailOpen = listing.mitigation_health?.fail_open_count ?? 0;
3253
+ if (listing.unreadable_count > 0) {
3254
+ collectionErrors.push(`${listing.unreadable_count} diagnostic summary file(s) unreadable`);
3255
+ }
3256
+ const dayAgoMs = nowMs - 24 * 60 * 60 * 1000;
3257
+ const hourAgoMs = nowMs - 60 * 60 * 1000;
3258
+ for (const summary of listing.summaries) {
3259
+ summarizedTotal += summary.summarized_count;
3260
+ const entry = byCategory[summary.category] ?? { total: 0, last_24h: 0 };
3261
+ const recent = recentByCategory[summary.category] ?? { last_1h: 0, latest_at: null };
3262
+ byCategory[summary.category] = entry;
3263
+ recentByCategory[summary.category] = recent;
3264
+ entry.total += summary.summarized_count;
3265
+ const day = countSummarizedSinceV3([summary], dayAgoMs, undefined, nowMs);
3266
+ const hour = countSummarizedSinceV3([summary], hourAgoMs, undefined, nowMs);
3267
+ entry.last_24h += day;
3268
+ diagnostics24h += day;
3269
+ recent.last_1h += hour;
3270
+ diagnostics1h += hour;
3271
+ const lastMs = summary.last_summarized_at ? Date.parse(summary.last_summarized_at) : NaN;
3272
+ if (Number.isFinite(lastMs)) {
3273
+ latestDiagnosticMs = Math.max(latestDiagnosticMs, lastMs);
3274
+ if (!recent.latest_at || lastMs > Date.parse(recent.latest_at)) {
3275
+ recent.latest_at = new Date(lastMs).toISOString();
3276
+ }
3277
+ }
3278
+ }
3279
+ } catch (error) {
3280
+ collectionErrors.push(`diagnostic summaries unreadable: ${errorText(error)}`);
3281
+ }
3282
+
3197
3283
  return {
3198
3284
  state: "live",
3199
3285
  mode: control.state,
@@ -3204,7 +3290,10 @@ export function collectEventLedgerHealthV3(root: string, nowMs = Date.now()): Ev
3204
3290
  pending_finalizations: pending,
3205
3291
  intake_spool: { total: intakeTotal, groups: intakeGroups },
3206
3292
  diagnostics_spool: {
3207
- total: diagnosticsTotal,
3293
+ total: diagnosticsTotal + summarizedTotal,
3294
+ loose_total: diagnosticsTotal,
3295
+ summarized_total: summarizedTotal,
3296
+ summary_files: summaryFiles,
3208
3297
  last_24h: diagnostics24h,
3209
3298
  last_1h: diagnostics1h,
3210
3299
  latest_at: Number.isFinite(latestDiagnosticMs)
@@ -3212,6 +3301,7 @@ export function collectEventLedgerHealthV3(root: string, nowMs = Date.now()): Ev
3212
3301
  : null,
3213
3302
  by_category: byCategory,
3214
3303
  recent_by_category: recentByCategory,
3304
+ mitigation_fail_open: mitigationFailOpen,
3215
3305
  },
3216
3306
  span_pressure: spanPressure,
3217
3307
  collection_errors: collectionErrors,
@@ -3717,13 +3807,15 @@ type ActiveHealthHeartbeat = {
3717
3807
  export function collectActiveAgentHealth(
3718
3808
  root: string,
3719
3809
  nowMs = Date.now(),
3810
+ readRows: (root: string) => ActiveHealthHeartbeat[] = readLiveCoordinationRows,
3811
+ freshnessSeconds = freshnessCutoffSecs(),
3720
3812
  ): ActiveAgentHealthSummary {
3721
3813
  const source: ActiveAgentHealthSummary["source"] = "event-ledger-v3";
3722
3814
  let heartbeats: ActiveHealthHeartbeat[] = [];
3723
3815
  try {
3724
3816
  const control = readEventV3ControlState(root);
3725
3817
  if (control.state === "candidate" || control.state === "active") {
3726
- heartbeats = readLiveCoordinationRows(root);
3818
+ heartbeats = readRows(root);
3727
3819
  }
3728
3820
  } catch {
3729
3821
  // The event-ledger section reports the authority read failure. Do not
@@ -3749,7 +3841,7 @@ export function collectActiveAgentHealth(
3749
3841
  const ageMs = Number.isFinite(lastObservedMs)
3750
3842
  ? nowMs - lastObservedMs
3751
3843
  : Number.POSITIVE_INFINITY;
3752
- if (ageMs > freshnessCutoffSecs() * 1000) stale += 1;
3844
+ if (ageMs > freshnessSeconds * 1000) stale += 1;
3753
3845
  }
3754
3846
  return {
3755
3847
  source,
@@ -3761,6 +3853,22 @@ export function collectActiveAgentHealth(
3761
3853
  };
3762
3854
  }
3763
3855
 
3856
+ export type HeartbeatCacheIssue = "no-name" | "invalid-heartbeat" | "stale-age";
3857
+
3858
+ /** Classify a parseable heartbeat cache file without conflating age with corruption. */
3859
+ export function classifyHeartbeatCacheIssue(
3860
+ heartbeat: Pick<Heartbeat, "name" | "last_heartbeat">,
3861
+ nowMs: number,
3862
+ staleAgeMs: number,
3863
+ ): HeartbeatCacheIssue | null {
3864
+ if (!heartbeat.name || heartbeat.name === "unknown") return "no-name";
3865
+ const lastHeartbeatMs = heartbeat.last_heartbeat
3866
+ ? Date.parse(heartbeat.last_heartbeat)
3867
+ : Number.NaN;
3868
+ if (!Number.isFinite(lastHeartbeatMs)) return "invalid-heartbeat";
3869
+ return nowMs - lastHeartbeatMs > staleAgeMs ? "stale-age" : null;
3870
+ }
3871
+
3764
3872
  function runHealth(opts: { since: string; json?: boolean }): void {
3765
3873
  if (opts.json) emit.config({ format: "json" });
3766
3874
 
@@ -3845,12 +3953,12 @@ function runHealth(opts: { since: string; json?: boolean }): void {
3845
3953
  .map(([agent, count]) => ({ agent, count }));
3846
3954
 
3847
3955
  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.
3851
- let zombieCount = 0;
3852
- const zombieSamples: string[] = [];
3853
- const ABSURD_AGE_MS = 24 * 60 * 60 * 1000; // > 1 day = clearly not a live, self-healing agent
3956
+ // Heartbeat cache issues: files in active/ that are unparseable, nameless,
3957
+ // invalidly timestamped, or stale. Old parseable timestamps are ordinary
3958
+ // staleness, not evidence of epoch-like timestamp corruption.
3959
+ let cacheIssueCount = 0;
3960
+ const cacheIssueSamples: string[] = [];
3961
+ const STALE_HEARTBEAT_AGE_MS = 24 * 60 * 60 * 1000;
3854
3962
  if (existsSync(activeDir)) {
3855
3963
  for (const file of readdirSync(activeDir)) {
3856
3964
  if (!file.endsWith(".json")) continue;
@@ -3862,20 +3970,16 @@ function runHealth(opts: { since: string; json?: boolean }): void {
3862
3970
  hb = null;
3863
3971
  }
3864
3972
  if (!hb || typeof hb.instance_id !== "string") {
3865
- zombieCount++;
3866
- if (zombieSamples.length < 5)
3867
- zombieSamples.push(`${idFromFile.slice(0, 12)} (unparseable/no-id)`);
3973
+ cacheIssueCount++;
3974
+ if (cacheIssueSamples.length < 5)
3975
+ cacheIssueSamples.push(`${idFromFile.slice(0, 12)} (unparseable/no-id)`);
3868
3976
  continue;
3869
3977
  }
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) {
3875
- zombieCount++;
3876
- if (zombieSamples.length < 5) {
3877
- const why = !hb.name || hb.name === "unknown" ? "no-name" : "epoch-age";
3878
- zombieSamples.push(`${idFromFile.slice(0, 12)} (${why})`);
3978
+ const cacheIssue = classifyHeartbeatCacheIssue(hb, nowMs, STALE_HEARTBEAT_AGE_MS);
3979
+ if (cacheIssue) {
3980
+ cacheIssueCount++;
3981
+ if (cacheIssueSamples.length < 5) {
3982
+ cacheIssueSamples.push(`${idFromFile.slice(0, 12)} (${cacheIssue})`);
3879
3983
  }
3880
3984
  }
3881
3985
  }
@@ -3891,11 +3995,11 @@ function runHealth(opts: { since: string; json?: boolean }): void {
3891
3995
  }
3892
3996
  }
3893
3997
 
3894
- // Anomaly detection.
3895
- const anomalies: string[] = [];
3998
+ // Finding detection.
3999
+ const findings: string[] = [];
3896
4000
  for (const { agent, count } of healTopAgents) {
3897
4001
  if (count >= 5) {
3898
- anomalies.push(
4002
+ findings.push(
3899
4003
  `${agent} self-healed ${count}x in ${opts.since}; possible idle-prune loop or PID instability`,
3900
4004
  );
3901
4005
  }
@@ -3906,7 +4010,7 @@ function runHealth(opts: { since: string; json?: boolean }): void {
3906
4010
  activeAgents.source === "event-ledger-v3"
3907
4011
  ? "lifecycle reconciliation may be delayed"
3908
4012
  : "heal mechanism may not be firing";
3909
- anomalies.push(
4013
+ findings.push(
3910
4014
  `${activeAgents.stale} active ${noun}(s) without activity for ${Math.floor(freshnessCutoffSecs() / 60)}min; ${action}`,
3911
4015
  );
3912
4016
  }
@@ -3915,31 +4019,33 @@ function runHealth(opts: { since: string; json?: boolean }): void {
3915
4019
  (schema) => schema !== expectedSchema,
3916
4020
  );
3917
4021
  if (unexpectedSchemas.length > 0) {
3918
- anomalies.push(
4022
+ findings.push(
3919
4023
  `Unexpected active-agent schema versions in use: ${unexpectedSchemas.join(", ")} (expected ${expectedSchema})`,
3920
4024
  );
3921
4025
  }
3922
- // Only recent hook failures are active anomalies. Historical rows remain in
4026
+ // Only recent hook failures are active findings. Historical rows remain in
3923
4027
  // the report with exact error signatures and their latest timestamp.
3924
4028
  if (hookErrors.last1h > 0) {
3925
4029
  const top = hookErrors.recentTopErrors[0];
3926
4030
  const detail = top ? `: top '${top.error.slice(0, 80)}' x${top.count} (${top.phase})` : "";
3927
- anomalies.push(`agent-hook errored ${hookErrors.last1h}x in the last hour${detail}`);
4031
+ findings.push(`agent-hook errored ${hookErrors.last1h}x in the last hour${detail}`);
3928
4032
  }
3929
4033
  if (stream.cursor_backlog > 500) {
3930
- anomalies.push(
4034
+ findings.push(
3931
4035
  `projection cursor is ${stream.cursor_backlog} events behind; drain lagging (stop projection may be failing)`,
3932
4036
  );
3933
4037
  }
3934
- // Raw V3 stream size is not an anomaly; catalog rotation bounds readers.
4038
+ // Raw V3 stream size is not a finding; catalog rotation bounds readers.
3935
4039
  if ((sweptByReason.unparseable ?? 0) > 0) {
3936
- anomalies.push(
4040
+ findings.push(
3937
4041
  `${sweptByReason.unparseable} heartbeat(s) swept as unparseable in ${opts.since}; possible corruption or a non-atomic writer`,
3938
4042
  );
3939
4043
  }
3940
- if (zombieCount > 0) {
3941
- anomalies.push(
3942
- `${zombieCount} zombie heartbeat(s) in active/ (${zombieSamples.join(", ")}); broken files the sweep isn't reaping`,
4044
+ if (cacheIssueCount > 0) {
4045
+ findings.push(
4046
+ `${cacheIssueCount} heartbeat cache issue(s) in active/ (${cacheIssueSamples.join(", ")}); ` +
4047
+ "rows the last sweep deliberately kept (malformed but mtime-fresh, or neither audit " +
4048
+ "write could persist), or that aged past the freshness cutoff since it ran",
3943
4049
  );
3944
4050
  }
3945
4051
  if (stopRemediation.total > 0) {
@@ -3947,7 +4053,7 @@ function runHealth(opts: { since: string; json?: boolean }): void {
3947
4053
  stopRemediation.sessions.length > 0
3948
4054
  ? ` (sessions: ${stopRemediation.sessions.map((s) => s.slice(0, 8)).join(", ")})`
3949
4055
  : "";
3950
- anomalies.push(
4056
+ findings.push(
3951
4057
  `stop-hook remediation cap exhausted ${stopRemediation.total}x in ${opts.since}${who}; these sessions ended turns without the end-of-turn ritual — check why their evidence never lands`,
3952
4058
  );
3953
4059
  }
@@ -3962,17 +4068,17 @@ function runHealth(opts: { since: string; json?: boolean }): void {
3962
4068
  (sum, generation) => sum + generation.span_count,
3963
4069
  0,
3964
4070
  );
3965
- anomalies.push(
4071
+ findings.push(
3966
4072
  `${orphanSpans} open tool span(s) across ${orphanGenerations.length} generation(s) with no open turn; orphaned spans block clean session end`,
3967
4073
  );
3968
4074
  }
3969
4075
  for (const pressure of eventLedger.span_pressure) {
3970
- anomalies.push(
4076
+ findings.push(
3971
4077
  `${pressure.instance_id} (${pressure.generation_id}) holds ${pressure.span_count} open spans (soft watermark ${SPAN_PRESSURE_SOFT_WATERMARK}; the reader's 256-span cap makes the state unreadable)`,
3972
4078
  );
3973
4079
  }
3974
4080
  for (const collectionError of eventLedger.collection_errors) {
3975
- anomalies.push(`event-ledger health: ${collectionError}`);
4081
+ findings.push(`event-ledger health: ${collectionError}`);
3976
4082
  }
3977
4083
  }
3978
4084
 
@@ -4017,14 +4123,14 @@ function runHealth(opts: { since: string; json?: boolean }): void {
4017
4123
  recent_top_errors: hookErrors.recentTopErrors,
4018
4124
  },
4019
4125
  stream,
4020
- zombies: { count: zombieCount, samples: zombieSamples },
4126
+ heartbeat_cache_issues: { count: cacheIssueCount, samples: cacheIssueSamples },
4021
4127
  event_ledger: eventLedger,
4022
4128
  stop_remediation: {
4023
4129
  total: stopRemediation.total,
4024
4130
  latest_at: stopRemediation.latestAt,
4025
4131
  sessions: stopRemediation.sessions,
4026
4132
  },
4027
- anomalies,
4133
+ findings,
4028
4134
  };
4029
4135
 
4030
4136
  if (opts.json) {
@@ -4095,7 +4201,7 @@ function renderHealthBox(report: HealthReport): void {
4095
4201
  `open spans ${ledger.open_spans.total}${orphanGenerations > 0 ? ` (${orphanGenerations} gen turn-closed)` : ""}`,
4096
4202
  `pending ends ${ledger.pending_finalizations.length}${pendingAges ? ` (${pendingAges})` : ""}`,
4097
4203
  `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)`,
4204
+ `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
4205
  ].join(" · ");
4100
4206
  }
4101
4207
 
@@ -4116,13 +4222,13 @@ function renderHealthBox(report: HealthReport): void {
4116
4222
  ["stream", streamStr],
4117
4223
  ["event ledger", ledgerStr],
4118
4224
  [
4119
- "zombies",
4120
- report.zombies.count === 0
4225
+ "cache issues",
4226
+ report.heartbeat_cache_issues.count === 0
4121
4227
  ? "0"
4122
- : `${report.zombies.count} (${report.zombies.samples.join(", ")})`,
4228
+ : `${report.heartbeat_cache_issues.count} (${report.heartbeat_cache_issues.samples.join(", ")})`,
4123
4229
  ],
4124
4230
  ["councils", councilParts.join(", ")],
4125
- ["anomalies", report.anomalies.length === 0 ? "(clean)" : `${report.anomalies.length} flagged`],
4231
+ ["findings", report.findings.length === 0 ? "(clean)" : `${report.findings.length} flagged`],
4126
4232
  ];
4127
4233
 
4128
4234
  const localTime = formatLocalTime(new Date(report.generated_at));
@@ -4130,9 +4236,9 @@ function renderHealthBox(report: HealthReport): void {
4130
4236
 
4131
4237
  process.stdout.write(`${formatBox(title, rows)}\n`); // lint-ok-emission: chat-paste path; mirrors runStatus's direct write so the box surfaces in both TTY + harn-session-teed contexts
4132
4238
 
4133
- if (report.anomalies.length > 0) {
4239
+ if (report.findings.length > 0) {
4134
4240
  process.stdout.write("\n"); // lint-ok-emission: same chat-paste path
4135
- for (const a of report.anomalies) {
4241
+ for (const a of report.findings) {
4136
4242
  process.stdout.write(` ! ${a}\n`); // lint-ok-emission: same
4137
4243
  }
4138
4244
  }
@@ -4552,24 +4658,66 @@ function runPing(name: string, message: string, opts: { json?: boolean }): void
4552
4658
  }
4553
4659
  const myOwner = resolveOwner();
4554
4660
  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
- });
4661
+ const root = monorepoRoot();
4662
+ emit.error(
4663
+ root
4664
+ ? sessionResolutionFailure(
4665
+ root,
4666
+ "not in an agent session; ppid walk found no pid-map entry",
4667
+ )
4668
+ : {
4669
+ code: "no_pidmap_entry",
4670
+ message: "not in an agent session; ppid walk found no pid-map entry",
4671
+ },
4672
+ );
4559
4673
  process.exit(1);
4560
4674
  }
4675
+ const coordRoot = monorepoRoot();
4561
4676
  const peerOwner = resolveOwnerByName(name);
4562
- if (!peerOwner) {
4677
+
4678
+ // A name with no live session is the common case, not an error: the agent it
4679
+ // refers to may have ended minutes ago and may come back under the same name.
4680
+ // Refuse only a name that no agent has ever held, which is a typo — queueing
4681
+ // that would swallow the message silently.
4682
+ if (!peerOwner && coordRoot && !isAddressableName(coordRoot, name)) {
4683
+ const suggestions = suggestNames(coordRoot, name);
4563
4684
  emit.error({
4564
- code: "no_peer",
4565
- message: `no live agent named "${name}" (case-insensitive). Run \`${resolveBinName()} agents list\` to see who's active.`,
4685
+ code: "unknown_agent",
4686
+ message:
4687
+ `no agent has ever been named "${name}". ` +
4688
+ (suggestions.length > 0 ? `Did you mean ${suggestions.join(", ")}? ` : "") +
4689
+ `Run \`${resolveBinName()} agents list\` for live sessions.`,
4566
4690
  });
4567
4691
  process.exit(1);
4568
4692
  }
4693
+
4569
4694
  const myHb = readCurrentCoordinationRow(myOwner);
4570
4695
  const fromName = myHb?.name ?? "anonymous";
4571
4696
  const body = `from agent-${fromName}: ${message.trim()}`;
4572
- const doc = appendEntry(peerOwner, "handoff", body);
4697
+
4698
+ // A live recipient gets the journal entry immediately, so a peer reading
4699
+ // their own journal mid-session sees it without waiting for a prompt. A
4700
+ // dormant recipient has no journal to write to yet; the drain writes it into
4701
+ // whichever session picks the message up.
4702
+ const doc = peerOwner ? appendEntry(peerOwner, "handoff", body) : null;
4703
+
4704
+ let queued: QueueResult;
4705
+ try {
4706
+ queued = queueMailboxMessage({
4707
+ coordRoot: coordRoot ?? process.cwd(),
4708
+ toName: name,
4709
+ fromName,
4710
+ fromInstanceId: myOwner,
4711
+ body: message.trim(),
4712
+ journaled: Boolean(peerOwner),
4713
+ });
4714
+ } catch (error) {
4715
+ if (error instanceof MailboxCapacityError) {
4716
+ emit.error({ code: `mailbox_${error.reason_code}`, message: error.message });
4717
+ process.exit(1);
4718
+ }
4719
+ throw error;
4720
+ }
4573
4721
 
4574
4722
  // Canonical delivery record: sender is the envelope owner, recipient rides
4575
4723
  // in data, so read-only observers can render the communication without
@@ -4581,18 +4729,21 @@ function runPing(name: string, message: string, opts: { json?: boolean }): void
4581
4729
  observation: {
4582
4730
  event_type: "coord.message_observed",
4583
4731
  direction: "sent",
4584
- subject: peerOwner,
4732
+ subject: peerOwner ?? `name:${queued.message.to_name}`,
4585
4733
  body: message.trim(),
4586
4734
  },
4587
4735
  });
4588
4736
 
4589
4737
  const data = {
4590
- peer: name,
4738
+ peer: queued.message.to_name,
4591
4739
  peer_instance_id: peerOwner,
4740
+ delivery: peerOwner ? ("live" as const) : ("queued" as const),
4741
+ message_id: queued.message.message_id,
4742
+ pending: queued.pending,
4592
4743
  from: fromName,
4593
4744
  body,
4594
- journal_path: doc.path,
4595
- journal_bytes: doc.bytes,
4745
+ journal_path: doc?.path ?? null,
4746
+ journal_bytes: doc?.bytes ?? null,
4596
4747
  };
4597
4748
 
4598
4749
  if (opts.json) {
@@ -4601,7 +4752,11 @@ function runPing(name: string, message: string, opts: { json?: boolean }): void
4601
4752
  return;
4602
4753
  }
4603
4754
  emit.data(data);
4604
- emit.text(`pinged agent-${name}: "${truncate(message.trim(), 80)}"\n`);
4755
+ emit.text(
4756
+ peerOwner
4757
+ ? `delivered to agent-${data.peer} (live; they see it on their next prompt): "${truncate(message.trim(), 80)}"\n`
4758
+ : `queued for agent-${data.peer} (no live session; delivered when a session of that name next starts): "${truncate(message.trim(), 80)}"\n`,
4759
+ );
4605
4760
  }
4606
4761
 
4607
4762
  async function runWait(
@@ -4722,21 +4877,22 @@ function emitWaitResult(
4722
4877
  }
4723
4878
 
4724
4879
  function runHeal(opts: {
4725
- owner: string;
4726
- kind: string;
4880
+ owner?: string;
4881
+ kind?: string;
4727
4882
  sessionId?: string;
4728
4883
  adapter?: string;
4729
4884
  pid?: string;
4885
+ quarantineTransaction?: string;
4886
+ approvalRecordId?: string;
4887
+ yes?: boolean;
4730
4888
  json?: boolean;
4731
4889
  }): void {
4732
4890
  if (opts.json) emit.config({ format: "json" });
4733
4891
 
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
- }
4892
+ const requestedOwner = opts.owner?.trim() ?? "";
4893
+ const quarantineTransaction = opts.quarantineTransaction?.trim() ?? "";
4894
+ const approvalRecordId = opts.approvalRecordId?.trim() ?? "";
4895
+ const kind = opts.kind?.trim() || "cache";
4740
4896
  if (kind !== "pidmap" && kind !== "cache") {
4741
4897
  emit.error({
4742
4898
  code: "bad_kind",
@@ -4744,6 +4900,30 @@ function runHeal(opts: {
4744
4900
  });
4745
4901
  process.exit(1);
4746
4902
  }
4903
+ if (quarantineTransaction) {
4904
+ if (opts.kind || opts.pid) {
4905
+ emit.error({
4906
+ code: "conflicting_recovery_options",
4907
+ message: "--quarantine-transaction cannot be combined with --kind or --pid",
4908
+ });
4909
+ process.exit(1);
4910
+ }
4911
+ if (!opts.yes || !approvalRecordId) {
4912
+ emit.error({
4913
+ code: "transaction_quarantine_confirmation_required",
4914
+ message:
4915
+ "--quarantine-transaction requires --approval-record-id <id> and --yes; " +
4916
+ "the command abandons one uncommitted authority mutation while preserving its record",
4917
+ });
4918
+ process.exit(1);
4919
+ }
4920
+ } else if (approvalRecordId || opts.yes) {
4921
+ emit.error({
4922
+ code: "transaction_quarantine_target_required",
4923
+ message: "--approval-record-id and --yes require --quarantine-transaction <id>",
4924
+ });
4925
+ process.exit(1);
4926
+ }
4747
4927
  if (
4748
4928
  opts.adapter &&
4749
4929
  opts.adapter !== "claude-code" &&
@@ -4766,7 +4946,52 @@ function runHeal(opts: {
4766
4946
  process.exit(1);
4767
4947
  }
4768
4948
 
4769
- const action = kind === "pidmap" ? "heal-pidmap" : "repair-coordination-cache";
4949
+ const currentSessionRepair =
4950
+ kind === "cache" &&
4951
+ opts.owner === undefined &&
4952
+ opts.sessionId === undefined &&
4953
+ opts.adapter === undefined &&
4954
+ !quarantineTransaction;
4955
+
4956
+ const ownerResolution = resolveOwnerWithSource();
4957
+ const bootstrapIdentity = currentSessionRepair ? commandSessionBootstrap() : null;
4958
+ const resolvedCurrentOwner =
4959
+ bootstrapIdentity &&
4960
+ (ownerResolution.source === "none" || ownerResolution.source === "active_singleton")
4961
+ ? bootstrapIdentity.sessionId
4962
+ : ownerResolution.owner;
4963
+ const owner = requestedOwner || resolvedCurrentOwner || sessionIdentityFromEnv() || "";
4964
+ if (!owner) {
4965
+ emit.error({
4966
+ code: "session_identity_missing",
4967
+ message:
4968
+ `could not resolve the current session; run ${resolveBinName()} doctor, or pass ` +
4969
+ "--owner <instance-id> --session-id <native-session-id> --adapter <adapter>",
4970
+ });
4971
+ process.exit(1);
4972
+ }
4973
+
4974
+ const currentRow = readLiveCoordinationRow(root, owner);
4975
+ const inferredAdapter = normalizeAdapter(
4976
+ opts.adapter?.trim() || currentRow?.platform || commandSessionBootstrap()?.adapter,
4977
+ );
4978
+ const sessionId =
4979
+ opts.sessionId?.trim() ||
4980
+ (currentSessionRepair ? sessionIdentityFromEnv() : null) ||
4981
+ nativeSessionIdentity(currentRow, owner);
4982
+
4983
+ if (kind === "cache") {
4984
+ const refusal = cacheHealAuthorityRefusal(root, owner, sessionId, inferredAdapter, currentRow);
4985
+ if (refusal) {
4986
+ emitHealFailure(refusal.reason, refusal.message);
4987
+ }
4988
+ }
4989
+
4990
+ const action = quarantineTransaction
4991
+ ? "quarantine-authority-transaction"
4992
+ : kind === "pidmap"
4993
+ ? "heal-pidmap"
4994
+ : "repair-coordination-cache";
4770
4995
 
4771
4996
  // Refuse to materialize a V3 cache at a truncated owner id.
4772
4997
  //
@@ -4809,23 +5034,72 @@ function runHeal(opts: {
4809
5034
  // heal-pidmap <instance_id> [<pid>]
4810
5035
  // repair-coordination-cache <instance_id> [<session_id>]
4811
5036
  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}`);
5037
+ if (quarantineTransaction) {
5038
+ helperArgs.push(
5039
+ quarantineTransaction,
5040
+ approvalRecordId,
5041
+ sessionId,
5042
+ `--adapter=${inferredAdapter}`,
5043
+ );
5044
+ } else {
5045
+ if (kind === "pidmap" && opts.pid) helperArgs.push(opts.pid);
5046
+ if (kind === "cache") helperArgs.push(sessionId, `--adapter=${inferredAdapter}`);
5047
+ }
4815
5048
 
4816
5049
  // Both recovery actions are handled by the bundled agent-coord binary.
4817
5050
  const helper = agentCoordOrExit(root);
4818
- const proc = spawnSync(helper, helperArgs, {
5051
+ let proc = spawnSync(helper, helperArgs, {
4819
5052
  encoding: "utf8",
4820
5053
  ...coordHelperOpts(root),
4821
5054
  });
4822
5055
 
4823
- if (proc.status !== 0) {
4824
- emit.error({
4825
- code: "heal_failed",
4826
- message: spawnFailureMessage(proc, `agent-coord ${action}`),
5056
+ let bootstrapState: "created" | "reused" | undefined;
5057
+ if (
5058
+ proc.status !== 0 &&
5059
+ currentSessionRepair &&
5060
+ missingAuthorityForCurrentSessionBootstrap(root, owner, sessionId)
5061
+ ) {
5062
+ const bootstrap = commandSessionBootstrap();
5063
+ if (
5064
+ !bootstrap ||
5065
+ bootstrap.sessionId !== sessionId ||
5066
+ bootstrap.sessionId !== owner ||
5067
+ bootstrap.adapter !== inferredAdapter
5068
+ ) {
5069
+ emitHealFailure(
5070
+ "native_identity_unverified",
5071
+ "the current adapter did not provide one matching native session id and adapter",
5072
+ );
5073
+ }
5074
+ try {
5075
+ const bootstrapped = bootstrapLiveCoordinationAuthorityV3({
5076
+ coordRoot: root,
5077
+ owner,
5078
+ nativeSessionId: bootstrap.sessionId,
5079
+ adapter: bootstrap.adapter,
5080
+ });
5081
+ bootstrapState = bootstrapped.state;
5082
+ } catch (error) {
5083
+ const reason =
5084
+ error instanceof LiveCoordinationAuthorityV3Error
5085
+ ? error.reason
5086
+ : "authority_bootstrap_failed";
5087
+ emitHealFailure(
5088
+ reason,
5089
+ "the current native session could not establish authority; no fallback cache was accepted",
5090
+ );
5091
+ }
5092
+ proc = spawnSync(helper, helperArgs, {
5093
+ encoding: "utf8",
5094
+ ...coordHelperOpts(root),
4827
5095
  });
4828
- process.exit(1);
5096
+ }
5097
+
5098
+ if (proc.status !== 0) {
5099
+ emitHealFailure(
5100
+ healFailureReason(root, owner, sessionId, inferredAdapter),
5101
+ spawnFailureMessage(proc, `agent-coord ${action}`),
5102
+ );
4829
5103
  }
4830
5104
 
4831
5105
  // Read the derived cache to surface post-action state.
@@ -4836,8 +5110,9 @@ function runHeal(opts: {
4836
5110
  after = null;
4837
5111
  }
4838
5112
 
4839
- const outcome =
4840
- kind === "pidmap"
5113
+ const outcome = quarantineTransaction
5114
+ ? "transaction_quarantined"
5115
+ : kind === "pidmap"
4841
5116
  ? proc.status === 0
4842
5117
  ? "ok"
4843
5118
  : "failed"
@@ -4852,10 +5127,15 @@ function runHeal(opts: {
4852
5127
  action,
4853
5128
  outcome,
4854
5129
  after,
5130
+ ...(quarantineTransaction ? { recovery: JSON.parse(proc.stdout.trim()) as unknown } : {}),
4855
5131
  },
4856
5132
  ],
4857
5133
  meta: {
4858
5134
  kind,
5135
+ automatic: currentSessionRepair && !quarantineTransaction,
5136
+ authority: "event-ledger-v3",
5137
+ adapter: kind === "cache" ? inferredAdapter : undefined,
5138
+ bootstrap: bootstrapState,
4859
5139
  // The path actually spawned, not a guess at the layout: the helper is
4860
5140
  // resolved from harnery's own package location, which differs between a
4861
5141
  // submodule, an installed dependency, and a standalone checkout.
@@ -4863,10 +5143,18 @@ function runHeal(opts: {
4863
5143
  },
4864
5144
  });
4865
5145
  if (!opts.json) {
4866
- if (kind === "pidmap") {
5146
+ if (quarantineTransaction) {
5147
+ emit.text(
5148
+ `coordination recovered: ${quarantineTransaction} quarantined with approval ${approvalRecordId}; ` +
5149
+ `cache ${after ? "present" : "absent"} (${inferredAdapter})\n`,
5150
+ );
5151
+ } else if (kind === "pidmap") {
4867
5152
  emit.text(`agent-coord ${action} ok\n`);
4868
5153
  } else {
4869
- emit.text(`agent-coord ${action} ok: cache ${after ? "present" : "absent"} after\n`);
5154
+ emit.text(
5155
+ `coordination repaired: V3 authority live; ${currentSessionRepair ? "current-session " : ""}` +
5156
+ `cache ${after ? "present" : "absent"} (${inferredAdapter})\n`,
5157
+ );
4870
5158
  }
4871
5159
  }
4872
5160
 
@@ -4877,6 +5165,98 @@ function runHeal(opts: {
4877
5165
  // unconditionally on every `harn agents heal`, which over-counted no-op heals.)
4878
5166
  }
4879
5167
 
5168
+ type HealAuthorityRefusal = {
5169
+ reason: "adapter_mismatch" | "owner_mismatch" | "session_mismatch" | "terminal_generation";
5170
+ message: string;
5171
+ };
5172
+
5173
+ function cacheHealAuthorityRefusal(
5174
+ root: string,
5175
+ owner: string,
5176
+ sessionId: string,
5177
+ adapter: "claude-code" | "cursor" | "codex",
5178
+ currentRow: LiveCoordinationRow | null,
5179
+ ): HealAuthorityRefusal | null {
5180
+ if (currentRow && normalizeAdapter(currentRow.platform) !== adapter) {
5181
+ return {
5182
+ reason: "adapter_mismatch",
5183
+ message: `the live generation belongs to adapter ${normalizeAdapter(currentRow.platform)}, not ${adapter}`,
5184
+ };
5185
+ }
5186
+ let producer: ReturnType<typeof readHookProducerStateV3>;
5187
+ try {
5188
+ producer = readHookProducerStateV3(root, adapter, sessionId);
5189
+ } catch {
5190
+ return {
5191
+ reason: "session_mismatch",
5192
+ message: "the native session producer state could not be read safely",
5193
+ };
5194
+ }
5195
+ if (producer?.terminal) {
5196
+ return {
5197
+ reason: "terminal_generation",
5198
+ message: "the matching generation is terminal and cannot be repaired or reopened by heal",
5199
+ };
5200
+ }
5201
+ if (producer && producer.instance_id !== liveInstanceIdV3(owner)) {
5202
+ return {
5203
+ reason: "owner_mismatch",
5204
+ message: "the native session is bound to a different instance owner",
5205
+ };
5206
+ }
5207
+ if (currentRow && (!producer || producer.generation_id !== currentRow.v3_generation_id)) {
5208
+ return {
5209
+ reason: "session_mismatch",
5210
+ message: "the native session does not bind to the requested live generation",
5211
+ };
5212
+ }
5213
+ return null;
5214
+ }
5215
+
5216
+ function missingAuthorityForCurrentSessionBootstrap(
5217
+ root: string,
5218
+ owner: string,
5219
+ sessionId: string,
5220
+ ): boolean {
5221
+ if (readLiveCoordinationRow(root, owner)) return false;
5222
+ try {
5223
+ const nativeSessionHasProducer = (["claude-code", "codex", "cursor"] as const).some(
5224
+ (adapter) => readHookProducerStateV3(root, adapter, sessionId) !== undefined,
5225
+ );
5226
+ if (nativeSessionHasProducer) return false;
5227
+ const instanceId = liveInstanceIdV3(owner);
5228
+ return !listHookProducerStateRecordsV3(root, { includeTerminal: true }).some(
5229
+ ({ state }) => state.instance_id === instanceId,
5230
+ );
5231
+ } catch {
5232
+ return false;
5233
+ }
5234
+ }
5235
+
5236
+ function healFailureReason(
5237
+ root: string,
5238
+ owner: string,
5239
+ sessionId: string,
5240
+ adapter: "claude-code" | "cursor" | "codex",
5241
+ ): string {
5242
+ const refusal = cacheHealAuthorityRefusal(
5243
+ root,
5244
+ owner,
5245
+ sessionId,
5246
+ adapter,
5247
+ readLiveCoordinationRow(root, owner),
5248
+ );
5249
+ return refusal?.reason ?? "authority_missing";
5250
+ }
5251
+
5252
+ function emitHealFailure(reason: string, message: string): never {
5253
+ emit.error({
5254
+ code: "heal_failed",
5255
+ message: `coordination heal refused (reason=${reason}): ${message}`,
5256
+ });
5257
+ process.exit(1);
5258
+ }
5259
+
4880
5260
  /**
4881
5261
  * Emit one V3 council audit transition keyed to the exact durable manifest.
4882
5262
  * Falls through silently when no live session can attest the observation.