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
@@ -10,9 +10,8 @@ import { spawnSync } from "node:child_process";
10
10
  import { existsSync, realpathSync, statSync } from "node:fs";
11
11
  import { dirname, isAbsolute, join, relative, resolve } from "node:path";
12
12
  import { type AgentFinalizationDisposition, agentsFinalizationRoots } from "../config.ts";
13
- import { readStreamTailBounded } from "./events/consume.ts";
14
-
15
- const CLAIM_HISTORY_CAP_BYTES = 128 * 1024 * 1024;
13
+ import { readFinalizationScopeV3 } from "../events/v3/finalization-view.ts";
14
+ import { liveInstanceIdV3, resolveLiveEventLedgerRouteV3 } from "../events/v3/live-routing.ts";
16
15
 
17
16
  const GIT_DISCOVERY_VARS = [
18
17
  "GIT_DIR",
@@ -42,6 +41,9 @@ export interface GitFinalizationResult {
42
41
  claim_history_complete: boolean;
43
42
  dirty_paths: string[];
44
43
  unpushed_repos: string[];
44
+ behind_repos: string[];
45
+ stale_submodules: string[];
46
+ diverged_submodules: string[];
45
47
  host_output_paths: string[];
46
48
  unsupported_paths: UnsupportedFinalizationPath[];
47
49
  unverifiable_paths: string[];
@@ -94,38 +96,16 @@ export interface SessionWriteClaims {
94
96
  export function readSessionWriteClaims(
95
97
  coordRoot: string,
96
98
  instanceId: string,
97
- sessionId: string,
99
+ _sessionId: string,
98
100
  ): SessionWriteClaims {
99
- const streamPath = join(coordRoot, ".harnery", "events.ndjson");
100
- const { text, truncated } = readStreamTailBounded(streamPath, CLAIM_HISTORY_CAP_BYTES);
101
- const paths = new Set<string>();
102
- let sawSessionStart = false;
103
-
104
- for (const line of text.split("\n")) {
105
- if (line.trim().length === 0) continue;
106
- try {
107
- const event = JSON.parse(line) as {
108
- event_type?: string;
109
- instance_id?: string;
110
- session_id?: string;
111
- data?: { path?: unknown; mode?: unknown };
112
- };
113
- if (event.instance_id !== instanceId || event.session_id !== sessionId) continue;
114
- if (event.event_type === "session.start") sawSessionStart = true;
115
- if (
116
- event.event_type === "claim.acquire" &&
117
- event.data?.mode === "write" &&
118
- typeof event.data.path === "string"
119
- ) {
120
- paths.add(event.data.path);
121
- }
122
- } catch {
123
- // Ignore malformed and crash-truncated event lines, matching the
124
- // canonical stream consumer's recovery behavior.
125
- }
101
+ const route = resolveLiveEventLedgerRouteV3(coordRoot);
102
+ if (route.state === "blocked") return { paths: [], complete: false };
103
+ try {
104
+ const scope = readFinalizationScopeV3(coordRoot, liveInstanceIdV3(instanceId));
105
+ return { paths: scope.files_touched, complete: true };
106
+ } catch {
107
+ return { paths: [], complete: false };
126
108
  }
127
-
128
- return { paths: [...paths], complete: !truncated || sawSessionStart };
129
109
  }
130
110
 
131
111
  function git(args: string[], cwd: string): GitResult {
@@ -417,6 +397,64 @@ function repoSyncState(repoRoot: string): "synced" | "unpushed" | "unverifiable"
417
397
  return containing.stdout.trim().length > 0 ? "synced" : "unpushed";
418
398
  }
419
399
 
400
+ function repoIsBehindUpstream(repoRoot: string): boolean {
401
+ if (!repoHasRemote(repoRoot)) return false;
402
+ const upstream = git(
403
+ ["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}"],
404
+ repoRoot,
405
+ );
406
+ if (upstream.status !== 0) return false;
407
+ const behind = git(["rev-list", "--count", "HEAD..@{upstream}"], repoRoot);
408
+ return behind.status === 0 && Number.parseInt(behind.stdout.trim(), 10) > 0;
409
+ }
410
+
411
+ function rootSubmoduleFreshness(repoRoot: string): {
412
+ stale: string[];
413
+ diverged: string[];
414
+ } {
415
+ const modules = git(
416
+ ["config", "--file", ".gitmodules", "--get-regexp", "^submodule\\..*\\.path$"],
417
+ repoRoot,
418
+ );
419
+ if (modules.status !== 0 || modules.stdout.trim().length === 0) {
420
+ return { stale: [], diverged: [] };
421
+ }
422
+
423
+ const stale: string[] = [];
424
+ const diverged: string[] = [];
425
+ for (const line of modules.stdout.trim().split("\n")) {
426
+ const path = line.trim().split(/\s+/).at(-1);
427
+ if (!path) continue;
428
+ const target = git(["rev-parse", `HEAD:${path}`], repoRoot);
429
+ const checkout = git(["rev-parse", "HEAD"], join(repoRoot, path));
430
+ if (target.status !== 0 || checkout.status !== 0) {
431
+ stale.push(path);
432
+ continue;
433
+ }
434
+ const targetSha = target.stdout.trim();
435
+ const checkoutSha = checkout.stdout.trim();
436
+ if (targetSha === checkoutSha) continue;
437
+
438
+ const checkoutBehind = git(
439
+ ["merge-base", "--is-ancestor", checkoutSha, targetSha],
440
+ join(repoRoot, path),
441
+ );
442
+ if (checkoutBehind.status === 0) {
443
+ stale.push(path);
444
+ continue;
445
+ }
446
+ const checkoutAhead = git(
447
+ ["merge-base", "--is-ancestor", targetSha, checkoutSha],
448
+ join(repoRoot, path),
449
+ );
450
+ // A checkout ahead of its gitlink is in-flight local work. Its owning
451
+ // session is responsible for the eventual pointer bump; unrelated turns
452
+ // must not be blocked globally while that work is active.
453
+ if (checkoutAhead.status !== 0) diverged.push(path);
454
+ }
455
+ return { stale: stale.sort(), diverged: diverged.sort() };
456
+ }
457
+
420
458
  /** Compare gitlink commits without treating dirty contents inside the child as a pointer change. */
421
459
  function gitlinkIsDirty(parentRoot: string, gitlink: string): boolean {
422
460
  const head = git(["rev-parse", `HEAD:${gitlink}`], parentRoot);
@@ -435,6 +473,9 @@ export function checkGitFinalization(
435
473
  options: { claimHistoryComplete?: boolean } = {},
436
474
  ): GitFinalizationResult {
437
475
  const root = resolve(coordRoot);
476
+ // Repository discovery resolves symlinks. Use the same physical base for
477
+ // display labels so macOS /var -> /private/var aliases stay repo-relative.
478
+ const labelRoot = physicalPath(root) ?? root;
438
479
  const repos = new Map<string, RepoWork>();
439
480
  const hostOutputPaths = new Set<string>();
440
481
  const unsupportedPaths: UnsupportedFinalizationPath[] = [];
@@ -466,7 +507,7 @@ export function checkGitFinalization(
466
507
  for (const repoPath of work.paths) {
467
508
  if (work.gitlinks.has(repoPath)) {
468
509
  if (gitlinkIsDirty(work.root, repoPath)) {
469
- const label = repoLabel(root, work.root);
510
+ const label = repoLabel(labelRoot, work.root);
470
511
  dirtyPaths.add(label === "." ? repoPath : `${label}/${repoPath}`);
471
512
  }
472
513
  continue;
@@ -476,36 +517,47 @@ export function checkGitFinalization(
476
517
  work.root,
477
518
  );
478
519
  if (status.status !== 0) {
479
- unverifiablePaths.push(join(repoLabel(root, work.root), repoPath).replaceAll("\\", "/"));
520
+ unverifiablePaths.push(
521
+ join(repoLabel(labelRoot, work.root), repoPath).replaceAll("\\", "/"),
522
+ );
480
523
  } else if (status.stdout.length > 0) {
481
- const label = repoLabel(root, work.root);
524
+ const label = repoLabel(labelRoot, work.root);
482
525
  dirtyPaths.add(label === "." ? repoPath : `${label}/${repoPath}`);
483
526
  }
484
527
  }
485
528
 
486
529
  const syncState = repoSyncState(work.root);
487
- const label = repoLabel(root, work.root);
530
+ const label = repoLabel(labelRoot, work.root);
488
531
  if (syncState === "unpushed") unpushedRepos.push(label);
489
532
  if (syncState === "unverifiable") unverifiableRepos.push(label);
490
533
  }
491
534
 
535
+ const behindRepos = repoIsBehindUpstream(root) ? ["."] : [];
536
+ const submoduleFreshness = rootSubmoduleFreshness(root);
537
+
492
538
  const result: GitFinalizationResult = {
493
539
  ok: false,
494
540
  claim_history_complete: options.claimHistoryComplete ?? true,
495
541
  dirty_paths: [...dirtyPaths].sort(),
496
542
  unpushed_repos: [...new Set(unpushedRepos)].sort(),
543
+ behind_repos: behindRepos,
544
+ stale_submodules: submoduleFreshness.stale,
545
+ diverged_submodules: submoduleFreshness.diverged,
497
546
  host_output_paths: [...hostOutputPaths].sort(),
498
547
  unsupported_paths: unsupportedPaths.sort(
499
548
  (a, b) => a.path.localeCompare(b.path) || a.reason.localeCompare(b.reason),
500
549
  ),
501
550
  unverifiable_paths: [...new Set(unverifiablePaths)].sort(),
502
551
  unverifiable_repos: [...new Set(unverifiableRepos)].sort(),
503
- repos_checked: [...repos.keys()].map((repo) => repoLabel(root, repo)).sort(),
552
+ repos_checked: [...repos.keys()].map((repo) => repoLabel(labelRoot, repo)).sort(),
504
553
  };
505
554
  result.ok =
506
555
  result.claim_history_complete &&
507
556
  result.dirty_paths.length === 0 &&
508
557
  result.unpushed_repos.length === 0 &&
558
+ result.behind_repos.length === 0 &&
559
+ result.stale_submodules.length === 0 &&
560
+ result.diverged_submodules.length === 0 &&
509
561
  result.unsupported_paths.length === 0 &&
510
562
  result.unverifiable_paths.length === 0 &&
511
563
  result.unverifiable_repos.length === 0;
@@ -526,6 +578,24 @@ export function formatGitFinalizationFailure(result: GitFinalizationResult, bin:
526
578
  ...result.unpushed_repos.map((repo) => ` - ${repo}`),
527
579
  );
528
580
  }
581
+ if (result.behind_repos.length > 0) {
582
+ lines.push(
583
+ "Repositories behind their upstream:",
584
+ ...result.behind_repos.map((repo) => ` - ${repo}`),
585
+ );
586
+ }
587
+ if (result.stale_submodules.length > 0) {
588
+ lines.push(
589
+ "Submodule checkouts behind their parent gitlinks:",
590
+ ...result.stale_submodules.map((path) => ` - ${path}`),
591
+ );
592
+ }
593
+ if (result.diverged_submodules.length > 0) {
594
+ lines.push(
595
+ "Submodule checkouts diverged from their parent gitlinks:",
596
+ ...result.diverged_submodules.map((path) => ` - ${path}`),
597
+ );
598
+ }
529
599
  if (result.unsupported_paths.length > 0) {
530
600
  lines.push(
531
601
  "Paths without an authorized end-turn disposition:",
@@ -549,6 +619,9 @@ export function formatGitFinalizationFailure(result: GitFinalizationResult, bin:
549
619
  if (
550
620
  result.dirty_paths.length > 0 ||
551
621
  result.unpushed_repos.length > 0 ||
622
+ result.behind_repos.length > 0 ||
623
+ result.stale_submodules.length > 0 ||
624
+ result.diverged_submodules.length > 0 ||
552
625
  result.unverifiable_paths.length > 0 ||
553
626
  result.unverifiable_repos.length > 0
554
627
  ) {
@@ -556,6 +629,15 @@ export function formatGitFinalizationFailure(result: GitFinalizationResult, bin:
556
629
  `Commit and push the owned Git work, then rerun \`${bin} agents status --end-turn\`.`,
557
630
  );
558
631
  }
632
+ if (
633
+ result.behind_repos.length > 0 ||
634
+ result.stale_submodules.length > 0 ||
635
+ result.diverged_submodules.length > 0
636
+ ) {
637
+ lines.push(
638
+ "Run the host repository's safe sync command, resolve any reported submodule state, then rerun the guarded status.",
639
+ );
640
+ }
559
641
  if (result.unsupported_paths.length > 0) {
560
642
  lines.push(
561
643
  "For a legacy claim, add the containing Git repository or intentional non-Git output root to the project's `agents.finalizationRoots`, then rerun the guarded status. For new work, start the task from the target Git project or configure that root before editing.",
@@ -1,14 +1,14 @@
1
1
  /**
2
2
  * agent-coord library public exports.
3
3
  *
4
- * `coord-client`: coordination helpers
5
- * (Heartbeat reader, owner-resolver via ppid-walk, monorepo-root finder).
6
- * Imported by every TS caller that needs to read coord state.
4
+ * `coord-client`: V3 producer identity resolution, ppid-map attribution, and
5
+ * coordination-root discovery.
7
6
  *
8
- * `canonical-emit`: fire-and-forget client for the canonical event stream;
9
- * spawns `bin/agent-coord emit-event` and never blocks the caller.
7
+ * `canonical-emit`: canonical V3 observation helpers.
10
8
  */
11
9
 
12
10
  export * from "./canonical-emit.js";
13
11
  export * from "./coord-client.js";
12
+ export * from "./live-observation-v3.js";
14
13
  export * from "./session-events.js";
14
+ export * from "./state/session-state.js";
@@ -0,0 +1,375 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import type { Adapter } from "../adapter.ts";
3
+ import type { AuthorityMutationV3 } from "../events/v3/authority-outbox.ts";
4
+ import { canonicalJsonV3, sha256V3 } from "../events/v3/canonical.ts";
5
+ import type { EventV3WriteMode } from "../events/v3/control.ts";
6
+ import {
7
+ readCoordinationViewV3,
8
+ requireAuthoritySafeCoordinationViewV3,
9
+ } from "../events/v3/coordination-view.ts";
10
+ import {
11
+ LIVE_HOOK_V3_PRODUCER_ID,
12
+ liveInstanceIdV3,
13
+ livePlatformV3,
14
+ resolveLiveEventLedgerRouteV3,
15
+ } from "../events/v3/live-routing.ts";
16
+ import type {
17
+ CoordinationAuthoritySignalV3,
18
+ CoordinationObservationBySignalV3,
19
+ } from "../events/v3/producers/coordination.ts";
20
+ import {
21
+ type RecordCoordinationAuthorityV3Result,
22
+ recordCoordinationAuthorityV3,
23
+ } from "../events/v3/producers/coordination-recorder.ts";
24
+ import {
25
+ readTerminalHookProducerStateV3,
26
+ recordHookSignalV3,
27
+ } from "../events/v3/producers/recorder.ts";
28
+ import {
29
+ acquireClaim,
30
+ type Heartbeat,
31
+ readHeartbeat,
32
+ releaseClaim,
33
+ setIdentityCache,
34
+ setLifecycleCache,
35
+ setTask,
36
+ } from "./state/heartbeat-writer.ts";
37
+ import {
38
+ ensureLiveCoordinationHeartbeat,
39
+ liveCoordinationAdapterV3,
40
+ } from "./state/live-coordination-view.ts";
41
+ import { recordNameAssumption } from "./state/names.ts";
42
+
43
+ export const LIVE_COORDINATION_V3_PRODUCER_ID = "prd_agent-coord" as const;
44
+
45
+ export class LiveCoordinationAuthorityV3Error extends Error {
46
+ constructor(public readonly reason: string) {
47
+ super(`event_v3_coordination_authority:${reason}`);
48
+ this.name = "LiveCoordinationAuthorityV3Error";
49
+ }
50
+ }
51
+
52
+ export type LiveCoordinationAuthorityV3Result =
53
+ | { state: "unchanged" }
54
+ | { state: "recorded"; result: RecordCoordinationAuthorityV3Result };
55
+
56
+ export interface ReopenedLiveCoordinationGenerationV3 {
57
+ state: "reopened";
58
+ adapter: Adapter;
59
+ prior_generation_id: `gen_${string}`;
60
+ generation_id: `gen_${string}`;
61
+ }
62
+
63
+ interface LiveAuthorityBaseV3 {
64
+ coordRoot: string;
65
+ owner: string;
66
+ subject?: string;
67
+ nativeSessionId: string;
68
+ adapter: Adapter;
69
+ observationId?: string;
70
+ }
71
+
72
+ /**
73
+ * Open a fresh derived generation for a human-facing session that is executing
74
+ * again after an authoritative terminal. The terminal generation is never
75
+ * changed or reused.
76
+ */
77
+ export function reopenLiveCoordinationGenerationV3(input: {
78
+ coordRoot: string;
79
+ owner: string;
80
+ nativeSessionId: string;
81
+ }): ReopenedLiveCoordinationGenerationV3 {
82
+ const route = resolveLiveEventLedgerRouteV3(input.coordRoot);
83
+ if (route.state === "blocked") throw new LiveCoordinationAuthorityV3Error(route.reason);
84
+ const instanceId = liveInstanceIdV3(input.owner);
85
+ const terminal = readTerminalHookProducerStateV3(
86
+ input.coordRoot,
87
+ input.nativeSessionId,
88
+ instanceId,
89
+ );
90
+ if (!terminal) {
91
+ throw new LiveCoordinationAuthorityV3Error("terminal_generation_identity_missing");
92
+ }
93
+ const view = requireAuthoritySafeCoordinationViewV3(readCoordinationViewV3(input.coordRoot));
94
+ const terminalView = view.terminal_generations[terminal.generation_id];
95
+ if (!terminalView || terminalView.instance_id !== instanceId) {
96
+ throw new LiveCoordinationAuthorityV3Error("terminal_generation_authority_missing");
97
+ }
98
+ if (terminalView.parent_generation_id || terminalView.delegation_id || terminalView.workflow_id) {
99
+ throw new LiveCoordinationAuthorityV3Error("lifecycle_not_human_facing");
100
+ }
101
+ const reopened = recordHookSignalV3({
102
+ coordRoot: input.coordRoot,
103
+ mode: route.mode,
104
+ signal: "session-start",
105
+ payload: { raw: {}, session_id: input.nativeSessionId },
106
+ adapter: terminal.adapter,
107
+ instance_id: instanceId,
108
+ producer_id: LIVE_HOOK_V3_PRODUCER_ID,
109
+ build_id: route.build_id,
110
+ platform: livePlatformV3(),
111
+ session_start_derivation: "approved_lifecycle_reopen",
112
+ });
113
+ if (reopened.state !== "recorded" && reopened.state !== "already_started") {
114
+ throw new LiveCoordinationAuthorityV3Error(`generation_reopen_failed:${reopened.state}`);
115
+ }
116
+ const heartbeat = ensureLiveCoordinationHeartbeat(
117
+ input.coordRoot,
118
+ input.owner,
119
+ input.nativeSessionId,
120
+ terminal.adapter,
121
+ );
122
+ if (!heartbeat) {
123
+ throw new LiveCoordinationAuthorityV3Error("reopened_generation_materialization_failed");
124
+ }
125
+ return {
126
+ state: "reopened",
127
+ adapter: terminal.adapter,
128
+ prior_generation_id: terminal.generation_id,
129
+ generation_id: heartbeat.v3_generation_id as `gen_${string}`,
130
+ };
131
+ }
132
+
133
+ export function recordLiveTaskChangeV3(
134
+ input: LiveAuthorityBaseV3 & { task: string },
135
+ ): LiveCoordinationAuthorityV3Result {
136
+ liveCoordinationWriteModeV3(input.coordRoot);
137
+ const before = requireHeartbeat(input, input.subject ?? input.owner);
138
+ const cleared = input.task.length === 0;
139
+ const desired = {
140
+ ...before,
141
+ task: undefined,
142
+ v3_task_state: cleared ? ("cleared" as const) : ("set" as const),
143
+ };
144
+ // A task declaration is also per-turn ritual evidence. Record repeated
145
+ // declarations, including cleared -> cleared, even when the disposable view
146
+ // does not change. Otherwise a conversational Cursor remediation turn can
147
+ // run `set-task ""` exactly as instructed and still loop forever because no
148
+ // coord.task_changed event reaches the verdict window.
149
+ return recordLiveAuthority(
150
+ input,
151
+ "task-changed",
152
+ {
153
+ native_observation_id: input.observationId ?? `task-${randomUUID()}`,
154
+ state: cleared ? "cleared" : "set",
155
+ ...(cleared ? {} : { task: input.task }),
156
+ },
157
+ before,
158
+ desired,
159
+ () => {
160
+ // The canonical event records only the privacy-safe set/cleared state.
161
+ // Task prose and its operator-facing suggested name live exclusively in
162
+ // this generation-bound disposable cache; they never enter the ledger.
163
+ if (!setTask(input.coordRoot, input.subject ?? input.owner, input.task)) {
164
+ throw new LiveCoordinationAuthorityV3Error("task_materialization_failed");
165
+ }
166
+ },
167
+ );
168
+ }
169
+
170
+ export function recordLiveLifecycleChangeV3(
171
+ input: LiveAuthorityBaseV3 & {
172
+ state: "active" | "blocked" | "done";
173
+ reason?: string;
174
+ suggestedSessionName?: string;
175
+ observedAt?: string;
176
+ },
177
+ ): LiveCoordinationAuthorityV3Result {
178
+ liveCoordinationWriteModeV3(input.coordRoot);
179
+ const subject = input.subject ?? input.owner;
180
+ const before = requireHeartbeat(input, subject);
181
+ const desired: Heartbeat = {
182
+ ...before,
183
+ task_state: input.state,
184
+ task_state_reason: input.state === "active" ? undefined : input.reason,
185
+ ...(input.suggestedSessionName ? { suggested_session_name: input.suggestedSessionName } : {}),
186
+ };
187
+ if (authorityStateDigest(before) === authorityStateDigest(desired)) return { state: "unchanged" };
188
+ return recordLiveAuthority(
189
+ input,
190
+ "lifecycle-changed",
191
+ {
192
+ native_observation_id: input.observationId ?? `lifecycle-${randomUUID()}`,
193
+ state: input.state,
194
+ ...(input.reason ? { reason_code: `operator_${input.state}` } : {}),
195
+ },
196
+ before,
197
+ desired,
198
+ () => {
199
+ if (
200
+ !setLifecycleCache(
201
+ input.coordRoot,
202
+ subject,
203
+ input.state,
204
+ input.reason,
205
+ input.suggestedSessionName,
206
+ )
207
+ ) {
208
+ throw new LiveCoordinationAuthorityV3Error("lifecycle_materialization_failed");
209
+ }
210
+ },
211
+ );
212
+ }
213
+
214
+ export function recordLiveClaimChangeV3(
215
+ input: LiveAuthorityBaseV3 & {
216
+ operation: "acquired" | "released";
217
+ path: string;
218
+ access?: "read" | "write";
219
+ },
220
+ ): LiveCoordinationAuthorityV3Result {
221
+ liveCoordinationWriteModeV3(input.coordRoot);
222
+ const subject = input.subject ?? input.owner;
223
+ const before = requireHeartbeat(input, subject);
224
+ const canonical = canonicalClaimPath(input.coordRoot, input.path);
225
+ const desiredFiles =
226
+ input.operation === "acquired"
227
+ ? [
228
+ ...new Set([
229
+ ...(before.files_touched ?? []).map((path) =>
230
+ canonicalClaimPath(input.coordRoot, path),
231
+ ),
232
+ canonical,
233
+ ]),
234
+ ].sort()
235
+ : (before.files_touched ?? []).filter(
236
+ (path) => canonicalClaimPath(input.coordRoot, path) !== canonical,
237
+ );
238
+ const desired: Heartbeat = { ...before, files_touched: desiredFiles };
239
+ if (authorityStateDigest(before) === authorityStateDigest(desired)) return { state: "unchanged" };
240
+ return recordLiveAuthority(
241
+ input,
242
+ "claim-changed",
243
+ {
244
+ native_observation_id: input.observationId ?? `claim-${randomUUID()}`,
245
+ operation: input.operation,
246
+ target: canonical,
247
+ access: input.access ?? "write",
248
+ },
249
+ before,
250
+ desired,
251
+ () => {
252
+ const result =
253
+ input.operation === "acquired"
254
+ ? acquireClaim(input.coordRoot, subject, canonical)
255
+ : releaseClaim(input.coordRoot, subject, canonical);
256
+ if (!result) throw new LiveCoordinationAuthorityV3Error("claim_materialization_failed");
257
+ },
258
+ );
259
+ }
260
+
261
+ export function recordLiveIdentityChangeV3(
262
+ input: LiveAuthorityBaseV3 & { name: string; identityId: string },
263
+ ): LiveCoordinationAuthorityV3Result {
264
+ liveCoordinationWriteModeV3(input.coordRoot);
265
+ const subject = input.subject ?? input.owner;
266
+ const before = requireHeartbeat(input, subject);
267
+ const desired: Heartbeat = { ...before, name: input.name, agent_id: input.identityId };
268
+ if (authorityStateDigest(before) === authorityStateDigest(desired)) return { state: "unchanged" };
269
+ return recordLiveAuthority(
270
+ input,
271
+ "identity-attested",
272
+ {
273
+ native_observation_id: input.observationId ?? `identity-${randomUUID()}`,
274
+ identity_id: input.identityId,
275
+ method: "operator_assumption",
276
+ },
277
+ before,
278
+ desired,
279
+ () => {
280
+ recordNameAssumption(input.coordRoot, subject, input.name, input.identityId, "session");
281
+ if (!setIdentityCache(input.coordRoot, subject, input.name, input.identityId)) {
282
+ throw new LiveCoordinationAuthorityV3Error("identity_materialization_failed");
283
+ }
284
+ },
285
+ );
286
+ }
287
+
288
+ function recordLiveAuthority<S extends CoordinationAuthoritySignalV3>(
289
+ input: LiveAuthorityBaseV3,
290
+ signal: S,
291
+ observation: CoordinationObservationBySignalV3[S],
292
+ expected: Heartbeat,
293
+ desired: Heartbeat,
294
+ apply: () => void,
295
+ ): LiveCoordinationAuthorityV3Result {
296
+ const route = resolveLiveEventLedgerRouteV3(input.coordRoot);
297
+ if (route.state === "blocked") throw new LiveCoordinationAuthorityV3Error(route.reason);
298
+ const adapter = liveCoordinationAdapterV3(input.coordRoot, input.owner);
299
+ if (!adapter) throw new LiveCoordinationAuthorityV3Error("actor_generation_missing");
300
+ const subject = input.subject ?? input.owner;
301
+ const result = recordAuthority({
302
+ coordRoot: input.coordRoot,
303
+ mode: route.mode,
304
+ signal,
305
+ observation,
306
+ adapter,
307
+ native_actor_session_id: input.nativeSessionId,
308
+ actor_instance_id: liveInstanceIdV3(input.owner),
309
+ subject_instance_id: liveInstanceIdV3(subject),
310
+ producer_id: LIVE_COORDINATION_V3_PRODUCER_ID,
311
+ build_id: route.build_id,
312
+ platform: livePlatformV3(),
313
+ expected_prior_state_digest: authorityStateDigest(expected),
314
+ desired_state_digest: authorityStateDigest(desired),
315
+ reconciler: {
316
+ readStateDigest: () => {
317
+ const heartbeat = readHeartbeat(input.coordRoot, subject);
318
+ if (!heartbeat || heartbeat.v3_generation_id !== expected.v3_generation_id) {
319
+ throw new LiveCoordinationAuthorityV3Error(`heartbeat_generation_mismatch:${subject}`);
320
+ }
321
+ return authorityStateDigest(heartbeat);
322
+ },
323
+ apply: (_mutation: AuthorityMutationV3) => apply(),
324
+ },
325
+ });
326
+ if (result.state === "gate_closed" || result.state === "generation_unavailable") {
327
+ throw new LiveCoordinationAuthorityV3Error(`${result.state}:${result.reason}`);
328
+ }
329
+ if (result.state === "pending_transaction") {
330
+ throw new LiveCoordinationAuthorityV3Error(`pending_transaction:${result.transaction_id}`);
331
+ }
332
+ return { state: "recorded", result };
333
+ }
334
+
335
+ function recordAuthority<S extends CoordinationAuthoritySignalV3>(
336
+ input: Parameters<typeof recordCoordinationAuthorityV3<S>>[0],
337
+ ): RecordCoordinationAuthorityV3Result {
338
+ return recordCoordinationAuthorityV3(input);
339
+ }
340
+
341
+ export function liveCoordinationWriteModeV3(coordRoot: string): EventV3WriteMode {
342
+ const route = resolveLiveEventLedgerRouteV3(coordRoot);
343
+ if (route.state === "blocked") throw new LiveCoordinationAuthorityV3Error(route.reason);
344
+ return route.mode;
345
+ }
346
+
347
+ function requireHeartbeat(input: LiveAuthorityBaseV3, owner: string): Heartbeat {
348
+ const heartbeat = ensureLiveCoordinationHeartbeat(
349
+ input.coordRoot,
350
+ owner,
351
+ owner === input.owner ? input.nativeSessionId : owner,
352
+ input.adapter,
353
+ );
354
+ if (!heartbeat) throw new LiveCoordinationAuthorityV3Error(`heartbeat_missing:${owner}`);
355
+ return heartbeat;
356
+ }
357
+
358
+ function authorityStateDigest(heartbeat: Heartbeat): `sha256:${string}` {
359
+ return sha256V3(
360
+ canonicalJsonV3({
361
+ instance_id: heartbeat.v3_instance_id ?? heartbeat.instance_id,
362
+ generation_id: heartbeat.v3_generation_id ?? null,
363
+ task_state: heartbeat.v3_task_state ?? (heartbeat.task ? "set" : "cleared"),
364
+ lifecycle_state: heartbeat.task_state ?? "active",
365
+ task_state_reason: heartbeat.task_state_reason ?? null,
366
+ files_touched: [...new Set(heartbeat.files_touched ?? [])].sort(),
367
+ identity_id: heartbeat.agent_id ?? null,
368
+ display_name: heartbeat.name ?? null,
369
+ }),
370
+ );
371
+ }
372
+
373
+ function canonicalClaimPath(coordRoot: string, path: string): string {
374
+ return path.startsWith(`${coordRoot}/`) ? path.slice(coordRoot.length + 1) : path;
375
+ }