harnery 0.36.0 → 0.38.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 (432) hide show
  1. package/dist/commander.d.ts +9 -0
  2. package/dist/commander.d.ts.map +1 -1
  3. package/dist/commander.js +10 -1
  4. package/dist/commands/admission.d.ts +21 -0
  5. package/dist/commands/admission.d.ts.map +1 -0
  6. package/dist/commands/admission.js +565 -0
  7. package/dist/commands/agents.d.ts +7 -0
  8. package/dist/commands/agents.d.ts.map +1 -1
  9. package/dist/commands/agents.js +148 -47
  10. package/dist/commands/artifacts.d.ts.map +1 -1
  11. package/dist/commands/artifacts.js +73 -2
  12. package/dist/commands/browse-ai.d.ts +2 -2
  13. package/dist/commands/browse-ai.d.ts.map +1 -1
  14. package/dist/commands/browse-ai.js +6 -4
  15. package/dist/commands/browse.d.ts.map +1 -1
  16. package/dist/commands/browse.js +360 -21
  17. package/dist/commands/diagnostics.d.ts +4 -0
  18. package/dist/commands/diagnostics.d.ts.map +1 -0
  19. package/dist/commands/diagnostics.js +229 -0
  20. package/dist/commands/fetch.js +1 -0
  21. package/dist/commands/files.d.ts +12 -0
  22. package/dist/commands/files.d.ts.map +1 -1
  23. package/dist/commands/files.js +54 -1
  24. package/dist/commands/governor.d.ts.map +1 -1
  25. package/dist/commands/governor.js +4 -0
  26. package/dist/commands/ledger-v3.d.ts.map +1 -1
  27. package/dist/commands/ledger-v3.js +71 -2
  28. package/dist/commands/qa-record.d.ts +144 -0
  29. package/dist/commands/qa-record.d.ts.map +1 -0
  30. package/dist/commands/qa-record.js +0 -0
  31. package/dist/commands/qa-run.d.ts +8 -0
  32. package/dist/commands/qa-run.d.ts.map +1 -0
  33. package/dist/commands/qa-run.js +396 -0
  34. package/dist/commands/qa-status.d.ts +71 -0
  35. package/dist/commands/qa-status.d.ts.map +1 -0
  36. package/dist/commands/qa-status.js +490 -0
  37. package/dist/commands/qa-verify.d.ts +40 -0
  38. package/dist/commands/qa-verify.d.ts.map +1 -0
  39. package/dist/commands/qa-verify.js +180 -0
  40. package/dist/commands/resources.d.ts +4 -0
  41. package/dist/commands/resources.d.ts.map +1 -0
  42. package/dist/commands/resources.js +29 -0
  43. package/dist/commands/review-pack.d.ts +4 -0
  44. package/dist/commands/review-pack.d.ts.map +1 -0
  45. package/dist/commands/review-pack.js +1001 -0
  46. package/dist/commands/supervisor.d.ts +4 -0
  47. package/dist/commands/supervisor.d.ts.map +1 -0
  48. package/dist/commands/supervisor.js +101 -0
  49. package/dist/commands/web.d.ts.map +1 -1
  50. package/dist/commands/web.js +17 -0
  51. package/dist/commands/workflow.d.ts.map +1 -1
  52. package/dist/commands/workflow.js +4 -0
  53. package/dist/core/agents/cli.js +7 -3
  54. package/dist/core/agents/health.d.ts +17 -0
  55. package/dist/core/agents/health.d.ts.map +1 -0
  56. package/dist/core/agents/health.js +109 -0
  57. package/dist/core/agents/mailbox.d.ts +92 -0
  58. package/dist/core/agents/mailbox.d.ts.map +1 -0
  59. package/dist/core/agents/mailbox.js +325 -0
  60. package/dist/core/agents/qa-signal.d.ts +111 -0
  61. package/dist/core/agents/qa-signal.d.ts.map +1 -0
  62. package/dist/core/agents/qa-signal.js +231 -0
  63. package/dist/core/agents/reconcile-coordination-v3.d.ts +44 -0
  64. package/dist/core/agents/reconcile-coordination-v3.d.ts.map +1 -0
  65. package/dist/core/agents/reconcile-coordination-v3.js +58 -0
  66. package/dist/core/agents/render/prompt-context.d.ts +5 -0
  67. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  68. package/dist/core/agents/render/prompt-context.js +34 -13
  69. package/dist/core/agents/render/session-context.d.ts +8 -0
  70. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  71. package/dist/core/agents/render/session-context.js +34 -3
  72. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
  73. package/dist/core/agents/rules/commit-conflict.js +50 -1
  74. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  75. package/dist/core/agents/rules/stop-hook.js +6 -10
  76. package/dist/core/agents/session-finalizer-v3.js +4 -1
  77. package/dist/core/agents/session-name-display.d.ts +20 -5
  78. package/dist/core/agents/session-name-display.d.ts.map +1 -1
  79. package/dist/core/agents/session-name-display.js +67 -7
  80. package/dist/core/agents/state/heartbeat-reader.d.ts +7 -0
  81. package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -1
  82. package/dist/core/agents/state/heartbeat-writer.d.ts +11 -0
  83. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  84. package/dist/core/agents/state/heartbeat-writer.js +17 -0
  85. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  86. package/dist/core/agents/state/live-coordination-view.js +1 -0
  87. package/dist/core/agents/state/live-coordination-writer.js +5 -0
  88. package/dist/core/artifacts/constants.d.ts +1 -1
  89. package/dist/core/artifacts/constants.js +1 -1
  90. package/dist/core/artifacts/index.d.ts +82 -6
  91. package/dist/core/artifacts/index.d.ts.map +1 -1
  92. package/dist/core/artifacts/index.js +410 -15
  93. package/dist/core/config.d.ts +20 -0
  94. package/dist/core/config.d.ts.map +1 -1
  95. package/dist/core/config.js +59 -0
  96. package/dist/core/diagnostics/advice.d.ts +9 -0
  97. package/dist/core/diagnostics/advice.d.ts.map +1 -0
  98. package/dist/core/diagnostics/advice.js +112 -0
  99. package/dist/core/diagnostics/bundle.d.ts +51 -0
  100. package/dist/core/diagnostics/bundle.d.ts.map +1 -0
  101. package/dist/core/diagnostics/bundle.js +968 -0
  102. package/dist/core/diagnostics/comparison.d.ts +5 -0
  103. package/dist/core/diagnostics/comparison.d.ts.map +1 -0
  104. package/dist/core/diagnostics/comparison.js +444 -0
  105. package/dist/core/diagnostics/contract.d.ts +245 -0
  106. package/dist/core/diagnostics/contract.d.ts.map +1 -0
  107. package/dist/core/diagnostics/contract.js +18 -0
  108. package/dist/core/diagnostics/identity.d.ts +3 -0
  109. package/dist/core/diagnostics/identity.d.ts.map +1 -0
  110. package/dist/core/diagnostics/identity.js +10 -0
  111. package/dist/core/diagnostics/index.d.ts +8 -0
  112. package/dist/core/diagnostics/index.d.ts.map +1 -0
  113. package/dist/core/diagnostics/index.js +7 -0
  114. package/dist/core/diagnostics/replay.d.ts +8 -0
  115. package/dist/core/diagnostics/replay.d.ts.map +1 -0
  116. package/dist/core/diagnostics/replay.js +213 -0
  117. package/dist/core/diagnostics/sanitize.d.ts +9 -0
  118. package/dist/core/diagnostics/sanitize.d.ts.map +1 -0
  119. package/dist/core/diagnostics/sanitize.js +84 -0
  120. package/dist/core/events/legacy-storage/compression.d.ts +13 -0
  121. package/dist/core/events/legacy-storage/compression.d.ts.map +1 -0
  122. package/dist/core/events/legacy-storage/compression.js +107 -0
  123. package/dist/core/events/legacy-storage/index.d.ts +1 -0
  124. package/dist/core/events/legacy-storage/index.d.ts.map +1 -1
  125. package/dist/core/events/legacy-storage/index.js +1 -0
  126. package/dist/core/events/v3/archive-retention.d.ts +33 -0
  127. package/dist/core/events/v3/archive-retention.d.ts.map +1 -0
  128. package/dist/core/events/v3/archive-retention.js +195 -0
  129. package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
  130. package/dist/core/events/v3/bootstrap.js +10 -0
  131. package/dist/core/events/v3/capabilities.d.ts +1 -1
  132. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  133. package/dist/core/events/v3/capabilities.js +1 -0
  134. package/dist/core/events/v3/coordination-view.d.ts +3 -0
  135. package/dist/core/events/v3/coordination-view.d.ts.map +1 -1
  136. package/dist/core/events/v3/coordination-view.js +69 -8
  137. package/dist/core/events/v3/index.d.ts +1 -0
  138. package/dist/core/events/v3/index.d.ts.map +1 -1
  139. package/dist/core/events/v3/index.js +1 -0
  140. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  141. package/dist/core/events/v3/live-routing.js +1 -0
  142. package/dist/core/events/v3/producers/hook-base.d.ts +1 -1
  143. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  144. package/dist/core/events/v3/producers/hook-base.js +13 -2
  145. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  146. package/dist/core/events/v3/producers/intake.js +10 -2
  147. package/dist/core/events/v3/producers/recorder.d.ts +39 -0
  148. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  149. package/dist/core/events/v3/producers/recorder.js +350 -17
  150. package/dist/core/hooks/adapter/output.d.ts +8 -0
  151. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  152. package/dist/core/hooks/adapter/output.js +11 -1
  153. package/dist/core/hooks/cli.js +303 -219
  154. package/dist/core/hooks/health.d.ts +59 -0
  155. package/dist/core/hooks/health.d.ts.map +1 -0
  156. package/dist/core/hooks/health.js +84 -0
  157. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  158. package/dist/core/hooks/resolve/transcript.js +10 -3
  159. package/dist/core/hooks/session-name-presence.d.ts.map +1 -1
  160. package/dist/core/hooks/session-name-presence.js +4 -1
  161. package/dist/core/qa-artifacts.d.ts +20 -0
  162. package/dist/core/qa-artifacts.d.ts.map +1 -0
  163. package/dist/core/qa-artifacts.js +110 -0
  164. package/dist/core/resources/contract.d.ts +96 -0
  165. package/dist/core/resources/contract.d.ts.map +1 -0
  166. package/dist/core/resources/contract.js +2 -0
  167. package/dist/core/resources/index.d.ts +6 -0
  168. package/dist/core/resources/index.d.ts.map +1 -0
  169. package/dist/core/resources/index.js +5 -0
  170. package/dist/core/resources/sampler.d.ts +34 -0
  171. package/dist/core/resources/sampler.d.ts.map +1 -0
  172. package/dist/core/resources/sampler.js +458 -0
  173. package/dist/core/resources/service-status.d.ts +3 -0
  174. package/dist/core/resources/service-status.d.ts.map +1 -0
  175. package/dist/core/resources/service-status.js +48 -0
  176. package/dist/core/resources/service.d.ts +26 -0
  177. package/dist/core/resources/service.d.ts.map +1 -0
  178. package/dist/core/resources/service.js +292 -0
  179. package/dist/core/resources/storage.d.ts +13 -0
  180. package/dist/core/resources/storage.d.ts.map +1 -0
  181. package/dist/core/resources/storage.js +30 -0
  182. package/dist/core/storage/atomic-json.d.ts +3 -0
  183. package/dist/core/storage/atomic-json.d.ts.map +1 -0
  184. package/dist/core/storage/atomic-json.js +15 -0
  185. package/dist/core/storage/builtins.d.ts.map +1 -1
  186. package/dist/core/storage/builtins.js +45 -6
  187. package/dist/core/storage/logger.d.ts +2 -0
  188. package/dist/core/storage/logger.d.ts.map +1 -1
  189. package/dist/core/storage/logger.js +2 -0
  190. package/dist/core/storage/query.d.ts +14 -0
  191. package/dist/core/storage/query.d.ts.map +1 -1
  192. package/dist/core/storage/query.js +51 -0
  193. package/dist/core/supervisor/activity.d.ts +4 -0
  194. package/dist/core/supervisor/activity.d.ts.map +1 -0
  195. package/dist/core/supervisor/activity.js +141 -0
  196. package/dist/core/supervisor/contract.d.ts +268 -0
  197. package/dist/core/supervisor/contract.d.ts.map +1 -0
  198. package/dist/core/supervisor/contract.js +35 -0
  199. package/dist/core/supervisor/explanations.d.ts +4 -0
  200. package/dist/core/supervisor/explanations.d.ts.map +1 -0
  201. package/dist/core/supervisor/explanations.js +71 -0
  202. package/dist/core/supervisor/findings.d.ts +20 -0
  203. package/dist/core/supervisor/findings.d.ts.map +1 -0
  204. package/dist/core/supervisor/findings.js +399 -0
  205. package/dist/core/supervisor/history.d.ts +9 -0
  206. package/dist/core/supervisor/history.d.ts.map +1 -0
  207. package/dist/core/supervisor/history.js +46 -0
  208. package/dist/core/supervisor/hook-health-alerts.d.ts +14 -0
  209. package/dist/core/supervisor/hook-health-alerts.d.ts.map +1 -0
  210. package/dist/core/supervisor/hook-health-alerts.js +70 -0
  211. package/dist/core/supervisor/hook-health-storage.d.ts +5 -0
  212. package/dist/core/supervisor/hook-health-storage.d.ts.map +1 -0
  213. package/dist/core/supervisor/hook-health-storage.js +24 -0
  214. package/dist/core/supervisor/hook-health.d.ts +72 -0
  215. package/dist/core/supervisor/hook-health.d.ts.map +1 -0
  216. package/dist/core/supervisor/hook-health.js +203 -0
  217. package/dist/core/supervisor/hooks.d.ts +10 -0
  218. package/dist/core/supervisor/hooks.d.ts.map +1 -0
  219. package/dist/core/supervisor/hooks.js +28 -0
  220. package/dist/core/supervisor/index.d.ts +15 -0
  221. package/dist/core/supervisor/index.d.ts.map +1 -0
  222. package/dist/core/supervisor/index.js +14 -0
  223. package/dist/core/supervisor/log-feed.d.ts +9 -0
  224. package/dist/core/supervisor/log-feed.d.ts.map +1 -0
  225. package/dist/core/supervisor/log-feed.js +103 -0
  226. package/dist/core/supervisor/service.d.ts +29 -0
  227. package/dist/core/supervisor/service.d.ts.map +1 -0
  228. package/dist/core/supervisor/service.js +450 -0
  229. package/dist/core/supervisor/services.d.ts +11 -0
  230. package/dist/core/supervisor/services.d.ts.map +1 -0
  231. package/dist/core/supervisor/services.js +155 -0
  232. package/dist/core/supervisor/status.d.ts +3 -0
  233. package/dist/core/supervisor/status.d.ts.map +1 -0
  234. package/dist/core/supervisor/status.js +48 -0
  235. package/dist/core/supervisor/storage.d.ts +30 -0
  236. package/dist/core/supervisor/storage.d.ts.map +1 -0
  237. package/dist/core/supervisor/storage.js +73 -0
  238. package/dist/core/supervisor/timeline.d.ts +3 -0
  239. package/dist/core/supervisor/timeline.d.ts.map +1 -0
  240. package/dist/core/supervisor/timeline.js +87 -0
  241. package/dist/core/workflow/admission.d.ts +23 -0
  242. package/dist/core/workflow/admission.d.ts.map +1 -0
  243. package/dist/core/workflow/admission.js +136 -0
  244. package/dist/core/workflow/engine.d.ts.map +1 -1
  245. package/dist/core/workflow/engine.js +77 -2
  246. package/dist/core/workflow/index.d.ts +3 -2
  247. package/dist/core/workflow/index.d.ts.map +1 -1
  248. package/dist/core/workflow/index.js +2 -1
  249. package/dist/core/workflow/proof.d.ts +2 -1
  250. package/dist/core/workflow/proof.d.ts.map +1 -1
  251. package/dist/core/workflow/proof.js +39 -1
  252. package/dist/core/workflow/run-state.d.ts +3 -2
  253. package/dist/core/workflow/run-state.d.ts.map +1 -1
  254. package/dist/core/workflow/run-state.js +8 -1
  255. package/dist/core/workflow/types.d.ts +33 -1
  256. package/dist/core/workflow/types.d.ts.map +1 -1
  257. package/dist/core/workflow/types.js +2 -1
  258. package/dist/lib/admission.d.ts +71 -0
  259. package/dist/lib/admission.d.ts.map +1 -0
  260. package/dist/lib/admission.js +264 -0
  261. package/dist/lib/agent-browser/client.d.ts +1 -1
  262. package/dist/lib/agent-browser/client.d.ts.map +1 -1
  263. package/dist/lib/agent-browser/client.js +1 -5
  264. package/dist/lib/browser/capture-fidelity.d.ts +39 -0
  265. package/dist/lib/browser/capture-fidelity.d.ts.map +1 -0
  266. package/dist/lib/browser/capture-fidelity.js +84 -0
  267. package/dist/lib/browser/client.d.ts +46 -1
  268. package/dist/lib/browser/client.d.ts.map +1 -1
  269. package/dist/lib/browser/client.js +168 -9
  270. package/dist/lib/browser/critique.d.ts +38 -1
  271. package/dist/lib/browser/critique.d.ts.map +1 -1
  272. package/dist/lib/browser/critique.js +34 -6
  273. package/dist/lib/browser/index.d.ts +5 -1
  274. package/dist/lib/browser/index.d.ts.map +1 -1
  275. package/dist/lib/browser/index.js +4 -0
  276. package/dist/lib/browser/page-review-judge.d.ts +64 -0
  277. package/dist/lib/browser/page-review-judge.d.ts.map +1 -0
  278. package/dist/lib/browser/page-review-judge.js +270 -0
  279. package/dist/lib/browser/page-review-pack.d.ts +613 -0
  280. package/dist/lib/browser/page-review-pack.d.ts.map +1 -0
  281. package/dist/lib/browser/page-review-pack.js +1751 -0
  282. package/dist/lib/browser/qa-run-contracts.d.ts +377 -0
  283. package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -0
  284. package/dist/lib/browser/qa-run-contracts.js +361 -0
  285. package/dist/lib/browser/qa-run.d.ts +141 -0
  286. package/dist/lib/browser/qa-run.d.ts.map +1 -0
  287. package/dist/lib/browser/qa-run.js +1283 -0
  288. package/dist/lib/browser/request-diagnostics.d.ts +13 -0
  289. package/dist/lib/browser/request-diagnostics.d.ts.map +1 -0
  290. package/dist/lib/browser/request-diagnostics.js +18 -0
  291. package/dist/lib/browser/tiling.d.ts +19 -0
  292. package/dist/lib/browser/tiling.d.ts.map +1 -1
  293. package/dist/lib/browser/tiling.js +28 -0
  294. package/dist/lib/cookies/client.d.ts +9 -0
  295. package/dist/lib/cookies/client.d.ts.map +1 -1
  296. package/dist/lib/cookies/client.js +197 -44
  297. package/dist/lib/cookies/extra.d.ts +18 -0
  298. package/dist/lib/cookies/extra.d.ts.map +1 -0
  299. package/dist/lib/cookies/extra.js +14 -0
  300. package/dist/lib/cookies/index.d.ts +2 -1
  301. package/dist/lib/cookies/index.d.ts.map +1 -1
  302. package/dist/lib/cookies/index.js +2 -1
  303. package/dist/lib/coord-root-id.d.ts +9 -0
  304. package/dist/lib/coord-root-id.d.ts.map +1 -0
  305. package/dist/lib/coord-root-id.js +17 -0
  306. package/dist/lib/durable-job.d.ts +124 -0
  307. package/dist/lib/durable-job.d.ts.map +1 -0
  308. package/dist/lib/durable-job.js +296 -0
  309. package/dist/lib/http/client.d.ts +7 -1
  310. package/dist/lib/http/client.d.ts.map +1 -1
  311. package/dist/lib/http/client.js +2 -0
  312. package/dist/lib/instructions/apply.d.ts +3 -1
  313. package/dist/lib/instructions/apply.d.ts.map +1 -1
  314. package/dist/lib/instructions/apply.js +74 -3
  315. package/dist/lib/instructions/templates.d.ts.map +1 -1
  316. package/dist/lib/instructions/templates.js +11 -2
  317. package/package.json +19 -2
  318. package/src/commander.ts +75 -1
  319. package/src/commands/admission.ts +699 -0
  320. package/src/commands/agents.ts +189 -50
  321. package/src/commands/artifacts.ts +132 -18
  322. package/src/commands/browse-ai.ts +10 -5
  323. package/src/commands/browse.ts +496 -20
  324. package/src/commands/diagnostics.ts +271 -0
  325. package/src/commands/fetch.ts +1 -0
  326. package/src/commands/files.ts +102 -2
  327. package/src/commands/governor.ts +8 -0
  328. package/src/commands/ledger-v3.ts +82 -0
  329. package/src/commands/qa-record.ts +682 -0
  330. package/src/commands/qa-run.ts +503 -0
  331. package/src/commands/qa-status.ts +608 -0
  332. package/src/commands/qa-verify.ts +238 -0
  333. package/src/commands/resources.ts +38 -0
  334. package/src/commands/review-pack.ts +1281 -0
  335. package/src/commands/supervisor.ts +141 -0
  336. package/src/commands/web.ts +19 -0
  337. package/src/commands/workflow.ts +8 -0
  338. package/src/core/agents/cli.ts +7 -3
  339. package/src/core/agents/health.ts +142 -0
  340. package/src/core/agents/mailbox.ts +373 -0
  341. package/src/core/agents/qa-signal.ts +261 -0
  342. package/src/core/agents/reconcile-coordination-v3.ts +77 -0
  343. package/src/core/agents/render/prompt-context.ts +42 -12
  344. package/src/core/agents/render/session-context.ts +37 -3
  345. package/src/core/agents/rules/commit-conflict.ts +58 -1
  346. package/src/core/agents/rules/stop-hook.ts +6 -12
  347. package/src/core/agents/session-finalizer-v3.ts +4 -1
  348. package/src/core/agents/session-name-display.ts +78 -7
  349. package/src/core/agents/state/heartbeat-reader.ts +7 -0
  350. package/src/core/agents/state/heartbeat-writer.ts +23 -0
  351. package/src/core/agents/state/live-coordination-view.ts +1 -0
  352. package/src/core/agents/state/live-coordination-writer.ts +5 -0
  353. package/src/core/artifacts/constants.ts +1 -1
  354. package/src/core/artifacts/index.ts +565 -30
  355. package/src/core/config.ts +134 -2
  356. package/src/core/diagnostics/advice.ts +147 -0
  357. package/src/core/diagnostics/bundle.ts +1250 -0
  358. package/src/core/diagnostics/comparison.ts +565 -0
  359. package/src/core/diagnostics/contract.ts +311 -0
  360. package/src/core/diagnostics/identity.ts +11 -0
  361. package/src/core/diagnostics/index.ts +7 -0
  362. package/src/core/diagnostics/replay.ts +314 -0
  363. package/src/core/diagnostics/sanitize.ts +97 -0
  364. package/src/core/events/legacy-storage/compression.ts +130 -0
  365. package/src/core/events/legacy-storage/index.ts +1 -0
  366. package/src/core/events/v3/archive-retention.ts +251 -0
  367. package/src/core/events/v3/bootstrap.ts +10 -0
  368. package/src/core/events/v3/capabilities.ts +2 -0
  369. package/src/core/events/v3/coordination-view.ts +100 -11
  370. package/src/core/events/v3/index.ts +9 -0
  371. package/src/core/events/v3/live-routing.ts +1 -0
  372. package/src/core/events/v3/producers/hook-base.ts +14 -2
  373. package/src/core/events/v3/producers/intake.ts +10 -2
  374. package/src/core/events/v3/producers/recorder.ts +420 -17
  375. package/src/core/hooks/adapter/output.ts +12 -1
  376. package/src/core/hooks/cli.ts +332 -247
  377. package/src/core/hooks/health.ts +146 -0
  378. package/src/core/hooks/resolve/transcript.ts +10 -3
  379. package/src/core/hooks/session-name-presence.ts +6 -1
  380. package/src/core/qa-artifacts.ts +126 -0
  381. package/src/core/resources/contract.ts +105 -0
  382. package/src/core/resources/index.ts +5 -0
  383. package/src/core/resources/sampler.ts +590 -0
  384. package/src/core/resources/service-status.ts +62 -0
  385. package/src/core/resources/service.ts +337 -0
  386. package/src/core/resources/storage.ts +44 -0
  387. package/src/core/storage/atomic-json.ts +15 -0
  388. package/src/core/storage/builtins.ts +62 -6
  389. package/src/core/storage/logger.ts +2 -0
  390. package/src/core/storage/query.ts +58 -0
  391. package/src/core/supervisor/activity.ts +193 -0
  392. package/src/core/supervisor/contract.ts +312 -0
  393. package/src/core/supervisor/explanations.ts +104 -0
  394. package/src/core/supervisor/findings.ts +788 -0
  395. package/src/core/supervisor/history.ts +61 -0
  396. package/src/core/supervisor/hook-health-alerts.ts +108 -0
  397. package/src/core/supervisor/hook-health-storage.ts +25 -0
  398. package/src/core/supervisor/hook-health.ts +301 -0
  399. package/src/core/supervisor/hooks.ts +35 -0
  400. package/src/core/supervisor/index.ts +14 -0
  401. package/src/core/supervisor/log-feed.ts +131 -0
  402. package/src/core/supervisor/service.ts +511 -0
  403. package/src/core/supervisor/services.ts +203 -0
  404. package/src/core/supervisor/status.ts +59 -0
  405. package/src/core/supervisor/storage.ts +126 -0
  406. package/src/core/supervisor/timeline.ts +133 -0
  407. package/src/core/workflow/admission.ts +215 -0
  408. package/src/core/workflow/engine.ts +93 -1
  409. package/src/core/workflow/index.ts +10 -0
  410. package/src/core/workflow/proof.ts +54 -1
  411. package/src/core/workflow/run-state.ts +13 -1
  412. package/src/core/workflow/types.ts +39 -1
  413. package/src/lib/admission.ts +347 -0
  414. package/src/lib/agent-browser/client.ts +2 -10
  415. package/src/lib/browser/capture-fidelity.ts +98 -0
  416. package/src/lib/browser/client.ts +212 -10
  417. package/src/lib/browser/critique.ts +62 -7
  418. package/src/lib/browser/index.ts +65 -0
  419. package/src/lib/browser/page-review-judge.ts +360 -0
  420. package/src/lib/browser/page-review-pack.ts +2384 -0
  421. package/src/lib/browser/qa-run-contracts.ts +743 -0
  422. package/src/lib/browser/qa-run.ts +1462 -0
  423. package/src/lib/browser/request-diagnostics.ts +27 -0
  424. package/src/lib/browser/tiling.ts +32 -0
  425. package/src/lib/cookies/client.ts +228 -42
  426. package/src/lib/cookies/extra.ts +28 -0
  427. package/src/lib/cookies/index.ts +2 -0
  428. package/src/lib/coord-root-id.ts +23 -0
  429. package/src/lib/durable-job.ts +407 -0
  430. package/src/lib/http/client.ts +13 -1
  431. package/src/lib/instructions/apply.ts +81 -2
  432. package/src/lib/instructions/templates.ts +11 -2
@@ -23,7 +23,6 @@ import { dirname, join } from "node:path";
23
23
  import { coordEnv } from "../../lib/env.ts";
24
24
  import { buildInstructionBundle } from "../../lib/instructions/bundle.ts";
25
25
  import type { Adapter } from "../adapter.ts";
26
- import { coordBinPath } from "../agents/coord-bin.ts";
27
26
  import { resolveCoordRoot } from "../agents/coord-client.ts";
28
27
  import {
29
28
  type ClaimFinalizationDecision,
@@ -31,20 +30,31 @@ import {
31
30
  classifyWriteClaimFinalization,
32
31
  formatWriteClaimFinalizationDenial,
33
32
  } from "../agents/finalization.ts";
34
- import { restoreLiveCoordinationStateAfterEpochV3 } from "../agents/live-authority-v3.ts";
33
+ import {
34
+ recordLiveClaimChangeV3,
35
+ restoreLiveCoordinationStateAfterEpochV3,
36
+ } from "../agents/live-authority-v3.ts";
35
37
  import { evaluateStopHook, STOP_REMEDIATION_MARKER } from "../agents/rules/stop-hook.ts";
36
38
  import {
37
39
  assistantTextStartsWithSessionNameBlock,
38
40
  isSessionNameRemediationCommand,
41
+ matchSessionNameDisplay,
42
+ sessionNameDisplayAcceptedNames,
39
43
  sessionNameDisplayInstruction,
40
44
  sessionNameDisplayPending,
41
45
  sessionNameDisplayRecoveryInstruction,
42
46
  toolResponseMintedSessionName,
43
47
  } from "../agents/session-name-display.ts";
44
48
  import type { Heartbeat } from "../agents/state/heartbeat-reader.ts";
45
- import { readHeartbeat, stampSessionNameSeen } from "../agents/state/heartbeat-writer.ts";
49
+ import {
50
+ readHeartbeat,
51
+ setAssignedNameCache,
52
+ stampSessionNameRequested,
53
+ stampSessionNameSeen,
54
+ } from "../agents/state/heartbeat-writer.ts";
46
55
  import { readLiveCoordinationRow } from "../agents/state/live-coordination-view.ts";
47
56
  import { ensureLiveCoordinationHeartbeat } from "../agents/state/live-coordination-writer.ts";
57
+ import { assignName } from "../agents/state/names.ts";
48
58
  import { writePidmapRow } from "../agents/state/pidmap.ts";
49
59
  import { agentsRequireGitFinalization, resolveBinName } from "../config.ts";
50
60
  import {
@@ -100,9 +110,17 @@ import {
100
110
  } from "./effects/index.ts";
101
111
  import { toolInputHash, toolTargetHash } from "./events/input-hash.ts";
102
112
  import { canonicalize } from "./guard-path.ts";
113
+ import {
114
+ beginHookHealth,
115
+ type HookHealthState,
116
+ observeHookDebug,
117
+ observeHookError,
118
+ writeHookHealthCompletion,
119
+ } from "./health.ts";
103
120
  import { adapterPidFromEnv, parsePsChainLine, selectAnchorPid } from "./resolve/anchor.ts";
104
121
  import { extractIntentComment, resolveIntent } from "./resolve/intent.ts";
105
122
  import { resolveOwner } from "./resolve/owner.ts";
123
+ import type { SessionNameDisplayInspection } from "./resolve/transcript.ts";
106
124
  import {
107
125
  inspectSessionNameDisplayImmediately,
108
126
  scanAssistantStatusBoxPresent,
@@ -118,6 +136,8 @@ interface Argv {
118
136
  extra: string[];
119
137
  }
120
138
 
139
+ let hookHealthState: HookHealthState | undefined;
140
+
121
141
  function parseArgv(argv: string[]): Argv {
122
142
  const out: Argv = { eventName: null, extra: [] };
123
143
  for (let i = 0; i < argv.length; i++) {
@@ -155,17 +175,16 @@ async function readStdin(): Promise<string> {
155
175
  }
156
176
 
157
177
  /**
158
- * Env for child agent-coord spawns, with the coord root pinned. The hook
159
- * process may be running with the session shell's cwd (inside a submodule or
160
- * journal dir), and agent-coord resolves its root from cwd unless overridden —
161
- * without the pin a child could write state to a different .harnery than the
162
- * one this hook resolved.
178
+ * Env for a detached hook retry worker, with the coord root pinned. The hook
179
+ * may run with the session shell's cwd (inside a submodule or journal dir), so
180
+ * the worker must retain the root this process already resolved.
163
181
  */
164
182
  function childEnv(coordRoot: string): NodeJS.ProcessEnv {
165
183
  return { ...process.env, HARNERY_COORD_ROOT_OVERRIDE: coordRoot };
166
184
  }
167
185
 
168
186
  function appendDebug(coordRoot: string, entry: Record<string, unknown>): void {
187
+ observeHookDebug(hookHealthState, entry);
169
188
  if (coordEnv("SHARED_LOGS") !== "0") {
170
189
  try {
171
190
  processLogger(coordRoot, "agent-hook").debug("agent_hook.diagnostic", legacyLogFields(entry));
@@ -184,6 +203,7 @@ function appendDebug(coordRoot: string, entry: Record<string, unknown>): void {
184
203
  }
185
204
 
186
205
  function logError(coordRoot: string | null, err: unknown, context: Record<string, unknown>): void {
206
+ observeHookError(hookHealthState, context.phase);
187
207
  if (!coordRoot) return;
188
208
  if (coordEnv("SHARED_LOGS") !== "0") {
189
209
  try {
@@ -216,43 +236,48 @@ function logError(coordRoot: string | null, err: unknown, context: Record<string
216
236
  }
217
237
 
218
238
  /**
219
- * Spawn `agent-coord assign-name <owner> <kind>` to mint or recover the
220
- * hurricane-style name for this owner. Returns null on any failure so
221
- * session.started emission never breaks the adapter flow.
222
- *
223
- * Lives at agent-hooks side (not agent-coord) to keep emitter/consumer
224
- * separation: we spawn rather than import.
239
+ * Mint or recover the hurricane-style name for this owner in-process. Returns
240
+ * null on any failure so session.started emission never breaks adapter flow.
225
241
  */
226
- function assignNameViaAgentCoord(
242
+ function assignNameInProcess(
227
243
  coordRoot: string,
228
244
  instanceId: string,
229
245
  kind: "session" | "subagent" | "transient",
230
246
  forkedFrom?: string,
231
247
  ): { name: string; kind: string } | null {
232
- const binary = coordBinPath("agent-coord", coordRoot) ?? "";
233
- if (!existsSync(binary)) return null;
234
248
  try {
235
- const args = ["assign-name", instanceId, kind];
236
- if (forkedFrom) args.push("--forked-from", forkedFrom);
237
- const result = spawnSync(binary, args, {
238
- encoding: "utf8",
239
- timeout: 2000,
240
- env: childEnv(coordRoot),
241
- });
242
- if (result.status !== 0 || !result.stdout) return null;
243
- const parsed = JSON.parse(result.stdout.trim()) as {
244
- name?: string;
245
- kind?: string;
246
- };
247
- if (parsed.name && parsed.kind) {
248
- return { name: parsed.name, kind: parsed.kind };
249
- }
250
- return null;
249
+ const name = assignName(coordRoot, instanceId, kind, forkedFrom ? { forkedFrom } : undefined);
250
+ return { name, kind };
251
251
  } catch {
252
252
  return null;
253
253
  }
254
254
  }
255
255
 
256
+ /** Mid-flight sessions can emit tools before SessionStart assigns a pool name.
257
+ * Stamp the disposable cache so Codec does not render the 8-character id. */
258
+ function ensureSessionDisplayName(
259
+ coordRoot: string,
260
+ instanceId: string,
261
+ sessionId: string,
262
+ adapter: Adapter,
263
+ ): void {
264
+ if (coordEnv("WORKFLOW_CHILD") === "1") return;
265
+ const row =
266
+ readLiveCoordinationRow(coordRoot, instanceId) ?? readHeartbeat(coordRoot, instanceId);
267
+ if (row?.kind === "subagent" || row?.kind === "transient" || row?.workflow_run_id) return;
268
+ if (row?.name?.trim()) return;
269
+ const assigned = assignNameInProcess(coordRoot, instanceId, "session");
270
+ if (!assigned?.name) return;
271
+ if (!readHeartbeat(coordRoot, instanceId)) {
272
+ try {
273
+ ensureLiveCoordinationHeartbeat(coordRoot, instanceId, sessionId, adapter);
274
+ } catch {
275
+ /* cache materialization is best-effort; history still holds the name */
276
+ }
277
+ }
278
+ setAssignedNameCache(coordRoot, instanceId, assigned.name, "session");
279
+ }
280
+
256
281
  /**
257
282
  * Direct (in-process) pidmap write, avoiding the spawn overhead of going via
258
283
  * the agent-coord CLI for every session.started signal. Pid-map rows
@@ -321,14 +346,9 @@ function buildEventData(
321
346
  // tool.requested heal path instead. The forkedFrom plumbing below stays
322
347
  // for adapters that DO report a parent at session start.
323
348
  const forkedFrom: string | undefined = undefined;
324
- // Assign (or recover) name + kind via agent-coord. Idempotent: resume
349
+ // Assign (or recover) name + kind in-process. Idempotent: resume
325
350
  // returns the original name; new owner consumes a counter slot.
326
- const assigned = assignNameViaAgentCoord(
327
- ctx.coordRoot,
328
- ctx.instanceId,
329
- "session",
330
- forkedFrom,
331
- );
351
+ const assigned = assignNameInProcess(ctx.coordRoot, ctx.instanceId, "session", forkedFrom);
332
352
  // Write the adapter pid-map row so `harn agents whoami` ppid-walks find
333
353
  // this owner. Prefer the payload pid (the actual claude binary), then the
334
354
  // anchor walk (the `node` ancestor for Cursor, which has no payload pid),
@@ -389,14 +409,12 @@ function buildEventData(
389
409
  };
390
410
 
391
411
  case "turn.started": {
392
- // Cursor can deliver beforeSubmitPrompt before sessionStart. Ensure that
393
- // high-confidence prompt bootstrap also mints durable display identity;
394
- // a later SessionStart remains idempotent.
395
- if (
396
- ctx.adapter === "cursor" &&
397
- !readLiveCoordinationRow(ctx.coordRoot, ctx.instanceId)?.name
398
- ) {
399
- assignNameViaAgentCoord(ctx.coordRoot, ctx.instanceId, "session");
412
+ // Mid-flight onboarding (any adapter) can observe a turn before
413
+ // SessionStart. Mint durable display identity here so a later
414
+ // SessionStart remains idempotent and Codec is not stuck on the
415
+ // 8-character native id.
416
+ if (!readLiveCoordinationRow(ctx.coordRoot, ctx.instanceId)?.name) {
417
+ assignNameInProcess(ctx.coordRoot, ctx.instanceId, "session");
400
418
  }
401
419
  const prompt = p?.prompt ?? "";
402
420
  const { value, truncated } = clampString(prompt, 4000);
@@ -467,7 +485,7 @@ function buildEventData(
467
485
  // (agent-coord/state/names.ts → kind=transient). Use the call ID as the
468
486
  // instance_id input; assignName falls through to transient.
469
487
  const childInstanceId = subagentCallId ?? ctx.instanceId;
470
- const assigned = assignNameViaAgentCoord(ctx.coordRoot, childInstanceId, "subagent");
488
+ const assigned = assignNameInProcess(ctx.coordRoot, childInstanceId, "subagent");
471
489
  return {
472
490
  agent_type:
473
491
  (p?.raw.agent_type as string | undefined) ??
@@ -597,10 +615,18 @@ function numberField(value: unknown): number | undefined {
597
615
 
598
616
  async function main(): Promise<number> {
599
617
  const hookStartedAt = performance.now();
618
+ const hookStartedRss = process.memoryUsage().rss;
600
619
  const hookClock = captureSpanClockV3();
601
620
  const { eventName, extra } = parseArgv(process.argv.slice(2));
602
621
  const adapter = detectAdapter(process.argv.slice(2));
603
622
  const raw = await readStdin();
623
+ hookHealthState = beginHookHealth({
624
+ started_at_ms: hookStartedAt,
625
+ started_rss_bytes: hookStartedRss,
626
+ event_name: eventName,
627
+ adapter,
628
+ payload_bytes: raw.length,
629
+ });
604
630
 
605
631
  // Cursor executes the Claude Code project hooks too on hosts wired for both
606
632
  // adapters, piping them its own payload (identifiable by the top-level
@@ -612,6 +638,7 @@ async function main(): Promise<number> {
612
638
  if (coordEnv("AGENT_COORD_OFF") !== "1") {
613
639
  const coordRoot = resolveCoordRoot(process.cwd());
614
640
  if (coordRoot) {
641
+ hookHealthState.coord_root = coordRoot;
615
642
  appendDebug(coordRoot, {
616
643
  ts: new Date().toISOString(),
617
644
  event_name: eventName,
@@ -668,6 +695,7 @@ async function main(): Promise<number> {
668
695
 
669
696
  const coordRoot = resolveCoordRoot(process.cwd());
670
697
  if (!coordRoot) return 0;
698
+ hookHealthState.coord_root = coordRoot;
671
699
  if (eventName === "runtime-context-retry") {
672
700
  return runRuntimeContextRetryWorker(coordRoot, adapter, extra);
673
701
  }
@@ -696,8 +724,9 @@ async function main(): Promise<number> {
696
724
  // that tool. It is not a transcript and therefore cannot prove that an
697
725
  // earlier assistant response omitted the required session-name block.
698
726
  // afterAgentResponse is the one native boundary that carries the completed
699
- // assistant text, so stamp a positive sighting here without retaining or
700
- // emitting the response body into V3.
727
+ // assistant text. Preserve only privacy-safe ritual booleans in the V3
728
+ // producer's open-turn state; Stop consumes them into the authoritative
729
+ // turn.completed event. The response body never enters V3 or heartbeat.
701
730
  if (adapter === "cursor" && eventName === "after-agent-response") {
702
731
  const payload = parsePayload(raw, adapter);
703
732
  const owner = resolveOwner({ payload: payload?.raw ?? null, coordRoot });
@@ -705,14 +734,80 @@ async function main(): Promise<number> {
705
734
  appendDebug(coordRoot, { ...debugBase, skipped: "no-owner-resolved" });
706
735
  return 0;
707
736
  }
708
- const name = sessionNameDisplayPending(readLiveCoordinationRow(coordRoot, owner.instance_id));
737
+ const row = readLiveCoordinationRow(coordRoot, owner.instance_id);
738
+ const name = sessionNameDisplayPending(row);
709
739
  const text = typeof payload?.raw.text === "string" ? payload.raw.text : "";
710
- if (name && assistantTextStartsWithSessionNameBlock(text, name)) {
711
- stampSessionNameSeen(coordRoot, owner.instance_id, name);
712
- appendDebug(coordRoot, { ...debugBase, effect: "session-name-display-stamped" });
740
+ const sighting = matchSessionNameDisplay(row, text);
741
+ if (sighting) {
742
+ stampSessionNameSeen(coordRoot, owner.instance_id, sighting.pending);
743
+ appendDebug(coordRoot, {
744
+ ...debugBase,
745
+ effect: "session-name-display-stamped",
746
+ session_name_pending: sighting.pending,
747
+ ...(sighting.displayed === sighting.pending
748
+ ? {}
749
+ : { session_name_displayed: sighting.displayed, session_name_drift: true }),
750
+ });
751
+ } else if (!name) {
752
+ // Nothing was owed. Distinct from a miss: conflating the two is what made
753
+ // a latched Cursor session undiagnosable from this log.
754
+ appendDebug(coordRoot, { ...debugBase, skipped: "no-pending-session-name" });
713
755
  } else {
714
- appendDebug(coordRoot, { ...debugBase, skipped: "no-session-name-sighting" });
756
+ appendDebug(coordRoot, {
757
+ ...debugBase,
758
+ skipped: "session-name-block-absent",
759
+ session_name_pending: name,
760
+ reply_bytes: text.length,
761
+ reply_leads_with_fence: /^\s*`{3,}/.test(text),
762
+ });
763
+ }
764
+ if (ledgerRoute.state === "blocked") {
765
+ appendDebug(coordRoot, {
766
+ ...debugBase,
767
+ skipped: "v3-control-blocked",
768
+ reason: ledgerRoute.reason,
769
+ owner_source: owner.source,
770
+ });
771
+ return 0;
715
772
  }
773
+ const statusBoxPresentStrict = scanAssistantStatusBoxPresent(undefined, text);
774
+ // The hook parser needs the completed reply long enough to scan it, but
775
+ // durable hook intake must never retain that body. Keep every other native
776
+ // field so turn correlation remains available to the producer.
777
+ const { text: _completedReply, ...privacySafeRaw } = payload?.raw ?? {};
778
+ const privacySafePayload = payload ? { ...payload, raw: privacySafeRaw } : null;
779
+ const v3Result = recordLiveHookSignalV3({
780
+ coordRoot,
781
+ route: ledgerRoute,
782
+ eventName,
783
+ payload: privacySafePayload,
784
+ adapter,
785
+ instanceId: owner.instance_id,
786
+ hook_name: eventName,
787
+ hook_duration_ms: Math.max(0, Math.floor(performance.now() - hookStartedAt)),
788
+ monotonic_ns: hookClock.monotonic_ns,
789
+ turn_ritual: {
790
+ status_box_present: statusBoxPresentStrict,
791
+ status_box_present_strict: statusBoxPresentStrict,
792
+ session_name_required: name !== undefined,
793
+ session_name_present: name ? assistantTextStartsWithSessionNameBlock(text, name) : false,
794
+ },
795
+ });
796
+ observeHookDebug(hookHealthState, { event_v3_state: v3Result.state });
797
+ appendDebug(coordRoot, {
798
+ ...debugBase,
799
+ effect: "cursor-response-ritual-observed",
800
+ owner_source: owner.source,
801
+ event_v3_state: v3Result.state,
802
+ ...(v3Result.state === "observed"
803
+ ? {
804
+ generation_id: v3Result.generation_id,
805
+ turn_id: v3Result.turn_id,
806
+ response_observed_at: v3Result.observed_at,
807
+ status_box_present_strict: statusBoxPresentStrict,
808
+ }
809
+ : {}),
810
+ });
716
811
  return 0;
717
812
  }
718
813
 
@@ -735,9 +830,20 @@ async function main(): Promise<number> {
735
830
  });
736
831
  return 0;
737
832
  }
833
+ hookHealthState.owner_id = owner.instance_id;
738
834
 
739
835
  const sessionId = payload?.session_id ?? payload?.conversation_id ?? owner.instance_id;
740
836
  const priorCoordination = readHeartbeat(coordRoot, owner.instance_id);
837
+ if (
838
+ norm.event_type !== "session.ended" &&
839
+ coordEnv("WORKFLOW_CHILD") !== "1" &&
840
+ priorCoordination?.kind !== "subagent" &&
841
+ priorCoordination?.kind !== "transient" &&
842
+ !priorCoordination?.workflow_run_id &&
843
+ !priorCoordination?.name?.trim()
844
+ ) {
845
+ assignNameInProcess(coordRoot, owner.instance_id, "session");
846
+ }
741
847
 
742
848
  const data = buildEventData(norm.event_type, {
743
849
  coordRoot,
@@ -812,6 +918,9 @@ async function main(): Promise<number> {
812
918
  ...(turnRitual ? { turn_ritual: turnRitual } : {}),
813
919
  ...(deferV3Drain ? { defer_drain: true } : {}),
814
920
  });
921
+ observeHookDebug(hookHealthState, {
922
+ ...(v3Result ? { event_v3_state: v3Result.state } : {}),
923
+ });
815
924
  const recordedGenerationId =
816
925
  v3Result && "event" in v3Result && "generation_id" in v3Result.event.scope
817
926
  ? (v3Result.event.scope.generation_id as `gen_${string}`)
@@ -830,6 +939,13 @@ async function main(): Promise<number> {
830
939
  logError(coordRoot, error, { phase: "epoch-coordination-restore" });
831
940
  }
832
941
  }
942
+ if (norm.event_type !== "session.ended") {
943
+ try {
944
+ ensureSessionDisplayName(coordRoot, owner.instance_id, sessionId, adapter);
945
+ } catch (error) {
946
+ logError(coordRoot, error, { phase: "session-display-name" });
947
+ }
948
+ }
833
949
  const v3EventId =
834
950
  v3Result && "event" in v3Result
835
951
  ? v3Result.event.event_id
@@ -966,6 +1082,7 @@ async function main(): Promise<number> {
966
1082
  // Session start is the only caller of the artifact janitor and the storage
967
1083
  // maintenance pass, so both load here instead of on every tool call.
968
1084
  const { autoCleanArtifacts } = await import("../artifacts/index.ts");
1085
+ const { autoCleanEventV3Archives } = await import("../events/v3/archive-retention.ts");
969
1086
  const { createAutomaticMaintenanceComposition, runAutomaticMaintenancePass } = await import(
970
1087
  "../storage/maintenance-providers.ts"
971
1088
  );
@@ -977,6 +1094,13 @@ async function main(): Promise<number> {
977
1094
  } catch (err) {
978
1095
  logError(coordRoot, err, { phase: "artifact-auto-clean" });
979
1096
  }
1097
+ // Effect: apply the same daily throttle to closed V3 epochs. The newest
1098
+ // recovery epochs remain protected by the archive retention policy.
1099
+ try {
1100
+ autoCleanEventV3Archives(coordRoot);
1101
+ } catch (err) {
1102
+ logError(coordRoot, err, { phase: "event-v3-archive-auto-clean" });
1103
+ }
980
1104
  // Plan one bounded, claim-first global slice from cached pressure only.
981
1105
  // Existing owner janitors above remain the only active executors until
982
1106
  // each provider receives a separate production activation.
@@ -1040,7 +1164,7 @@ async function main(): Promise<number> {
1040
1164
  // agnostic since v0.5.0.
1041
1165
  if (norm.event_type === "session.ended") {
1042
1166
  try {
1043
- cleanupSessionEnd(coordRoot, owner.instance_id, (data.reason as string) ?? "unknown");
1167
+ cleanupSessionEnd(coordRoot, owner.instance_id);
1044
1168
  } catch (err) {
1045
1169
  logError(coordRoot, err, { phase: "session-end-cleanup" });
1046
1170
  }
@@ -1065,27 +1189,9 @@ async function main(): Promise<number> {
1065
1189
  if (norm.event_type === "agent.started") {
1066
1190
  try {
1067
1191
  const childInstanceId = (data.agent_id as string | undefined) ?? owner.instance_id;
1068
- const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1069
- if (existsSync(agentCoordBin)) {
1070
- spawnSync(agentCoordBin, ["project"], {
1071
- encoding: "utf8",
1072
- timeout: 3000,
1073
- env: childEnv(coordRoot),
1074
- });
1075
- spawnSync(
1076
- agentCoordBin,
1077
- [
1078
- "log",
1079
- `SUBAGENT_START agent_type=${(data.agent_type as string) ?? "unknown"} agent_id=${childInstanceId.slice(0, 8)} platform=${adapterPlatform(adapter)}`,
1080
- "--instance",
1081
- childInstanceId,
1082
- ],
1083
- { encoding: "utf8", timeout: 2000, env: childEnv(coordRoot) },
1084
- );
1085
- }
1086
- emitSubagentStartContext(coordRoot, childInstanceId, sessionId, data, adapter);
1192
+ await emitSubagentStartContext(coordRoot, childInstanceId, sessionId, data, adapter);
1087
1193
  } catch (err) {
1088
- logError(coordRoot, err, { phase: "subagent-start-project" });
1194
+ logError(coordRoot, err, { phase: "subagent-start-context" });
1089
1195
  }
1090
1196
  }
1091
1197
 
@@ -1093,20 +1199,7 @@ async function main(): Promise<number> {
1093
1199
  if (norm.event_type === "agent.completed") {
1094
1200
  try {
1095
1201
  const childInstanceId = payload?.subagent_id ?? payload?.agent_id ?? owner.instance_id;
1096
- cleanupSessionEnd(coordRoot, childInstanceId, (data.reason as string) ?? "unknown");
1097
- const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1098
- if (existsSync(agentCoordBin)) {
1099
- spawnSync(
1100
- agentCoordBin,
1101
- [
1102
- "log",
1103
- `SUBAGENT_STOP agent_id=${childInstanceId.slice(0, 8)} platform=${adapterPlatform(adapter)}`,
1104
- "--instance",
1105
- childInstanceId,
1106
- ],
1107
- { encoding: "utf8", timeout: 2000, env: childEnv(coordRoot) },
1108
- );
1109
- }
1202
+ cleanupSessionEnd(coordRoot, childInstanceId);
1110
1203
  const { reconcileSessionFinalizationV3 } = await import("../agents/session-finalizer-v3.ts");
1111
1204
  reconcileSessionFinalizationV3(coordRoot, { archive_observations: [] });
1112
1205
  } catch (err) {
@@ -1338,6 +1431,11 @@ async function main(): Promise<number> {
1338
1431
  try {
1339
1432
  const name = sessionNameDisplayPending(readLiveCoordinationRow(coordRoot, owner.instance_id));
1340
1433
  if (name && toolResponseMintedSessionName(payload?.tool_response, name)) {
1434
+ // Record the title before asking for it. The suggestion can still
1435
+ // change afterwards (an assigned-name rewrite, a lifecycle re-mint, a
1436
+ // rebuilt cache), and the agent must not be stranded for displaying
1437
+ // exactly what it was handed.
1438
+ stampSessionNameRequested(coordRoot, owner.instance_id, name);
1341
1439
  const { emitContext } = await import("./adapter/output.ts");
1342
1440
  emitContext(adapter, "PostToolUse", sessionNameDisplayInstruction(name));
1343
1441
  }
@@ -1414,25 +1512,7 @@ async function enforcePendingSessionNameDisplay(
1414
1512
  const command = extractBashCommand(payload?.tool_name, payload?.tool_input);
1415
1513
  if (isSessionNameRemediationCommand(command, resolveBinName(coordRoot))) return true;
1416
1514
 
1417
- const inspection =
1418
- adapter === "cursor" && payload?.agent_message !== undefined
1419
- ? {
1420
- state: assistantTextStartsWithSessionNameBlock(payload.agent_message, name)
1421
- ? ("present" as const)
1422
- : ("unavailable" as const),
1423
- }
1424
- : inspectSessionNameDisplayImmediately(
1425
- // Codex hook payloads omit transcript_path on every event, which
1426
- // left this inspection permanently unavailable and the latch never
1427
- // stamped. Discover the rollout by session id; the scan only runs
1428
- // while a name is pending, so the latch closes after one success.
1429
- payload?.transcript_path ??
1430
- (adapter === "codex"
1431
- ? discoverCodexSessionTranscript(payload?.session_id ?? instanceId)
1432
- : undefined),
1433
- name,
1434
- assistantTextStartsWithSessionNameBlock,
1435
- );
1515
+ const inspection = inspectDisplayEvidence(instanceId, adapter, payload, coordination);
1436
1516
  if (inspection.state === "present") {
1437
1517
  stampSessionNameSeen(coordRoot, instanceId, name);
1438
1518
  return true;
@@ -1447,11 +1527,65 @@ async function enforcePendingSessionNameDisplay(
1447
1527
  return true;
1448
1528
  }
1449
1529
 
1530
+ // Record the refusal. Without this the gate was the one enforcement path
1531
+ // that left no trace, so a session reporting "the gate keeps denying me"
1532
+ // could not be confirmed or refuted from the hook log.
1533
+ appendDebug(coordRoot, {
1534
+ ts: new Date().toISOString(),
1535
+ event_name: "pre-tool-use",
1536
+ adapter,
1537
+ effect: "session-name-display-denied",
1538
+ session_name_pending: name,
1539
+ tool_name: payload?.tool_name,
1540
+ });
1450
1541
  const { emitDeny } = await import("./adapter/output.ts");
1451
1542
  emitDeny(adapter, sessionNameDisplayRecoveryInstruction(name, resolveBinName(coordRoot)));
1452
1543
  return false;
1453
1544
  }
1454
1545
 
1546
+ /**
1547
+ * Evidence for the pending display, over every title whose display counts.
1548
+ *
1549
+ * Cursor supplies the current narration directly; Claude Code and Codex are
1550
+ * resolved from their JSONL transcripts. Absent is the only state that denies,
1551
+ * so a title is refused only when a readable surface positively shows some
1552
+ * other opening text for every accepted title.
1553
+ */
1554
+ function inspectDisplayEvidence(
1555
+ instanceId: string,
1556
+ adapter: Adapter,
1557
+ payload: ParsedPayload | null,
1558
+ coordination: Heartbeat | null,
1559
+ ): SessionNameDisplayInspection {
1560
+ if (adapter === "cursor" && payload?.agent_message !== undefined) {
1561
+ return matchSessionNameDisplay(coordination, payload.agent_message)
1562
+ ? { state: "present" }
1563
+ : { state: "unavailable", reason: "transcript_not_ready" };
1564
+ }
1565
+
1566
+ // Codex hook payloads omit transcript_path on every event, which left this
1567
+ // inspection permanently unavailable and the latch never stamped. Discover
1568
+ // the rollout by session id; the scan only runs while a name is pending, so
1569
+ // the latch closes after one success.
1570
+ const transcriptPath =
1571
+ payload?.transcript_path ??
1572
+ (adapter === "codex"
1573
+ ? discoverCodexSessionTranscript(payload?.session_id ?? instanceId)
1574
+ : undefined);
1575
+
1576
+ let verdict: SessionNameDisplayInspection = { state: "absent" };
1577
+ for (const candidate of sessionNameDisplayAcceptedNames(coordination)) {
1578
+ const inspection = inspectSessionNameDisplayImmediately(
1579
+ transcriptPath,
1580
+ candidate,
1581
+ assistantTextStartsWithSessionNameBlock,
1582
+ );
1583
+ if (inspection.state === "present") return inspection;
1584
+ if (inspection.state === "unavailable") verdict = inspection;
1585
+ }
1586
+ return verdict;
1587
+ }
1588
+
1455
1589
  function generationBoundHeartbeat(
1456
1590
  heartbeat: Heartbeat | null,
1457
1591
  generationId: `gen_${string}` | undefined,
@@ -1494,42 +1628,19 @@ async function runPreToolUseGuard(
1494
1628
  }
1495
1629
  if (targets.length === 0) return true;
1496
1630
 
1497
- const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1498
- if (!existsSync(agentCoordBin)) {
1499
- if (agentsRequireGitFinalization(coordRoot)) {
1500
- const { emitDeny } = await import("./adapter/output.ts");
1501
- emitDeny(
1502
- adapter,
1503
- "Harnery denied the write before mutation because the claim coordinator is unavailable; repair the project's Harnery installation and retry.",
1504
- );
1505
- return false;
1506
- }
1507
- return true;
1508
- }
1631
+ const { evaluateClaim } = await import("../agents/rules/claim-conflict.ts");
1509
1632
 
1510
1633
  // For apply_patch (multi-file), collect siblings so the deny reason names
1511
1634
  // them. For single-file tools the array has one entry.
1512
1635
  for (const target of targets) {
1513
- const verdictReq = JSON.stringify({
1514
- rule: "claim",
1515
- instance_id: instanceId,
1516
- session_id: sessionId,
1517
- path: target.path,
1518
- });
1519
- const result = spawnSync(agentCoordBin, ["verdict"], {
1520
- input: verdictReq,
1521
- encoding: "utf8",
1522
- timeout: 3000,
1523
- env: childEnv(coordRoot),
1524
- });
1525
- if (result.status !== 0 || !result.stdout) continue;
1526
- let parsed: { allow?: boolean; reason?: string } = {};
1527
1636
  try {
1528
- parsed = JSON.parse(result.stdout.trim());
1529
- } catch {
1530
- continue;
1531
- }
1532
- if (parsed.allow === false) {
1637
+ const parsed = evaluateClaim(coordRoot, {
1638
+ rule: "claim",
1639
+ instance_id: instanceId,
1640
+ session_id: sessionId,
1641
+ path: target.path,
1642
+ });
1643
+ if (parsed.allow !== false) continue;
1533
1644
  let reason =
1534
1645
  parsed.reason ?? `Path ${target.path} is currently being edited by another agent.`;
1535
1646
  if (targets.length > 1) {
@@ -1545,7 +1656,7 @@ async function runPreToolUseGuard(
1545
1656
  const { emitDeny } = await import("./adapter/output.ts");
1546
1657
  emitDeny(adapter, reason);
1547
1658
  return false;
1548
- }
1659
+ } catch {}
1549
1660
  }
1550
1661
  return true;
1551
1662
  }
@@ -1748,16 +1859,23 @@ function releaseClaimOnFailure(
1748
1859
  const row = readLiveCoordinationRow(coordRoot, instanceId);
1749
1860
  if (!row?.files_touched?.includes(canonical)) return;
1750
1861
 
1751
- const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1752
- if (!existsSync(agentCoordBin)) return;
1753
- spawnSync(agentCoordBin, ["release-claim", instanceId, canonical], {
1754
- encoding: "utf8",
1755
- timeout: 2000,
1756
- env: childEnv(coordRoot),
1757
- });
1862
+ const before = readHeartbeat(coordRoot, instanceId);
1863
+ try {
1864
+ recordLiveClaimChangeV3({
1865
+ coordRoot,
1866
+ owner: instanceId,
1867
+ nativeSessionId: before?.session_id ?? instanceId,
1868
+ adapter: adapterFromPlatform(before?.platform),
1869
+ operation: "released",
1870
+ path: canonical,
1871
+ access: "write",
1872
+ });
1873
+ } catch {
1874
+ /* best-effort release must not break adapter flow */
1875
+ }
1758
1876
  }
1759
1877
 
1760
- function cleanupSessionEnd(coordRoot: string, instanceId: string, reason: string): void {
1878
+ function cleanupSessionEnd(coordRoot: string, instanceId: string): void {
1761
1879
  // Sweep pid-map entries pointing to this instance
1762
1880
  const pidmapDir = join(coordRoot, ".harnery", "pid-map");
1763
1881
  if (existsSync(pidmapDir)) {
@@ -1779,15 +1897,6 @@ function cleanupSessionEnd(coordRoot: string, instanceId: string, reason: string
1779
1897
  /* swallow */
1780
1898
  }
1781
1899
  }
1782
- // Activity log
1783
- const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1784
- if (existsSync(agentCoordBin)) {
1785
- spawnSync(
1786
- agentCoordBin,
1787
- ["log", `SESSION_END reason=${reason}`, "--instance", instanceId],
1788
- { encoding: "utf8", timeout: 2000 },
1789
- );
1790
- }
1791
1900
  }
1792
1901
 
1793
1902
  async function emitUserPromptSubmitSystemMessage(
@@ -1798,33 +1907,18 @@ async function emitUserPromptSubmitSystemMessage(
1798
1907
  workspaceCwd?: string,
1799
1908
  recoveryBriefing = "",
1800
1909
  ): Promise<boolean> {
1801
- const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1802
- let additionalContext = "";
1803
-
1804
- if (existsSync(agentCoordBin)) {
1805
- const args = ["prompt-context", "--instance", instanceId, "--session", sessionId];
1806
- // Every human-facing adapter gets the first-session naming reminder from
1807
- // the shared hook path. Cursor + Codex additionally get ongoing set-task
1808
- // staleness nudges; Claude Code enforces those via its Stop transcript.
1809
- // Codex also gets the optional project-owned prompt reminder. Claude Code
1810
- // already has native output-style reminders, so duplicating it would add
1811
- // noise. Cursor's current beforeSubmitPrompt output can allow or block but
1812
- // cannot inject model context; an Always Apply rule is its durable carrier.
1813
- // Only the boolean route travels through argv, never the host's text.
1814
- if (adapter === "codex") args.push("--host-prompt-reminder");
1815
- // Codex gets a fresh status-footer reminder on every prompt. Its Stop hook
1816
- // stays observe-only, so missing the footer never replaces the answer.
1817
- // Claude Code gets a fresh per-turn ritual reminder: satisfying the
1818
- // contract up front is far cheaper than the bounce-and-retry the Stop hook
1819
- // otherwise forces. Cursor's beforeSubmitPrompt cannot inject context, so
1820
- // its Stop follow-up remains the supported enforcement channel.
1821
- args.push("--session-name-nudge");
1822
- if (adapter === "cursor" || adapter === "codex") args.push("--task-nudge");
1823
- if (adapter === "codex") args.push("--status-footer-nudge");
1824
- if (adapter === "claude-code") args.push("--turn-ritual-nudge", adapter);
1825
- const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
1826
- if (result.status === 0 && result.stdout) additionalContext = result.stdout.trim();
1827
- }
1910
+ const { renderPromptContext } = await import("../agents/render/prompt-context.ts");
1911
+ let additionalContext = renderPromptContext({
1912
+ coordRoot,
1913
+ instanceId,
1914
+ sessionId,
1915
+ adapter,
1916
+ sessionNameNudge: true,
1917
+ taskNudge: adapter === "cursor" || adapter === "codex",
1918
+ hostPromptReminder: adapter === "codex",
1919
+ statusFooterNudge: adapter === "codex",
1920
+ turnRitualNudge: adapter === "claude-code" ? adapter : undefined,
1921
+ }).trim();
1828
1922
  if (adapter === "codex") {
1829
1923
  const fileLinkContext = renderCodexWslFileLinkContext(coordRoot, workspaceCwd);
1830
1924
  if (fileLinkContext) {
@@ -1841,14 +1935,14 @@ async function emitUserPromptSubmitSystemMessage(
1841
1935
  return true;
1842
1936
  }
1843
1937
 
1844
- function emitSubagentStartContext(
1938
+ async function emitSubagentStartContext(
1845
1939
  coordRoot: string,
1846
1940
  instanceId: string,
1847
1941
  sessionId: string,
1848
1942
  data: Record<string, unknown>,
1849
1943
  adapter: Adapter,
1850
- ): void {
1851
- // Look up the subagent's assigned name (just-written by agent-coord assignName
1944
+ ): Promise<void> {
1945
+ // Look up the subagent's assigned name (just-written by the in-process name
1852
1946
  // in session.started data) + the parent's short id for the "you are a subagent
1853
1947
  // of X" framing.
1854
1948
  const subagentName = (data.name as string | undefined) ?? "";
@@ -1861,23 +1955,20 @@ function emitSubagentStartContext(
1861
1955
  // Render peer table inline since the subagent might want to know who else
1862
1956
  // is around. Reuse prompt-context (which dedups against the per-owner hash);
1863
1957
  // first call will always emit.
1864
- const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1865
1958
  let combined = message;
1866
- if (existsSync(agentCoordBin)) {
1867
- const result = spawnSync(
1868
- agentCoordBin,
1869
- ["prompt-context", "--instance", instanceId, "--session", sessionId, "--name", subagentName],
1870
- { encoding: "utf8", timeout: 3000 },
1871
- );
1872
- const ctx = (result.stdout ?? "").trim();
1873
- if (ctx) combined = `${message}\n\n${ctx}`;
1874
- }
1959
+ const { renderPromptContext } = await import("../agents/render/prompt-context.ts");
1960
+ const context = renderPromptContext({
1961
+ coordRoot,
1962
+ instanceId,
1963
+ sessionId,
1964
+ agentName: subagentName,
1965
+ }).trim();
1966
+ if (context) combined = `${message}\n\n${context}`;
1875
1967
 
1876
1968
  // Use SubagentStart event-name in CC's hookSpecificOutput shape; cursor's
1877
1969
  // flat `additional_context` works the same way.
1878
- void import("./adapter/output.ts").then(({ emitContext }) => {
1879
- emitContext(adapter, "SubagentStart", combined);
1880
- });
1970
+ const { emitContext } = await import("./adapter/output.ts");
1971
+ emitContext(adapter, "SubagentStart", combined);
1881
1972
  }
1882
1973
 
1883
1974
  function adapterPlatform(adapter: Adapter): string {
@@ -1885,6 +1976,12 @@ function adapterPlatform(adapter: Adapter): string {
1885
1976
  return adapter;
1886
1977
  }
1887
1978
 
1979
+ function adapterFromPlatform(platform: unknown): Adapter {
1980
+ if (platform === "cursor") return "cursor";
1981
+ if (platform === "codex") return "codex";
1982
+ return "claude-code";
1983
+ }
1984
+
1888
1985
  async function emitSessionStartSystemMessage(
1889
1986
  coordRoot: string,
1890
1987
  instanceId: string,
@@ -1893,53 +1990,29 @@ async function emitSessionStartSystemMessage(
1893
1990
  adapter: Adapter,
1894
1991
  recoveryBriefing = "",
1895
1992
  ): Promise<boolean> {
1896
- const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
1897
1993
  const workflowChild = coordEnv("WORKFLOW_CHILD") === "1";
1898
1994
  let additionalContext = "";
1899
- if (existsSync(agentCoordBin)) {
1900
- // Sync-project so the heartbeat exists for downstream readers (peer table,
1901
- // wiring check, council invites).
1902
- spawnSync(agentCoordBin, ["project"], { encoding: "utf8", timeout: 3000 });
1903
- // Opportunistic reconciliation makes normal session starts a failsafe for
1904
- // archive, idle, cascade, and host lifecycle observations.
1905
- spawnSync(agentCoordBin, ["reconcile-finalization"], {
1906
- encoding: "utf8",
1907
- timeout: 5000,
1908
- env: { ...process.env, HARNERY_COORD_ROOT_OVERRIDE: coordRoot },
1909
- });
1910
-
1911
- // SESSION_START activity log line, fired across all adapters.
1912
- const model = (emittedData.model as string | undefined) ?? "unknown";
1913
- const source = (emittedData.source as string | undefined) ?? "startup";
1914
- const platform = adapterPlatform(adapter);
1915
- spawnSync(
1916
- agentCoordBin,
1917
- [
1918
- "log",
1919
- `SESSION_START model=${model} source=${source} platform=${platform}`,
1920
- "--instance",
1921
- instanceId,
1922
- ],
1923
- { encoding: "utf8", timeout: 2000 },
1924
- );
1925
-
1926
- // Workflow children retain lifecycle/event capture but do not receive
1927
- // operator-facing peer, council, or init-remediation context. Injecting
1928
- // that context can make a bounded child follow housekeeping instructions
1929
- // instead of its assigned prompt.
1930
- if (!workflowChild) {
1931
- const agentName = (emittedData.name as string | undefined) ?? "";
1932
- const args = ["session-context", "--instance", instanceId, "--session", sessionId];
1933
- if (agentName) args.push("--name", agentName);
1934
- // The "You are agent-X." prefix in session-context renders unqualified by
1935
- // default (claude-code-style). For cursor/codex the bash dispatchers add
1936
- // a "(Cursor)" / "(Codex)" suffix; pass it through as --platform-label.
1937
- if (adapter !== "claude-code") {
1938
- args.push("--platform-label", platform === "cursor" ? "Cursor" : "Codex");
1939
- }
1940
- const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
1941
- if (result.status === 0 && result.stdout) additionalContext = result.stdout.trim();
1942
- }
1995
+ // Opportunistic reconciliation makes normal session starts a failsafe for
1996
+ // archive, idle, cascade, and host lifecycle observations. It also runs the
1997
+ // stale cache sweep through the shared ADR 0077 composition.
1998
+ const { reconcileCoordinationV3 } = await import("../agents/reconcile-coordination-v3.ts");
1999
+ reconcileCoordinationV3(coordRoot);
2000
+
2001
+ // Workflow children retain lifecycle/event capture but do not receive
2002
+ // operator-facing peer, council, or init-remediation context. Injecting
2003
+ // that context can make a bounded child follow housekeeping instructions
2004
+ // instead of its assigned prompt.
2005
+ if (!workflowChild) {
2006
+ const agentName = (emittedData.name as string | undefined) ?? "";
2007
+ const { renderSessionContext } = await import("../agents/render/session-context.ts");
2008
+ additionalContext = renderSessionContext({
2009
+ coordRoot,
2010
+ instanceId,
2011
+ sessionId,
2012
+ agentName: agentName || undefined,
2013
+ platformLabel:
2014
+ adapter === "claude-code" ? undefined : adapter === "cursor" ? "Cursor" : "Codex",
2015
+ }).trim();
1943
2016
  }
1944
2017
 
1945
2018
  // Effect (claude-code): merge the journal recovery cue into the session-start
@@ -1987,6 +2060,11 @@ function completeRecoveryInjection(
1987
2060
 
1988
2061
  main()
1989
2062
  .then(async (code) => {
2063
+ writeHookHealthCompletion(hookHealthState, {
2064
+ finished_at_ms: performance.now(),
2065
+ finished_rss_bytes: process.memoryUsage().rss,
2066
+ pid: process.pid,
2067
+ });
1990
2068
  await closeProcessLoggers();
1991
2069
  process.exit(code);
1992
2070
  })
@@ -1994,6 +2072,13 @@ main()
1994
2072
  logError(resolveCoordRoot(process.cwd()), err, {
1995
2073
  argv: process.argv.slice(2),
1996
2074
  pid: process.pid,
2075
+ phase: "top-level",
2076
+ });
2077
+ writeHookHealthCompletion(hookHealthState, {
2078
+ finished_at_ms: performance.now(),
2079
+ finished_rss_bytes: process.memoryUsage().rss,
2080
+ pid: process.pid,
2081
+ faulted: true,
1997
2082
  });
1998
2083
  await closeProcessLoggers();
1999
2084
  process.exit(0);