harnery 0.32.0 → 0.34.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 (665) hide show
  1. package/README.md +2 -0
  2. package/dist/commander.d.ts.map +1 -1
  3. package/dist/commander.js +7 -1
  4. package/dist/commands/adapter.js +2 -2
  5. package/dist/commands/agents.d.ts +144 -1
  6. package/dist/commands/agents.d.ts.map +1 -1
  7. package/dist/commands/agents.js +1408 -565
  8. package/dist/commands/artifacts.d.ts.map +1 -1
  9. package/dist/commands/artifacts.js +7 -6
  10. package/dist/commands/backup.d.ts +1 -1
  11. package/dist/commands/backup.d.ts.map +1 -1
  12. package/dist/commands/backup.js +29 -16
  13. package/dist/commands/browse.d.ts.map +1 -1
  14. package/dist/commands/browse.js +234 -12
  15. package/dist/commands/checkpoint.d.ts.map +1 -1
  16. package/dist/commands/checkpoint.js +3 -2
  17. package/dist/commands/claude-desktop.d.ts +2 -2
  18. package/dist/commands/claude-desktop.d.ts.map +1 -1
  19. package/dist/commands/claude-desktop.js +2 -2
  20. package/dist/commands/context.js +1 -6
  21. package/dist/commands/decision.d.ts.map +1 -1
  22. package/dist/commands/decision.js +22 -38
  23. package/dist/commands/docs.d.ts.map +1 -1
  24. package/dist/commands/docs.js +91 -28
  25. package/dist/commands/doctor.d.ts +4 -2
  26. package/dist/commands/doctor.d.ts.map +1 -1
  27. package/dist/commands/doctor.js +55 -7
  28. package/dist/commands/events.d.ts +5 -0
  29. package/dist/commands/events.d.ts.map +1 -0
  30. package/dist/commands/events.js +189 -0
  31. package/dist/commands/governor.d.ts.map +1 -1
  32. package/dist/commands/governor.js +13 -4
  33. package/dist/commands/init.d.ts +10 -2
  34. package/dist/commands/init.d.ts.map +1 -1
  35. package/dist/commands/init.js +233 -51
  36. package/dist/commands/instructions.d.ts +4 -0
  37. package/dist/commands/instructions.d.ts.map +1 -0
  38. package/dist/commands/instructions.js +100 -0
  39. package/dist/commands/journal.d.ts.map +1 -1
  40. package/dist/commands/journal.js +4 -13
  41. package/dist/commands/ledger-v3.d.ts +5 -0
  42. package/dist/commands/ledger-v3.d.ts.map +1 -0
  43. package/dist/commands/ledger-v3.js +91 -0
  44. package/dist/commands/presence.d.ts.map +1 -1
  45. package/dist/commands/presence.js +15 -6
  46. package/dist/commands/sync.d.ts +1 -1
  47. package/dist/commands/sync.js +1 -1
  48. package/dist/commands/web.d.ts +6 -0
  49. package/dist/commands/web.d.ts.map +1 -1
  50. package/dist/commands/web.js +67 -7
  51. package/dist/commands/work.d.ts.map +1 -1
  52. package/dist/commands/work.js +22 -5
  53. package/dist/core/adapter.d.ts +5 -0
  54. package/dist/core/adapter.d.ts.map +1 -0
  55. package/dist/core/adapter.js +1 -0
  56. package/dist/core/adapters/attest.d.ts +5 -2
  57. package/dist/core/adapters/attest.d.ts.map +1 -1
  58. package/dist/core/adapters/attest.js +8 -3
  59. package/dist/core/adapters/profiles.d.ts +6 -6
  60. package/dist/core/adapters/profiles.d.ts.map +1 -1
  61. package/dist/core/adapters/profiles.js +4 -4
  62. package/dist/core/agents/canonical-emit.d.ts +17 -15
  63. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  64. package/dist/core/agents/canonical-emit.js +27 -25
  65. package/dist/core/agents/cli.js +212 -235
  66. package/dist/core/agents/codex-archive-v3.d.ts +14 -0
  67. package/dist/core/agents/codex-archive-v3.d.ts.map +1 -0
  68. package/dist/core/agents/codex-archive-v3.js +110 -0
  69. package/dist/core/agents/coord-client.d.ts +19 -70
  70. package/dist/core/agents/coord-client.d.ts.map +1 -1
  71. package/dist/core/agents/coord-client.js +65 -155
  72. package/dist/core/agents/finalization.d.ts +4 -1
  73. package/dist/core/agents/finalization.d.ts.map +1 -1
  74. package/dist/core/agents/finalization.js +89 -32
  75. package/dist/core/agents/index.d.ts +5 -5
  76. package/dist/core/agents/index.d.ts.map +1 -1
  77. package/dist/core/agents/index.js +5 -5
  78. package/dist/core/agents/live-authority-v3.d.ts +59 -0
  79. package/dist/core/agents/live-authority-v3.d.ts.map +1 -0
  80. package/dist/core/agents/live-authority-v3.js +233 -0
  81. package/dist/core/agents/live-lifecycle-v3.d.ts +20 -0
  82. package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -0
  83. package/dist/core/agents/live-lifecycle-v3.js +91 -0
  84. package/dist/core/agents/live-observation-v3.d.ts +25 -0
  85. package/dist/core/agents/live-observation-v3.d.ts.map +1 -0
  86. package/dist/core/agents/live-observation-v3.js +157 -0
  87. package/dist/core/agents/render/prompt-context.d.ts +10 -4
  88. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  89. package/dist/core/agents/render/prompt-context.js +61 -55
  90. package/dist/core/agents/render/session-context.d.ts +1 -1
  91. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  92. package/dist/core/agents/render/session-context.js +15 -33
  93. package/dist/core/agents/rules/claim-conflict.d.ts +3 -3
  94. package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
  95. package/dist/core/agents/rules/claim-conflict.js +79 -127
  96. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
  97. package/dist/core/agents/rules/commit-conflict.js +3 -18
  98. package/dist/core/agents/rules/stop-hook.d.ts +9 -50
  99. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  100. package/dist/core/agents/rules/stop-hook.js +193 -236
  101. package/dist/core/agents/session-events.d.ts +5 -7
  102. package/dist/core/agents/session-events.d.ts.map +1 -1
  103. package/dist/core/agents/session-events.js +127 -95
  104. package/dist/core/agents/session-finalization-state-v3.d.ts +30 -0
  105. package/dist/core/agents/session-finalization-state-v3.d.ts.map +1 -0
  106. package/dist/core/agents/session-finalization-state-v3.js +40 -0
  107. package/dist/core/agents/session-finalizer-v3.d.ts +107 -0
  108. package/dist/core/agents/session-finalizer-v3.d.ts.map +1 -0
  109. package/dist/core/agents/session-finalizer-v3.js +734 -0
  110. package/dist/core/agents/session-name-display.d.ts +40 -0
  111. package/dist/core/agents/session-name-display.d.ts.map +1 -0
  112. package/dist/core/agents/session-name-display.js +119 -0
  113. package/dist/core/agents/state/activity-log.d.ts +3 -3
  114. package/dist/core/agents/state/activity-log.d.ts.map +1 -1
  115. package/dist/core/agents/state/activity-log.js +7 -16
  116. package/dist/core/agents/state/heartbeat-writer.d.ts +29 -46
  117. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  118. package/dist/core/agents/state/heartbeat-writer.js +59 -199
  119. package/dist/core/agents/state/live-coordination-view.d.ts +31 -0
  120. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -0
  121. package/dist/core/agents/state/live-coordination-view.js +209 -0
  122. package/dist/core/agents/state/session-state.d.ts +45 -0
  123. package/dist/core/agents/state/session-state.d.ts.map +1 -0
  124. package/dist/core/agents/state/session-state.js +90 -0
  125. package/dist/core/agents/state/stale-sweep.d.ts +1 -1
  126. package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
  127. package/dist/core/agents/state/stale-sweep.js +26 -15
  128. package/dist/core/artifacts/index.d.ts.map +1 -1
  129. package/dist/core/artifacts/index.js +5 -7
  130. package/dist/core/config.d.ts +33 -2
  131. package/dist/core/config.d.ts.map +1 -1
  132. package/dist/core/config.js +98 -2
  133. package/dist/core/context/index.d.ts +1 -4
  134. package/dist/core/context/index.d.ts.map +1 -1
  135. package/dist/core/context/index.js +9 -9
  136. package/dist/core/events/span-parent.d.ts +15 -0
  137. package/dist/core/events/span-parent.d.ts.map +1 -0
  138. package/dist/core/events/span-parent.js +34 -0
  139. package/dist/core/events/v3/advance.d.ts +14 -0
  140. package/dist/core/events/v3/advance.d.ts.map +1 -0
  141. package/dist/core/events/v3/advance.js +134 -0
  142. package/dist/core/events/v3/authority-outbox.d.ts +78 -0
  143. package/dist/core/events/v3/authority-outbox.d.ts.map +1 -0
  144. package/dist/core/events/v3/authority-outbox.js +399 -0
  145. package/dist/core/events/v3/base-builder.d.ts +20 -0
  146. package/dist/core/events/v3/base-builder.d.ts.map +1 -0
  147. package/dist/core/events/v3/base-builder.js +29 -0
  148. package/dist/core/events/v3/base-contract.d.ts +7576 -0
  149. package/dist/core/events/v3/base-contract.d.ts.map +1 -0
  150. package/dist/core/events/v3/base-contract.js +647 -0
  151. package/dist/core/events/v3/bootstrap.d.ts +34 -0
  152. package/dist/core/events/v3/bootstrap.d.ts.map +1 -0
  153. package/dist/core/events/v3/bootstrap.js +175 -0
  154. package/dist/core/events/v3/builder.d.ts +20 -0
  155. package/dist/core/events/v3/builder.d.ts.map +1 -0
  156. package/dist/core/events/v3/builder.js +28 -0
  157. package/dist/core/events/v3/canonical.d.ts +31 -0
  158. package/dist/core/events/v3/canonical.d.ts.map +1 -0
  159. package/dist/core/events/v3/canonical.js +100 -0
  160. package/dist/core/events/v3/capabilities.d.ts +31 -0
  161. package/dist/core/events/v3/capabilities.d.ts.map +1 -0
  162. package/dist/core/events/v3/capabilities.js +107 -0
  163. package/dist/core/events/v3/capability-drift.d.ts +22 -0
  164. package/dist/core/events/v3/capability-drift.d.ts.map +1 -0
  165. package/dist/core/events/v3/capability-drift.js +134 -0
  166. package/dist/core/events/v3/catalog.d.ts +38 -0
  167. package/dist/core/events/v3/catalog.d.ts.map +1 -0
  168. package/dist/core/events/v3/catalog.js +135 -0
  169. package/dist/core/events/v3/clock-order.d.ts +34 -0
  170. package/dist/core/events/v3/clock-order.d.ts.map +1 -0
  171. package/dist/core/events/v3/clock-order.js +35 -0
  172. package/dist/core/events/v3/contract.d.ts +171 -0
  173. package/dist/core/events/v3/contract.d.ts.map +1 -0
  174. package/dist/core/events/v3/contract.js +180 -0
  175. package/dist/core/events/v3/control.d.ts +111 -0
  176. package/dist/core/events/v3/control.d.ts.map +1 -0
  177. package/dist/core/events/v3/control.js +419 -0
  178. package/dist/core/events/v3/coordination-view.d.ts +69 -0
  179. package/dist/core/events/v3/coordination-view.d.ts.map +1 -0
  180. package/dist/core/events/v3/coordination-view.js +119 -0
  181. package/dist/core/events/v3/economics.d.ts +77 -0
  182. package/dist/core/events/v3/economics.d.ts.map +1 -0
  183. package/dist/core/events/v3/economics.js +274 -0
  184. package/dist/core/events/v3/finalization-view.d.ts +26 -0
  185. package/dist/core/events/v3/finalization-view.d.ts.map +1 -0
  186. package/dist/core/events/v3/finalization-view.js +37 -0
  187. package/dist/core/events/v3/fingerprint-keys.d.ts +25 -0
  188. package/dist/core/events/v3/fingerprint-keys.d.ts.map +1 -0
  189. package/dist/core/events/v3/fingerprint-keys.js +217 -0
  190. package/dist/core/events/v3/generated.d.ts +4 -0
  191. package/dist/core/events/v3/generated.d.ts.map +1 -0
  192. package/dist/core/events/v3/generated.js +47 -0
  193. package/dist/core/events/v3/ids.d.ts +9 -0
  194. package/dist/core/events/v3/ids.d.ts.map +1 -0
  195. package/dist/core/events/v3/ids.js +25 -0
  196. package/dist/core/events/v3/index.d.ts +35 -0
  197. package/dist/core/events/v3/index.d.ts.map +1 -0
  198. package/dist/core/events/v3/index.js +33 -0
  199. package/dist/core/events/v3/latency.d.ts +63 -0
  200. package/dist/core/events/v3/latency.d.ts.map +1 -0
  201. package/dist/core/events/v3/latency.js +412 -0
  202. package/dist/core/events/v3/live-feed.d.ts +45 -0
  203. package/dist/core/events/v3/live-feed.d.ts.map +1 -0
  204. package/dist/core/events/v3/live-feed.js +246 -0
  205. package/dist/core/events/v3/live-observation.d.ts +35 -0
  206. package/dist/core/events/v3/live-observation.d.ts.map +1 -0
  207. package/dist/core/events/v3/live-observation.js +1 -0
  208. package/dist/core/events/v3/live-routing.d.ts +57 -0
  209. package/dist/core/events/v3/live-routing.d.ts.map +1 -0
  210. package/dist/core/events/v3/live-routing.js +107 -0
  211. package/dist/core/events/v3/producers/command-recorder.d.ts +67 -0
  212. package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -0
  213. package/dist/core/events/v3/producers/command-recorder.js +477 -0
  214. package/dist/core/events/v3/producers/command.d.ts +50 -0
  215. package/dist/core/events/v3/producers/command.d.ts.map +1 -0
  216. package/dist/core/events/v3/producers/command.js +135 -0
  217. package/dist/core/events/v3/producers/coordination-recorder.d.ts +53 -0
  218. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -0
  219. package/dist/core/events/v3/producers/coordination-recorder.js +376 -0
  220. package/dist/core/events/v3/producers/coordination.d.ts +90 -0
  221. package/dist/core/events/v3/producers/coordination.d.ts.map +1 -0
  222. package/dist/core/events/v3/producers/coordination.js +229 -0
  223. package/dist/core/events/v3/producers/hook-base.d.ts +54 -0
  224. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -0
  225. package/dist/core/events/v3/producers/hook-base.js +424 -0
  226. package/dist/core/events/v3/producers/hook.d.ts +29 -0
  227. package/dist/core/events/v3/producers/hook.d.ts.map +1 -0
  228. package/dist/core/events/v3/producers/hook.js +71 -0
  229. package/dist/core/events/v3/producers/intake.d.ts +65 -0
  230. package/dist/core/events/v3/producers/intake.d.ts.map +1 -0
  231. package/dist/core/events/v3/producers/intake.js +244 -0
  232. package/dist/core/events/v3/producers/recorder.d.ts +240 -0
  233. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -0
  234. package/dist/core/events/v3/producers/recorder.js +2176 -0
  235. package/dist/core/events/v3/projection.d.ts +101 -0
  236. package/dist/core/events/v3/projection.d.ts.map +1 -0
  237. package/dist/core/events/v3/projection.js +479 -0
  238. package/dist/core/events/v3/reader.d.ts +75 -0
  239. package/dist/core/events/v3/reader.d.ts.map +1 -0
  240. package/dist/core/events/v3/reader.js +778 -0
  241. package/dist/core/events/v3/recovery-record.d.ts +47 -0
  242. package/dist/core/events/v3/recovery-record.d.ts.map +1 -0
  243. package/dist/core/events/v3/recovery-record.js +167 -0
  244. package/dist/core/events/v3/recovery.d.ts +22 -0
  245. package/dist/core/events/v3/recovery.d.ts.map +1 -0
  246. package/dist/core/events/v3/recovery.js +227 -0
  247. package/dist/core/events/v3/span-state.d.ts +52 -0
  248. package/dist/core/events/v3/span-state.d.ts.map +1 -0
  249. package/dist/core/events/v3/span-state.js +142 -0
  250. package/dist/core/events/v3/targets.d.ts +23 -0
  251. package/dist/core/events/v3/targets.d.ts.map +1 -0
  252. package/dist/core/events/v3/targets.js +134 -0
  253. package/dist/core/events/v3/turn-telemetry.d.ts +41 -0
  254. package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -0
  255. package/dist/core/events/v3/turn-telemetry.js +168 -0
  256. package/dist/core/events/v3/validate.d.ts +9 -0
  257. package/dist/core/events/v3/validate.d.ts.map +1 -0
  258. package/dist/core/events/v3/validate.js +281 -0
  259. package/dist/core/events/v3/writer.d.ts +56 -0
  260. package/dist/core/events/v3/writer.d.ts.map +1 -0
  261. package/dist/core/events/v3/writer.js +335 -0
  262. package/dist/core/governor/index.d.ts +1 -1
  263. package/dist/core/governor/index.d.ts.map +1 -1
  264. package/dist/core/governor/index.js +1 -1
  265. package/dist/core/governor/plan-api.d.ts +2 -1
  266. package/dist/core/governor/plan-api.d.ts.map +1 -1
  267. package/dist/core/governor/plan-api.js +6 -3
  268. package/dist/core/governor/read.d.ts +1 -1
  269. package/dist/core/governor/read.d.ts.map +1 -1
  270. package/dist/core/governor/read.js +1 -1
  271. package/dist/core/governor/state.d.ts +9 -0
  272. package/dist/core/governor/state.d.ts.map +1 -1
  273. package/dist/core/governor/state.js +40 -3
  274. package/dist/core/guard/config.d.ts +5 -0
  275. package/dist/core/guard/config.d.ts.map +1 -0
  276. package/dist/core/guard/config.js +157 -0
  277. package/dist/core/guard/coordinator.d.ts +14 -0
  278. package/dist/core/guard/coordinator.d.ts.map +1 -0
  279. package/dist/core/guard/coordinator.js +173 -0
  280. package/dist/core/guard/evaluator.d.ts +4 -0
  281. package/dist/core/guard/evaluator.d.ts.map +1 -0
  282. package/dist/core/guard/evaluator.js +242 -0
  283. package/dist/core/guard/evidence-v3.d.ts +15 -0
  284. package/dist/core/guard/evidence-v3.d.ts.map +1 -0
  285. package/dist/core/guard/evidence-v3.js +171 -0
  286. package/dist/core/guard/index.d.ts +10 -0
  287. package/dist/core/guard/index.d.ts.map +1 -0
  288. package/dist/core/guard/index.js +6 -0
  289. package/dist/core/guard/live-source-v3.d.ts +40 -0
  290. package/dist/core/guard/live-source-v3.d.ts.map +1 -0
  291. package/dist/core/guard/live-source-v3.js +128 -0
  292. package/dist/core/guard/storage.d.ts +27 -0
  293. package/dist/core/guard/storage.d.ts.map +1 -0
  294. package/dist/core/guard/storage.js +140 -0
  295. package/dist/core/guard/types.d.ts +119 -0
  296. package/dist/core/guard/types.d.ts.map +1 -0
  297. package/dist/core/guard/types.js +1 -0
  298. package/dist/core/hooks/adapter/detect.d.ts +18 -1
  299. package/dist/core/hooks/adapter/detect.d.ts.map +1 -1
  300. package/dist/core/hooks/adapter/detect.js +29 -0
  301. package/dist/core/hooks/adapter/events.d.ts +7 -4
  302. package/dist/core/hooks/adapter/events.d.ts.map +1 -1
  303. package/dist/core/hooks/adapter/events.js +13 -4
  304. package/dist/core/hooks/adapter/output.d.ts +2 -2
  305. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  306. package/dist/core/hooks/adapter/parse.d.ts +7 -4
  307. package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
  308. package/dist/core/hooks/adapter/parse.js +64 -24
  309. package/dist/core/hooks/adapter/wiring.d.ts +30 -4
  310. package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
  311. package/dist/core/hooks/adapter/wiring.js +89 -11
  312. package/dist/core/hooks/cli.d.ts +1 -1
  313. package/dist/core/hooks/cli.js +345 -400
  314. package/dist/core/hooks/codex-authorization.d.ts +30 -0
  315. package/dist/core/hooks/codex-authorization.d.ts.map +1 -0
  316. package/dist/core/hooks/codex-authorization.js +199 -0
  317. package/dist/core/hooks/effects/image-capture.d.ts +20 -34
  318. package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
  319. package/dist/core/hooks/effects/image-capture.js +212 -221
  320. package/dist/core/hooks/effects/index.d.ts +1 -9
  321. package/dist/core/hooks/effects/index.d.ts.map +1 -1
  322. package/dist/core/hooks/effects/index.js +1 -24
  323. package/dist/core/hooks/events/input-hash.d.ts +7 -0
  324. package/dist/core/hooks/events/input-hash.d.ts.map +1 -0
  325. package/dist/core/hooks/events/input-hash.js +43 -0
  326. package/dist/core/hooks/index.d.ts +4 -3
  327. package/dist/core/hooks/index.d.ts.map +1 -1
  328. package/dist/core/hooks/index.js +2 -3
  329. package/dist/core/hooks/resolve/coord-root.d.ts +1 -1
  330. package/dist/core/hooks/resolve/coord-root.js +1 -1
  331. package/dist/core/hooks/resolve/owner.d.ts +16 -15
  332. package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
  333. package/dist/core/hooks/resolve/owner.js +51 -42
  334. package/dist/core/hooks/resolve/transcript.d.ts +33 -3
  335. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  336. package/dist/core/hooks/resolve/transcript.js +155 -14
  337. package/dist/core/hooks/session-name-presence.d.ts +9 -10
  338. package/dist/core/hooks/session-name-presence.d.ts.map +1 -1
  339. package/dist/core/hooks/session-name-presence.js +15 -15
  340. package/dist/core/hooks/unsafe-cross-shell.d.ts +1 -1
  341. package/dist/core/hooks/unsafe-cross-shell.d.ts.map +1 -1
  342. package/dist/core/journal/index.d.ts +2 -2
  343. package/dist/core/journal/index.d.ts.map +1 -1
  344. package/dist/core/journal/index.js +9 -22
  345. package/dist/core/presence/blob.d.ts +8 -3
  346. package/dist/core/presence/blob.d.ts.map +1 -1
  347. package/dist/core/presence/blob.js +54 -41
  348. package/dist/core/presence/codec-digest.d.ts +29 -0
  349. package/dist/core/presence/codec-digest.d.ts.map +1 -0
  350. package/dist/core/presence/codec-digest.js +170 -0
  351. package/dist/core/presence/index.js +15 -1
  352. package/dist/core/presence/relay-client.d.ts +1 -1
  353. package/dist/core/presence/relay-client.d.ts.map +1 -1
  354. package/dist/core/presence/relay-client.js +5 -5
  355. package/dist/core/work/index.d.ts +1 -1
  356. package/dist/core/work/index.d.ts.map +1 -1
  357. package/dist/core/work/index.js +1 -1
  358. package/dist/core/work/read.d.ts +1 -1
  359. package/dist/core/work/read.d.ts.map +1 -1
  360. package/dist/core/work/read.js +1 -1
  361. package/dist/core/work/runner.d.ts.map +1 -1
  362. package/dist/core/work/runner.js +6 -0
  363. package/dist/core/work/state.d.ts +9 -0
  364. package/dist/core/work/state.d.ts.map +1 -1
  365. package/dist/core/work/state.js +17 -3
  366. package/dist/core/workflow/engine.js +24 -25
  367. package/dist/core/workflow/live-session-v3.d.ts +19 -0
  368. package/dist/core/workflow/live-session-v3.d.ts.map +1 -0
  369. package/dist/core/workflow/live-session-v3.js +86 -0
  370. package/dist/core/workflow/scope-id.d.ts +3 -0
  371. package/dist/core/workflow/scope-id.d.ts.map +1 -0
  372. package/dist/core/workflow/scope-id.js +5 -0
  373. package/dist/core/workflow/workspaces/leases.d.ts +4 -0
  374. package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
  375. package/dist/core/workflow/workspaces/leases.js +53 -19
  376. package/dist/index.d.ts +1 -1
  377. package/dist/index.js +1 -1
  378. package/dist/lib/browser/client.d.ts +41 -0
  379. package/dist/lib/browser/client.d.ts.map +1 -1
  380. package/dist/lib/browser/client.js +203 -0
  381. package/dist/lib/browser/critique.d.ts +28 -2
  382. package/dist/lib/browser/critique.d.ts.map +1 -1
  383. package/dist/lib/browser/critique.js +74 -18
  384. package/dist/lib/browser/geometry.d.ts +1 -1
  385. package/dist/lib/browser/geometry.d.ts.map +1 -1
  386. package/dist/lib/browser/geometry.js +130 -6
  387. package/dist/lib/browser/index.d.ts +3 -0
  388. package/dist/lib/browser/index.d.ts.map +1 -1
  389. package/dist/lib/browser/index.js +3 -0
  390. package/dist/lib/browser/qa-plan.d.ts +174 -0
  391. package/dist/lib/browser/qa-plan.d.ts.map +1 -0
  392. package/dist/lib/browser/qa-plan.js +321 -0
  393. package/dist/lib/browser/qa-reuse.d.ts +99 -0
  394. package/dist/lib/browser/qa-reuse.d.ts.map +1 -0
  395. package/dist/lib/browser/qa-reuse.js +222 -0
  396. package/dist/lib/browser/qa-snapshot.d.ts +64 -0
  397. package/dist/lib/browser/qa-snapshot.d.ts.map +1 -0
  398. package/dist/lib/browser/qa-snapshot.js +171 -0
  399. package/dist/lib/browser/runts.d.ts.map +1 -1
  400. package/dist/lib/browser/runts.js +22 -1
  401. package/dist/lib/browser/tiling.d.ts +71 -0
  402. package/dist/lib/browser/tiling.d.ts.map +1 -0
  403. package/dist/lib/browser/tiling.js +118 -0
  404. package/dist/lib/context/index.d.ts +0 -3
  405. package/dist/lib/context/index.d.ts.map +1 -1
  406. package/dist/lib/context/index.js +20 -42
  407. package/dist/lib/council/index.d.ts +2 -2
  408. package/dist/lib/council/index.d.ts.map +1 -1
  409. package/dist/lib/council/index.js +9 -20
  410. package/dist/lib/docs-frontmatter.d.ts +1 -6
  411. package/dist/lib/docs-frontmatter.d.ts.map +1 -1
  412. package/dist/lib/docs-frontmatter.js +12 -78
  413. package/dist/lib/docs-index.d.ts +9 -0
  414. package/dist/lib/docs-index.d.ts.map +1 -1
  415. package/dist/lib/docs-index.js +32 -3
  416. package/dist/lib/docs-lint.d.ts.map +1 -1
  417. package/dist/lib/docs-lint.js +14 -30
  418. package/dist/lib/docs-metadata-audit.d.ts +19 -0
  419. package/dist/lib/docs-metadata-audit.d.ts.map +1 -0
  420. package/dist/lib/docs-metadata-audit.js +132 -0
  421. package/dist/lib/docs-metadata-managed.d.ts +23 -0
  422. package/dist/lib/docs-metadata-managed.d.ts.map +1 -0
  423. package/dist/lib/docs-metadata-managed.js +78 -0
  424. package/dist/lib/docs-metadata-sync.d.ts +20 -0
  425. package/dist/lib/docs-metadata-sync.d.ts.map +1 -0
  426. package/dist/lib/docs-metadata-sync.js +222 -0
  427. package/dist/lib/docs-metadata-v2-schema.d.ts +273 -0
  428. package/dist/lib/docs-metadata-v2-schema.d.ts.map +1 -0
  429. package/dist/lib/docs-metadata-v2-schema.js +134 -0
  430. package/dist/lib/docs-metadata-v2.d.ts +21 -0
  431. package/dist/lib/docs-metadata-v2.d.ts.map +1 -0
  432. package/dist/lib/docs-metadata-v2.js +424 -0
  433. package/dist/lib/docs-new.d.ts +11 -0
  434. package/dist/lib/docs-new.d.ts.map +1 -0
  435. package/dist/lib/docs-new.js +52 -0
  436. package/dist/lib/docs-sweep.d.ts.map +1 -1
  437. package/dist/lib/docs-sweep.js +45 -29
  438. package/dist/lib/headless/index.d.ts +98 -0
  439. package/dist/lib/headless/index.d.ts.map +1 -0
  440. package/dist/lib/headless/index.js +211 -0
  441. package/dist/lib/identities/assume.d.ts +4 -4
  442. package/dist/lib/identities/assume.d.ts.map +1 -1
  443. package/dist/lib/identities/assume.js +52 -68
  444. package/dist/lib/instructions/apply.d.ts +5 -4
  445. package/dist/lib/instructions/apply.d.ts.map +1 -1
  446. package/dist/lib/instructions/apply.js +32 -20
  447. package/dist/lib/instructions/bundle.d.ts +33 -0
  448. package/dist/lib/instructions/bundle.d.ts.map +1 -0
  449. package/dist/lib/instructions/bundle.js +149 -0
  450. package/dist/lib/instructions/splice.d.ts +0 -1
  451. package/dist/lib/instructions/splice.d.ts.map +1 -1
  452. package/dist/lib/instructions/splice.js +22 -6
  453. package/dist/lib/instructions/templates.d.ts +7 -5
  454. package/dist/lib/instructions/templates.d.ts.map +1 -1
  455. package/dist/lib/instructions/templates.js +79 -9
  456. package/package.json +27 -6
  457. package/schemas/config.schema.json +120 -2
  458. package/schemas/docs-metadata-v2.schema.json +441 -0
  459. package/schemas/event-v3.schema.json +24472 -0
  460. package/src/commander.ts +7 -1
  461. package/src/commands/adapter.ts +2 -2
  462. package/src/commands/agents.ts +1737 -570
  463. package/src/commands/artifacts.ts +7 -6
  464. package/src/commands/backup.ts +29 -21
  465. package/src/commands/browse.ts +349 -8
  466. package/src/commands/checkpoint.ts +4 -3
  467. package/src/commands/claude-desktop.ts +7 -5
  468. package/src/commands/context.ts +1 -6
  469. package/src/commands/decision.ts +27 -44
  470. package/src/commands/docs.ts +100 -33
  471. package/src/commands/doctor.ts +73 -8
  472. package/src/commands/events.ts +256 -0
  473. package/src/commands/governor.ts +18 -4
  474. package/src/commands/init.ts +264 -57
  475. package/src/commands/instructions.ts +129 -0
  476. package/src/commands/journal.ts +4 -13
  477. package/src/commands/ledger-v3.ts +111 -0
  478. package/src/commands/presence.ts +18 -11
  479. package/src/commands/sync.ts +1 -1
  480. package/src/commands/web.ts +67 -8
  481. package/src/commands/work.ts +28 -5
  482. package/src/core/adapter.ts +5 -0
  483. package/src/core/adapters/attest.ts +8 -3
  484. package/src/core/adapters/profiles.ts +4 -6
  485. package/src/core/agents/canonical-emit.ts +39 -28
  486. package/src/core/agents/cli.ts +242 -263
  487. package/src/core/agents/codex-archive-v3.ts +138 -0
  488. package/src/core/agents/coord-client.ts +75 -177
  489. package/src/core/agents/finalization.ts +120 -38
  490. package/src/core/agents/index.ts +5 -5
  491. package/src/core/agents/live-authority-v3.ts +375 -0
  492. package/src/core/agents/live-lifecycle-v3.ts +140 -0
  493. package/src/core/agents/live-observation-v3.ts +216 -0
  494. package/src/core/agents/render/prompt-context.ts +89 -55
  495. package/src/core/agents/render/session-context.ts +23 -32
  496. package/src/core/agents/rules/claim-conflict.ts +85 -126
  497. package/src/core/agents/rules/commit-conflict.ts +3 -14
  498. package/src/core/agents/rules/stop-hook.ts +239 -293
  499. package/src/core/agents/session-events.ts +137 -104
  500. package/src/core/agents/session-finalization-state-v3.ts +90 -0
  501. package/src/core/agents/session-finalizer-v3.ts +953 -0
  502. package/src/core/agents/session-name-display.ts +149 -0
  503. package/src/core/agents/state/activity-log.ts +6 -14
  504. package/src/core/agents/state/heartbeat-writer.ts +98 -242
  505. package/src/core/agents/state/live-coordination-view.ts +290 -0
  506. package/src/core/agents/state/session-state.ts +143 -0
  507. package/src/core/agents/state/stale-sweep.ts +40 -17
  508. package/src/core/artifacts/index.ts +4 -5
  509. package/src/core/config.ts +148 -3
  510. package/src/core/context/index.ts +9 -17
  511. package/src/core/events/span-parent.ts +46 -0
  512. package/src/core/events/v3/advance.ts +168 -0
  513. package/src/core/events/v3/authority-outbox.ts +548 -0
  514. package/src/core/events/v3/base-builder.ts +60 -0
  515. package/src/core/events/v3/base-contract.ts +882 -0
  516. package/src/core/events/v3/bootstrap.ts +226 -0
  517. package/src/core/events/v3/builder.ts +59 -0
  518. package/src/core/events/v3/canonical.ts +153 -0
  519. package/src/core/events/v3/capabilities.ts +171 -0
  520. package/src/core/events/v3/capability-drift.ts +177 -0
  521. package/src/core/events/v3/catalog.ts +202 -0
  522. package/src/core/events/v3/clock-order.ts +41 -0
  523. package/src/core/events/v3/contract.ts +365 -0
  524. package/src/core/events/v3/control.ts +576 -0
  525. package/src/core/events/v3/coordination-view.ts +193 -0
  526. package/src/core/events/v3/economics.ts +384 -0
  527. package/src/core/events/v3/finalization-view.ts +67 -0
  528. package/src/core/events/v3/fingerprint-keys.ts +260 -0
  529. package/src/core/events/v3/generated.ts +48 -0
  530. package/src/core/events/v3/ids.ts +33 -0
  531. package/src/core/events/v3/index.ts +322 -0
  532. package/src/core/events/v3/latency.ts +551 -0
  533. package/src/core/events/v3/live-feed.ts +319 -0
  534. package/src/core/events/v3/live-observation.ts +39 -0
  535. package/src/core/events/v3/live-routing.ts +135 -0
  536. package/src/core/events/v3/producers/command-recorder.ts +631 -0
  537. package/src/core/events/v3/producers/command.ts +201 -0
  538. package/src/core/events/v3/producers/coordination-recorder.ts +538 -0
  539. package/src/core/events/v3/producers/coordination.ts +355 -0
  540. package/src/core/events/v3/producers/hook-base.ts +578 -0
  541. package/src/core/events/v3/producers/hook.ts +119 -0
  542. package/src/core/events/v3/producers/intake.ts +319 -0
  543. package/src/core/events/v3/producers/recorder.ts +2805 -0
  544. package/src/core/events/v3/projection.ts +653 -0
  545. package/src/core/events/v3/reader.ts +1127 -0
  546. package/src/core/events/v3/recovery-record.ts +244 -0
  547. package/src/core/events/v3/recovery.ts +271 -0
  548. package/src/core/events/v3/span-state.ts +187 -0
  549. package/src/core/events/v3/targets.ts +182 -0
  550. package/src/core/events/v3/turn-telemetry.ts +259 -0
  551. package/src/core/events/v3/validate.ts +361 -0
  552. package/src/core/events/v3/writer.ts +419 -0
  553. package/src/core/governor/index.ts +3 -0
  554. package/src/core/governor/plan-api.ts +10 -2
  555. package/src/core/governor/read.ts +3 -0
  556. package/src/core/governor/state.ts +52 -5
  557. package/src/core/guard/config.ts +206 -0
  558. package/src/core/guard/coordinator.ts +227 -0
  559. package/src/core/guard/evaluator.ts +343 -0
  560. package/src/core/guard/evidence-v3.ts +227 -0
  561. package/src/core/guard/index.ts +35 -0
  562. package/src/core/guard/live-source-v3.ts +204 -0
  563. package/src/core/guard/storage.ts +188 -0
  564. package/src/core/guard/types.ts +152 -0
  565. package/src/core/hooks/adapter/detect.ts +28 -1
  566. package/src/core/hooks/adapter/events.ts +15 -6
  567. package/src/core/hooks/adapter/output.ts +7 -2
  568. package/src/core/hooks/adapter/parse.ts +81 -36
  569. package/src/core/hooks/adapter/wiring.ts +119 -13
  570. package/src/core/hooks/cli.ts +398 -422
  571. package/src/core/hooks/codex-authorization.ts +253 -0
  572. package/src/core/hooks/effects/image-capture.ts +228 -238
  573. package/src/core/hooks/effects/index.ts +1 -36
  574. package/src/core/hooks/events/input-hash.ts +47 -0
  575. package/src/core/hooks/index.ts +4 -11
  576. package/src/core/hooks/resolve/coord-root.ts +1 -1
  577. package/src/core/hooks/resolve/owner.ts +52 -45
  578. package/src/core/hooks/resolve/transcript.ts +165 -14
  579. package/src/core/hooks/session-name-presence.ts +14 -15
  580. package/src/core/hooks/unsafe-cross-shell.ts +1 -1
  581. package/src/core/journal/index.ts +15 -22
  582. package/src/core/presence/blob.ts +63 -38
  583. package/src/core/presence/codec-digest.ts +215 -0
  584. package/src/core/presence/index.ts +18 -1
  585. package/src/core/presence/relay-client.ts +5 -5
  586. package/src/core/work/index.ts +3 -0
  587. package/src/core/work/read.ts +3 -0
  588. package/src/core/work/runner.ts +6 -0
  589. package/src/core/work/state.ts +27 -3
  590. package/src/core/workflow/engine.ts +24 -24
  591. package/src/core/workflow/live-session-v3.ts +126 -0
  592. package/src/core/workflow/scope-id.ts +6 -0
  593. package/src/core/workflow/workspaces/leases.ts +56 -19
  594. package/src/index.ts +1 -1
  595. package/src/lib/browser/client.ts +230 -0
  596. package/src/lib/browser/critique.ts +104 -27
  597. package/src/lib/browser/geometry.ts +143 -14
  598. package/src/lib/browser/index.ts +34 -0
  599. package/src/lib/browser/qa-plan.ts +501 -0
  600. package/src/lib/browser/qa-reuse.ts +306 -0
  601. package/src/lib/browser/qa-snapshot.ts +223 -0
  602. package/src/lib/browser/runts.ts +27 -2
  603. package/src/lib/browser/tiling.ts +164 -0
  604. package/src/lib/context/index.ts +22 -46
  605. package/src/lib/council/index.ts +9 -21
  606. package/src/lib/docs-frontmatter.ts +8 -79
  607. package/src/lib/docs-index.ts +33 -3
  608. package/src/lib/docs-lint.ts +15 -29
  609. package/src/lib/docs-metadata-audit.ts +166 -0
  610. package/src/lib/docs-metadata-managed.ts +83 -0
  611. package/src/lib/docs-metadata-sync.ts +262 -0
  612. package/src/lib/docs-metadata-v2-schema.ts +138 -0
  613. package/src/lib/docs-metadata-v2.ts +646 -0
  614. package/src/lib/docs-new.ts +63 -0
  615. package/src/lib/docs-sweep.ts +42 -28
  616. package/src/lib/headless/index.ts +287 -0
  617. package/src/lib/identities/assume.ts +67 -86
  618. package/src/lib/instructions/apply.ts +33 -20
  619. package/src/lib/instructions/bundle.ts +199 -0
  620. package/src/lib/instructions/splice.ts +21 -7
  621. package/src/lib/instructions/templates.ts +85 -13
  622. package/dist/core/agents/cli-emit.d.ts +0 -27
  623. package/dist/core/agents/cli-emit.d.ts.map +0 -1
  624. package/dist/core/agents/cli-emit.js +0 -57
  625. package/dist/core/agents/codex-replay.d.ts +0 -29
  626. package/dist/core/agents/codex-replay.d.ts.map +0 -1
  627. package/dist/core/agents/codex-replay.js +0 -138
  628. package/dist/core/agents/events/consume.d.ts +0 -82
  629. package/dist/core/agents/events/consume.d.ts.map +0 -1
  630. package/dist/core/agents/events/consume.js +0 -195
  631. package/dist/core/agents/events/emit.d.ts +0 -42
  632. package/dist/core/agents/events/emit.d.ts.map +0 -1
  633. package/dist/core/agents/events/emit.js +0 -75
  634. package/dist/core/agents/events/ulid.d.ts +0 -11
  635. package/dist/core/agents/events/ulid.d.ts.map +0 -1
  636. package/dist/core/agents/events/ulid.js +0 -47
  637. package/dist/core/agents/state/heartbeat-projector.d.ts +0 -65
  638. package/dist/core/agents/state/heartbeat-projector.d.ts.map +0 -1
  639. package/dist/core/agents/state/heartbeat-projector.js +0 -527
  640. package/dist/core/hooks/events/emit.d.ts +0 -31
  641. package/dist/core/hooks/events/emit.d.ts.map +0 -1
  642. package/dist/core/hooks/events/emit.js +0 -93
  643. package/dist/core/hooks/events/rotate.d.ts +0 -43
  644. package/dist/core/hooks/events/rotate.d.ts.map +0 -1
  645. package/dist/core/hooks/events/rotate.js +0 -142
  646. package/dist/core/hooks/events/schema.d.ts +0 -312
  647. package/dist/core/hooks/events/schema.d.ts.map +0 -1
  648. package/dist/core/hooks/events/schema.js +0 -12
  649. package/dist/core/hooks/events/ulid.d.ts +0 -10
  650. package/dist/core/hooks/events/ulid.d.ts.map +0 -1
  651. package/dist/core/hooks/events/ulid.js +0 -47
  652. package/dist/lib/docs-frontmatter-migrate.d.ts +0 -33
  653. package/dist/lib/docs-frontmatter-migrate.d.ts.map +0 -1
  654. package/dist/lib/docs-frontmatter-migrate.js +0 -364
  655. package/src/core/agents/cli-emit.ts +0 -64
  656. package/src/core/agents/codex-replay.ts +0 -163
  657. package/src/core/agents/events/consume.ts +0 -254
  658. package/src/core/agents/events/emit.ts +0 -115
  659. package/src/core/agents/events/ulid.ts +0 -51
  660. package/src/core/agents/state/heartbeat-projector.ts +0 -582
  661. package/src/core/hooks/events/emit.ts +0 -125
  662. package/src/core/hooks/events/rotate.ts +0 -151
  663. package/src/core/hooks/events/schema.ts +0 -538
  664. package/src/core/hooks/events/ulid.ts +0 -51
  665. package/src/lib/docs-frontmatter-migrate.ts +0 -427
@@ -1,6 +1,6 @@
1
1
  import { existsSync as __existsSyncForDocs } from "node:fs";
2
2
  import { resolve as __resolveForDocs } from "node:path";
3
- import { readDocStatus } from "./docs-frontmatter.ts";
3
+ import { parseFrontmatter, readDocStatus } from "./docs-frontmatter.ts";
4
4
  import { sh } from "./exec.ts";
5
5
 
6
6
  // Module-level docs context, initialized by initDocsContext() before any
@@ -22,7 +22,7 @@ function isSubmoduleInitialized(name: string): boolean {
22
22
  return __existsSyncForDocs(__resolveForDocs(REPO_ROOT, name, ".git"));
23
23
  }
24
24
 
25
- import { existsSync, readdirSync, statSync } from "node:fs";
25
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
26
26
  import { join, relative } from "node:path";
27
27
 
28
28
  /**
@@ -141,7 +141,18 @@ function walkMdFiles(dir: string, skipReadme = false): string[] {
141
141
  return out;
142
142
  }
143
143
 
144
- function sweepPlans(repoName: string, repoPath: string, ages: AgeMap, items: SweepItem[]): void {
144
+ function metadataAgeDays(file: string, field: string, nowMs = Date.now()): number | null {
145
+ try {
146
+ const value = parseFrontmatter(readFileSync(file, "utf8")).data[field];
147
+ if (typeof value !== "string") return null;
148
+ const parsed = Date.parse(value);
149
+ return Number.isNaN(parsed) ? null : Math.floor((nowMs - parsed) / (1000 * 60 * 60 * 24));
150
+ } catch {
151
+ return null;
152
+ }
153
+ }
154
+
155
+ function sweepPlans(repoName: string, repoPath: string, items: SweepItem[]): void {
145
156
  const plansDir = join(repoPath, "docs", "plans");
146
157
  if (!existsSync(plansDir)) return;
147
158
 
@@ -150,7 +161,7 @@ function sweepPlans(repoName: string, repoPath: string, ages: AgeMap, items: Swe
150
161
  const displayPath = join(repoName === "(root)" ? "" : repoName, rel);
151
162
  const isArchived = rel.includes("/archive/");
152
163
  const status = readDocStatus(full, "plan");
153
- const age = ageDays(ages, rel);
164
+ const age = metadataAgeDays(full, "status_changed_at");
154
165
  if (age == null) continue;
155
166
 
156
167
  if (!isArchived && status === "in-progress" && age > STALLED_PLAN_DAYS) {
@@ -159,7 +170,7 @@ function sweepPlans(repoName: string, repoPath: string, ages: AgeMap, items: Swe
159
170
  repo: repoName,
160
171
  path: displayPath,
161
172
  ageDays: age,
162
- message: `plan is in-progress, last touched ${age}d ago; confirm still active or bump status`,
173
+ message: `plan has remained in-progress for ${age}d; confirm it is still active or change status`,
163
174
  });
164
175
  }
165
176
  if (!isArchived && status === "shipped" && age > UNARCHIVED_SHIPPED_DAYS) {
@@ -174,7 +185,7 @@ function sweepPlans(repoName: string, repoPath: string, ages: AgeMap, items: Swe
174
185
  }
175
186
  }
176
187
 
177
- function sweepIssues(repoName: string, repoPath: string, ages: AgeMap, items: SweepItem[]): void {
188
+ function sweepIssues(repoName: string, repoPath: string, items: SweepItem[]): void {
178
189
  const issuesDir = join(repoPath, "docs", "issues");
179
190
  if (!existsSync(issuesDir)) return;
180
191
 
@@ -185,7 +196,7 @@ function sweepIssues(repoName: string, repoPath: string, ages: AgeMap, items: Sw
185
196
  const displayPath = join(repoName === "(root)" ? "" : repoName, rel);
186
197
  const status = readDocStatus(full, "issue");
187
198
  if (status !== "open") continue;
188
- const age = ageDays(ages, rel);
199
+ const age = metadataAgeDays(full, "status_changed_at");
189
200
  if (age == null || age <= OPEN_ISSUE_DAYS) continue;
190
201
  items.push({
191
202
  kind: "open-issue-cold",
@@ -197,7 +208,7 @@ function sweepIssues(repoName: string, repoPath: string, ages: AgeMap, items: Sw
197
208
  }
198
209
  }
199
210
 
200
- function sweepHandoffs(repoName: string, repoPath: string, ages: AgeMap, items: SweepItem[]): void {
211
+ function sweepHandoffs(repoName: string, repoPath: string, items: SweepItem[]): void {
201
212
  const handoffsDir = join(repoPath, "docs", "handoffs");
202
213
  if (!existsSync(handoffsDir)) return;
203
214
 
@@ -205,7 +216,7 @@ function sweepHandoffs(repoName: string, repoPath: string, ages: AgeMap, items:
205
216
  const rel = relative(repoPath, full);
206
217
  const status = readDocStatus(full, "handoff");
207
218
  if (status !== "open") continue;
208
- const age = ageDays(ages, rel);
219
+ const age = metadataAgeDays(full, "status_changed_at");
209
220
  if (age == null || age <= COLD_HANDOFF_DAYS) continue;
210
221
  const displayPath = join(repoName === "(root)" ? "" : repoName, rel);
211
222
  items.push({
@@ -218,19 +229,23 @@ function sweepHandoffs(repoName: string, repoPath: string, ages: AgeMap, items:
218
229
  }
219
230
  }
220
231
 
221
- function sweepRunbook(repoName: string, repoPath: string, ages: AgeMap, items: SweepItem[]): void {
222
- const runbook = join(repoPath, "docs", "runbook.md");
223
- if (!existsSync(runbook)) return;
224
- const age = ageDays(ages, "docs/runbook.md");
225
- if (age == null || age <= RUNBOOK_DAYS) return;
226
- const displayPath = join(repoName === "(root)" ? "" : repoName, "docs/runbook.md");
227
- items.push({
228
- kind: "runbook-unverified",
229
- repo: repoName,
230
- path: displayPath,
231
- ageDays: age,
232
- message: `runbook hasn't been edited in ${age}d; re-verify procedures`,
233
- });
232
+ function sweepRunbooks(repoName: string, repoPath: string, items: SweepItem[]): void {
233
+ const docs = join(repoPath, "docs");
234
+ if (!existsSync(docs)) return;
235
+ for (const runbook of walkMdFiles(docs)) {
236
+ const metadata = parseFrontmatter(readFileSync(runbook, "utf8")).data;
237
+ if (metadata.schema !== "harnery-doc/v2" || metadata.type !== "runbook") continue;
238
+ const age = metadataAgeDays(runbook, "reviewed_at");
239
+ if (age == null || age <= RUNBOOK_DAYS) continue;
240
+ const rel = relative(repoPath, runbook);
241
+ items.push({
242
+ kind: "runbook-unverified",
243
+ repo: repoName,
244
+ path: join(repoName === "(root)" ? "" : repoName, rel),
245
+ ageDays: age,
246
+ message: `runbook has not been reviewed for ${age}d; verify it with docs metadata sync --reviewed`,
247
+ });
248
+ }
234
249
  }
235
250
 
236
251
  function sweepTopicDocs(
@@ -324,10 +339,10 @@ export async function runSweep(opts: SweepOpts): Promise<SweepItem[]> {
324
339
  for (let i = 0; i < filtered.length; i++) {
325
340
  const { name, path } = filtered[i]!;
326
341
  const ages = ageMaps[i]!;
327
- sweepPlans(name, path, ages, items);
328
- sweepIssues(name, path, ages, items);
329
- sweepHandoffs(name, path, ages, items);
330
- sweepRunbook(name, path, ages, items);
342
+ sweepPlans(name, path, items);
343
+ sweepIssues(name, path, items);
344
+ sweepHandoffs(name, path, items);
345
+ sweepRunbooks(name, path, items);
331
346
  sweepTopicDocs(name, path, ages, items);
332
347
  await sweepDecisions(name, path, ages, items);
333
348
  }
@@ -344,7 +359,6 @@ export async function runSweep(opts: SweepOpts): Promise<SweepItem[]> {
344
359
  */
345
360
  export async function countColdHandoffs(): Promise<number> {
346
361
  const items: SweepItem[] = [];
347
- const ages = await loadDocsAges(REPO_ROOT);
348
- sweepHandoffs("(root)", REPO_ROOT, ages, items);
362
+ sweepHandoffs("(root)", REPO_ROOT, items);
349
363
  return items.length;
350
364
  }
@@ -0,0 +1,287 @@
1
+ /**
2
+ * Headless harness calling — run a one-shot prompt (optionally with images)
3
+ * through a locally installed AI coding harness CLI and return its reply.
4
+ *
5
+ * Backends, in default preference order (subscription seats an embedding
6
+ * host already pays for, before any metered API a host might add on top):
7
+ *
8
+ * 1. claude-code `claude -p` JSON envelope on stdout
9
+ * 2. codex `codex exec` last message written to a file
10
+ * 3. cursor `cursor-agent -p` plain text on stdout
11
+ *
12
+ * Design rules, each learned from a live failure:
13
+ *
14
+ * - Every call runs from a NEUTRAL temp cwd holding only the staged images,
15
+ * so the nested session loads no repo instructions, hooks, or coordination
16
+ * rituals from the caller's checkout.
17
+ * - The child's stdin is CLOSED immediately. execFile leaves it open as a
18
+ * pipe, and codex interprets that as "more prompt coming" and blocks on
19
+ * it, then exits with no output.
20
+ * - An empty reply THROWS instead of returning "": a one-shot call that
21
+ * produced nothing was inconclusive, and callers gating on the result must
22
+ * fail closed rather than read silence as success.
23
+ * - `runHeadless` walks the backend chain PER CALL: a backend that is
24
+ * installed but errors (rate limit, timeout, transient exec failure) hands
25
+ * the same request to the next backend instead of failing the call. "On
26
+ * PATH" is not "working", and under parallel load the first backend can
27
+ * flake on a fraction of calls while the second runs clean.
28
+ *
29
+ * Env knobs (read through coordEnv, so the HARNERY_ prefix stays in one
30
+ * place): HARNERY_HEADLESS_BACKEND forces one backend and disables the
31
+ * fallback walk; HARNERY_HEADLESS_MODEL overrides the model passed to
32
+ * whichever backend runs.
33
+ */
34
+
35
+ import { execFile } from "node:child_process";
36
+ import {
37
+ accessSync,
38
+ constants,
39
+ existsSync,
40
+ mkdtempSync,
41
+ readFileSync,
42
+ rmSync,
43
+ statSync,
44
+ writeFileSync,
45
+ } from "node:fs";
46
+ import { tmpdir } from "node:os";
47
+ import { delimiter, isAbsolute, join } from "node:path";
48
+ import { promisify } from "node:util";
49
+ import { coordEnv } from "../env.ts";
50
+
51
+ const execFileAsync = promisify(execFile);
52
+
53
+ /** Names accepted by `runHeadlessOn`, `runHeadless({backends})`, and the
54
+ * HARNERY_HEADLESS_BACKEND env knob. */
55
+ export type HeadlessBackendName = "claude-code" | "codex" | "cursor";
56
+
57
+ /** An image to stage into the call's neutral cwd. `data` is the PNG bytes
58
+ * (Buffer) or their base64 encoding (string). */
59
+ export interface HeadlessImage {
60
+ data: Buffer | string;
61
+ /** Staged filename inside the neutral dir (default `image-<n>.png`). */
62
+ name?: string;
63
+ }
64
+
65
+ export interface HeadlessRequest {
66
+ /**
67
+ * The prompt, or a builder receiving the staged image paths. Backends that
68
+ * cannot attach an image natively (claude-code, cursor) rely on the prompt
69
+ * naming the staged paths so the harness reads them with its own tools;
70
+ * codex additionally attaches every image via `-i`.
71
+ */
72
+ prompt: string | ((ctx: { imagePaths: string[] }) => string);
73
+ images?: HeadlessImage[];
74
+ /** Model override for this call; HARNERY_HEADLESS_MODEL wins over it. */
75
+ model?: string;
76
+ /** Kill the child after this long (default 240_000 ms). */
77
+ timeoutMs?: number;
78
+ /** Agentic turn budget where the backend supports one (default 4). */
79
+ maxTurns?: number;
80
+ }
81
+
82
+ export interface HeadlessResult {
83
+ /** The harness's final reply text, never empty (empty replies throw). */
84
+ text: string;
85
+ /** Which backend produced it. */
86
+ backend: HeadlessBackendName;
87
+ }
88
+
89
+ export interface RunHeadlessOptions {
90
+ /** Preference order (default: HEADLESS_BACKENDS order). */
91
+ backends?: HeadlessBackendName[];
92
+ /** Walk the chain past a failing backend (default true). Forcing a backend
93
+ * via HARNERY_HEADLESS_BACKEND implies false. */
94
+ fallback?: boolean;
95
+ }
96
+
97
+ const MAX_BUFFER = 32 * 1024 * 1024;
98
+ const DEFAULT_TIMEOUT_MS = 240_000;
99
+ const DEFAULT_MAX_TURNS = 4;
100
+
101
+ /** Cross-runtime `which`: walk PATH (and PATHEXT on Windows) for an
102
+ * executable. Node has no built-in and Bun.which only exists under Bun. */
103
+ export function whichBin(bin: string): string | undefined {
104
+ if (isAbsolute(bin)) return isExecutable(bin) ? bin : undefined;
105
+ const paths = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
106
+ const exts =
107
+ process.platform === "win32" ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";") : [""];
108
+ for (const dir of paths) {
109
+ for (const ext of exts) {
110
+ const candidate = join(dir, bin + ext.toLowerCase());
111
+ if (isExecutable(candidate)) return candidate;
112
+ if (ext) {
113
+ const upper = join(dir, bin + ext);
114
+ if (isExecutable(upper)) return upper;
115
+ }
116
+ }
117
+ }
118
+ return undefined;
119
+ }
120
+
121
+ function isExecutable(path: string): boolean {
122
+ try {
123
+ if (!statSync(path).isFile()) return false;
124
+ accessSync(path, constants.X_OK);
125
+ return true;
126
+ } catch {
127
+ return false;
128
+ }
129
+ }
130
+
131
+ interface StagedCall {
132
+ dir: string;
133
+ imagePaths: string[];
134
+ prompt: string;
135
+ model?: string;
136
+ timeoutMs: number;
137
+ maxTurns: number;
138
+ }
139
+
140
+ /** Write the request's images into a fresh neutral dir and resolve the
141
+ * prompt against their staged paths. Caller must clean the dir up. */
142
+ function stageCall(req: HeadlessRequest): StagedCall {
143
+ const dir = mkdtempSync(join(tmpdir(), "harnery-headless-"));
144
+ const imagePaths = (req.images ?? []).map((img, i) => {
145
+ const path = join(dir, img.name ?? `image-${i + 1}.png`);
146
+ writeFileSync(path, typeof img.data === "string" ? Buffer.from(img.data, "base64") : img.data);
147
+ return path;
148
+ });
149
+ const prompt = typeof req.prompt === "function" ? req.prompt({ imagePaths }) : req.prompt;
150
+ return {
151
+ dir,
152
+ imagePaths,
153
+ prompt,
154
+ model: coordEnv("HEADLESS_MODEL") ?? req.model,
155
+ timeoutMs: req.timeoutMs ?? DEFAULT_TIMEOUT_MS,
156
+ maxTurns: req.maxTurns ?? DEFAULT_MAX_TURNS,
157
+ };
158
+ }
159
+
160
+ /** Run a harness CLI from the neutral dir with stdin CLOSED (see module
161
+ * comment: an open stdin pipe deadlocks codex). */
162
+ function execHarness(bin: string, args: string[], call: StagedCall) {
163
+ const pending = execFileAsync(bin, args, {
164
+ cwd: call.dir,
165
+ timeout: call.timeoutMs,
166
+ maxBuffer: MAX_BUFFER,
167
+ });
168
+ pending.child.stdin?.end();
169
+ return pending;
170
+ }
171
+
172
+ function assertReply(text: string, backend: HeadlessBackendName): HeadlessResult {
173
+ if (!text.trim()) throw new Error(`${backend}: empty reply (inconclusive; failing closed)`);
174
+ return { text, backend };
175
+ }
176
+
177
+ async function runClaudeCode(bin: string, call: StagedCall): Promise<HeadlessResult> {
178
+ const args = ["-p", call.prompt, "--output-format", "json", "--max-turns", String(call.maxTurns)];
179
+ if (call.imagePaths.length) args.push("--allowedTools", "Read");
180
+ if (call.model) args.push("--model", call.model);
181
+ const { stdout } = await execHarness(bin, args, call);
182
+ const envelope = JSON.parse(stdout) as { is_error?: boolean; result?: unknown };
183
+ if (envelope.is_error) {
184
+ throw new Error(
185
+ typeof envelope.result === "string" ? envelope.result : "claude-code: headless error",
186
+ );
187
+ }
188
+ return assertReply(typeof envelope.result === "string" ? envelope.result : "", "claude-code");
189
+ }
190
+
191
+ async function runCodex(bin: string, call: StagedCall): Promise<HeadlessResult> {
192
+ const outPath = join(call.dir, "last-message.txt");
193
+ const args = ["exec", "--skip-git-repo-check"];
194
+ for (const png of call.imagePaths) args.push("-i", png);
195
+ args.push("--output-last-message", outPath);
196
+ if (call.model) args.push("-m", call.model);
197
+ args.push(call.prompt);
198
+ await execHarness(bin, args, call);
199
+ return assertReply(existsSync(outPath) ? readFileSync(outPath, "utf-8") : "", "codex");
200
+ }
201
+
202
+ /** `-f` trusts the neutral dir so cursor's read tool runs without a prompt. */
203
+ async function runCursor(bin: string, call: StagedCall): Promise<HeadlessResult> {
204
+ const args = ["-p", call.prompt, "--output-format", "text", "-f"];
205
+ if (call.model) args.push("--model", call.model);
206
+ const { stdout } = await execHarness(bin, args, call);
207
+ return assertReply(stdout, "cursor");
208
+ }
209
+
210
+ type BackendRunner = (bin: string, call: StagedCall) => Promise<HeadlessResult>;
211
+
212
+ /** The backend registry in default preference order. */
213
+ export const HEADLESS_BACKENDS: ReadonlyArray<{ name: HeadlessBackendName; bin: string }> = [
214
+ { name: "claude-code", bin: "claude" },
215
+ { name: "codex", bin: "codex" },
216
+ { name: "cursor", bin: "cursor-agent" },
217
+ ];
218
+
219
+ const RUNNERS: Record<HeadlessBackendName, BackendRunner> = {
220
+ "claude-code": runClaudeCode,
221
+ codex: runCodex,
222
+ cursor: runCursor,
223
+ };
224
+
225
+ function backendBin(name: HeadlessBackendName): string | undefined {
226
+ const entry = HEADLESS_BACKENDS.find((b) => b.name === name);
227
+ return entry ? whichBin(entry.bin) : undefined;
228
+ }
229
+
230
+ /** Backends whose binary is on PATH right now, in preference order. Being
231
+ * listed means installed, not proven working — that is what the per-call
232
+ * fallback in `runHeadless` is for. */
233
+ export function availableHeadlessBackends(): HeadlessBackendName[] {
234
+ return HEADLESS_BACKENDS.filter((b) => whichBin(b.bin)).map((b) => b.name);
235
+ }
236
+
237
+ /** Run the request on exactly one named backend. Throws when the backend is
238
+ * not installed or the call fails. */
239
+ export async function runHeadlessOn(
240
+ name: HeadlessBackendName,
241
+ req: HeadlessRequest,
242
+ ): Promise<HeadlessResult> {
243
+ const bin = backendBin(name);
244
+ if (!bin) throw new Error(`headless backend not installed: ${name}`);
245
+ const call = stageCall(req);
246
+ try {
247
+ return await RUNNERS[name](bin, call);
248
+ } finally {
249
+ rmSync(call.dir, { recursive: true, force: true });
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Run the request on the first backend that succeeds, walking the preference
255
+ * order past installed-but-failing backends (unless fallback is disabled or a
256
+ * backend is forced via HARNERY_HEADLESS_BACKEND). Throws when no backend is
257
+ * installed, or every attempted backend failed — the error message carries
258
+ * each backend's failure so a flaky chain is diagnosable.
259
+ */
260
+ export async function runHeadless(
261
+ req: HeadlessRequest,
262
+ opts: RunHeadlessOptions = {},
263
+ ): Promise<HeadlessResult> {
264
+ const forced = coordEnv("HEADLESS_BACKEND") as HeadlessBackendName | undefined;
265
+ if (forced && !opts.backends) {
266
+ if (!HEADLESS_BACKENDS.some((b) => b.name === forced)) {
267
+ throw new Error(`unknown HARNERY_HEADLESS_BACKEND: ${forced}`);
268
+ }
269
+ return runHeadlessOn(forced, req);
270
+ }
271
+ const order = opts.backends ?? HEADLESS_BACKENDS.map((b) => b.name);
272
+ const installed = order.filter((name) => backendBin(name));
273
+ if (!installed.length) {
274
+ throw new Error(`no headless backend installed (looked for: ${order.join(", ")})`);
275
+ }
276
+ const fallback = opts.fallback ?? true;
277
+ const attempts = fallback ? installed : installed.slice(0, 1);
278
+ const failures: string[] = [];
279
+ for (const name of attempts) {
280
+ try {
281
+ return await runHeadlessOn(name, req);
282
+ } catch (err) {
283
+ failures.push(`${name}: ${err instanceof Error ? err.message : String(err)}`);
284
+ }
285
+ }
286
+ throw new Error(`every headless backend failed:\n ${failures.join("\n ")}`);
287
+ }
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * The operation is serialized because "is this name live?" and "claim it"
5
5
  * must be one critical section. Authoritative state is written twice on
6
- * purpose: `.name-history` heals a missing heartbeat, while the canonical
7
- * `identity.assumed` event makes replay and derived readers converge.
6
+ * purpose: `.name-history` supplies display metadata, while the canonical
7
+ * `coord.identity_attested` event makes replay and derived readers converge.
8
8
  *
9
9
  * Local collision policy: a fresh heartbeat alone is not enough to block.
10
10
  * If the namesake has no live pid-map process (crashed session, healed
@@ -14,21 +14,17 @@
14
14
  */
15
15
 
16
16
  import { randomUUID } from "node:crypto";
17
- import {
18
- existsSync,
19
- mkdirSync,
20
- readdirSync,
21
- readFileSync,
22
- statSync,
23
- unlinkSync,
24
- writeFileSync,
25
- } from "node:fs";
17
+ import { existsSync, mkdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from "node:fs";
26
18
  import { join } from "node:path";
27
19
 
28
- import { emitAndProject } from "../../core/agents/cli-emit.ts";
29
- import { emit } from "../../core/agents/events/emit.ts";
30
- import { type Heartbeat, readHeartbeat } from "../../core/agents/state/heartbeat-writer.ts";
31
- import { recordNameAssumption, resolveForkAncestry } from "../../core/agents/state/names.ts";
20
+ import { recordLiveIdentityChangeV3 } from "../../core/agents/live-authority-v3.ts";
21
+ import { recordLiveSweepObservationV3 } from "../../core/agents/live-lifecycle-v3.ts";
22
+ import type { Heartbeat } from "../../core/agents/state/heartbeat-writer.ts";
23
+ import {
24
+ readLiveCoordinationRow,
25
+ readLiveCoordinationRows,
26
+ } from "../../core/agents/state/live-coordination-view.ts";
27
+ import { resolveForkAncestry } from "../../core/agents/state/names.ts";
32
28
  import { instanceHasLivePid, removePidmapRowsForInstance } from "../../core/agents/state/pidmap.ts";
33
29
  import { coordFreshnessSeconds } from "../../core/config.ts";
34
30
  import { readRemoteMachines } from "../../core/presence/index.ts";
@@ -44,7 +40,7 @@ export type IdentityAssumeErrorCode =
44
40
  | "identity_is_ancestor"
45
41
  | "identity_not_found"
46
42
  | "invalid_identity"
47
- | "no_heartbeat"
43
+ | "no_live_generation"
48
44
  | "not_session"
49
45
  | "projection_failed";
50
46
 
@@ -91,22 +87,19 @@ export function findIdentityConflict(
91
87
  instanceId: string,
92
88
  name: string,
93
89
  nowMs = Date.now(),
90
+ excludedInstanceIds: ReadonlySet<string> = new Set(),
94
91
  ): IdentityConflict | null {
95
92
  const wanted = name.toLowerCase();
96
93
  const cutoffMs = nowMs - coordFreshnessSeconds(coordRoot) * 1000;
97
- const activeDir = join(coordRoot, ".harnery", "active");
98
- if (existsSync(activeDir)) {
99
- for (const file of readdirSync(activeDir)) {
100
- if (!file.endsWith(".json")) continue;
101
- try {
102
- const hb = JSON.parse(readFileSync(join(activeDir, file), "utf8")) as Heartbeat;
103
- if (hb.instance_id === instanceId || !heartbeatIsFresh(hb, cutoffMs)) continue;
104
- if ((hb.name ?? "").toLowerCase() === wanted) {
105
- return { instance_id: hb.instance_id, name: hb.name ?? name, scope: "local" };
106
- }
107
- } catch {
108
- // Malformed heartbeats are handled by stale sweep, not this command.
109
- }
94
+ for (const row of readLiveCoordinationRows(coordRoot)) {
95
+ if (
96
+ row.instance_id === instanceId ||
97
+ excludedInstanceIds.has(row.instance_id) ||
98
+ !heartbeatIsFresh(row, cutoffMs)
99
+ )
100
+ continue;
101
+ if ((row.name ?? "").toLowerCase() === wanted) {
102
+ return { instance_id: row.instance_id, name: row.name ?? name, scope: "local" };
110
103
  }
111
104
  }
112
105
 
@@ -143,13 +136,20 @@ export function reclaimAbandonedLocalConflict(
143
136
  let adapter: "claude-code" | "cursor" | "codex" = "claude-code";
144
137
  let sessionId = conflict.instance_id;
145
138
  let ageSecs: number | undefined;
139
+ const liveRow = readLiveCoordinationRow(coordRoot, conflict.instance_id);
140
+ if (liveRow) {
141
+ adapter = adapterOf(liveRow.platform);
142
+ sessionId = liveRow.session_id || conflict.instance_id;
143
+ const ts = Date.parse(liveRow.last_heartbeat);
144
+ if (Number.isFinite(ts)) ageSecs = Math.max(0, Math.floor((Date.now() - ts) / 1000));
145
+ }
146
146
  if (existsSync(hbPath)) {
147
147
  try {
148
148
  const hb = JSON.parse(readFileSync(hbPath, "utf8")) as Heartbeat;
149
+ // Native producer identity is private cache metadata, not ledger authority.
150
+ // It is required to join the exact producer state when recording the sweep.
149
151
  adapter = adapterOf(hb.platform);
150
152
  sessionId = hb.session_id || conflict.instance_id;
151
- const ts = Date.parse(hb.last_heartbeat);
152
- if (Number.isFinite(ts)) ageSecs = Math.max(0, Math.floor((Date.now() - ts) / 1000));
153
153
  } catch {
154
154
  /* content unreadable — still reclaim the file */
155
155
  }
@@ -160,23 +160,14 @@ export function reclaimAbandonedLocalConflict(
160
160
  }
161
161
  }
162
162
  removePidmapRowsForInstance(coordRoot, conflict.instance_id);
163
- try {
164
- emit(coordRoot, {
165
- event_type: "health.heartbeat_swept",
166
- instance_id: conflict.instance_id,
167
- session_id: sessionId,
168
- adapter,
169
- source: "agent-coord",
170
- data: {
171
- reason: "stale",
172
- ...(ageSecs !== undefined ? { age_secs: ageSecs } : {}),
173
- reclaimed_by: "identity.assume",
174
- },
175
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
176
- } as Parameters<typeof emit>[1]);
177
- } catch {
178
- /* telemetry only */
179
- }
163
+ recordLiveSweepObservationV3({
164
+ coordRoot,
165
+ owner: conflict.instance_id,
166
+ nativeSessionId: sessionId,
167
+ adapter,
168
+ observation: "stale_heartbeat",
169
+ ageMs: Math.max(0, (ageSecs ?? 0) * 1_000),
170
+ });
180
171
  return true;
181
172
  }
182
173
 
@@ -260,11 +251,11 @@ export function assumeIdentity(
260
251
  ): IdentityAssumeResult {
261
252
  const release = acquireLock(coordRoot);
262
253
  try {
263
- const hb = readHeartbeat(coordRoot, instanceId);
254
+ const hb = readLiveCoordinationRow(coordRoot, instanceId);
264
255
  if (!hb) {
265
256
  throw new IdentityAssumeError(
266
- "no_heartbeat",
267
- `no live heartbeat for instance '${instanceId}'`,
257
+ "no_live_generation",
258
+ `no authority-safe live V3 generation for instance '${instanceId}'`,
268
259
  );
269
260
  }
270
261
  if (hb.kind && hb.kind !== "session") {
@@ -298,7 +289,16 @@ export function assumeIdentity(
298
289
  let conflict = findIdentityConflict(coordRoot, instanceId, targetIdentity.name);
299
290
  if (conflict && reclaimAbandonedLocalConflict(coordRoot, conflict)) {
300
291
  reclaimedInstanceId = conflict.instance_id;
301
- conflict = findIdentityConflict(coordRoot, instanceId, targetIdentity.name);
292
+ // The V3 sweep is intentionally provisional, so the generation remains
293
+ // replay-visible after its disposable cache is removed. Ignore that one
294
+ // reclaimed holder while still checking for any additional namesake.
295
+ conflict = findIdentityConflict(
296
+ coordRoot,
297
+ instanceId,
298
+ targetIdentity.name,
299
+ Date.now(),
300
+ new Set([reclaimedInstanceId]),
301
+ );
302
302
  }
303
303
  if (conflict) {
304
304
  const where = conflict.scope === "remote" ? ` on ${conflict.machine}` : "";
@@ -312,15 +312,7 @@ export function assumeIdentity(
312
312
 
313
313
  const previousName = hb.name || null;
314
314
  const previousAgentId = hb.agent_id || null;
315
- const history = recordNameAssumption(
316
- coordRoot,
317
- instanceId,
318
- identity.name,
319
- identity.agent_id,
320
- "session",
321
- );
322
- const changed =
323
- history.changed || previousName !== identity.name || previousAgentId !== identity.agent_id;
315
+ const changed = previousName !== identity.name || previousAgentId !== identity.agent_id;
324
316
  if (!changed) {
325
317
  return {
326
318
  changed: false,
@@ -336,34 +328,20 @@ export function assumeIdentity(
336
328
  };
337
329
  }
338
330
 
339
- const emitted = emitAndProject(
340
- {
341
- event_type: "identity.assumed",
342
- instance_id: instanceId,
343
- session_id: hb.session_id,
344
- adapter: adapterOf(hb.platform),
345
- data: {
346
- name: identity.name,
347
- agent_id: identity.agent_id,
348
- ...(previousName ? { previous_name: previousName } : {}),
349
- ...(previousAgentId ? { previous_agent_id: previousAgentId } : {}),
350
- ...(reclaimedInstanceId ? { reclaimed_instance_id: reclaimedInstanceId } : {}),
351
- },
352
- },
353
- { coordRoot },
354
- );
355
- if (!emitted?.projected) {
356
- throw new IdentityAssumeError(
357
- "projection_failed",
358
- "the durable name binding was recorded but event projection failed; rerun the command to heal it",
359
- );
360
- }
331
+ const emitted = recordLiveIdentityChangeV3({
332
+ coordRoot,
333
+ owner: instanceId,
334
+ nativeSessionId: hb.native_session_id ?? hb.session_id,
335
+ adapter: adapterOf(hb.platform),
336
+ name: identity.name,
337
+ identityId: identity.agent_id,
338
+ });
361
339
 
362
- const projected = readHeartbeat(coordRoot, instanceId);
340
+ const projected = readLiveCoordinationRow(coordRoot, instanceId);
363
341
  if (projected?.name !== identity.name || projected.agent_id !== identity.agent_id) {
364
342
  throw new IdentityAssumeError(
365
343
  "projection_failed",
366
- "identity.assumed was emitted but the heartbeat did not converge; rerun the command",
344
+ "coord.identity_attested was emitted but the V3 projection did not converge; rerun the command",
367
345
  );
368
346
  }
369
347
  return {
@@ -375,7 +353,10 @@ export function assumeIdentity(
375
353
  name: identity.name,
376
354
  agent_id: identity.agent_id,
377
355
  identity_created: created,
378
- event_id: emitted.envelope.event_id,
356
+ event_id:
357
+ emitted.state === "recorded" && emitted.result.state === "recorded"
358
+ ? emitted.result.event.event_id
359
+ : null,
379
360
  reclaimed_instance_id: reclaimedInstanceId,
380
361
  };
381
362
  } finally {