harnery 0.38.0 → 0.40.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 (378) hide show
  1. package/dist/commands/agents.d.ts.map +1 -1
  2. package/dist/commands/agents.js +32 -8
  3. package/dist/commands/artifacts.d.ts.map +1 -1
  4. package/dist/commands/artifacts.js +97 -6
  5. package/dist/commands/backup.d.ts +16 -0
  6. package/dist/commands/backup.d.ts.map +1 -1
  7. package/dist/commands/backup.js +239 -33
  8. package/dist/commands/browse.d.ts +8 -0
  9. package/dist/commands/browse.d.ts.map +1 -1
  10. package/dist/commands/browse.js +466 -231
  11. package/dist/commands/diagnostics.d.ts.map +1 -1
  12. package/dist/commands/diagnostics.js +6 -3
  13. package/dist/commands/ledger-v3.d.ts.map +1 -1
  14. package/dist/commands/ledger-v3.js +20 -4
  15. package/dist/commands/qa-run.d.ts.map +1 -1
  16. package/dist/commands/qa-run.js +26 -3
  17. package/dist/commands/qa-status.d.ts.map +1 -1
  18. package/dist/commands/qa-status.js +7 -2
  19. package/dist/commands/resources.d.ts.map +1 -1
  20. package/dist/commands/resources.js +23 -3
  21. package/dist/commands/review-pack.d.ts.map +1 -1
  22. package/dist/commands/review-pack.js +98 -23
  23. package/dist/commands/tunnel.d.ts.map +1 -1
  24. package/dist/commands/tunnel.js +2 -2
  25. package/dist/core/adapters/profiles.d.ts +1 -1
  26. package/dist/core/agents/canonical-emit.d.ts +3 -2
  27. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  28. package/dist/core/agents/canonical-emit.js +2 -0
  29. package/dist/core/agents/cli.js +13 -6
  30. package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
  31. package/dist/core/agents/live-authority-v3.js +5 -3
  32. package/dist/core/agents/live-lifecycle-v3.d.ts +2 -2
  33. package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -1
  34. package/dist/core/agents/render/prompt-context.d.ts +7 -5
  35. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  36. package/dist/core/agents/render/prompt-context.js +63 -8
  37. package/dist/core/agents/session-finalizer-v3.d.ts +2 -2
  38. package/dist/core/agents/session-finalizer-v3.d.ts.map +1 -1
  39. package/dist/core/agents/state/live-coordination-view.d.ts +3 -3
  40. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  41. package/dist/core/agents/state/live-coordination-view.js +2 -1
  42. package/dist/core/agents/state/names.d.ts +35 -2
  43. package/dist/core/agents/state/names.d.ts.map +1 -1
  44. package/dist/core/agents/state/names.js +80 -5
  45. package/dist/core/agents/state/stale-sweep.d.ts +2 -1
  46. package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
  47. package/dist/core/agents/state/stale-sweep.js +23 -6
  48. package/dist/core/agents/turn-elapsed.d.ts +51 -0
  49. package/dist/core/agents/turn-elapsed.d.ts.map +1 -0
  50. package/dist/core/agents/turn-elapsed.js +91 -0
  51. package/dist/core/artifacts/activity.d.ts +14 -0
  52. package/dist/core/artifacts/activity.d.ts.map +1 -0
  53. package/dist/core/artifacts/activity.js +52 -0
  54. package/dist/core/artifacts/delivery-card.d.ts +39 -0
  55. package/dist/core/artifacts/delivery-card.d.ts.map +1 -0
  56. package/dist/core/artifacts/delivery-card.js +282 -0
  57. package/dist/core/artifacts/index.d.ts +42 -7
  58. package/dist/core/artifacts/index.d.ts.map +1 -1
  59. package/dist/core/artifacts/index.js +288 -76
  60. package/dist/core/artifacts/mutation-lock.d.ts +2 -0
  61. package/dist/core/artifacts/mutation-lock.d.ts.map +1 -0
  62. package/dist/core/artifacts/mutation-lock.js +91 -0
  63. package/dist/core/backup/host-snapshot.d.ts +18 -0
  64. package/dist/core/backup/host-snapshot.d.ts.map +1 -0
  65. package/dist/core/backup/host-snapshot.js +64 -0
  66. package/dist/core/config.d.ts +20 -5
  67. package/dist/core/config.d.ts.map +1 -1
  68. package/dist/core/config.js +44 -10
  69. package/dist/core/diagnostics/advice.d.ts +38 -3
  70. package/dist/core/diagnostics/advice.d.ts.map +1 -1
  71. package/dist/core/diagnostics/advice.js +103 -99
  72. package/dist/core/diagnostics/bundle.d.ts.map +1 -1
  73. package/dist/core/diagnostics/bundle.js +111 -47
  74. package/dist/core/diagnostics/comparison.d.ts.map +1 -1
  75. package/dist/core/diagnostics/comparison.js +3 -2
  76. package/dist/core/diagnostics/contract.d.ts +15 -31
  77. package/dist/core/diagnostics/contract.d.ts.map +1 -1
  78. package/dist/core/diagnostics/contract.js +2 -5
  79. package/dist/core/diagnostics/index.d.ts +2 -0
  80. package/dist/core/diagnostics/index.d.ts.map +1 -1
  81. package/dist/core/diagnostics/index.js +2 -0
  82. package/dist/core/diagnostics/pressure-contract.d.ts +260 -0
  83. package/dist/core/diagnostics/pressure-contract.d.ts.map +1 -0
  84. package/dist/core/diagnostics/pressure-contract.js +70 -0
  85. package/dist/core/diagnostics/pressure.d.ts +25 -0
  86. package/dist/core/diagnostics/pressure.d.ts.map +1 -0
  87. package/dist/core/diagnostics/pressure.js +1138 -0
  88. package/dist/core/diagnostics/replay.d.ts.map +1 -1
  89. package/dist/core/diagnostics/replay.js +90 -10
  90. package/dist/core/events/v3/adapter-id.d.ts +6 -0
  91. package/dist/core/events/v3/adapter-id.d.ts.map +1 -0
  92. package/dist/core/events/v3/adapter-id.js +7 -0
  93. package/dist/core/events/v3/archive-retention.d.ts.map +1 -1
  94. package/dist/core/events/v3/archive-retention.js +3 -2
  95. package/dist/core/events/v3/bootstrap.d.ts +41 -4
  96. package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
  97. package/dist/core/events/v3/bootstrap.js +120 -17
  98. package/dist/core/events/v3/capabilities.d.ts +16 -9
  99. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  100. package/dist/core/events/v3/capabilities.js +37 -2
  101. package/dist/core/events/v3/capability-drift.d.ts +2 -2
  102. package/dist/core/events/v3/capability-drift.d.ts.map +1 -1
  103. package/dist/core/events/v3/control-witness.d.ts +48 -5
  104. package/dist/core/events/v3/control-witness.d.ts.map +1 -1
  105. package/dist/core/events/v3/control-witness.js +91 -36
  106. package/dist/core/events/v3/control.d.ts.map +1 -1
  107. package/dist/core/events/v3/control.js +22 -2
  108. package/dist/core/events/v3/index.d.ts +2 -1
  109. package/dist/core/events/v3/index.d.ts.map +1 -1
  110. package/dist/core/events/v3/index.js +2 -1
  111. package/dist/core/events/v3/live-feed.d.ts +7 -1
  112. package/dist/core/events/v3/live-feed.d.ts.map +1 -1
  113. package/dist/core/events/v3/live-feed.js +21 -3
  114. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  115. package/dist/core/events/v3/live-routing.js +10 -2
  116. package/dist/core/events/v3/producers/command-recorder.d.ts +2 -2
  117. package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
  118. package/dist/core/events/v3/producers/command-recorder.js +2 -1
  119. package/dist/core/events/v3/producers/coordination-recorder.d.ts +2 -2
  120. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  121. package/dist/core/events/v3/producers/coordination-recorder.js +2 -1
  122. package/dist/core/events/v3/producers/hook-base.d.ts +2 -2
  123. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  124. package/dist/core/events/v3/producers/hook-base.js +15 -5
  125. package/dist/core/events/v3/producers/hook.d.ts.map +1 -1
  126. package/dist/core/events/v3/producers/hook.js +17 -4
  127. package/dist/core/events/v3/producers/intake.d.ts +4 -4
  128. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  129. package/dist/core/events/v3/producers/intake.js +3 -2
  130. package/dist/core/events/v3/producers/producer-state-observer.d.ts.map +1 -1
  131. package/dist/core/events/v3/producers/producer-state-observer.js +2 -1
  132. package/dist/core/events/v3/producers/recorder.d.ts +16 -5
  133. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  134. package/dist/core/events/v3/producers/recorder.js +31 -9
  135. package/dist/core/events/v3/reader.d.ts.map +1 -1
  136. package/dist/core/events/v3/reader.js +10 -13
  137. package/dist/core/events/v3/runtime-build.d.ts.map +1 -1
  138. package/dist/core/events/v3/runtime-build.js +3 -2
  139. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +2 -2
  140. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -1
  141. package/dist/core/events/v3/turn-telemetry.d.ts +2 -2
  142. package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
  143. package/dist/core/hooks/adapter/output.d.ts +16 -14
  144. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  145. package/dist/core/hooks/adapter/output.js +36 -38
  146. package/dist/core/hooks/backup-schedule.d.ts +34 -0
  147. package/dist/core/hooks/backup-schedule.d.ts.map +1 -0
  148. package/dist/core/hooks/backup-schedule.js +114 -0
  149. package/dist/core/hooks/cli.js +61 -18
  150. package/dist/core/hooks/codex-wsl-bridge.d.ts +2 -0
  151. package/dist/core/hooks/codex-wsl-bridge.d.ts.map +1 -1
  152. package/dist/core/hooks/codex-wsl-bridge.js +18 -4
  153. package/dist/core/hooks/index.d.ts +1 -0
  154. package/dist/core/hooks/index.d.ts.map +1 -1
  155. package/dist/core/hooks/index.js +1 -0
  156. package/dist/core/hooks/prompt-context/contract.d.ts +61 -0
  157. package/dist/core/hooks/prompt-context/contract.d.ts.map +1 -0
  158. package/dist/core/hooks/prompt-context/contract.js +102 -0
  159. package/dist/core/hooks/prompt-context/index.d.ts +5 -0
  160. package/dist/core/hooks/prompt-context/index.d.ts.map +1 -0
  161. package/dist/core/hooks/prompt-context/index.js +2 -0
  162. package/dist/core/hooks/prompt-context/runner.d.ts +24 -0
  163. package/dist/core/hooks/prompt-context/runner.d.ts.map +1 -0
  164. package/dist/core/hooks/prompt-context/runner.js +249 -0
  165. package/dist/core/qa-artifacts.d.ts +3 -0
  166. package/dist/core/qa-artifacts.d.ts.map +1 -1
  167. package/dist/core/qa-artifacts.js +25 -3
  168. package/dist/core/resources/contract.d.ts +69 -3
  169. package/dist/core/resources/contract.d.ts.map +1 -1
  170. package/dist/core/resources/contract.js +1 -1
  171. package/dist/core/resources/index.d.ts +1 -0
  172. package/dist/core/resources/index.d.ts.map +1 -1
  173. package/dist/core/resources/index.js +1 -0
  174. package/dist/core/resources/native.d.ts +36 -0
  175. package/dist/core/resources/native.d.ts.map +1 -0
  176. package/dist/core/resources/native.js +418 -0
  177. package/dist/core/resources/sampler.d.ts +2 -0
  178. package/dist/core/resources/sampler.d.ts.map +1 -1
  179. package/dist/core/resources/sampler.js +31 -1
  180. package/dist/core/resources/status.d.ts +61 -0
  181. package/dist/core/resources/status.d.ts.map +1 -0
  182. package/dist/core/resources/status.js +536 -0
  183. package/dist/core/resources/system.d.ts +27 -0
  184. package/dist/core/resources/system.d.ts.map +1 -0
  185. package/dist/core/resources/system.js +439 -0
  186. package/dist/core/semantic/contract.d.ts +13 -13
  187. package/dist/core/semantic/service.d.ts +2 -0
  188. package/dist/core/semantic/service.d.ts.map +1 -1
  189. package/dist/core/semantic/service.js +27 -4
  190. package/dist/core/storage/builtins.js +41 -0
  191. package/dist/core/supervisor/contract.d.ts +41 -3
  192. package/dist/core/supervisor/contract.d.ts.map +1 -1
  193. package/dist/core/supervisor/contract.js +3 -2
  194. package/dist/core/supervisor/findings.d.ts +3 -0
  195. package/dist/core/supervisor/findings.d.ts.map +1 -1
  196. package/dist/core/supervisor/findings.js +88 -0
  197. package/dist/core/supervisor/history.d.ts.map +1 -1
  198. package/dist/core/supervisor/history.js +14 -0
  199. package/dist/core/supervisor/ledger-state.d.ts +55 -0
  200. package/dist/core/supervisor/ledger-state.d.ts.map +1 -0
  201. package/dist/core/supervisor/ledger-state.js +0 -0
  202. package/dist/core/supervisor/service.d.ts.map +1 -1
  203. package/dist/core/supervisor/service.js +120 -7
  204. package/dist/core/supervisor/storage.d.ts +3 -1
  205. package/dist/core/supervisor/storage.d.ts.map +1 -1
  206. package/dist/core/supervisor/storage.js +4 -0
  207. package/dist/core/workflow/admission.d.ts +3 -0
  208. package/dist/core/workflow/admission.d.ts.map +1 -1
  209. package/dist/core/workflow/admission.js +28 -16
  210. package/dist/core/workflow/engine.js +2 -2
  211. package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
  212. package/dist/core/workflow/live-session-v3.js +6 -1
  213. package/dist/core/workflow/proof.d.ts.map +1 -1
  214. package/dist/core/workflow/proof.js +4 -3
  215. package/dist/lib/browser/capture-fidelity.d.ts +7 -0
  216. package/dist/lib/browser/capture-fidelity.d.ts.map +1 -1
  217. package/dist/lib/browser/capture-fidelity.js +17 -0
  218. package/dist/lib/browser/client.d.ts +9 -0
  219. package/dist/lib/browser/client.d.ts.map +1 -1
  220. package/dist/lib/browser/client.js +85 -37
  221. package/dist/lib/browser/index.d.ts +3 -1
  222. package/dist/lib/browser/index.d.ts.map +1 -1
  223. package/dist/lib/browser/index.js +2 -1
  224. package/dist/lib/browser/page-review-budget.d.ts +13 -0
  225. package/dist/lib/browser/page-review-budget.d.ts.map +1 -0
  226. package/dist/lib/browser/page-review-budget.js +251 -0
  227. package/dist/lib/browser/page-review-contracts.d.ts +127 -0
  228. package/dist/lib/browser/page-review-contracts.d.ts.map +1 -0
  229. package/dist/lib/browser/page-review-contracts.js +5 -0
  230. package/dist/lib/browser/page-review-evidence.d.ts +48 -0
  231. package/dist/lib/browser/page-review-evidence.d.ts.map +1 -0
  232. package/dist/lib/browser/page-review-evidence.js +340 -0
  233. package/dist/lib/browser/page-review-judge.d.ts +1 -1
  234. package/dist/lib/browser/page-review-judge.d.ts.map +1 -1
  235. package/dist/lib/browser/page-review-judge.js +46 -38
  236. package/dist/lib/browser/page-review-pack.d.ts +44 -22
  237. package/dist/lib/browser/page-review-pack.d.ts.map +1 -1
  238. package/dist/lib/browser/page-review-pack.js +116 -36
  239. package/dist/lib/browser/page-review-source.d.ts +12 -0
  240. package/dist/lib/browser/page-review-source.d.ts.map +1 -0
  241. package/dist/lib/browser/page-review-source.js +22 -0
  242. package/dist/lib/browser/qa-run-contracts.d.ts +35 -9
  243. package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -1
  244. package/dist/lib/browser/qa-run-contracts.js +48 -14
  245. package/dist/lib/browser/qa-run.d.ts.map +1 -1
  246. package/dist/lib/browser/qa-run.js +215 -68
  247. package/dist/lib/browser/qa-snapshot.d.ts +6 -0
  248. package/dist/lib/browser/qa-snapshot.d.ts.map +1 -1
  249. package/dist/lib/browser/qa-snapshot.js +259 -48
  250. package/dist/lib/browser/review-capture-transaction.d.ts +13 -0
  251. package/dist/lib/browser/review-capture-transaction.d.ts.map +1 -0
  252. package/dist/lib/browser/review-capture-transaction.js +79 -0
  253. package/dist/lib/browser/standalone-html.d.ts.map +1 -1
  254. package/dist/lib/browser/standalone-html.js +4 -2
  255. package/dist/lib/browser/thumbnail-association.d.ts +34 -0
  256. package/dist/lib/browser/thumbnail-association.d.ts.map +1 -0
  257. package/dist/lib/browser/thumbnail-association.js +158 -0
  258. package/dist/lib/browser/tiling.d.ts +30 -0
  259. package/dist/lib/browser/tiling.d.ts.map +1 -1
  260. package/dist/lib/browser/tiling.js +38 -0
  261. package/dist/lib/docs-metadata-managed.d.ts.map +1 -1
  262. package/dist/lib/docs-metadata-managed.js +4 -1
  263. package/dist/lib/identities/assume.d.ts.map +1 -1
  264. package/dist/lib/identities/assume.js +7 -1
  265. package/dist/lib/instructions/templates.d.ts.map +1 -1
  266. package/dist/lib/instructions/templates.js +1 -0
  267. package/dist/lib/local-file-url.d.ts +12 -0
  268. package/dist/lib/local-file-url.d.ts.map +1 -1
  269. package/dist/lib/local-file-url.js +16 -2
  270. package/dist/lib/tunnel/state.d.ts +19 -4
  271. package/dist/lib/tunnel/state.d.ts.map +1 -1
  272. package/dist/lib/tunnel/state.js +53 -13
  273. package/package.json +7 -4
  274. package/schemas/config.schema.json +69 -2
  275. package/src/commands/agents.ts +42 -9
  276. package/src/commands/artifacts.ts +130 -6
  277. package/src/commands/backup.ts +287 -34
  278. package/src/commands/browse.ts +564 -267
  279. package/src/commands/diagnostics.ts +6 -3
  280. package/src/commands/ledger-v3.ts +20 -3
  281. package/src/commands/qa-run.ts +37 -3
  282. package/src/commands/qa-status.ts +11 -2
  283. package/src/commands/resources.ts +23 -3
  284. package/src/commands/review-pack.ts +165 -62
  285. package/src/commands/tunnel.ts +2 -1
  286. package/src/core/agents/canonical-emit.ts +4 -2
  287. package/src/core/agents/cli.ts +14 -6
  288. package/src/core/agents/live-authority-v3.ts +7 -3
  289. package/src/core/agents/live-lifecycle-v3.ts +2 -2
  290. package/src/core/agents/render/prompt-context.ts +68 -14
  291. package/src/core/agents/session-finalizer-v3.ts +2 -2
  292. package/src/core/agents/state/live-coordination-view.ts +4 -4
  293. package/src/core/agents/state/names.ts +92 -7
  294. package/src/core/agents/state/stale-sweep.ts +22 -8
  295. package/src/core/agents/turn-elapsed.ts +135 -0
  296. package/src/core/artifacts/activity.ts +71 -0
  297. package/src/core/artifacts/delivery-card.ts +375 -0
  298. package/src/core/artifacts/index.ts +385 -91
  299. package/src/core/artifacts/mutation-lock.ts +106 -0
  300. package/src/core/backup/host-snapshot.ts +76 -0
  301. package/src/core/config.ts +66 -13
  302. package/src/core/diagnostics/advice.ts +148 -120
  303. package/src/core/diagnostics/bundle.ts +138 -52
  304. package/src/core/diagnostics/comparison.ts +6 -2
  305. package/src/core/diagnostics/contract.ts +39 -42
  306. package/src/core/diagnostics/index.ts +2 -0
  307. package/src/core/diagnostics/pressure-contract.ts +294 -0
  308. package/src/core/diagnostics/pressure.ts +1361 -0
  309. package/src/core/diagnostics/replay.ts +116 -11
  310. package/src/core/events/v3/adapter-id.ts +12 -0
  311. package/src/core/events/v3/archive-retention.ts +3 -6
  312. package/src/core/events/v3/bootstrap.ts +163 -16
  313. package/src/core/events/v3/capabilities.ts +75 -25
  314. package/src/core/events/v3/capability-drift.ts +2 -2
  315. package/src/core/events/v3/control-witness.ts +172 -41
  316. package/src/core/events/v3/control.ts +34 -2
  317. package/src/core/events/v3/index.ts +3 -0
  318. package/src/core/events/v3/live-feed.ts +23 -5
  319. package/src/core/events/v3/live-routing.ts +14 -2
  320. package/src/core/events/v3/producers/command-recorder.ts +4 -4
  321. package/src/core/events/v3/producers/coordination-recorder.ts +4 -4
  322. package/src/core/events/v3/producers/hook-base.ts +21 -16
  323. package/src/core/events/v3/producers/hook.ts +21 -4
  324. package/src/core/events/v3/producers/intake.ts +6 -6
  325. package/src/core/events/v3/producers/producer-state-observer.ts +2 -1
  326. package/src/core/events/v3/producers/recorder.ts +50 -21
  327. package/src/core/events/v3/reader.ts +14 -13
  328. package/src/core/events/v3/runtime-build.ts +3 -2
  329. package/src/core/events/v3/runtime-telemetry-capabilities.ts +3 -3
  330. package/src/core/events/v3/turn-telemetry.ts +4 -4
  331. package/src/core/hooks/adapter/output.ts +50 -36
  332. package/src/core/hooks/backup-schedule.ts +147 -0
  333. package/src/core/hooks/cli.ts +65 -14
  334. package/src/core/hooks/codex-wsl-bridge.ts +21 -5
  335. package/src/core/hooks/index.ts +1 -0
  336. package/src/core/hooks/prompt-context/contract.ts +177 -0
  337. package/src/core/hooks/prompt-context/index.ts +22 -0
  338. package/src/core/hooks/prompt-context/runner.ts +303 -0
  339. package/src/core/qa-artifacts.ts +29 -3
  340. package/src/core/resources/contract.ts +76 -3
  341. package/src/core/resources/index.ts +1 -0
  342. package/src/core/resources/native.ts +481 -0
  343. package/src/core/resources/sampler.ts +46 -1
  344. package/src/core/resources/status.ts +717 -0
  345. package/src/core/resources/system.ts +530 -0
  346. package/src/core/semantic/service.ts +37 -3
  347. package/src/core/storage/builtins.ts +41 -0
  348. package/src/core/supervisor/contract.ts +45 -3
  349. package/src/core/supervisor/findings.ts +159 -0
  350. package/src/core/supervisor/history.ts +15 -0
  351. package/src/core/supervisor/ledger-state.ts +0 -0
  352. package/src/core/supervisor/service.ts +133 -5
  353. package/src/core/supervisor/storage.ts +7 -0
  354. package/src/core/workflow/admission.ts +33 -17
  355. package/src/core/workflow/engine.ts +2 -2
  356. package/src/core/workflow/live-session-v3.ts +6 -8
  357. package/src/core/workflow/proof.ts +4 -3
  358. package/src/lib/browser/capture-fidelity.ts +23 -0
  359. package/src/lib/browser/client.ts +96 -44
  360. package/src/lib/browser/index.ts +15 -1
  361. package/src/lib/browser/page-review-budget.ts +309 -0
  362. package/src/lib/browser/page-review-contracts.ts +129 -0
  363. package/src/lib/browser/page-review-evidence.ts +465 -0
  364. package/src/lib/browser/page-review-judge.ts +56 -40
  365. package/src/lib/browser/page-review-pack.ts +181 -43
  366. package/src/lib/browser/page-review-source.ts +30 -0
  367. package/src/lib/browser/qa-run-contracts.ts +62 -18
  368. package/src/lib/browser/qa-run.ts +259 -71
  369. package/src/lib/browser/qa-snapshot.ts +289 -48
  370. package/src/lib/browser/review-capture-transaction.ts +106 -0
  371. package/src/lib/browser/standalone-html.ts +4 -2
  372. package/src/lib/browser/thumbnail-association.ts +190 -0
  373. package/src/lib/browser/tiling.ts +63 -0
  374. package/src/lib/docs-metadata-managed.ts +4 -1
  375. package/src/lib/identities/assume.ts +12 -4
  376. package/src/lib/instructions/templates.ts +1 -0
  377. package/src/lib/local-file-url.ts +17 -2
  378. package/src/lib/tunnel/state.ts +70 -13
@@ -13,6 +13,7 @@ import {
13
13
  replayDiagnosticBundle,
14
14
  showDiagnosticBundle,
15
15
  } from "../core/diagnostics/index.ts";
16
+ import { readPublishedPressure } from "../core/resources/status.ts";
16
17
  import {
17
18
  buildSupervisorTimeline,
18
19
  explainSupervisorFinding,
@@ -112,14 +113,16 @@ export function registerDiagnosticsCommand(
112
113
  }
113
114
  const report = readSupervisorFindings(repoRoot);
114
115
  const findings = mergeFindings(report?.active ?? [], report?.transitions ?? []);
115
- const sourceCapability = liveFindingsCapability(repoRoot, report !== undefined);
116
+ const published = readPublishedPressure(repoRoot);
116
117
  emit.data({
117
118
  schema_version: DIAGNOSTIC_COMMAND_SCHEMA_VERSION,
118
119
  kind: "diagnostic_advice",
119
120
  source: { mode: "live" },
120
121
  advice: buildDiagnosticAdvice({
121
- findings,
122
- sourceCapability,
122
+ assessment: published.assessment,
123
+ priorHysteresis: published.prior_hysteresis,
124
+ sourceCapability: published.capability,
125
+ activeFindingCount: findings.filter((finding) => finding.state === "opened").length,
123
126
  evaluatedAt: new Date().toISOString(),
124
127
  }),
125
128
  });
@@ -15,6 +15,7 @@ import {
15
15
  cleanEventV3Archives,
16
16
  initializeEventLedgerV3,
17
17
  inventoryEventV3Archives,
18
+ listHookProducerStateRecordsV3,
18
19
  readEventV3ControlState,
19
20
  recoverInvalidEventLedgerV3,
20
21
  sha256V3,
@@ -54,9 +55,24 @@ export function registerLedgerV3Command(
54
55
  command
55
56
  .command("status")
56
57
  .description("Read the V3 control boundary without changing it")
57
- .action(() => {
58
+ .option("--root <path>", "Explicit coordination root")
59
+ .action((options: { root?: string }) => {
58
60
  try {
59
- emit.data(readEventV3ControlState(coordRoot(context)));
61
+ const root = resolve(options.root ?? coordRoot(context));
62
+ const control = readEventV3ControlState(root);
63
+ const producers = listHookProducerStateRecordsV3(root, { includeTerminal: true });
64
+ const counts = producers.reduce<Record<string, number>>((summary, record) => {
65
+ summary[record.state.adapter] = (summary[record.state.adapter] ?? 0) + 1;
66
+ return summary;
67
+ }, {});
68
+ emit.data({
69
+ ...control,
70
+ summary: {
71
+ adapters: Object.keys(counts).sort(),
72
+ producer_states: producers.length,
73
+ producer_states_by_adapter: counts,
74
+ },
75
+ });
60
76
  } catch (error) {
61
77
  emitFailure(emit, "ledger_v3_status_failed", error);
62
78
  }
@@ -467,7 +483,8 @@ export function registerLedgerV3Command(
467
483
 
468
484
  function coordRoot(context: HarneryProgramContext | undefined): string {
469
485
  return resolve(
470
- context?.resolveCoordRoot?.() ??
486
+ process.env.HARNERY_COORD_ROOT_OVERRIDE ??
487
+ context?.resolveCoordRoot?.() ??
471
488
  context?.repoRoot ??
472
489
  process.env.HARNERY_COORD_ROOT ??
473
490
  process.cwd(),
@@ -11,7 +11,11 @@ import type { EmitContext, HarneryProgramContext } from "../commander.ts";
11
11
  import { recordQaSignal } from "../core/agents/qa-signal.ts";
12
12
  import { artifactsRoot } from "../core/artifacts/index.ts";
13
13
  import { resolveBinName, reviewPackAutoCleanEnabled } from "../core/config.ts";
14
- import { createManagedQaOutParent, resolveQaRepoRoot } from "../core/qa-artifacts.ts";
14
+ import {
15
+ createManagedQaOutParent,
16
+ managedQaReviewGuidance,
17
+ resolveQaRepoRoot,
18
+ } from "../core/qa-artifacts.ts";
15
19
  import { acquireAdmission, admissionBaseDir, admissionStatus } from "../lib/admission.ts";
16
20
  import {
17
21
  deleteExpiredPacks,
@@ -44,6 +48,8 @@ interface QaRunOpts {
44
48
  mode: string;
45
49
  concurrency?: string;
46
50
  pool?: string;
51
+ tileBudget?: string;
52
+ acceptDispositions?: boolean;
47
53
  allowMetered?: boolean;
48
54
  retain?: string;
49
55
  outDir?: string;
@@ -91,6 +97,14 @@ export function registerQaRunCommand(
91
97
  "Vision calls in flight during the judge stage, across every context (1-16; default: " +
92
98
  "the provider's own concurrency). Sets policy.critique_pool.",
93
99
  )
100
+ .option(
101
+ "--tile-budget <n>",
102
+ "Maximum native tiles across the complete review pack (8-400; default 96).",
103
+ )
104
+ .option(
105
+ "--accept-dispositions",
106
+ "Apply fully reviewed prior decisions only to identical findings on identical native tiles.",
107
+ )
94
108
  .option(
95
109
  "--allow-metered",
96
110
  "Permit the critique provider's metered-API fallback. Default: subscription-backed " +
@@ -208,6 +222,19 @@ export function registerQaRunCommand(
208
222
  }
209
223
 
210
224
  const policy = { ...validation.job.policy };
225
+ if (opts.tileBudget !== undefined) {
226
+ const n = Number(opts.tileBudget);
227
+ if (!Number.isInteger(n) || n < 8 || n > 400) {
228
+ emit.error({
229
+ code: "qa_run_invalid_tile_budget",
230
+ message: "--tile-budget must be an integer between 8 and 400",
231
+ });
232
+ process.exitCode = 1;
233
+ return;
234
+ }
235
+ policy.critique_tile_budget = n;
236
+ }
237
+ if (opts.acceptDispositions) policy.accept_dispositions = true;
211
238
  if (opts.concurrency !== undefined) {
212
239
  const n = Number.parseInt(opts.concurrency, 10);
213
240
  if (!Number.isInteger(n) || n < 1 || n > 8) {
@@ -272,7 +299,9 @@ export function registerQaRunCommand(
272
299
  outParent =
273
300
  opts.outDir !== undefined
274
301
  ? resolve(opts.outDir)
275
- : createManagedQaOutParent(repoRoot, "qa-run");
302
+ : createManagedQaOutParent(repoRoot, "qa-run", {
303
+ onCleanupWarning: (message) => emit.log(message, "warn"),
304
+ });
276
305
  } catch (err: unknown) {
277
306
  emit.error({
278
307
  code: "qa_run_output_unavailable",
@@ -347,6 +376,8 @@ export function registerQaRunCommand(
347
376
  job.mode,
348
377
  ...(opts.concurrency !== undefined ? ["--concurrency", opts.concurrency] : []),
349
378
  ...(opts.pool !== undefined ? ["--pool", opts.pool] : []),
379
+ ...(opts.tileBudget !== undefined ? ["--tile-budget", opts.tileBudget] : []),
380
+ ...(opts.acceptDispositions ? ["--accept-dispositions"] : []),
350
381
  ...(opts.allowMetered ? ["--allow-metered"] : []),
351
382
  ...(opts.retain !== undefined ? ["--retain", opts.retain] : []),
352
383
  "--out-dir",
@@ -473,7 +504,10 @@ export function registerQaRunCommand(
473
504
  // session age. Best-effort by contract: never throws.
474
505
  recordQaSignal(result);
475
506
 
476
- if (opts.json) emit.data(result);
507
+ const afterReview = managedQaReviewGuidance(repoRoot, outParent);
508
+ if (opts.json)
509
+ emit.data({ ...result, ...(afterReview ? { after_review: afterReview } : {}) });
510
+ if (afterReview) emit.log(afterReview, "info");
477
511
  const resultPath = join(result.run.out_dir, QA_RUN_RESULT_FILENAME);
478
512
  for (const blocker of result.blockers) {
479
513
  emit.log(
@@ -11,7 +11,11 @@ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
11
11
  import { dirname, join, resolve } from "node:path";
12
12
  import type { Command } from "commander";
13
13
  import type { EmitContext, HarneryProgramContext } from "../commander.ts";
14
- import { latestManagedQaRun, resolveQaRepoRoot } from "../core/qa-artifacts.ts";
14
+ import {
15
+ latestManagedQaRun,
16
+ managedQaReviewGuidance,
17
+ resolveQaRepoRoot,
18
+ } from "../core/qa-artifacts.ts";
15
19
  import {
16
20
  type AdmissionEntry,
17
21
  admissionBaseDir,
@@ -578,8 +582,13 @@ export function registerQaStatusCommand(
578
582
  const report = outcome.report;
579
583
  const settled = report.terminal || report.state === "dead";
580
584
  if (settled || !opts.wait) {
581
- if (opts.json) emit.data(report);
585
+ const afterReview = report.terminal
586
+ ? managedQaReviewGuidance(resolveQaRepoRoot(context), dirname(runDir))
587
+ : undefined;
588
+ if (opts.json)
589
+ emit.data({ ...report, ...(afterReview ? { after_review: afterReview } : {}) });
582
590
  renderReport(emit, report);
591
+ if (afterReview) emit.log(afterReview, "info");
583
592
  if (!settled && !opts.wait) {
584
593
  emit.log("still in progress; rerun with --wait to block until the run settles", "info");
585
594
  }
@@ -1,7 +1,7 @@
1
1
  import { resolve } from "node:path";
2
2
  import type { Command } from "commander";
3
3
  import type { EmitContext, HarneryProgramContext } from "../commander.ts";
4
- import { sampleResources } from "../core/resources/index.ts";
4
+ import { formatResourceStatus, readResourceStatus } from "../core/resources/status.ts";
5
5
 
6
6
  export function registerResourcesCommand(
7
7
  program: Command,
@@ -10,14 +10,34 @@ export function registerResourcesCommand(
10
10
  ): void {
11
11
  const resources = program
12
12
  .command("resources")
13
- .description("Observe local CPU and memory pressure by agent and process tree");
13
+ .description("Observe local CPU, memory, disk capacity, and resource pressure");
14
+
15
+ resources
16
+ .command("status")
17
+ .description("Read the supervisor's cached resource measurements without sampling")
18
+ .option("--root <path>", "Explicit coordination root")
19
+ .option("--json", "Bounded structured output")
20
+ .option("--processes", "Include up to 20 processes, largest memory first")
21
+ .action((options: { root?: string; json?: boolean; processes?: boolean }) => {
22
+ const status = readResourceStatus(resolve(options.root ?? coordRoot(context)), {
23
+ includeProcesses: options.processes,
24
+ });
25
+ if (options.json) {
26
+ emit.config({ format: "json" });
27
+ emit.data(status);
28
+ } else {
29
+ emit.config({ format: "text" });
30
+ emit.text(formatResourceStatus(status, program.name()));
31
+ }
32
+ });
14
33
 
15
34
  resources
16
35
  .command("snapshot")
17
36
  .description("Capture one machine and process-resource snapshot")
18
37
  .option("--root <path>", "Explicit coordination root")
19
- .action((options: { root?: string }) => {
38
+ .action(async (options: { root?: string }) => {
20
39
  try {
40
+ const { sampleResources } = await import("../core/resources/sampler.ts");
21
41
  emit.data(sampleResources(resolve(options.root ?? coordRoot(context))).snapshot);
22
42
  } catch (error) {
23
43
  fail(emit, "resource_snapshot_failed", error);
@@ -4,14 +4,18 @@
4
4
  // composes the same two library halves; this command exposes them directly
5
5
  // so an agent can prepare a page for review, or review a pack, on its own.
6
6
 
7
- import { mkdirSync, writeFileSync } from "node:fs";
7
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
8
+ import { userInfo } from "node:os";
8
9
  import { resolve } from "node:path";
9
10
  import type { Command } from "commander";
10
11
  import type { EmitContext, HarneryProgramContext } from "../commander.ts";
12
+ import { resolveOwner } from "../core/agents/index.ts";
13
+ import { readLiveCoordinationRow } from "../core/agents/state/live-coordination-view.ts";
11
14
  import { artifactsRoot } from "../core/artifacts/index.ts";
12
15
  import { resolveBinName, reviewPackAutoCleanEnabled } from "../core/config.ts";
13
16
  import { createManagedQaOutParent, resolveQaRepoRoot } from "../core/qa-artifacts.ts";
14
17
  import { DEFAULT_CRITIQUE_RUBRIC } from "../lib/browser/critique.ts";
18
+ import { persistPackReviewDecisions } from "../lib/browser/page-review-evidence.ts";
15
19
  import { judgePageReviewPack, toCritiqueRecords } from "../lib/browser/page-review-judge.ts";
16
20
  import {
17
21
  aggregateMachineOutcome,
@@ -55,7 +59,6 @@ interface CreateOpts {
55
59
  out?: string;
56
60
  context?: string[];
57
61
  scope?: string[];
58
- noBands?: boolean;
59
62
  maxTiles?: string;
60
63
  concurrency?: string;
61
64
  timeout?: string;
@@ -167,6 +170,9 @@ interface ReviewAddOpts {
167
170
  }
168
171
 
169
172
  interface DispositionOpts {
173
+ target?: string[];
174
+ allHigh?: boolean;
175
+ context?: string;
170
176
  note?: string;
171
177
  by?: string;
172
178
  json?: boolean;
@@ -174,6 +180,7 @@ interface DispositionOpts {
174
180
 
175
181
  interface VerdictOpts {
176
182
  json?: boolean;
183
+ snapshotStore?: string;
177
184
  }
178
185
 
179
186
  /** Next free review-subagent finding id in the `F001` series. */
@@ -373,10 +380,9 @@ export function registerReviewPackCommand(
373
380
  (value: string, previous: string[] = []) => [...previous, value],
374
381
  [] as string[],
375
382
  )
376
- .option("--no-bands", "Keep only --scope tiles; skip full-page bands.")
377
383
  .option(
378
384
  "--max-tiles <n>",
379
- "Full-page band cap per context (browse --check-critique-max-tiles).",
385
+ "Native tile cap per context, including required top and bottom bands.",
380
386
  )
381
387
  .option("--concurrency <n>", "Concurrent capture browsers (1-8; default 2).", "2")
382
388
  .option("--timeout <ms>", "Per-capture timeout in milliseconds (default 120000).", "120000")
@@ -465,7 +471,6 @@ export function registerReviewPackCommand(
465
471
  ctx.theme,
466
472
  "--qa-state",
467
473
  ctx.state,
468
- ...(opts.noBands ? ["--no-review-pack-bands"] : []),
469
474
  ...(opts.scope ?? []).flatMap((selector) => ["--review-pack-scope", selector]),
470
475
  ...(opts.maxTiles !== undefined ? ["--check-critique-max-tiles", opts.maxTiles] : []),
471
476
  ];
@@ -637,13 +642,14 @@ export function registerReviewPackCommand(
637
642
 
638
643
  const merged = new Map((manifest.critique ?? []).map((row) => [row.context_id, row]));
639
644
  for (const row of toCritiqueRecords(result)) merged.set(row.context_id, row);
645
+ const judgedRecords = new Map(result.contexts.map((row) => [row.context_id, row.record]));
640
646
  finalizePageReviewPack({
641
647
  packDir,
642
648
  target: manifest.target,
643
649
  ...(manifest.tested_revision !== undefined
644
650
  ? { tested_revision: manifest.tested_revision }
645
651
  : {}),
646
- contexts: manifest.contexts,
652
+ contexts: manifest.contexts.map((record) => judgedRecords.get(record.id) ?? record),
647
653
  gates: manifest.gates,
648
654
  critique: [...merged.values()],
649
655
  pool: result.pool,
@@ -931,6 +937,24 @@ export function registerReviewPackCommand(
931
937
  .option("--json", "Print the summary as JSON.")
932
938
  .action((dir: string, opts: { json?: boolean }) => {
933
939
  const packDir = resolve(dir);
940
+ const stubPath = resolve(packDir, "pack-expired.json");
941
+ if (existsSync(stubPath)) {
942
+ try {
943
+ const stub = JSON.parse(readFileSync(stubPath, "utf8"));
944
+ if (stub.schema !== "harnery-page-review-expired/v1")
945
+ throw new Error("Unknown expired pack schema");
946
+ if (opts.json) emit.data(stub);
947
+ else
948
+ emit.log(
949
+ `expired pack: ${stub.target}; machine ${stub.machine_outcome ?? "not judged"}; reviewed ${stub.result?.reviewed_outcome ?? "no verdict"}`,
950
+ "info",
951
+ );
952
+ } catch (error) {
953
+ emit.error({ code: "review_pack_invalid_stub", message: String(error) });
954
+ process.exitCode = 1;
955
+ }
956
+ return;
957
+ }
934
958
  let manifest: ReturnType<typeof readPackManifest>;
935
959
  try {
936
960
  manifest = readPackManifest(packDir);
@@ -1165,7 +1189,7 @@ export function registerReviewPackCommand(
1165
1189
  });
1166
1190
 
1167
1191
  root
1168
- .command("disposition <dir> <target> <disposition>")
1192
+ .command("disposition <dir> <target-or-disposition> [disposition]")
1169
1193
  .description(
1170
1194
  "Record the reviewer's verdict on one machine finding. <target> is " +
1171
1195
  "<context-id>/<tile-id>#<n>, n the finding's 0-based position among that tile's " +
@@ -1174,62 +1198,117 @@ export function registerReviewPackCommand(
1174
1198
  "target is replaced. evidence/critique.json itself is never rewritten.",
1175
1199
  )
1176
1200
  .option("--note <text>", "Why; what the tile actually shows.")
1177
- .option("--by <name>", "Who dispositioned it.")
1201
+ .option("--by <name>", "Who dispositioned it (default: current agent or local account).")
1202
+ .option(
1203
+ "--target <target>",
1204
+ "Explicit target (repeatable); use disposition as the first positional argument.",
1205
+ (value: string, previous: string[] = []) => [...previous, value],
1206
+ [] as string[],
1207
+ )
1208
+ .option("--all-high", "Disposition every high finding in --context.")
1209
+ .option("--context <id>", "Required with --all-high.")
1178
1210
  .option("--json", "Print the written disposition as JSON.")
1179
- .action((dir: string, target: string, disposition: string, opts: DispositionOpts) => {
1180
- const pack = readReviewerPack(dir, emit);
1181
- if (!pack) return;
1182
- const { packDir, manifest, findings: doc } = pack;
1183
- if (!(PAGE_REVIEW_DISPOSITIONS as readonly string[]).includes(disposition)) {
1184
- emit.error({
1185
- code: "review_pack_invalid_disposition",
1186
- message: `disposition must be one of ${PAGE_REVIEW_DISPOSITIONS.join(", ")} (got ${JSON.stringify(disposition)})`,
1187
- });
1188
- process.exitCode = 1;
1189
- return;
1190
- }
1191
- if (manifest.critique === null) {
1192
- emit.error({
1193
- code: "review_pack_not_judged",
1194
- message: `the judge has not run for this pack, so there is no machine finding to disposition; run: ${judgeCommandFor(packDir)}`,
1195
- });
1196
- process.exitCode = 1;
1197
- return;
1198
- }
1199
- const targets = machineFindingTargets(manifest.critique);
1200
- const machine = targets.get(target.trim());
1201
- if (!machine) {
1202
- const sample = [...targets.keys()].slice(0, 8).join(", ");
1203
- emit.error({
1204
- code: "review_pack_unknown_finding",
1205
- message:
1206
- `${JSON.stringify(target)} names no machine finding in evidence/critique.json` +
1207
- (sample ? ` (known targets include: ${sample})` : " (the critique holds no findings)"),
1208
- });
1209
- process.exitCode = 1;
1210
- return;
1211
- }
1212
- const entry = {
1213
- target: target.trim(),
1214
- disposition: disposition as PageReviewDisposition,
1215
- ...(opts.note !== undefined ? { note: opts.note } : {}),
1216
- ...(opts.by !== undefined ? { by: opts.by } : {}),
1217
- at: new Date().toISOString(),
1218
- };
1219
- const kept = (doc.dispositions ?? []).filter((d) => d.target !== entry.target);
1220
- const next: PageReviewFindingsDocument = {
1221
- ...doc,
1222
- reviewed_at: new Date().toISOString(),
1223
- dispositions: [...kept, entry],
1224
- };
1225
- if (!commitFindings(packDir, next, emit)) return;
1226
- emit.log(
1227
- `${entry.target} · ${machine.severity} · ${machine.category} → ${entry.disposition}` +
1228
- (kept.length < (doc.dispositions ?? []).length ? " (replaced)" : ""),
1229
- "info",
1230
- );
1231
- if (opts.json) emit.data(entry as unknown as Record<string, unknown>);
1232
- });
1211
+ .action(
1212
+ (
1213
+ dir: string,
1214
+ targetOrDisposition: string,
1215
+ positionalDisposition: string | undefined,
1216
+ opts: DispositionOpts,
1217
+ ) => {
1218
+ const disposition = positionalDisposition ?? targetOrDisposition;
1219
+ const pack = readReviewerPack(dir, emit);
1220
+ if (!pack) return;
1221
+ const { packDir, manifest, findings: doc } = pack;
1222
+ if (!(PAGE_REVIEW_DISPOSITIONS as readonly string[]).includes(disposition)) {
1223
+ emit.error({
1224
+ code: "review_pack_invalid_disposition",
1225
+ message: `disposition must be one of ${PAGE_REVIEW_DISPOSITIONS.join(", ")} (got ${JSON.stringify(disposition)})`,
1226
+ });
1227
+ process.exitCode = 1;
1228
+ return;
1229
+ }
1230
+ if (manifest.critique === null) {
1231
+ emit.error({
1232
+ code: "review_pack_not_judged",
1233
+ message: `the judge has not run for this pack, so there is no machine finding to disposition; run: ${judgeCommandFor(packDir)}`,
1234
+ });
1235
+ process.exitCode = 1;
1236
+ return;
1237
+ }
1238
+ const targets = machineFindingTargets(manifest.critique);
1239
+ if (opts.allHigh && (!opts.context || positionalDisposition || opts.target?.length)) {
1240
+ emit.error({
1241
+ code: "review_pack_invalid_selection",
1242
+ message: "--all-high requires --context and cannot be combined with explicit targets",
1243
+ });
1244
+ process.exitCode = 1;
1245
+ return;
1246
+ }
1247
+ if (opts.context && !manifest.contexts.some((ctx) => ctx.id === opts.context)) {
1248
+ emit.error({
1249
+ code: "review_pack_unknown_context",
1250
+ message: "Unknown disposition context",
1251
+ });
1252
+ process.exitCode = 1;
1253
+ return;
1254
+ }
1255
+ const selected = [
1256
+ ...new Set(
1257
+ opts.allHigh
1258
+ ? [...targets]
1259
+ .filter(([, f]) => f.context_id === opts.context && f.severity === "high")
1260
+ .map(([key]) => key)
1261
+ : [
1262
+ ...(positionalDisposition ? targetOrDisposition.split(",") : []),
1263
+ ...(opts.target ?? []),
1264
+ ]
1265
+ .map((t) => t.trim())
1266
+ .filter(Boolean),
1267
+ ),
1268
+ ];
1269
+ const invalid = selected.filter((target) => !targets.has(target));
1270
+ if (!selected.length || invalid.length) {
1271
+ emit.error({
1272
+ code: "review_pack_unknown_finding",
1273
+ message: `No valid selection, or unknown target(s): ${invalid.join(", ")} (known targets include: ${[...targets.keys()].slice(0, 8).join(", ")})`,
1274
+ });
1275
+ process.exitCode = 1;
1276
+ return;
1277
+ }
1278
+ const owner = resolveOwner();
1279
+ const by =
1280
+ opts.by?.trim() ||
1281
+ (owner
1282
+ ? readLiveCoordinationRow(resolveQaRepoRoot(context), owner)?.name || owner
1283
+ : userInfo().username);
1284
+ const entries = selected.map((target) => ({
1285
+ target,
1286
+ disposition: disposition as PageReviewDisposition,
1287
+ ...(opts.note === undefined ? {} : { note: opts.note }),
1288
+ by,
1289
+ at: new Date().toISOString(),
1290
+ }));
1291
+ const next: PageReviewFindingsDocument = {
1292
+ ...doc,
1293
+ reviewed_at: new Date().toISOString(),
1294
+ dispositions: [
1295
+ ...(doc.dispositions ?? []).filter((d) => !selected.includes(d.target)),
1296
+ ...entries,
1297
+ ],
1298
+ };
1299
+ if (!commitFindings(packDir, next, emit)) return;
1300
+ emit.log(
1301
+ `${entries.length} finding(s) dispositioned ${disposition} by ${by}${(doc.dispositions ?? []).some((d) => selected.includes(d.target)) ? " (replaced)" : ""}`,
1302
+ "info",
1303
+ );
1304
+ if (opts.json)
1305
+ emit.data(
1306
+ entries.length === 1
1307
+ ? (entries[0] as unknown as Record<string, unknown>)
1308
+ : { dispositions: entries },
1309
+ );
1310
+ },
1311
+ );
1233
1312
 
1234
1313
  root
1235
1314
  .command("verdict <dir>")
@@ -1241,6 +1320,10 @@ export function registerReviewPackCommand(
1241
1320
  "and refreshes review.md. Exit 2 on fail, 4 when critique or delegated coverage is " +
1242
1321
  "skipped or incomplete, 1 on a findings.json validation error.",
1243
1322
  )
1323
+ .option(
1324
+ "--snapshot-store <dir>",
1325
+ "Native baseline and durable decision store (default: local QA cache).",
1326
+ )
1244
1327
  .option("--json", "Print the verdict as JSON.")
1245
1328
  .action((dir: string, opts: VerdictOpts) => {
1246
1329
  const pack = readReviewerPack(dir, emit);
@@ -1261,6 +1344,26 @@ export function registerReviewPackCommand(
1261
1344
  ...resolvePackVerdict(manifest, readPackInspectionPlan(packDir), doc),
1262
1345
  reviewed_at: new Date().toISOString(),
1263
1346
  };
1347
+ try {
1348
+ // Incomplete submissions may report their outcome, but cannot publish decisions.
1349
+ if (
1350
+ verdict.uncovered_primary_tiles.length === 0 &&
1351
+ verdict.machine_outcome !== "skipped" &&
1352
+ verdict.machine_outcome !== "incomplete"
1353
+ ) {
1354
+ persistPackReviewDecisions(
1355
+ packDir,
1356
+ opts.snapshotStore ? { root: resolve(opts.snapshotStore) } : {},
1357
+ );
1358
+ }
1359
+ } catch (error) {
1360
+ emit.error({
1361
+ code: "review_pack_decisions_not_saved",
1362
+ message: error instanceof Error ? error.message : String(error),
1363
+ });
1364
+ process.exitCode = 1;
1365
+ return;
1366
+ }
1264
1367
  const paths = packPaths(packDir);
1265
1368
  mkdirSync(paths.evidenceDir, { recursive: true });
1266
1369
  writeFileSync(paths.verdict, `${JSON.stringify(verdict, null, 2)}\n`);
@@ -16,6 +16,7 @@ import {
16
16
  ensureCloudflared,
17
17
  gateLogFile,
18
18
  isProcessAlive,
19
+ isTunnelStateLive,
19
20
  listStates,
20
21
  providerLogFile,
21
22
  readConfig,
@@ -433,7 +434,7 @@ function providerIsAlive(state: TunnelState): boolean {
433
434
  }
434
435
 
435
436
  function tunnelIsAlive(state: TunnelState): boolean {
436
- return isProcessAlive(state.gate_pid) && providerIsAlive(state);
437
+ return isTunnelStateLive(state);
437
438
  }
438
439
 
439
440
  interface GateSpawnOpts {
@@ -11,6 +11,7 @@
11
11
  */
12
12
 
13
13
  import { spawnSync } from "node:child_process";
14
+ import type { EventAdapterIdV3 } from "../events/v3/adapter-id.ts";
14
15
  import type { LiveCoordinationObservationV3 } from "../events/v3/live-observation.ts";
15
16
  import { coordBinPath } from "./coord-bin.ts";
16
17
  import { resolveCoordRoot } from "./coord-client.ts";
@@ -28,7 +29,7 @@ export type EventV3EmitObservation =
28
29
  export interface EventV3EmitInput {
29
30
  owner: string;
30
31
  session: string;
31
- adapter: "claude-code" | "cursor" | "codex";
32
+ adapter: EventAdapterIdV3;
32
33
  observation: EventV3EmitObservation;
33
34
  }
34
35
 
@@ -92,9 +93,10 @@ export function emitEventV3(input: EventV3EmitInput): boolean {
92
93
  /**
93
94
  * Normalize the heartbeat's `platform` field to the canonical Adapter type.
94
95
  */
95
- export function normalizeAdapter(platform: string | undefined): "claude-code" | "cursor" | "codex" {
96
+ export function normalizeAdapter(platform: string | undefined): EventAdapterIdV3 {
96
97
  if (platform === "cursor") return "cursor";
97
98
  if (platform === "codex") return "codex";
99
+ if (platform === "openclaw") return "openclaw";
98
100
  return "claude-code";
99
101
  }
100
102