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
@@ -0,0 +1,71 @@
1
+ import { createHash } from "node:crypto";
2
+ import { lstatSync, readdirSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { ARTIFACT_MANIFEST } from "./constants.ts";
5
+
6
+ /** A checkpoint taken before an internal manifest write, never an expiry override. */
7
+ export interface ArtifactActivity {
8
+ last_changed_at: string;
9
+ root_entries_sha256: string;
10
+ }
11
+
12
+ export function validArtifactActivity(value: unknown): value is ArtifactActivity {
13
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
14
+ const item = value as Partial<ArtifactActivity>;
15
+ return (
16
+ typeof item.last_changed_at === "string" &&
17
+ Number.isFinite(Date.parse(item.last_changed_at)) &&
18
+ typeof item.root_entries_sha256 === "string" &&
19
+ /^[a-f0-9]{64}$/.test(item.root_entries_sha256)
20
+ );
21
+ }
22
+
23
+ export function artifactRootEntries(path: string): string {
24
+ return createHash("sha256")
25
+ .update(
26
+ JSON.stringify(
27
+ readdirSync(path)
28
+ .filter((name) => name !== ARTIFACT_MANIFEST)
29
+ .sort(),
30
+ ),
31
+ )
32
+ .digest("hex");
33
+ }
34
+
35
+ /** Metadata writes change both the manifest and its parent directory timestamps.
36
+ * Keep the prior root activity while its payload entries match the checkpoint.
37
+ * A root deletion or rename changes that fingerprint; nested changes retain
38
+ * their ordinary filesystem timestamps. Symlinks are inspected, never followed.
39
+ */
40
+ export function readArtifactActivity(
41
+ path: string,
42
+ now: Date,
43
+ previous?: ArtifactActivity,
44
+ ): ArtifactActivity {
45
+ const entries = artifactRootEntries(path);
46
+ const nowMs = now.getTime();
47
+ const accept = (timestamp: number): number =>
48
+ Number.isFinite(timestamp) && timestamp <= nowMs + 5 * 60 * 1000
49
+ ? Math.min(timestamp, nowMs)
50
+ : 0;
51
+ const walk = (entry: string, root = false): number => {
52
+ const stat = lstatSync(entry);
53
+ let latest =
54
+ root && previous?.root_entries_sha256 === entries
55
+ ? accept(Date.parse(previous.last_changed_at))
56
+ : Math.max(accept(stat.mtimeMs), accept(stat.ctimeMs));
57
+ if (stat.isDirectory() && !stat.isSymbolicLink()) {
58
+ for (const name of readdirSync(entry)) {
59
+ // Only this unit's own control manifest is metadata. Nested artifact
60
+ // manifests are payload from the containing workspace's point of view.
61
+ if (root && previous && name === ARTIFACT_MANIFEST) continue;
62
+ latest = Math.max(latest, walk(join(entry, name)));
63
+ }
64
+ }
65
+ return latest;
66
+ };
67
+ const latest = Math.max(accept(Date.parse(previous?.last_changed_at ?? "")), walk(path, true));
68
+ if (artifactRootEntries(path) !== entries)
69
+ throw new Error("artifact entries changed during scan");
70
+ return { last_changed_at: new Date(latest).toISOString(), root_entries_sha256: entries };
71
+ }
@@ -0,0 +1,375 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { randomUUID } from "node:crypto";
3
+ import {
4
+ existsSync,
5
+ lstatSync,
6
+ readdirSync,
7
+ readFileSync,
8
+ realpathSync,
9
+ renameSync,
10
+ rmSync,
11
+ writeFileSync,
12
+ } from "node:fs";
13
+ import { isAbsolute, relative, resolve, sep } from "node:path";
14
+ import { encodeLinkSafeComponent } from "../../lib/local-file-url.ts";
15
+ import { findLiveTunnelForOrigin } from "../../lib/tunnel/state.ts";
16
+ import { resolveWebPort } from "../config.ts";
17
+ import { ARTIFACT_MANIFEST } from "./constants.ts";
18
+ import { resolveArtifactRef, showArtifact } from "./index.ts";
19
+
20
+ export const ARTIFACT_DELIVERY_MANIFEST = ".harnery-delivery.json";
21
+ export const ARTIFACT_DELIVERY_SCHEMA_VERSION = 1 as const;
22
+ export const ARTIFACT_DELIVERY_AUTO_ITEM_LIMIT = 5;
23
+
24
+ export interface ArtifactDeliveryUrl {
25
+ kind: "url";
26
+ label: string;
27
+ target: string;
28
+ }
29
+
30
+ export interface ArtifactDeliveryPath {
31
+ kind: "path";
32
+ label: string;
33
+ path: string;
34
+ }
35
+
36
+ export type ArtifactDeliveryItem = ArtifactDeliveryUrl | ArtifactDeliveryPath;
37
+
38
+ export interface ArtifactDeliveryManifest {
39
+ schema_version: typeof ARTIFACT_DELIVERY_SCHEMA_VERSION;
40
+ title: string;
41
+ items: ArtifactDeliveryItem[];
42
+ }
43
+
44
+ export interface ArtifactDeliveryCard {
45
+ artifact_path: string;
46
+ manifest_path: string;
47
+ markdown: string;
48
+ auto_items: number;
49
+ omitted_auto_items: number;
50
+ }
51
+
52
+ interface DisplayEnvironment {
53
+ platform?: NodeJS.Platform;
54
+ wslDistroName?: string;
55
+ webPort?: number;
56
+ tunnelUrl?: string | null;
57
+ }
58
+
59
+ export function writeArtifactDeliveryManifest(
60
+ repoRoot: string,
61
+ ref: string,
62
+ input: Omit<ArtifactDeliveryManifest, "schema_version">,
63
+ ): ArtifactDeliveryManifest {
64
+ const artifactPath = managedArtifactPath(repoRoot, ref);
65
+ const manifest = validateManifest(artifactPath, {
66
+ schema_version: ARTIFACT_DELIVERY_SCHEMA_VERSION,
67
+ ...input,
68
+ });
69
+ const target = resolve(artifactPath, ARTIFACT_DELIVERY_MANIFEST);
70
+ const tmp = `${target}.tmp.${process.pid}.${randomUUID().slice(0, 8)}`;
71
+ try {
72
+ writeFileSync(tmp, `${JSON.stringify(manifest, null, 2)}\n`, {
73
+ encoding: "utf8",
74
+ mode: 0o600,
75
+ flag: "wx",
76
+ });
77
+ renameSync(tmp, target);
78
+ } finally {
79
+ rmSync(tmp, { force: true });
80
+ }
81
+ return manifest;
82
+ }
83
+
84
+ export function readArtifactDeliveryManifest(
85
+ repoRoot: string,
86
+ ref: string,
87
+ ): ArtifactDeliveryManifest {
88
+ const artifactPath = managedArtifactPath(repoRoot, ref);
89
+ const path = resolve(artifactPath, ARTIFACT_DELIVERY_MANIFEST);
90
+ let parsed: unknown;
91
+ try {
92
+ parsed = JSON.parse(readFileSync(path, "utf8"));
93
+ } catch (error) {
94
+ throw new Error(
95
+ `cannot read ${ARTIFACT_DELIVERY_MANIFEST}: ${error instanceof Error ? error.message : String(error)}`,
96
+ );
97
+ }
98
+ return validateManifest(artifactPath, parsed);
99
+ }
100
+
101
+ export function resolveArtifactDeliveryManifest(
102
+ repoRoot: string,
103
+ ref: string,
104
+ ): ArtifactDeliveryManifest {
105
+ const artifactPath = managedArtifactPath(repoRoot, ref);
106
+ if (!existsSync(resolve(artifactPath, ARTIFACT_DELIVERY_MANIFEST))) {
107
+ return {
108
+ schema_version: ARTIFACT_DELIVERY_SCHEMA_VERSION,
109
+ title: "Artifact delivery",
110
+ items: [],
111
+ };
112
+ }
113
+ return readArtifactDeliveryManifest(repoRoot, ref);
114
+ }
115
+
116
+ export function renderArtifactDeliveryCard(
117
+ repoRoot: string,
118
+ ref: string,
119
+ manifest = resolveArtifactDeliveryManifest(repoRoot, ref),
120
+ environment: DisplayEnvironment = {},
121
+ ): ArtifactDeliveryCard {
122
+ const artifactPath = managedArtifactPath(repoRoot, ref);
123
+ const valid = validateManifest(artifactPath, manifest);
124
+ const linkBase = deliveryLinkBase(repoRoot, environment);
125
+ const rows: Array<{ label: string; target: string; href: string; icon: string }> = [];
126
+
127
+ for (const item of valid.items.filter((candidate) => candidate.kind === "url")) {
128
+ rows.push({ label: item.label, target: item.target, href: item.target, icon: "🌐" });
129
+ }
130
+
131
+ rows.push({
132
+ label: "Artifact folder",
133
+ target: displayPath(artifactPath, environment),
134
+ href: artifactBrowserUrl(repoRoot, artifactPath, linkBase, true),
135
+ icon: "📁",
136
+ });
137
+
138
+ for (const item of valid.items.filter((candidate) => candidate.kind === "path")) {
139
+ const absolute = resolveArtifactItem(artifactPath, item.path);
140
+ rows.push({
141
+ label: item.label,
142
+ target: displayPath(absolute, environment),
143
+ href: artifactBrowserUrl(repoRoot, absolute, linkBase, lstatSync(absolute).isDirectory()),
144
+ icon: iconForPath(absolute),
145
+ });
146
+ }
147
+
148
+ const discovered = valid.items.length === 0 ? discoverArtifactRootItems(artifactPath) : [];
149
+ const autoItems = discovered.slice(0, ARTIFACT_DELIVERY_AUTO_ITEM_LIMIT);
150
+ for (const item of autoItems) {
151
+ rows.push({
152
+ label: item.name,
153
+ target: displayPath(item.path, environment),
154
+ href: artifactBrowserUrl(repoRoot, item.path, linkBase, item.directory),
155
+ icon: iconForPath(item.path),
156
+ });
157
+ }
158
+ const omittedAutoItems = discovered.length - autoItems.length;
159
+
160
+ let links = rows
161
+ .map((row) => `- ${row.icon} [${escapeMarkdown(row.label)}](${markdownDestination(row.href)})`)
162
+ .join("\n");
163
+ if (omittedAutoItems > 0) {
164
+ links += `\n- 📁 **More root items:** ${omittedAutoItems} additional ${omittedAutoItems === 1 ? "entry" : "entries"}; open the artifact folder.`;
165
+ }
166
+ const plain = rows.map((row) => `${row.label.toUpperCase()}\n${row.target}`).join("\n\n");
167
+
168
+ return {
169
+ artifact_path: artifactPath,
170
+ manifest_path: resolve(artifactPath, ARTIFACT_DELIVERY_MANIFEST),
171
+ markdown: `### ${escapeMarkdown(valid.title)}\n\n${links}\n\n\`\`\`text\n${plain}\n\`\`\``,
172
+ auto_items: autoItems.length,
173
+ omitted_auto_items: omittedAutoItems,
174
+ };
175
+ }
176
+
177
+ export function parseArtifactDeliverySpec(
178
+ kind: "url" | "path",
179
+ spec: string,
180
+ ): ArtifactDeliveryItem {
181
+ const delimiter = spec.indexOf("=");
182
+ if (delimiter < 1 || delimiter === spec.length - 1) {
183
+ throw new Error(`${kind} entries must use LABEL=VALUE`);
184
+ }
185
+ const label = spec.slice(0, delimiter).trim();
186
+ const value = spec.slice(delimiter + 1).trim();
187
+ return kind === "url" ? { kind, label, target: value } : { kind, label, path: value };
188
+ }
189
+
190
+ function managedArtifactPath(repoRoot: string, ref: string): string {
191
+ showArtifact(repoRoot, ref);
192
+ return realpathSync(resolveArtifactRef(repoRoot, ref));
193
+ }
194
+
195
+ function validateManifest(artifactPath: string, value: unknown): ArtifactDeliveryManifest {
196
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
197
+ throw new Error("delivery manifest must be an object");
198
+ }
199
+ const candidate = value as Record<string, unknown>;
200
+ if (candidate.schema_version !== ARTIFACT_DELIVERY_SCHEMA_VERSION) {
201
+ throw new Error(`delivery manifest schema_version must be ${ARTIFACT_DELIVERY_SCHEMA_VERSION}`);
202
+ }
203
+ const title = typeof candidate.title === "string" ? candidate.title.trim() : "";
204
+ if (!title) throw new Error("delivery title must not be empty");
205
+ if (!Array.isArray(candidate.items)) throw new Error("delivery manifest items must be an array");
206
+
207
+ const labels = new Set<string>();
208
+ const items = candidate.items.map((raw): ArtifactDeliveryItem => {
209
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
210
+ throw new Error("each delivery item must be an object");
211
+ }
212
+ const item = raw as Record<string, unknown>;
213
+ const label = typeof item.label === "string" ? item.label.trim() : "";
214
+ if (!label) throw new Error("delivery item labels must not be empty");
215
+ const normalizedLabel = label.toLowerCase();
216
+ if (normalizedLabel === "artifact folder") {
217
+ throw new Error('"Artifact folder" is reserved and included automatically');
218
+ }
219
+ if (labels.has(normalizedLabel)) throw new Error(`duplicate delivery label: ${label}`);
220
+ labels.add(normalizedLabel);
221
+
222
+ if (item.kind === "url") {
223
+ const target = typeof item.target === "string" ? item.target.trim() : "";
224
+ let url: URL;
225
+ try {
226
+ url = new URL(target);
227
+ } catch {
228
+ throw new Error(`invalid delivery URL for ${label}`);
229
+ }
230
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
231
+ throw new Error(`delivery URL for ${label} must use http or https`);
232
+ }
233
+ return { kind: "url", label, target: url.toString() };
234
+ }
235
+
236
+ if (item.kind === "path") {
237
+ const path = typeof item.path === "string" ? item.path.trim() : "";
238
+ if (!path || isAbsolute(path)) {
239
+ throw new Error(`delivery path for ${label} must be relative to the artifact folder`);
240
+ }
241
+ const absolute = resolveArtifactItem(artifactPath, path);
242
+ const normalized = relative(artifactPath, absolute).split(sep).join("/");
243
+ return { kind: "path", label, path: normalized };
244
+ }
245
+
246
+ throw new Error(`delivery item ${label} has an unsupported kind`);
247
+ });
248
+
249
+ return {
250
+ schema_version: ARTIFACT_DELIVERY_SCHEMA_VERSION,
251
+ title,
252
+ items,
253
+ };
254
+ }
255
+
256
+ function resolveArtifactItem(artifactPath: string, itemPath: string): string {
257
+ const root = realpathSync(artifactPath);
258
+ const lexical = resolve(root, itemPath);
259
+ if (lexical === root || !lexical.startsWith(`${root}${sep}`)) {
260
+ throw new Error(`delivery path escapes the artifact folder: ${itemPath}`);
261
+ }
262
+ let target: string;
263
+ try {
264
+ target = realpathSync(lexical);
265
+ } catch (error) {
266
+ throw new Error(
267
+ `delivery path does not exist: ${itemPath} (${error instanceof Error ? error.message : String(error)})`,
268
+ );
269
+ }
270
+ if (!target.startsWith(`${root}${sep}`)) {
271
+ throw new Error(`delivery path escapes the artifact folder through a symlink: ${itemPath}`);
272
+ }
273
+ const stat = lstatSync(target);
274
+ if (!stat.isFile() && !stat.isDirectory()) {
275
+ throw new Error(`delivery path must be a file or directory: ${itemPath}`);
276
+ }
277
+ return target;
278
+ }
279
+
280
+ function discoverArtifactRootItems(
281
+ artifactPath: string,
282
+ ): Array<{ name: string; path: string; directory: boolean }> {
283
+ return readdirSync(artifactPath, { withFileTypes: true })
284
+ .filter(
285
+ (entry) =>
286
+ !entry.name.startsWith(".") &&
287
+ entry.name !== ARTIFACT_MANIFEST &&
288
+ entry.name !== ARTIFACT_DELIVERY_MANIFEST &&
289
+ (entry.isFile() || entry.isDirectory()),
290
+ )
291
+ .map((entry) => ({
292
+ name: entry.name,
293
+ path: resolveArtifactItem(artifactPath, entry.name),
294
+ directory: entry.isDirectory(),
295
+ }))
296
+ .sort((left, right) => {
297
+ if (left.directory !== right.directory) return left.directory ? -1 : 1;
298
+ return left.name.localeCompare(right.name, "en");
299
+ });
300
+ }
301
+
302
+ function displayPath(path: string, environment: DisplayEnvironment): string {
303
+ const distro = environment.wslDistroName ?? process.env.WSL_DISTRO_NAME;
304
+ const platform = environment.platform ?? process.platform;
305
+ if (platform === "linux" && distro) {
306
+ const suffix = resolve(path).replaceAll("/", "\\");
307
+ return `\\\\wsl.localhost\\${distro}${suffix}`;
308
+ }
309
+ if (
310
+ platform === "linux" &&
311
+ (process.env.WSL_INTEROP || process.env.HARNERY_AGENT_COORD_BRIDGE === "codex-wsl")
312
+ ) {
313
+ try {
314
+ return execFileSync("wslpath", ["-w", resolve(path)], { encoding: "utf8" }).trim();
315
+ } catch {
316
+ // Fall through to the native path when wslpath is unavailable.
317
+ }
318
+ }
319
+ return resolve(path);
320
+ }
321
+
322
+ function deliveryLinkBase(repoRoot: string, environment: DisplayEnvironment): string {
323
+ const webPort = environment.webPort ?? resolveWebPort(undefined, repoRoot);
324
+ // Every href below is a dashboard route, so only a tunnel that serves the
325
+ // dashboard's own origin will answer them. A tunnel sharing this upstream
326
+ // port under another Host serves a different site and would 400 on /browse
327
+ // and /files, so fall back to the local URL rather than publish that host.
328
+ const tunnelUrl =
329
+ environment.tunnelUrl === undefined
330
+ ? findLiveTunnelForOrigin(webPort, `localhost:${webPort}`, repoRoot)?.url
331
+ : environment.tunnelUrl;
332
+ return (tunnelUrl ?? `http://localhost:${webPort}`).replace(/\/+$/, "");
333
+ }
334
+
335
+ function artifactBrowserUrl(
336
+ repoRoot: string,
337
+ target: string,
338
+ base: string,
339
+ directory: boolean,
340
+ ): string {
341
+ const relPath = relative(realpathSync(repoRoot), realpathSync(target)).split(sep).join("/");
342
+ const query = directory
343
+ ? `dir=${encodeLinkSafeComponent(relPath)}`
344
+ : `path=${encodeLinkSafeComponent(relPath)}`;
345
+ return `${base}/${directory ? "browse" : "files"}?${query}`;
346
+ }
347
+
348
+ /**
349
+ * Render a destination for a Markdown inline link.
350
+ *
351
+ * The angle-bracket form is valid CommonMark but not every renderer implements
352
+ * it, and one that does not can style the text as a link while dropping the
353
+ * href, leaving something that looks clickable and is not. So use the plain
354
+ * form, which every renderer handles, and reserve the brackets for a supplied
355
+ * URL that actually needs them.
356
+ */
357
+ function markdownDestination(href: string): string {
358
+ return /[\s()<>]/.test(href) ? `<${href}>` : href;
359
+ }
360
+
361
+ function iconForPath(path: string): string {
362
+ if (lstatSync(path).isDirectory()) return "📁";
363
+ if (imagePath(path)) return "🖼️";
364
+ if (/\.(?:m4v|mkv|mov|mp4|webm)$/i.test(path)) return "🎬";
365
+ if (/\.(?:aac|flac|m4a|mp3|ogg|wav)$/i.test(path)) return "🎵";
366
+ return "📄";
367
+ }
368
+
369
+ function imagePath(path: string): boolean {
370
+ return /\.(?:avif|gif|jpe?g|png|svg|webp)$/i.test(path);
371
+ }
372
+
373
+ function escapeMarkdown(value: string): string {
374
+ return value.replaceAll("\\", "\\\\").replaceAll("[", "\\[").replaceAll("]", "\\]");
375
+ }