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
@@ -20,11 +20,58 @@
20
20
 
21
21
  import { spawnSync } from "node:child_process";
22
22
  import { randomBytes } from "node:crypto";
23
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
23
+ import {
24
+ existsSync,
25
+ lstatSync,
26
+ mkdirSync,
27
+ readdirSync,
28
+ readFileSync,
29
+ rmSync,
30
+ writeFileSync,
31
+ } from "node:fs";
32
+ import { hostname } from "node:os";
24
33
  import path from "node:path";
25
34
  import type { Command } from "commander";
26
35
  import type { EmitContext } from "../commander.ts";
27
- import { backupConfig } from "../core/config.ts";
36
+ import {
37
+ newestSnapshotTime,
38
+ parseBackupDuration,
39
+ recordHostSnapshot,
40
+ } from "../core/backup/host-snapshot.ts";
41
+ import { type BackupConfig, backupConfig } from "../core/config.ts";
42
+ import { createStorageCatalog } from "../core/storage/catalog.ts";
43
+ import type { HarneryStorageClass } from "../core/storage/contract.ts";
44
+
45
+ export {
46
+ hostSnapshotCachePath,
47
+ newestSnapshotTime,
48
+ parseBackupDuration,
49
+ readHostSnapshotCache,
50
+ } from "../core/backup/host-snapshot.ts";
51
+
52
+ export const DEFAULT_BACKUP_MAX_BYTES = 50 * 1_024 * 1_024;
53
+ export const DEFAULT_BACKUP_CLASSES = new Set<HarneryStorageClass>([
54
+ "canonical-authority",
55
+ "durable-object-history",
56
+ "recovery-state",
57
+ ]);
58
+ export const DEFAULT_BACKUP_EXCLUDED_CLASSES = new Set<HarneryStorageClass>([
59
+ "debug-log",
60
+ "managed-artifact",
61
+ "operational-log",
62
+ "repairable-cache",
63
+ ]);
64
+ export const DEFAULT_BACKUP_EXCLUDED_FAMILY_IDS = new Set([
65
+ "event-v3-canonical-active",
66
+ "event-v3-canonical-archives",
67
+ "event-v3-support-active",
68
+ "event-v3-support-archives",
69
+ "event-v3-recovery-records",
70
+ "legacy-canonical-ledgers",
71
+ "managed-artifacts",
72
+ "captured-images",
73
+ "storage-exports",
74
+ ]);
28
75
 
29
76
  function defaultRepo(): string {
30
77
  return backupConfig().repo;
@@ -54,6 +101,170 @@ function ensurePasswordFile(file: string): void {
54
101
  writeFileSync(file, `${pw}\n`, { encoding: "utf-8", mode: 0o600 });
55
102
  }
56
103
 
104
+ function isFilesystemRepository(repo: string): boolean {
105
+ if (/^[a-zA-Z]:[\\/]/.test(repo)) return true;
106
+ return !/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(repo);
107
+ }
108
+
109
+ function inside(base: string, candidate: string): boolean {
110
+ const relative = path.relative(base, candidate);
111
+ return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
112
+ }
113
+
114
+ function configPath(harneryDir: string, value: string): string | null {
115
+ if (path.isAbsolute(value)) return null;
116
+ const normalized = value.replaceAll("\\", "/").replace(/^\.harnery\//, "");
117
+ if (!normalized || normalized.split("/").some((part) => part === ".." || part === "")) {
118
+ return null;
119
+ }
120
+ const resolved = path.resolve(harneryDir, normalized);
121
+ return inside(harneryDir, resolved) ? resolved : null;
122
+ }
123
+
124
+ export interface BackupSelection {
125
+ targets: readonly string[];
126
+ familyIds: readonly string[];
127
+ }
128
+
129
+ export function resolveBackupSelection(
130
+ projectRoot: string,
131
+ config: BackupConfig = backupConfig(projectRoot),
132
+ includeArtifacts = false,
133
+ ): BackupSelection {
134
+ const root = path.resolve(projectRoot);
135
+ const harneryDir = path.join(root, ".harnery");
136
+ const catalog = createStorageCatalog({ coord_root: root, project_root: root });
137
+ const knownFamilyIds = new Set(catalog.families.map((family) => family.id));
138
+ const configuredFamilyExclusions = new Set(
139
+ config.exclude.filter((entry) => knownFamilyIds.has(entry)),
140
+ );
141
+ const configuredPathExclusions = config.exclude
142
+ .filter((entry) => !knownFamilyIds.has(entry))
143
+ .map((entry) => configPath(harneryDir, entry))
144
+ .filter((entry): entry is string => entry !== null);
145
+ const selectedFamilies = catalog.families.filter(
146
+ (family) =>
147
+ DEFAULT_BACKUP_CLASSES.has(family.storage_class) &&
148
+ !DEFAULT_BACKUP_EXCLUDED_FAMILY_IDS.has(family.id) &&
149
+ !configuredFamilyExclusions.has(family.id),
150
+ );
151
+ const excludedByPath = (candidate: string): boolean =>
152
+ configuredPathExclusions.some(
153
+ (excluded) => candidate === excluded || inside(excluded, candidate),
154
+ );
155
+ const targets = selectedFamilies
156
+ .flatMap((family) => family.resolved_roots.map((storageRoot) => storageRoot.path))
157
+ .filter((candidate) => inside(harneryDir, candidate))
158
+ .filter((candidate) => !excludedByPath(candidate));
159
+ for (const entry of config.include) {
160
+ const candidate = configPath(harneryDir, entry);
161
+ if (candidate && !excludedByPath(candidate)) targets.push(candidate);
162
+ }
163
+ if (includeArtifacts) targets.push(path.join(harneryDir, "artifacts"));
164
+ return {
165
+ targets: [...new Set(targets)].filter(existsSync).sort(),
166
+ familyIds: selectedFamilies.map((family) => family.id).sort(),
167
+ };
168
+ }
169
+
170
+ export function backupCatalogCoverage(projectRoot: string): {
171
+ uncovered: readonly string[];
172
+ } {
173
+ const root = path.resolve(projectRoot);
174
+ const harneryDir = path.join(root, ".harnery");
175
+ const catalog = createStorageCatalog({ coord_root: root, project_root: root });
176
+ const uncovered = catalog.families
177
+ .filter((family) => {
178
+ const selected =
179
+ DEFAULT_BACKUP_CLASSES.has(family.storage_class) &&
180
+ !DEFAULT_BACKUP_EXCLUDED_FAMILY_IDS.has(family.id);
181
+ const excluded =
182
+ DEFAULT_BACKUP_EXCLUDED_CLASSES.has(family.storage_class) ||
183
+ DEFAULT_BACKUP_EXCLUDED_FAMILY_IDS.has(family.id);
184
+ const externalOnly =
185
+ family.resolved_roots.length === 0 ||
186
+ family.resolved_roots.every((storageRoot) => !inside(harneryDir, storageRoot.path));
187
+ return !selected && !excluded && !externalOnly;
188
+ })
189
+ .map((family) => family.id);
190
+ return { uncovered };
191
+ }
192
+
193
+ export function selectedLogicalBytes(targets: readonly string[]): number {
194
+ const visited = new Set<string>();
195
+ const measure = (candidate: string): number => {
196
+ let stat: ReturnType<typeof lstatSync>;
197
+ try {
198
+ stat = lstatSync(candidate);
199
+ } catch {
200
+ return 0;
201
+ }
202
+ const identity = `${stat.dev}:${stat.ino}`;
203
+ if (visited.has(identity)) return 0;
204
+ visited.add(identity);
205
+ if (stat.isSymbolicLink()) return 0;
206
+ if (stat.isFile()) return stat.size;
207
+ if (!stat.isDirectory()) return 0;
208
+ return readdirSync(candidate).reduce(
209
+ (total, entry) => total + measure(path.join(candidate, entry)),
210
+ 0,
211
+ );
212
+ };
213
+ return targets.reduce((total, target) => total + measure(target), 0);
214
+ }
215
+
216
+ function lockOwnerIsAlive(lockDir: string): boolean {
217
+ try {
218
+ const owner = JSON.parse(readFileSync(path.join(lockDir, "owner.json"), "utf8")) as {
219
+ pid?: number;
220
+ created_at?: string;
221
+ };
222
+ if (typeof owner.pid === "number" && owner.pid > 0) {
223
+ try {
224
+ process.kill(owner.pid, 0);
225
+ return true;
226
+ } catch {
227
+ // The owner is gone; the directory is reclaimable.
228
+ }
229
+ }
230
+ const createdAt = typeof owner.created_at === "string" ? Date.parse(owner.created_at) : 0;
231
+ return Number.isFinite(createdAt) && Date.now() - createdAt < 60 * 60 * 1_000;
232
+ } catch {
233
+ return false;
234
+ }
235
+ }
236
+
237
+ function acquireSnapshotLock(harneryDir: string): { acquired: boolean; release(): void } {
238
+ const locksDir = path.join(harneryDir, "locks");
239
+ const lockDir = path.join(locksDir, "backup-snapshot.lock");
240
+ mkdirSync(locksDir, { recursive: true });
241
+ const create = (): boolean => {
242
+ try {
243
+ mkdirSync(lockDir);
244
+ writeFileSync(
245
+ path.join(lockDir, "owner.json"),
246
+ `${JSON.stringify({ pid: process.pid, created_at: new Date().toISOString() })}\n`,
247
+ "utf8",
248
+ );
249
+ return true;
250
+ } catch (error) {
251
+ if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
252
+ return false;
253
+ }
254
+ };
255
+ if (!create()) {
256
+ if (lockOwnerIsAlive(lockDir)) return { acquired: false, release() {} };
257
+ rmSync(lockDir, { recursive: true, force: true });
258
+ if (!create()) return { acquired: false, release() {} };
259
+ }
260
+ return {
261
+ acquired: true,
262
+ release() {
263
+ rmSync(lockDir, { recursive: true, force: true });
264
+ },
265
+ };
266
+ }
267
+
57
268
  interface RunOpts {
58
269
  repo?: string;
59
270
  passwordFile?: string;
@@ -121,7 +332,7 @@ export function registerBackupCommand(program: Command, emit: EmitContext): void
121
332
  const repo = opts.repo ?? defaultRepo();
122
333
  const pwFile = opts.passwordFile ?? defaultPasswordFile();
123
334
  ensurePasswordFile(pwFile);
124
- mkdirSync(path.dirname(repo), { recursive: true });
335
+ if (isFilesystemRepository(repo)) mkdirSync(path.dirname(repo), { recursive: true });
125
336
  const r = runRestic(["init"], { repo, passwordFile: pwFile, stdio: "inherit" });
126
337
  if (r.exitCode === 0) {
127
338
  emit.text(`restic repo initialized at ${repo}\npassword file: ${pwFile}`);
@@ -143,19 +354,23 @@ export function registerBackupCommand(program: Command, emit: EmitContext): void
143
354
  "--include-artifacts",
144
355
  "Include managed working artifacts (default: excluded; potentially large + ephemeral)",
145
356
  )
357
+ .option("--allow-large", "Permit a selected set larger than backup.max_bytes")
358
+ .option("--if-stale <duration>", "Skip when this host has a newer snapshot (for example 24h)")
146
359
  .action(
147
360
  (
148
361
  opts: BaseOpts & {
149
362
  tag: string[];
150
363
  includeArtifacts?: boolean;
364
+ allowLarge?: boolean;
365
+ ifStale?: string;
151
366
  },
152
367
  ) => {
153
368
  if (!checkRestic(emit)) {
154
369
  emit.setExitCode(1);
155
370
  return;
156
371
  }
157
- const harnery = findHarneryDir();
158
- if (!harnery) {
372
+ const harneryDir = findHarneryDir();
373
+ if (!harneryDir) {
159
374
  emit.error({
160
375
  code: "target_missing",
161
376
  message: "No .harnery/ found above cwd; run from an initialized project",
@@ -163,40 +378,78 @@ export function registerBackupCommand(program: Command, emit: EmitContext): void
163
378
  emit.setExitCode(1);
164
379
  return;
165
380
  }
166
- const passThrough: string[] = [];
167
- for (const t of opts.tag) {
168
- passThrough.push("--tag", t);
169
- }
170
- const safeTargets = [
171
- "ledgers",
172
- "councils",
173
- "journal",
174
- "work",
175
- "workflows",
176
- "decisions",
177
- "config.jsonc",
178
- ".name-history",
179
- ]
180
- .map((entry) => path.join(harnery, entry))
181
- .filter(existsSync);
182
- if (opts.includeArtifacts && existsSync(path.join(harnery, "artifacts"))) {
183
- safeTargets.push(path.join(harnery, "artifacts"));
184
- }
185
- if (safeTargets.length === 0) {
381
+ const staleMs = opts.ifStale ? parseBackupDuration(opts.ifStale) : null;
382
+ if (opts.ifStale && staleMs === null) {
186
383
  emit.error({
187
- code: "backup_empty",
188
- message: "No durable V3 state is available to back up",
384
+ code: "backup_invalid_duration",
385
+ message: `Invalid --if-stale duration: ${opts.ifStale}`,
386
+ hint: "Use an integer duration such as 30m, 24h, or 7d",
189
387
  });
190
388
  emit.setExitCode(1);
191
389
  return;
192
390
  }
193
- const r = runRestic(["backup", ...safeTargets], {
194
- repo: opts.repo,
195
- passwordFile: opts.passwordFile,
196
- stdio: "inherit",
197
- passThrough,
198
- });
199
- emit.setExitCode(r.exitCode);
391
+ const lock = acquireSnapshotLock(harneryDir);
392
+ if (!lock.acquired) {
393
+ emit.text("backup snapshot already running; skipped");
394
+ return;
395
+ }
396
+ try {
397
+ if (staleMs !== null) {
398
+ const latest = runRestic(["snapshots", "--json", "--host", hostname()], {
399
+ repo: opts.repo,
400
+ passwordFile: opts.passwordFile,
401
+ stdio: "pipe",
402
+ });
403
+ if (latest.exitCode !== 0) {
404
+ emit.error({ code: "backup_snapshot_list_failed", message: latest.stdout.trim() });
405
+ emit.setExitCode(latest.exitCode);
406
+ return;
407
+ }
408
+ const newest = newestSnapshotTime(latest.stdout);
409
+ if (newest !== null && Date.now() - newest < staleMs) {
410
+ recordHostSnapshot(harneryDir, newest);
411
+ emit.text(`latest snapshot for ${hostname()} is newer than ${opts.ifStale}; skipped`);
412
+ return;
413
+ }
414
+ }
415
+ const config = backupConfig(path.dirname(harneryDir));
416
+ const selection = resolveBackupSelection(
417
+ path.dirname(harneryDir),
418
+ config,
419
+ opts.includeArtifacts,
420
+ );
421
+ if (selection.targets.length === 0) {
422
+ emit.error({
423
+ code: "backup_empty",
424
+ message: "No durable Harnery state is available to back up",
425
+ });
426
+ emit.setExitCode(1);
427
+ return;
428
+ }
429
+ const logicalBytes = selectedLogicalBytes(selection.targets);
430
+ if (!opts.allowLarge && logicalBytes > config.maxBytes) {
431
+ emit.error({
432
+ code: "backup_too_large",
433
+ message: `Selected backup is ${logicalBytes} bytes; limit is ${config.maxBytes} bytes`,
434
+ hint: "Review backup.include/exclude or pass --allow-large for this snapshot",
435
+ });
436
+ emit.setExitCode(1);
437
+ return;
438
+ }
439
+ const passThrough: string[] = [];
440
+ for (const tag of opts.tag) passThrough.push("--tag", tag);
441
+ const startedAt = Date.now();
442
+ const result = runRestic(["backup", ...selection.targets], {
443
+ repo: opts.repo,
444
+ passwordFile: opts.passwordFile,
445
+ stdio: "inherit",
446
+ passThrough,
447
+ });
448
+ if (result.exitCode === 0) recordHostSnapshot(harneryDir, startedAt);
449
+ emit.setExitCode(result.exitCode);
450
+ } finally {
451
+ lock.release();
452
+ }
200
453
  },
201
454
  );
202
455