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
@@ -141,6 +141,14 @@ interface TurnHarnessTimingV3 {
141
141
  slowest_hook_ms: number;
142
142
  }
143
143
 
144
+ interface CursorResponseRitualV3 {
145
+ turn_id: `tid_${string}`;
146
+ native_turn_id?: string;
147
+ observed_at: string;
148
+ status_box_present: boolean;
149
+ status_box_present_strict: boolean;
150
+ }
151
+
144
152
  interface PendingEventV3 {
145
153
  source_id?: `hid_${string}`;
146
154
  event: EventV3;
@@ -201,6 +209,10 @@ export interface HookProducerStateV3 {
201
209
  current_turn_id?: `tid_${string}`;
202
210
  /** Native turn identity retained owner-only for transcript attribution. */
203
211
  current_native_turn_id?: string;
212
+ /** Latest completed assistant response for Cursor's open turn. The response
213
+ * body is discarded by agent-hook; only these booleans survive until Stop
214
+ * copies them into the authoritative turn.completed ritual observation. */
215
+ cursor_response_ritual?: CursorResponseRitualV3;
204
216
  tool_call_count: number;
205
217
  tool_call_count_turn_id?: `tid_${string}`;
206
218
  last_event_id?: `evt_${string}`;
@@ -288,6 +300,12 @@ export type RecordHookSignalV3Result =
288
300
  /** A late signal for a span already closed in memory; preserved in diagnostics, never re-opened. */
289
301
  | { state: "suppressed"; reason: "closed_span" }
290
302
  | { state: "ignored" }
303
+ | {
304
+ state: "observed";
305
+ generation_id: `gen_${string}`;
306
+ turn_id: `tid_${string}`;
307
+ observed_at: string;
308
+ }
291
309
  /** Durably queued in the intake spool; a lease holder or drain hook records it. */
292
310
  | { state: "spooled" }
293
311
  | { state: "recorded"; event: EventV3; durability: WriteEventV3Result; recovered: boolean };
@@ -677,7 +695,7 @@ function processHookSignalLocked(
677
695
  const durability = writeEventV3(input.coordRoot, pendingEvent, input.writerOptions);
678
696
  applyCommittedEvent(state, pendingEvent);
679
697
  state.pending = undefined;
680
- publishProducerState(path, state);
698
+ publishProducerState(input.coordRoot, path, state);
681
699
  if (pendingSource && incomingSource === pendingSource) {
682
700
  recovered = { state: "recorded", event: pendingEvent, durability, recovered: true };
683
701
  }
@@ -736,7 +754,16 @@ function processHookSignalLocked(
736
754
  );
737
755
  const cursorPromptBootstrap = isCursorPromptBootstrap(input);
738
756
  const onboarding = buildMidFlightSessionStart(input, state, rootId, cursorPromptBootstrap);
739
- commitEventLocked(input, state, path, onboarding);
757
+ // Onboarding commits eagerly even when the triggering hook defers its
758
+ // drain. The coordination view reads committed history only, so a
759
+ // spooled session.started leaves the session invisible to every
760
+ // authority command (set-task, status --end-turn, heal) until some other
761
+ // writer happens to drain the spool.
762
+ const onboardingInput = withEagerDrain(input);
763
+ commitEventLocked(onboardingInput, state, path, onboarding);
764
+ if (midFlightSignalImpliesOpenTurn(input.signal)) {
765
+ commitMidFlightTurnStart(onboardingInput, state, path, rootId);
766
+ }
740
767
  if (!cursorPromptBootstrap) {
741
768
  writeProducerDiagnosticV3(input.coordRoot, "mid_flight_onboarding", {
742
769
  adapter: input.adapter,
@@ -863,7 +890,7 @@ function processHookSignalLocked(
863
890
  span_id: state.current_turn_span?.span_id,
864
891
  payload: input.payload,
865
892
  });
866
- publishProducerState(path, state);
893
+ publishProducerState(input.coordRoot, path, state);
867
894
  return { state: "ignored" };
868
895
  }
869
896
 
@@ -871,6 +898,51 @@ function processHookSignalLocked(
871
898
  // Sample once for the native event and every span it opens or closes so
872
899
  // their self-contained timing cannot drift by a millisecond.
873
900
  const eventClock = signalClock(input);
901
+ if (input.signal === "after-agent-response") {
902
+ if (
903
+ input.adapter !== "cursor" ||
904
+ !state.current_turn_id ||
905
+ !state.current_turn_span ||
906
+ !input.turn_ritual
907
+ ) {
908
+ writeProducerDiagnosticV3(input.coordRoot, "cursor_response_ritual_unbound", {
909
+ adapter: input.adapter,
910
+ instance_id: input.instance_id,
911
+ generation_id: state.generation_id,
912
+ signal: input.signal,
913
+ reason: !state.current_turn_id
914
+ ? "no_open_turn"
915
+ : !state.current_turn_span
916
+ ? "no_open_turn_span"
917
+ : "ritual_observation_missing",
918
+ });
919
+ publishProducerState(input.coordRoot, path, state);
920
+ return { state: "ignored" };
921
+ }
922
+ const observation: CursorResponseRitualV3 = {
923
+ turn_id: state.current_turn_id,
924
+ ...(input.payload.turn_id ? { native_turn_id: input.payload.turn_id } : {}),
925
+ observed_at: eventClock.observed_at,
926
+ status_box_present: input.turn_ritual.status_box_present,
927
+ status_box_present_strict: input.turn_ritual.status_box_present_strict,
928
+ };
929
+ state.cursor_response_ritual = observation;
930
+ publishProducerState(input.coordRoot, path, state);
931
+ writeProducerDiagnosticV3(input.coordRoot, "cursor_response_ritual_observed", {
932
+ instance_id: state.instance_id,
933
+ generation_id: state.generation_id,
934
+ turn_id: observation.turn_id,
935
+ ...(observation.native_turn_id ? { native_turn_id: observation.native_turn_id } : {}),
936
+ response_observed_at: observation.observed_at,
937
+ status_box_present_strict: observation.status_box_present_strict,
938
+ });
939
+ return {
940
+ state: "observed",
941
+ generation_id: state.generation_id,
942
+ turn_id: observation.turn_id,
943
+ observed_at: observation.observed_at,
944
+ };
945
+ }
874
946
  if (input.signal === "user-prompt-submit" && !state.current_turn_span) {
875
947
  state.current_turn_span = openSpanStateV3({
876
948
  span_id: spanIdV3(),
@@ -1096,6 +1168,38 @@ function processHookSignalLocked(
1096
1168
  // Before the signal's own event: the tool call or turn that carries the
1097
1169
  // new effort already ran under it, so it must ride the new attestation.
1098
1170
  maybeAttestTuningChange(input, state, path, rootId);
1171
+ const cursorResponseRitual =
1172
+ input.adapter === "cursor" &&
1173
+ (input.signal === "stop" || input.signal === "stop-failure") &&
1174
+ state.current_turn_id &&
1175
+ state.cursor_response_ritual?.turn_id === state.current_turn_id
1176
+ ? state.cursor_response_ritual
1177
+ : undefined;
1178
+ const terminalTurnRitual =
1179
+ input.adapter === "cursor" && (input.signal === "stop" || input.signal === "stop-failure")
1180
+ ? cursorResponseRitual
1181
+ ? {
1182
+ status_box_present: cursorResponseRitual.status_box_present,
1183
+ status_box_present_strict: cursorResponseRitual.status_box_present_strict,
1184
+ session_name_required: false,
1185
+ session_name_present: false,
1186
+ }
1187
+ : undefined
1188
+ : input.turn_ritual;
1189
+ if (cursorResponseRitual) {
1190
+ writeProducerDiagnosticV3(input.coordRoot, "cursor_response_ritual_consumed", {
1191
+ instance_id: state.instance_id,
1192
+ generation_id: state.generation_id,
1193
+ turn_id: cursorResponseRitual.turn_id,
1194
+ ...(cursorResponseRitual.native_turn_id
1195
+ ? { response_native_turn_id: cursorResponseRitual.native_turn_id }
1196
+ : {}),
1197
+ ...(input.payload.turn_id ? { stop_native_turn_id: input.payload.turn_id } : {}),
1198
+ response_observed_at: cursorResponseRitual.observed_at,
1199
+ stop_observed_at: eventClock.observed_at,
1200
+ status_box_present_strict: cursorResponseRitual.status_box_present_strict,
1201
+ });
1202
+ }
1099
1203
  const event = normalizeHookEventV3(input.signal, eventInput.payload, {
1100
1204
  coordRoot: input.coordRoot,
1101
1205
  adapter: input.adapter,
@@ -1154,7 +1258,7 @@ function processHookSignalLocked(
1154
1258
  child_generation_id: delegation?.child_generation_id,
1155
1259
  agent_role: delegation?.role,
1156
1260
  stop_remediation: input.stop_remediation,
1157
- turn_ritual: input.turn_ritual,
1261
+ turn_ritual: terminalTurnRitual,
1158
1262
  });
1159
1263
  if (!event) return { state: "ignored" };
1160
1264
  if (
@@ -1710,6 +1814,114 @@ function commitRecoveredToolTurnStart(
1710
1814
  commitEventLocked(input, state, path, event);
1711
1815
  }
1712
1816
 
1817
+ /**
1818
+ * Signals an adapter can only deliver while a turn is executing. A session
1819
+ * onboarded mid-flight by one of these is provably inside a turn, so the
1820
+ * generation opens with one instead of waiting for the next native prompt.
1821
+ * The native prompt path opens its own turn, session boundaries carry no
1822
+ * turn, and compaction can run between turns.
1823
+ */
1824
+ function midFlightSignalImpliesOpenTurn(signal: HookSignalV3): boolean {
1825
+ switch (signal) {
1826
+ case "session-start":
1827
+ case "session-end":
1828
+ case "user-prompt-submit":
1829
+ case "pre-compact":
1830
+ case "post-compact":
1831
+ return false;
1832
+ default:
1833
+ return true;
1834
+ }
1835
+ }
1836
+
1837
+ /** Commit through the append path even when the hook asked to defer its drain. */
1838
+ function withEagerDrain(input: RecordHookSignalV3Input): RecordHookSignalV3Input {
1839
+ if (!input.writerOptions?.deferDrain) return input;
1840
+ return { ...input, writerOptions: { ...input.writerOptions, deferDrain: false } };
1841
+ }
1842
+
1843
+ /**
1844
+ * Open a derived turn for a session onboarded mid-flight (ADR 0078) by a
1845
+ * signal that only an executing turn can deliver. Without it the fresh
1846
+ * generation has no current turn: command telemetry refuses to join
1847
+ * (`turn_not_started`), tool spans nest under the session span, and after an
1848
+ * epoch rotation (ADR 0137) the live session cannot satisfy its end-of-turn
1849
+ * gate until a human submits the next prompt. The payload's native turn id
1850
+ * is kept when the adapter supplies one, so the turn already running keeps
1851
+ * its identity across the boundary and later signals join it directly.
1852
+ */
1853
+ function commitMidFlightTurnStart(
1854
+ input: RecordHookSignalV3Input,
1855
+ state: HookProducerStateV3,
1856
+ path: string,
1857
+ rootId: `root_${string}`,
1858
+ recovery?: {
1859
+ source_event: string;
1860
+ confidence: "high" | "medium" | "low";
1861
+ attribution_method: "native_payload" | "session_env";
1862
+ },
1863
+ ): void {
1864
+ const fingerprintContext = fingerprintContextV3(
1865
+ input.coordRoot,
1866
+ rootId,
1867
+ state.generation_id,
1868
+ state.privacy_epoch_id,
1869
+ );
1870
+ const clock = signalClock(input);
1871
+ const span = openSpanStateV3({
1872
+ span_id: spanIdV3(),
1873
+ parent_span_id: state.session_span.span_id,
1874
+ boot_id: state.boot_id,
1875
+ clock,
1876
+ });
1877
+ state.current_turn_span = span;
1878
+ const nativeTurnId = input.payload.turn_id;
1879
+ state.current_native_turn_id = nativeTurnId;
1880
+ const event = normalizeHookEventV3("user-prompt-submit", recoveryBoundaryPayload(input.payload), {
1881
+ coordRoot: input.coordRoot,
1882
+ adapter: input.adapter,
1883
+ adapterVersion: input.adapterVersion,
1884
+ harnessVersion: input.harnessVersion,
1885
+ root_id: rootId,
1886
+ run_id: input.run_id,
1887
+ workflow_id: input.workflow_id,
1888
+ workflow_agent_id: input.workflow_agent_id,
1889
+ instance_id: state.instance_id,
1890
+ generation_id: state.generation_id,
1891
+ attestation_id: state.attestation_id,
1892
+ producer_id: input.producer_id,
1893
+ boot_id: state.boot_id,
1894
+ sequence: state.next_sequence,
1895
+ build_id: input.build_id,
1896
+ platform: input.platform,
1897
+ bridge: input.bridge,
1898
+ capability_profile: state.capability_profile,
1899
+ fingerprintContext,
1900
+ turn_native_id: nativeTurnId ?? `mid-flight:${state.generation_id}:${state.turn_ordinal + 1}`,
1901
+ span_id: span.span_id,
1902
+ caused_by: state.last_event_id ? [state.last_event_id] : [],
1903
+ observed_at: clock.observed_at,
1904
+ monotonic_ns: orderedEventMonotonic(state, input.monotonic_ns),
1905
+ clock_id: state.clock_id,
1906
+ });
1907
+ if (event?.event_type !== "turn.started") {
1908
+ throw new Error("mid-flight turn start could not be normalized");
1909
+ }
1910
+ event.provenance = {
1911
+ ...event.provenance,
1912
+ source_event: recovery?.source_event ?? `${input.adapter}.recovery`,
1913
+ attestation: "derived",
1914
+ confidence: recovery?.confidence ?? (nativeTurnId ? "medium" : "low"),
1915
+ attribution: {
1916
+ method: recovery?.attribution_method ?? (nativeTurnId ? "native_payload" : "session_env"),
1917
+ state: "verified",
1918
+ subject_instance_id: state.instance_id,
1919
+ },
1920
+ };
1921
+ assertEventV3(event);
1922
+ commitEventLocked(input, state, path, event);
1923
+ }
1924
+
1713
1925
  /** The single pending-publish/write/apply/publish cycle every locked event commit uses. */
1714
1926
  function commitEventLocked(
1715
1927
  input: RecordHookSignalV3Input,
@@ -1721,11 +1933,11 @@ function commitEventLocked(
1721
1933
  markObservedClockRegressionV3(event, state.last_observed_at);
1722
1934
  assertEventV3(event);
1723
1935
  state.pending = { ...(sourceId ? { source_id: sourceId } : {}), event };
1724
- publishProducerState(path, state);
1936
+ publishProducerState(input.coordRoot, path, state);
1725
1937
  const durability = writeEventV3(input.coordRoot, event, input.writerOptions);
1726
1938
  applyCommittedEvent(state, event);
1727
1939
  state.pending = undefined;
1728
- publishProducerState(path, state);
1940
+ publishProducerState(input.coordRoot, path, state);
1729
1941
  return durability;
1730
1942
  }
1731
1943
 
@@ -1782,7 +1994,7 @@ function commitContextObservation(
1782
1994
  contextProvenance?.source_witness &&
1783
1995
  state.last_context_source_witness === contextProvenance.source_witness
1784
1996
  ) {
1785
- publishProducerState(path, state);
1997
+ publishProducerState(input.coordRoot, path, state);
1786
1998
  return;
1787
1999
  }
1788
2000
  if (measurement.state === "observed" && contextProvenance?.source_witness) {
@@ -1913,13 +2125,13 @@ function maybeCommitActiveRuntimeContextObservation(
1913
2125
  return;
1914
2126
  }
1915
2127
  if (input.adapter === "cursor" && state.cursor_mode === "cloud") {
1916
- publishProducerState(path, state);
2128
+ publishProducerState(input.coordRoot, path, state);
1917
2129
  return;
1918
2130
  }
1919
2131
 
1920
2132
  const transcriptPath = runtimeTranscriptPath(input, state);
1921
2133
  if (!transcriptPath && input.adapter !== "cursor") {
1922
- publishProducerState(path, state);
2134
+ publishProducerState(input.coordRoot, path, state);
1923
2135
  return;
1924
2136
  }
1925
2137
  const runtime = readRuntimeContextTelemetry(
@@ -1938,7 +2150,7 @@ function maybeCommitActiveRuntimeContextObservation(
1938
2150
  );
1939
2151
  if (runtime.bytes_read > 0) recordRuntimeTelemetryTiming(state, runtime.io_duration_ms);
1940
2152
  if (runtime.state !== "observed") {
1941
- publishProducerState(path, state);
2153
+ publishProducerState(input.coordRoot, path, state);
1942
2154
  return;
1943
2155
  }
1944
2156
 
@@ -2205,7 +2417,7 @@ function reconcilePendingRuntimeContexts(
2205
2417
  if (state.pending_runtime_contexts?.length === 0) {
2206
2418
  state.pending_runtime_contexts = undefined;
2207
2419
  }
2208
- publishProducerState(path, state);
2420
+ publishProducerState(input.coordRoot, path, state);
2209
2421
  }
2210
2422
 
2211
2423
  function reconcilePendingRuntimeContextsBeforeApprovedEnd(
@@ -2983,7 +3195,7 @@ export function recordApprovedSessionEndV3(
2983
3195
  const durability = writeEventV3(input.coordRoot, pending, input.writerOptions);
2984
3196
  applyCommittedEvent(state, pending);
2985
3197
  state.pending = undefined;
2986
- publishProducerState(record.path, state);
3198
+ publishProducerState(input.coordRoot, record.path, state);
2987
3199
  recovered = true;
2988
3200
  if (pending.event_type === "session.ended") {
2989
3201
  return { state: "recorded", event: pending, durability, recovered };
@@ -3080,11 +3292,11 @@ export function recordApprovedSessionEndV3(
3080
3292
  assertEventV3(event);
3081
3293
 
3082
3294
  state.pending = { event };
3083
- publishProducerState(record.path, state);
3295
+ publishProducerState(input.coordRoot, record.path, state);
3084
3296
  const durability = writeEventV3(input.coordRoot, event, input.writerOptions);
3085
3297
  applyCommittedEvent(state, event);
3086
3298
  state.pending = undefined;
3087
- publishProducerState(record.path, state);
3299
+ publishProducerState(input.coordRoot, record.path, state);
3088
3300
  return { state: "recorded", event, durability, recovered };
3089
3301
  } finally {
3090
3302
  lease.release();
@@ -3168,7 +3380,7 @@ export function salvageOpenSpansV3(input: SalvageOpenSpansV3Input): SalvageOpenS
3168
3380
  writeEventV3(input.coordRoot, pendingEvent, input.writerOptions);
3169
3381
  applyCommittedEvent(state, pendingEvent);
3170
3382
  state.pending = undefined;
3171
- publishProducerState(record.path, state);
3383
+ publishProducerState(input.coordRoot, record.path, state);
3172
3384
  }
3173
3385
  const allowed = new Set(input.allowed_span_ids);
3174
3386
  const fingerprintContext = fingerprintContextV3(
@@ -3250,6 +3462,155 @@ export function listHookProducerStateRecordsV3(
3250
3462
  );
3251
3463
  }
3252
3464
 
3465
+ export interface ReanchorArchivedHookProducersV3Input {
3466
+ coordRoot: string;
3467
+ archivedEpoch: string;
3468
+ mode: EventV3WriteMode;
3469
+ build_id: `build_${string}`;
3470
+ platform: "linux" | "windows" | "macos" | "unknown";
3471
+ observed_at?: string;
3472
+ }
3473
+
3474
+ export interface ReanchorArchivedHookProducersV3Result {
3475
+ sessions: number;
3476
+ turns: number;
3477
+ }
3478
+
3479
+ /**
3480
+ * Re-anchor every live archived hook producer into a newly activated epoch.
3481
+ *
3482
+ * The archive rename is the rotation's atomic snapshot: it includes every
3483
+ * state published before the boundary without copying any old boot sequence
3484
+ * or causal link into the successor. Each live session gets a fresh
3485
+ * generation and attestation. Only a turn that was open at the boundary is
3486
+ * reopened, which makes command telemetry joinable before another adapter
3487
+ * hook fires while preserving the between-turn state for idle sessions.
3488
+ */
3489
+ export function reanchorArchivedHookProducersV3(
3490
+ input: ReanchorArchivedHookProducersV3Input,
3491
+ ): ReanchorArchivedHookProducersV3Result {
3492
+ const control = readEventV3ControlState(input.coordRoot);
3493
+ if (control.state !== input.mode) {
3494
+ throw new Error(`event_v3_rotation_reanchor_gate_closed:${control.state}`);
3495
+ }
3496
+ const rootId = control.genesis.event.scope.root_id as `root_${string}`;
3497
+ const epochId = control.genesis.profile.privacy_key_epoch;
3498
+ const genesisId = control.genesis.event.payload.genesis_id as `gex_${string}`;
3499
+ const boundaryEventId =
3500
+ control.state === "candidate"
3501
+ ? control.genesis.event.event_id
3502
+ : control.activation.event.event_id;
3503
+ const observedAt = input.observed_at ?? new Date().toISOString();
3504
+ let sessions = 0;
3505
+ let turns = 0;
3506
+
3507
+ for (const archived of listArchivedHookProducerStatesV3(input.archivedEpoch)) {
3508
+ const previous = archived.state;
3509
+ if (previous.terminal || !previous.started_event_id) continue;
3510
+ const path = producerStatePath(input.coordRoot, previous.adapter, archived.sessionHash);
3511
+ const lease = acquireStateLeaseWithRetry(input.coordRoot, path, 40);
3512
+ if (!lease) {
3513
+ throw new Error(`event_v3_rotation_reanchor_busy:${previous.instance_id}`);
3514
+ }
3515
+ try {
3516
+ if (existsSync(path)) {
3517
+ const current = readProducerState(path);
3518
+ if (current.epoch_genesis_id === genesisId) continue;
3519
+ }
3520
+ const sourceEvent = `${previous.adapter}.epoch-rotation-reanchor`;
3521
+ const rotationInput: RecordHookSignalV3Input = {
3522
+ coordRoot: input.coordRoot,
3523
+ mode: input.mode,
3524
+ signal: "session-start",
3525
+ payload: {
3526
+ raw: {},
3527
+ ...(previous.current_native_turn_id ? { turn_id: previous.current_native_turn_id } : {}),
3528
+ ...(previous.adapter === "cursor" && previous.cursor_mode
3529
+ ? { cursor_mode: previous.cursor_mode }
3530
+ : {}),
3531
+ },
3532
+ adapter: previous.adapter,
3533
+ instance_id: previous.instance_id,
3534
+ producer_id: "prd_agent-hook",
3535
+ build_id: input.build_id,
3536
+ platform: input.platform,
3537
+ observed_at: observedAt,
3538
+ writerOptions: { expectedGenesisId: genesisId },
3539
+ };
3540
+ const state = newProducerState(
3541
+ rotationInput,
3542
+ previous.session_id,
3543
+ epochId,
3544
+ boundaryEventId as `evt_${string}`,
3545
+ genesisId,
3546
+ );
3547
+ const sessionStart = buildMidFlightSessionStart(rotationInput, state, rootId);
3548
+ if (sessionStart.event_type !== "session.started") {
3549
+ throw new Error("rotation re-anchor session start could not be normalized");
3550
+ }
3551
+ sessionStart.provenance = {
3552
+ ...sessionStart.provenance,
3553
+ source_event: sourceEvent,
3554
+ attestation: "derived",
3555
+ confidence: "high",
3556
+ attribution: {
3557
+ method: "session_env",
3558
+ state: "verified",
3559
+ subject_instance_id: state.instance_id,
3560
+ },
3561
+ };
3562
+ sessionStart.payload.resume = {
3563
+ state: "unknown",
3564
+ reason: "epoch_rotation_reanchor",
3565
+ };
3566
+ assertEventV3(sessionStart);
3567
+ commitEventLocked(rotationInput, state, path, sessionStart);
3568
+ sessions += 1;
3569
+
3570
+ if (previous.current_turn_id && previous.current_turn_span) {
3571
+ commitMidFlightTurnStart(rotationInput, state, path, rootId, {
3572
+ source_event: sourceEvent,
3573
+ confidence: "high",
3574
+ attribution_method: "session_env",
3575
+ });
3576
+ turns += 1;
3577
+ }
3578
+ } finally {
3579
+ lease.release();
3580
+ }
3581
+ }
3582
+ return { sessions, turns };
3583
+ }
3584
+
3585
+ function listArchivedHookProducerStatesV3(
3586
+ archivedEpoch: string,
3587
+ ): Array<{ sessionHash: `hid_${string}`; state: HookProducerStateV3 }> {
3588
+ const producerRoot = join(resolve(archivedEpoch), "private-producers");
3589
+ if (!existsSync(producerRoot)) return [];
3590
+ const records: Array<{ sessionHash: `hid_${string}`; state: HookProducerStateV3 }> = [];
3591
+ for (const adapter of ["claude-code", "codex", "cursor"] as const) {
3592
+ const directory = join(producerRoot, adapter);
3593
+ if (!existsSync(directory)) continue;
3594
+ const metadata = lstatSync(directory);
3595
+ if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
3596
+ throw new Error("V3 archived producer state directory is unsafe");
3597
+ }
3598
+ for (const name of readdirSync(directory).filter((entry) =>
3599
+ /^hid_[a-f0-9]{64}\.json$/.test(entry),
3600
+ )) {
3601
+ records.push({
3602
+ sessionHash: name.slice(0, -".json".length) as `hid_${string}`,
3603
+ state: readProducerState(join(directory, name)),
3604
+ });
3605
+ }
3606
+ }
3607
+ return records.sort(
3608
+ (left, right) =>
3609
+ left.state.generation_id.localeCompare(right.state.generation_id) ||
3610
+ left.sessionHash.localeCompare(right.sessionHash),
3611
+ );
3612
+ }
3613
+
3253
3614
  function hookSignalCapability(signal: HookSignalV3): AdapterSignalV3 {
3254
3615
  switch (signal) {
3255
3616
  case "session-start":
@@ -3258,6 +3619,8 @@ function hookSignalCapability(signal: HookSignalV3): AdapterSignalV3 {
3258
3619
  return "session_end";
3259
3620
  case "user-prompt-submit":
3260
3621
  return "prompt";
3622
+ case "after-agent-response":
3623
+ return "assistant_reply_text";
3261
3624
  case "stop":
3262
3625
  case "stop-failure":
3263
3626
  return "turn_completion";
@@ -3515,6 +3878,7 @@ function applyCommittedEvent(state: HookProducerStateV3, event: EventV3): void {
3515
3878
  if (event.event_type === "turn.started") {
3516
3879
  const nextTurnId = (event.scope as { turn_id: `tid_${string}` }).turn_id;
3517
3880
  state.current_turn_id = nextTurnId;
3881
+ state.cursor_response_ritual = undefined;
3518
3882
  state.session_start_derivation = undefined;
3519
3883
  if (state.tool_call_count_turn_id !== nextTurnId) {
3520
3884
  state.tool_call_count = 0;
@@ -3600,6 +3964,7 @@ function applyCommittedEvent(state: HookProducerStateV3, event: EventV3): void {
3600
3964
  }
3601
3965
  state.current_turn_id = undefined;
3602
3966
  state.current_native_turn_id = undefined;
3967
+ state.cursor_response_ritual = undefined;
3603
3968
  state.current_turn_span = undefined;
3604
3969
  state.tool_call_count = 0;
3605
3970
  state.tool_call_count_turn_id = undefined;
@@ -3824,7 +4189,12 @@ function acquireStateLease(coordRoot: string, statePath: string) {
3824
4189
  mkdirSync(directory, { recursive: true, mode: 0o700 });
3825
4190
  chmodSync(producerRoot, 0o700);
3826
4191
  chmodSync(directory, 0o700);
3827
- return acquireNoClobberLease({
4192
+ const acquiredControl = readEventV3ControlState(coordRoot);
4193
+ const acquiredGenesis =
4194
+ acquiredControl.state === "candidate" || acquiredControl.state === "active"
4195
+ ? acquiredControl.genesis.event.payload.genesis_id
4196
+ : undefined;
4197
+ const lease = acquireNoClobberLease({
3828
4198
  path: `${statePath}.lease`,
3829
4199
  scope: "event-v3-hook-producer",
3830
4200
  authoritySha256: createHash("sha256")
@@ -3835,9 +4205,32 @@ function acquireStateLease(coordRoot: string, statePath: string) {
3835
4205
  staleAfterMs: 5_000,
3836
4206
  validateStaleOwner: (owner) => owner.host === hostname() && !pidIsAlive(owner.pid),
3837
4207
  });
4208
+ return {
4209
+ ...lease,
4210
+ release() {
4211
+ try {
4212
+ lease.release();
4213
+ } catch (error) {
4214
+ const current = readEventV3ControlState(coordRoot);
4215
+ const epochReplaced =
4216
+ acquiredGenesis !== undefined &&
4217
+ (current.state === "candidate" || current.state === "active") &&
4218
+ current.genesis.event.payload.genesis_id !== acquiredGenesis;
4219
+ if ((error as NodeJS.ErrnoException).code === "ENOENT" && epochReplaced) return;
4220
+ throw error;
4221
+ }
4222
+ },
4223
+ };
3838
4224
  }
3839
4225
 
3840
- function publishProducerState(path: string, state: HookProducerStateV3): void {
4226
+ function publishProducerState(coordRoot: string, path: string, state: HookProducerStateV3): void {
4227
+ const control = readEventV3ControlState(coordRoot);
4228
+ if (
4229
+ (control.state === "candidate" || control.state === "active") &&
4230
+ state.epoch_genesis_id !== control.genesis.event.payload.genesis_id
4231
+ ) {
4232
+ return;
4233
+ }
3841
4234
  const temporary = `${path}.tmp-${process.pid}-${randomUUID()}`;
3842
4235
  let fd: number | undefined;
3843
4236
  try {
@@ -3904,6 +4297,7 @@ function readProducerState(path: string): HookProducerStateV3 {
3904
4297
  "current_native_turn_id",
3905
4298
  "current_turn_span",
3906
4299
  "cursor_mode",
4300
+ "cursor_response_ritual",
3907
4301
  "delegations",
3908
4302
  "epoch_genesis_id",
3909
4303
  "format",
@@ -4021,6 +4415,15 @@ function readProducerState(path: string): HookProducerStateV3 {
4021
4415
  (typeof state.current_native_turn_id !== "string" ||
4022
4416
  state.current_native_turn_id.length === 0 ||
4023
4417
  state.current_native_turn_id.length > 512)) ||
4418
+ (state.cursor_response_ritual !== undefined &&
4419
+ (!/^tid_[a-f0-9]{64}$/.test(state.cursor_response_ritual.turn_id) ||
4420
+ (state.cursor_response_ritual.native_turn_id !== undefined &&
4421
+ (typeof state.cursor_response_ritual.native_turn_id !== "string" ||
4422
+ state.cursor_response_ritual.native_turn_id.length === 0 ||
4423
+ state.cursor_response_ritual.native_turn_id.length > 512)) ||
4424
+ !Number.isFinite(Date.parse(state.cursor_response_ritual.observed_at)) ||
4425
+ typeof state.cursor_response_ritual.status_box_present !== "boolean" ||
4426
+ typeof state.cursor_response_ritual.status_box_present_strict !== "boolean")) ||
4024
4427
  (state.last_event_id !== undefined && !/^evt_[0-9a-f-]{36}$/.test(state.last_event_id)) ||
4025
4428
  (state.last_monotonic_ns !== undefined && !/^\d+$/.test(state.last_monotonic_ns)) ||
4026
4429
  (state.last_observed_at !== undefined &&
@@ -31,10 +31,21 @@ export type SystemEvent =
31
31
  | "PreToolUse"
32
32
  | "PostToolUse";
33
33
 
34
+ /**
35
+ * Whether this adapter can actually receive injected context for an event.
36
+ * Cursor's beforeSubmitPrompt hook can allow or block a turn but cannot inject
37
+ * model context, so anything rendered for that event is discarded. A caller
38
+ * that consumes state to build the text (draining a mailbox, for instance)
39
+ * must check this first, or the state is spent on output nobody reads.
40
+ */
41
+ export function canReceiveContext(adapter: Adapter, event: SystemEvent): boolean {
42
+ return !(adapter === "cursor" && event === "UserPromptSubmit");
43
+ }
44
+
34
45
  /** Emit a context-injection (peer table, wiring check, council pending, …). */
35
46
  export function emitContext(adapter: Adapter, event: SystemEvent, text: string): void {
36
47
  if (!text || text.length === 0) return;
37
- if (adapter === "cursor" && event === "UserPromptSubmit") return;
48
+ if (!canReceiveContext(adapter, event)) return;
38
49
  const json = buildContextJson(adapter, event, text);
39
50
  process.stdout.write(`${JSON.stringify(json)}\n`);
40
51
  }