@reticlehq/server 3.5.0 → 3.7.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 (721) hide show
  1. package/README.md +1 -1
  2. package/SKILL.md +123 -116
  3. package/dist/chromium-launch-options.d.ts +3 -1
  4. package/dist/chromium-launch-options.js +2 -1
  5. package/dist/command/cli/adhoc-suite.d.ts +14 -0
  6. package/dist/command/cli/adhoc-suite.js +42 -7
  7. package/dist/command/cli/adhoc-verdict.d.ts +19 -2
  8. package/dist/command/cli/adhoc-verdict.js +76 -9
  9. package/dist/command/cli/answers/gate-exit.d.ts +23 -0
  10. package/dist/command/cli/answers/gate-exit.js +45 -0
  11. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  12. package/dist/command/cli/answers/gate-hook-message.js +3 -1
  13. package/dist/command/cli/answers/open-note.d.ts +2 -0
  14. package/dist/command/cli/answers/open-note.js +22 -0
  15. package/dist/command/cli/auth/device-flow.d.ts +13 -2
  16. package/dist/command/cli/auth/device-flow.js +17 -0
  17. package/dist/command/cli/cli-doctor.js +14 -0
  18. package/dist/command/cli/cli-flow-commands.d.ts +0 -11
  19. package/dist/command/cli/cli-flow-commands.js +31 -112
  20. package/dist/command/cli/cli-kill.js +3 -2
  21. package/dist/command/cli/cli-parse-grammar.d.ts +24 -0
  22. package/dist/command/cli/cli-parse-grammar.js +75 -0
  23. package/dist/command/cli/cli-parse-verify.d.ts +2 -0
  24. package/dist/command/cli/cli-parse-verify.js +18 -0
  25. package/dist/command/cli/cli-parse.d.ts +19 -28
  26. package/dist/command/cli/cli-parse.js +82 -182
  27. package/dist/command/cli/cli-update-commands.d.ts +1 -1
  28. package/dist/command/cli/cli-update-commands.js +61 -9
  29. package/dist/command/cli/cli-usage.d.ts +33 -0
  30. package/dist/command/cli/cli-usage.js +287 -0
  31. package/dist/command/cli/cli-verify.d.ts +35 -5
  32. package/dist/command/cli/cli-verify.js +114 -35
  33. package/dist/command/cli/cloud-cli.d.ts +13 -0
  34. package/dist/command/cli/cloud-cli.js +192 -341
  35. package/dist/command/cli/cloud-kit.d.ts +12 -0
  36. package/dist/command/cli/cloud-kit.js +41 -2
  37. package/dist/command/cli/cloud-link.d.ts +57 -0
  38. package/dist/command/cli/cloud-link.js +308 -0
  39. package/dist/command/cli/cloud-login.d.ts +22 -0
  40. package/dist/command/cli/cloud-login.js +96 -8
  41. package/dist/command/cli/context-command.d.ts +1 -0
  42. package/dist/command/cli/context-command.js +33 -0
  43. package/dist/command/cli/daemon-start-options.d.ts +3 -0
  44. package/dist/command/cli/daemon-start-options.js +24 -3
  45. package/dist/command/cli/doctor/browser/chromium-hint.d.ts +46 -0
  46. package/dist/command/cli/doctor/browser/chromium-hint.js +99 -1
  47. package/dist/command/cli/doctor/doctor-coverage-line.d.ts +2 -0
  48. package/dist/command/cli/doctor/doctor-coverage-line.js +47 -0
  49. package/dist/command/cli/doctor/doctor-project-line.d.ts +0 -12
  50. package/dist/command/cli/doctor/doctor-project-line.js +5 -4
  51. package/dist/command/cli/doctor/doctor-rows.d.ts +6 -0
  52. package/dist/command/cli/doctor/doctor-rows.js +6 -0
  53. package/dist/command/cli/doctor/doctor-signing-line.d.ts +38 -0
  54. package/dist/command/cli/doctor/doctor-signing-line.js +114 -0
  55. package/dist/command/cli/drive/drive-attach.d.ts +27 -2
  56. package/dist/command/cli/drive/drive-attach.js +71 -4
  57. package/dist/command/cli/drive/drive-command.d.ts +2 -1
  58. package/dist/command/cli/drive/drive-command.js +13 -7
  59. package/dist/command/cli/known-regression.d.ts +13 -0
  60. package/dist/command/cli/known-regression.js +34 -0
  61. package/dist/command/cli/launch/sdk-version-match.d.ts +12 -0
  62. package/dist/command/cli/launch/sdk-version-match.js +25 -0
  63. package/dist/command/cli/lifecycle/daemon-lifecycle.js +15 -3
  64. package/dist/command/cli/mcp-command.d.ts +6 -0
  65. package/dist/command/cli/mcp-command.js +13 -5
  66. package/dist/command/cli/ports/port-holder.d.ts +10 -0
  67. package/dist/command/cli/ports/port-holder.js +25 -1
  68. package/dist/command/cli/project-name.d.ts +29 -1
  69. package/dist/command/cli/project-name.js +107 -2
  70. package/dist/command/cli/setup-mcp-cli.d.ts +17 -1
  71. package/dist/command/cli/setup-mcp-cli.js +35 -12
  72. package/dist/command/cli/status/status-lines.d.ts +1 -0
  73. package/dist/command/cli/status/status-lines.js +47 -2
  74. package/dist/command/cli/status/workspace-links.d.ts +10 -0
  75. package/dist/command/cli/status/workspace-links.js +29 -0
  76. package/dist/command/cli/try-command.d.ts +96 -0
  77. package/dist/command/cli/try-command.js +362 -0
  78. package/dist/command/cli/tutorial.d.ts +0 -100
  79. package/dist/command/cli/tutorial.js +0 -181
  80. package/dist/command/cli/verify-results.d.ts +19 -0
  81. package/dist/command/cli/verify-results.js +29 -0
  82. package/dist/command/cli-onboarding.d.ts +0 -11
  83. package/dist/command/cli-onboarding.js +0 -15
  84. package/dist/command/cli.d.ts +20 -0
  85. package/dist/command/cli.js +130 -104
  86. package/dist/command/daemon/binding/daemon-status-probe.d.ts +2 -0
  87. package/dist/command/daemon/binding/daemon-status-probe.js +1 -0
  88. package/dist/command/daemon/daemon-resilience.js +4 -4
  89. package/dist/command/daemon/daemon-resolve.d.ts +23 -1
  90. package/dist/command/daemon/daemon-resolve.js +79 -9
  91. package/dist/command/setup/agent-writer.d.ts +1 -1
  92. package/dist/command/setup/agent-writer.js +3 -2
  93. package/dist/command/setup/bringup/bridge-port.d.ts +3 -1
  94. package/dist/command/setup/bringup/bridge-port.js +13 -3
  95. package/dist/command/setup/bringup/connect-lease.d.ts +1 -0
  96. package/dist/command/setup/bringup/connect-lease.js +1 -0
  97. package/dist/command/setup/bringup/dev-server-log-cap.js +2 -0
  98. package/dist/command/setup/bringup/dev-server-wait.d.ts +8 -0
  99. package/dist/command/setup/bringup/dev-server-wait.js +19 -0
  100. package/dist/command/setup/bringup/ensure-daemon.js +9 -2
  101. package/dist/command/setup/init/agent-restart.d.ts +23 -0
  102. package/dist/command/setup/init/agent-restart.js +28 -0
  103. package/dist/command/setup/init/init-port.d.ts +14 -1
  104. package/dist/command/setup/init/init-port.js +32 -2
  105. package/dist/command/setup/init/init-runtime.d.ts +22 -2
  106. package/dist/command/setup/init/init-runtime.js +114 -38
  107. package/dist/command/setup/node-effects.d.ts +2 -0
  108. package/dist/command/setup/node-effects.js +38 -9
  109. package/dist/command/setup/probe/existing-app.d.ts +12 -0
  110. package/dist/command/setup/probe/existing-app.js +14 -0
  111. package/dist/command/setup/remaining-steps.js +2 -1
  112. package/dist/command/setup/run-setup.d.ts +34 -9
  113. package/dist/command/setup/run-setup.js +65 -51
  114. package/dist/command/setup/setup-command.d.ts +25 -1
  115. package/dist/command/setup/setup-command.js +59 -4
  116. package/dist/command/setup/setup-mcp.js +25 -2
  117. package/dist/command/setup/tauri-signing.d.ts +19 -0
  118. package/dist/command/setup/tauri-signing.js +79 -0
  119. package/dist/command/setup/terminal/listeners.d.ts +10 -1
  120. package/dist/command/setup/terminal/listeners.js +37 -6
  121. package/dist/command/update/update-nudge.d.ts +9 -0
  122. package/dist/command/update/update-nudge.js +1 -1
  123. package/dist/command/update/updater.js +11 -15
  124. package/dist/command/version/version-nudge.js +3 -0
  125. package/dist/command/version/version-skew.d.ts +20 -1
  126. package/dist/command/version/version-skew.js +49 -4
  127. package/dist/features/crawl/crawl-tools.js +4 -0
  128. package/dist/features/crawl/crawl.d.ts +6 -0
  129. package/dist/features/crawl/crawl.js +23 -2
  130. package/dist/features/exhaust/ledger.d.ts +21 -14
  131. package/dist/features/exhaust/ledger.js +35 -9
  132. package/dist/features/harness/app-findings.d.ts +2 -0
  133. package/dist/features/harness/app-findings.js +52 -0
  134. package/dist/features/harness/drive-report.d.ts +61 -1
  135. package/dist/features/harness/drive-report.js +394 -26
  136. package/dist/features/harness/drive-runs.d.ts +120 -0
  137. package/dist/features/harness/drive-runs.js +289 -0
  138. package/dist/features/harness/drivers.d.ts +10 -14
  139. package/dist/features/harness/drivers.js +10 -14
  140. package/dist/features/harness/explore/console-pages.d.ts +15 -0
  141. package/dist/features/harness/explore/console-pages.js +146 -0
  142. package/dist/features/harness/explore/disparity.d.ts +19 -0
  143. package/dist/features/harness/explore/disparity.js +71 -0
  144. package/dist/features/harness/explore/fake-app.d.ts +16 -0
  145. package/dist/features/harness/explore/fake-app.js +49 -0
  146. package/dist/features/harness/explore/goal-search.d.ts +26 -0
  147. package/dist/features/harness/explore/goal-search.js +144 -0
  148. package/dist/features/harness/explore/page-tree.d.ts +49 -0
  149. package/dist/features/harness/explore/page-tree.js +148 -0
  150. package/dist/features/harness/explore/site-map.d.ts +34 -0
  151. package/dist/features/harness/explore/site-map.js +150 -0
  152. package/dist/features/harness/fill-values.d.ts +3 -73
  153. package/dist/features/harness/fill-values.js +3 -169
  154. package/dist/features/harness/goals.d.ts +82 -0
  155. package/dist/features/harness/goals.js +330 -0
  156. package/dist/features/harness/harness.d.ts +51 -1
  157. package/dist/features/harness/harness.js +207 -6
  158. package/dist/features/harness/platform/drive-target.d.ts +30 -0
  159. package/dist/features/harness/platform/drive-target.js +81 -0
  160. package/dist/features/harness/platform/local-apps.d.ts +127 -0
  161. package/dist/features/harness/platform/local-apps.js +280 -0
  162. package/dist/features/harness/platform/persona-credentials.d.ts +20 -0
  163. package/dist/features/harness/platform/persona-credentials.js +69 -0
  164. package/dist/features/harness/platform/platform-drives.d.ts +61 -0
  165. package/dist/features/harness/platform/platform-drives.js +114 -0
  166. package/dist/features/harness/platform/refusal.d.ts +52 -0
  167. package/dist/features/harness/platform/refusal.js +71 -0
  168. package/dist/features/harness/platform/remote-drive.d.ts +186 -0
  169. package/dist/features/harness/platform/remote-drive.js +378 -0
  170. package/dist/features/harness/platform/script.d.ts +94 -0
  171. package/dist/features/harness/platform/script.js +260 -0
  172. package/dist/features/harness/platform/server-driver.d.ts +54 -0
  173. package/dist/features/harness/platform/server-driver.js +182 -0
  174. package/dist/features/harness/platform-config.d.ts +41 -1
  175. package/dist/features/harness/platform-config.js +106 -9
  176. package/dist/features/harness/route-guess.d.ts +13 -0
  177. package/dist/features/harness/route-guess.js +49 -0
  178. package/dist/features/harness/script/app-controls.d.ts +5 -0
  179. package/dist/features/harness/script/app-controls.js +40 -0
  180. package/dist/features/harness/script/lane-ids.d.ts +14 -0
  181. package/dist/features/harness/script/lane-ids.js +16 -0
  182. package/dist/features/harness/script/script-run.d.ts +70 -0
  183. package/dist/features/harness/script/script-run.js +606 -0
  184. package/dist/features/license/license.d.ts +2 -2
  185. package/dist/features/visual/step-shots.d.ts +31 -0
  186. package/dist/features/visual/step-shots.js +231 -0
  187. package/dist/features/visual/visual-tools.d.ts +10 -1
  188. package/dist/features/visual/visual-tools.js +62 -17
  189. package/dist/hooks/client-directory.d.ts +18 -0
  190. package/dist/hooks/client-directory.js +57 -0
  191. package/dist/hooks/coding-agents.d.ts +34 -0
  192. package/dist/hooks/coding-agents.js +117 -0
  193. package/dist/hooks/driven-by.d.ts +23 -0
  194. package/dist/hooks/driven-by.js +56 -0
  195. package/dist/hooks/hook-bus.d.ts +4 -0
  196. package/dist/hooks/hook-bus.js +18 -0
  197. package/dist/hooks/hook-commands.js +15 -4
  198. package/dist/hooks/tool-log.d.ts +9 -0
  199. package/dist/hooks/tool-log.js +29 -0
  200. package/dist/index.d.ts +2 -0
  201. package/dist/index.js +80 -243
  202. package/dist/judgement/capsule/capsule-store.d.ts +2 -2
  203. package/dist/judgement/capsule/causal-summary.d.ts +15 -1
  204. package/dist/judgement/capsule/causal-summary.js +33 -0
  205. package/dist/judgement/runs/artifact/build-verification-run.d.ts +1 -1
  206. package/dist/judgement/runs/artifact/build-verification-run.js +25 -3
  207. package/dist/judgement/runs/artifact/gap-summary.d.ts +0 -18
  208. package/dist/judgement/runs/artifact/gap-summary.js +12 -3
  209. package/dist/judgement/runs/artifact/replay-mapping.d.ts +1 -1
  210. package/dist/judgement/runs/artifact/replay-mapping.js +37 -11
  211. package/dist/judgement/runs/artifact/run-store.d.ts +14 -2
  212. package/dist/judgement/runs/artifact/run-store.js +195 -3
  213. package/dist/judgement/runs/context-tools.js +59 -1
  214. package/dist/judgement/runs/default-run-id.d.ts +3 -0
  215. package/dist/judgement/runs/default-run-id.js +16 -0
  216. package/dist/judgement/runs/drive-run.d.ts +71 -1
  217. package/dist/judgement/runs/drive-run.js +317 -5
  218. package/dist/judgement/runs/repair-prompt.js +1 -1
  219. package/dist/judgement/runs/resume.d.ts +44 -0
  220. package/dist/judgement/runs/resume.js +137 -0
  221. package/dist/judgement/runs/reticle-runner.js +13 -3
  222. package/dist/judgement/runs/runner-port.d.ts +5 -1
  223. package/dist/judgement/runs/runner-port.js +8 -2
  224. package/dist/judgement/runs/verification-sync.d.ts +5 -2
  225. package/dist/judgement/runs/verification-sync.js +40 -18
  226. package/dist/language/flows/change/gate.d.ts +10 -0
  227. package/dist/language/flows/change/gate.js +22 -0
  228. package/dist/language/flows/decision.js +36 -1
  229. package/dist/language/flows/fields/flow-secret-field.d.ts +12 -0
  230. package/dist/language/flows/fields/flow-secret-field.js +25 -2
  231. package/dist/language/flows/flow-anchor.d.ts +61 -10
  232. package/dist/language/flows/flow-anchor.js +98 -6
  233. package/dist/language/flows/flow-cross-step.d.ts +15 -0
  234. package/dist/language/flows/flow-cross-step.js +21 -0
  235. package/dist/language/flows/flow-intent.d.ts +1 -0
  236. package/dist/language/flows/flow-journey.d.ts +6 -0
  237. package/dist/language/flows/flow-journey.js +20 -0
  238. package/dist/language/flows/flow-learning.d.ts +4 -0
  239. package/dist/language/flows/flow-learning.js +45 -14
  240. package/dist/language/flows/flow-mutate-tools.js +5 -3
  241. package/dist/language/flows/flow-replay-run.d.ts +23 -9
  242. package/dist/language/flows/flow-replay-run.js +115 -110
  243. package/dist/language/flows/flow-replay-types.d.ts +1 -1
  244. package/dist/language/flows/flow-replay.d.ts +40 -1
  245. package/dist/language/flows/flow-replay.js +110 -22
  246. package/dist/language/flows/flow-result.d.ts +22 -1
  247. package/dist/language/flows/flow-result.js +47 -2
  248. package/dist/language/flows/flow-scope.js +5 -1
  249. package/dist/language/flows/flow-step-runners.d.ts +22 -2
  250. package/dist/language/flows/flow-step-runners.js +247 -47
  251. package/dist/language/flows/flow-store-for-session.d.ts +2 -2
  252. package/dist/language/flows/flow-store-for-session.js +7 -3
  253. package/dist/language/flows/flow-tools.d.ts +10 -0
  254. package/dist/language/flows/flow-tools.js +112 -89
  255. package/dist/language/flows/flows.d.ts +16 -1
  256. package/dist/language/flows/flows.js +74 -12
  257. package/dist/language/flows/heal-run.js +6 -4
  258. package/dist/language/flows/narrow-write.d.ts +7 -0
  259. package/dist/language/flows/narrow-write.js +36 -1
  260. package/dist/language/flows/recording/flake.d.ts +2 -2
  261. package/dist/language/flows/recording/recording-backtrack.js +14 -1
  262. package/dist/language/flows/recording/tape/recordings.d.ts +58 -4
  263. package/dist/language/flows/recording/tape/recordings.js +95 -13
  264. package/dist/language/flows/replay-from-hud.d.ts +20 -0
  265. package/dist/language/flows/replay-from-hud.js +51 -0
  266. package/dist/language/flows/replay.d.ts +9 -5
  267. package/dist/language/flows/replay.js +56 -15
  268. package/dist/language/flows/single-replay.d.ts +7 -0
  269. package/dist/language/flows/single-replay.js +26 -0
  270. package/dist/language/flows/suite/suite-flakes.js +2 -0
  271. package/dist/language/flows/suite-selection.d.ts +2 -15
  272. package/dist/language/flows/suite-selection.js +4 -3
  273. package/dist/language/flows/verify-change-tools.d.ts +1 -0
  274. package/dist/language/flows/verify-change-tools.js +202 -191
  275. package/dist/launch-chromium.d.ts +27 -5
  276. package/dist/launch-chromium.js +38 -8
  277. package/dist/memory/cloud/cloud-config.d.ts +22 -1
  278. package/dist/memory/cloud/cloud-config.js +34 -5
  279. package/dist/memory/cloud/cloud-sync.d.ts +17 -14
  280. package/dist/memory/cloud/cloud-sync.js +15 -4
  281. package/dist/memory/cloud/harness-config.d.ts +75 -1
  282. package/dist/memory/cloud/harness-config.js +115 -24
  283. package/dist/memory/cloud/hud-notices-source.d.ts +21 -0
  284. package/dist/memory/cloud/hud-notices-source.js +128 -0
  285. package/dist/memory/cloud/memory-scope.d.ts +161 -0
  286. package/dist/memory/cloud/memory-scope.js +227 -0
  287. package/dist/memory/cloud/sync-cycle.d.ts +44 -7
  288. package/dist/memory/cloud/sync-cycle.js +129 -15
  289. package/dist/memory/cloud/sync-daemon.d.ts +11 -0
  290. package/dist/memory/cloud/sync-daemon.js +121 -9
  291. package/dist/memory/cloud/sync-disk.d.ts +1 -1
  292. package/dist/memory/cloud/sync-disk.js +31 -10
  293. package/dist/memory/cloud/sync-screenshots.d.ts +32 -0
  294. package/dist/memory/cloud/sync-screenshots.js +105 -0
  295. package/dist/memory/cloud/unsynced-roots.d.ts +47 -0
  296. package/dist/memory/cloud/unsynced-roots.js +166 -0
  297. package/dist/memory/impact/account-watch.d.ts +34 -0
  298. package/dist/memory/impact/account-watch.js +59 -0
  299. package/dist/memory/impact/impact-recorder.d.ts +8 -0
  300. package/dist/memory/impact/impact-recorder.js +12 -2
  301. package/dist/memory/impact/impact-store.d.ts +17 -4
  302. package/dist/memory/impact/impact-store.js +169 -63
  303. package/dist/memory/intent/inline-intent.d.ts +1 -0
  304. package/dist/memory/intent/intent-shard-store.js +16 -4
  305. package/dist/memory/intent/intent-shard.d.ts +14 -2
  306. package/dist/memory/intent/intent-store.d.ts +1 -0
  307. package/dist/memory/intent/intent-tools.js +122 -4
  308. package/dist/memory/intent/open-intents.d.ts +6 -0
  309. package/dist/memory/intent/open-intents.js +10 -1
  310. package/dist/memory/intent/settled-words.d.ts +24 -0
  311. package/dist/memory/intent/settled-words.js +130 -0
  312. package/dist/memory/journal/drive-flow.d.ts +16 -0
  313. package/dist/memory/journal/drive-flow.js +34 -2
  314. package/dist/memory/journal/drive-run-flush.d.ts +2 -0
  315. package/dist/memory/journal/drive-run-flush.js +20 -5
  316. package/dist/memory/journal/envelope.d.ts +8 -8
  317. package/dist/memory/journal/journal-recorder.js +52 -3
  318. package/dist/memory/journal/on-disk/retention.d.ts +8 -0
  319. package/dist/memory/journal/on-disk/retention.js +32 -2
  320. package/dist/memory/journal/on-disk/startup-maintenance.js +3 -1
  321. package/dist/memory/journal/on-disk/workspace-tiers.js +9 -4
  322. package/dist/memory/journal/session-end.d.ts +15 -1
  323. package/dist/memory/journal/session-end.js +42 -9
  324. package/dist/memory/project/artifact-root-resolver.d.ts +26 -1
  325. package/dist/memory/project/artifact-root-resolver.js +125 -16
  326. package/dist/memory/project/artifact-root.d.ts +46 -8
  327. package/dist/memory/project/artifact-root.js +89 -10
  328. package/dist/memory/project/dir/reticle-dir.d.ts +18 -2
  329. package/dist/memory/project/dir/reticle-dir.js +26 -3
  330. package/dist/memory/project/link-directory.d.ts +15 -0
  331. package/dist/memory/project/link-directory.js +44 -0
  332. package/dist/memory/project/project-tools.js +22 -3
  333. package/dist/memory/project/root-claims.d.ts +6 -0
  334. package/dist/memory/project/root-claims.js +39 -0
  335. package/dist/memory/project/session-root.d.ts +26 -1
  336. package/dist/memory/project/session-root.js +49 -5
  337. package/dist/memory/project/sync-status.d.ts +85 -0
  338. package/dist/memory/project/sync-status.js +224 -0
  339. package/dist/memory/recall/memory-tools.js +47 -2
  340. package/dist/memory/recall/platform-memory.d.ts +34 -0
  341. package/dist/memory/recall/platform-memory.js +139 -0
  342. package/dist/memory/recall/project-memory.d.ts +19 -0
  343. package/dist/memory/recall/project-memory.js +80 -13
  344. package/dist/portal/bridge/bridge.d.ts +9 -3
  345. package/dist/portal/bridge/bridge.js +82 -22
  346. package/dist/portal/bridge/harness-request.d.ts +23 -0
  347. package/dist/portal/bridge/harness-request.js +27 -0
  348. package/dist/portal/bridge/pairing-token.d.ts +9 -0
  349. package/dist/portal/bridge/pairing-token.js +17 -0
  350. package/dist/portal/bridge/wrong-path.d.ts +17 -0
  351. package/dist/portal/bridge/wrong-path.js +35 -0
  352. package/dist/portal/input/network-mock-tools.js +11 -2
  353. package/dist/portal/input/real-input.d.ts +83 -10
  354. package/dist/portal/input/real-input.js +218 -30
  355. package/dist/portal/input/viewport-tools.js +3 -3
  356. package/dist/portal/pool/browser-pool.d.ts +70 -9
  357. package/dist/portal/pool/browser-pool.js +190 -37
  358. package/dist/portal/pool/context-permissions.d.ts +33 -0
  359. package/dist/portal/pool/context-permissions.js +33 -0
  360. package/dist/portal/pool/lease-marker-stamp.d.ts +23 -0
  361. package/dist/portal/pool/lease-marker-stamp.js +49 -0
  362. package/dist/portal/pool/playwright-launcher.d.ts +35 -0
  363. package/dist/portal/pool/playwright-launcher.js +64 -3
  364. package/dist/portal/pool/pool-contract.d.ts +28 -5
  365. package/dist/portal/session/agent-link.d.ts +8 -0
  366. package/dist/portal/session/agent-link.js +17 -0
  367. package/dist/portal/session/command-payload.d.ts +8 -0
  368. package/dist/portal/session/command-payload.js +24 -0
  369. package/dist/portal/session/daemon-answers.d.ts +3 -3
  370. package/dist/portal/session/daemon-answers.js +4 -2
  371. package/dist/portal/session/dev-server/dev-command.d.ts +21 -0
  372. package/dist/portal/session/dev-server/dev-command.js +87 -12
  373. package/dist/portal/session/facts/departure-note.d.ts +22 -0
  374. package/dist/portal/session/facts/departure-note.js +47 -0
  375. package/dist/portal/session/facts/observed-state.d.ts +16 -18
  376. package/dist/portal/session/facts/observed-state.js +46 -3
  377. package/dist/portal/session/facts/session-replaced.d.ts +5 -0
  378. package/dist/portal/session/facts/session-replaced.js +5 -0
  379. package/dist/portal/session/first-run-wiring.d.ts +42 -0
  380. package/dist/portal/session/first-run-wiring.js +132 -0
  381. package/dist/portal/session/human/live-control.d.ts +9 -2
  382. package/dist/portal/session/human/live-control.js +12 -3
  383. package/dist/portal/session/human/notes-ledger.d.ts +20 -0
  384. package/dist/portal/session/human/notes-ledger.js +55 -0
  385. package/dist/portal/session/human/review-store.d.ts +12 -0
  386. package/dist/portal/session/human/review-store.js +18 -10
  387. package/dist/portal/session/live-control-tools.d.ts +0 -13
  388. package/dist/portal/session/live-control-tools.js +107 -13
  389. package/dist/portal/session/narration-args.d.ts +5 -0
  390. package/dist/portal/session/narration-args.js +17 -0
  391. package/dist/portal/session/no-session-diagnosis.d.ts +8 -1
  392. package/dist/portal/session/no-session-diagnosis.js +46 -9
  393. package/dist/portal/session/no-session-next-action.d.ts +31 -0
  394. package/dist/portal/session/no-session-next-action.js +159 -60
  395. package/dist/portal/session/no-session-watch.d.ts +14 -1
  396. package/dist/portal/session/no-session-watch.js +227 -17
  397. package/dist/portal/session/presence/session-lease.js +1 -1
  398. package/dist/portal/session/presence/session-mirror.js +3 -0
  399. package/dist/portal/session/recorded-gaps.d.ts +97 -0
  400. package/dist/portal/session/recorded-gaps.js +251 -0
  401. package/dist/portal/session/serving-directory.d.ts +27 -0
  402. package/dist/portal/session/serving-directory.js +45 -0
  403. package/dist/portal/session/session-health.d.ts +18 -0
  404. package/dist/portal/session/session-health.js +9 -1
  405. package/dist/portal/session/session-info.d.ts +8 -1
  406. package/dist/portal/session/session-info.js +8 -1
  407. package/dist/portal/session/session-manager.d.ts +39 -0
  408. package/dist/portal/session/session-manager.js +98 -11
  409. package/dist/portal/session/session-reaper.js +4 -1
  410. package/dist/portal/session/session-successor.d.ts +13 -0
  411. package/dist/portal/session/session-successor.js +1 -1
  412. package/dist/portal/session/session-tools.js +26 -3
  413. package/dist/portal/session/session.d.ts +22 -30
  414. package/dist/portal/session/session.js +81 -79
  415. package/dist/portal/session/timing/command-timeout.js +25 -1
  416. package/dist/portal/session/timing/wall-clock.d.ts +1 -1
  417. package/dist/portal/session/timing/wall-clock.js +1 -1
  418. package/dist/portal/session/zero-install-first-call.d.ts +31 -0
  419. package/dist/portal/session/zero-install-first-call.js +88 -0
  420. package/dist/start-options.d.ts +12 -0
  421. package/dist/start-wiring.d.ts +63 -0
  422. package/dist/start-wiring.js +169 -0
  423. package/dist/status-payload.d.ts +23 -1
  424. package/dist/status-payload.js +36 -1
  425. package/dist/surface/http-server.js +18 -2
  426. package/dist/surface/mcp/attach-memory.d.ts +1 -0
  427. package/dist/surface/mcp/attach-memory.js +12 -1
  428. package/dist/surface/mcp/mcp-proxy.d.ts +9 -0
  429. package/dist/surface/mcp/mcp-proxy.js +65 -13
  430. package/dist/surface/mcp/mcp.d.ts +34 -6
  431. package/dist/surface/mcp/mcp.js +61 -17
  432. package/dist/surface/mcp/proxy/drive-calls.d.ts +10 -0
  433. package/dist/surface/mcp/proxy/drive-calls.js +27 -0
  434. package/dist/surface/mcp/proxy/mcp-post-transport.js +5 -0
  435. package/dist/surface/mcp/server-instructions.d.ts +4 -2
  436. package/dist/surface/mcp/server-instructions.js +32 -14
  437. package/dist/surface/mcp/shared-params.js +2 -2
  438. package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
  439. package/dist/surface/mcp/surface-vocabulary.js +1 -0
  440. package/dist/surface/tools/account-tool.d.ts +22 -0
  441. package/dist/surface/tools/account-tool.js +157 -0
  442. package/dist/surface/tools/act/act-danger.d.ts +11 -0
  443. package/dist/surface/tools/act/act-danger.js +38 -1
  444. package/dist/surface/tools/act/act-observation.d.ts +33 -0
  445. package/dist/surface/tools/act/act-observation.js +57 -0
  446. package/dist/surface/tools/act/act-preflight.js +25 -2
  447. package/dist/surface/tools/act/act-target.js +8 -3
  448. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +8 -0
  449. package/dist/surface/tools/act/navigation/navigate-arrival.js +56 -2
  450. package/dist/surface/tools/act/resolve-target.d.ts +1 -1
  451. package/dist/surface/tools/act/resolve-target.js +18 -3
  452. package/dist/surface/tools/act/screen-request.d.ts +34 -0
  453. package/dist/surface/tools/act/screen-request.js +113 -0
  454. package/dist/surface/tools/act/sequence-grade.d.ts +8 -0
  455. package/dist/surface/tools/act/sequence-grade.js +13 -2
  456. package/dist/surface/tools/act/settle-in-flight.js +25 -3
  457. package/dist/surface/tools/act-sequence-tool.js +138 -29
  458. package/dist/surface/tools/act-tools.d.ts +0 -9
  459. package/dist/surface/tools/act-tools.js +71 -41
  460. package/dist/surface/tools/agent/app-notes-learning.d.ts +7 -0
  461. package/dist/surface/tools/agent/app-notes-learning.js +80 -0
  462. package/dist/surface/tools/agent/app-notes.d.ts +4 -0
  463. package/dist/surface/tools/agent/app-notes.js +48 -0
  464. package/dist/surface/tools/agent/build-staleness.d.ts +7 -0
  465. package/dist/surface/tools/agent/build-staleness.js +62 -0
  466. package/dist/surface/tools/agent/compact-envelope.d.ts +80 -0
  467. package/dist/surface/tools/agent/compact-envelope.js +374 -0
  468. package/dist/surface/tools/agent/for-the-agent.d.ts +12 -0
  469. package/dist/surface/tools/agent/for-the-agent.js +44 -0
  470. package/dist/surface/tools/agent/notices.d.ts +50 -0
  471. package/dist/surface/tools/agent/notices.js +152 -0
  472. package/dist/surface/tools/agent/reteach.d.ts +11 -0
  473. package/dist/surface/tools/agent/reteach.js +50 -0
  474. package/dist/surface/tools/args/alias-args.d.ts +5 -0
  475. package/dist/surface/tools/args/alias-args.js +10 -0
  476. package/dist/surface/tools/args/confirm-dangerous-arg.d.ts +6 -0
  477. package/dist/surface/tools/args/confirm-dangerous-arg.js +6 -0
  478. package/dist/surface/tools/assert/assert-source.d.ts +15 -0
  479. package/dist/surface/tools/assert/assert-source.js +40 -0
  480. package/dist/surface/tools/assert/assert-verdict.d.ts +1 -1
  481. package/dist/surface/tools/assert/assert-verdict.js +42 -17
  482. package/dist/surface/tools/browser-tools.js +51 -2
  483. package/dist/surface/tools/chat-drives.d.ts +101 -0
  484. package/dist/surface/tools/chat-drives.js +409 -0
  485. package/dist/surface/tools/coverage-tools.d.ts +2 -10
  486. package/dist/surface/tools/coverage-tools.js +2 -53
  487. package/dist/surface/tools/dynamic-tools.js +29 -1
  488. package/dist/surface/tools/empty-session-list.d.ts +51 -0
  489. package/dist/surface/tools/empty-session-list.js +120 -0
  490. package/dist/surface/tools/error-recovery.d.ts +14 -0
  491. package/dist/surface/tools/error-recovery.js +105 -8
  492. package/dist/surface/tools/explore-tools.d.ts +31 -1
  493. package/dist/surface/tools/explore-tools.js +438 -66
  494. package/dist/surface/tools/feedback-tools.d.ts +2 -3
  495. package/dist/surface/tools/feedback-tools.js +18 -3
  496. package/dist/surface/tools/gap-novelty.d.ts +3 -1
  497. package/dist/surface/tools/gap-novelty.js +8 -1
  498. package/dist/surface/tools/harness-explore.d.ts +118 -57
  499. package/dist/surface/tools/harness-explore.js +344 -292
  500. package/dist/surface/tools/harness-gate.d.ts +88 -0
  501. package/dist/surface/tools/harness-gate.js +235 -0
  502. package/dist/surface/tools/harness-hunt.d.ts +43 -0
  503. package/dist/surface/tools/harness-hunt.js +215 -0
  504. package/dist/surface/tools/harness-plan.d.ts +17 -0
  505. package/dist/surface/tools/harness-plan.js +38 -0
  506. package/dist/surface/tools/harness-script.d.ts +30 -0
  507. package/dist/surface/tools/harness-script.js +560 -0
  508. package/dist/surface/tools/harness-tab-guard.d.ts +5 -0
  509. package/dist/surface/tools/harness-tab-guard.js +27 -0
  510. package/dist/surface/tools/harness-toolset.d.ts +22 -1
  511. package/dist/surface/tools/harness-toolset.js +101 -7
  512. package/dist/surface/tools/human-notes.d.ts +16 -0
  513. package/dist/surface/tools/human-notes.js +27 -0
  514. package/dist/surface/tools/invoke-tool.d.ts +5 -2
  515. package/dist/surface/tools/invoke-tool.js +263 -85
  516. package/dist/surface/tools/lease-hint.js +26 -5
  517. package/dist/surface/tools/lease-permissions.d.ts +33 -0
  518. package/dist/surface/tools/lease-permissions.js +73 -0
  519. package/dist/surface/tools/lease-readiness.d.ts +38 -0
  520. package/dist/surface/tools/lease-readiness.js +57 -0
  521. package/dist/surface/tools/lease-seed.d.ts +49 -0
  522. package/dist/surface/tools/lease-seed.js +167 -0
  523. package/dist/surface/tools/lease-tools.d.ts +13 -24
  524. package/dist/surface/tools/lease-tools.js +146 -197
  525. package/dist/surface/tools/live-call-text.js +4 -4
  526. package/dist/surface/tools/merge-tools.js +42 -2
  527. package/dist/surface/tools/merged-name-redirect.js +4 -0
  528. package/dist/surface/tools/next-step.d.ts +29 -0
  529. package/dist/surface/tools/next-step.js +214 -0
  530. package/dist/surface/tools/observe-tools.js +45 -9
  531. package/dist/surface/tools/platform-moment.d.ts +72 -0
  532. package/dist/surface/tools/platform-moment.js +296 -0
  533. package/dist/surface/tools/query-hint-schema.d.ts +7 -0
  534. package/dist/surface/tools/query-hint-schema.js +10 -0
  535. package/dist/surface/tools/read-tools.js +71 -14
  536. package/dist/surface/tools/real-input-attempt.js +96 -13
  537. package/dist/surface/tools/reticle-result.d.ts +120 -0
  538. package/dist/surface/tools/reticle-result.js +364 -0
  539. package/dist/surface/tools/tool-kit.d.ts +83 -3
  540. package/dist/surface/tools/tool-kit.js +77 -7
  541. package/dist/surface/tools/tools.js +43 -59
  542. package/dist/telemetry/account-envelope.d.ts +7 -0
  543. package/dist/telemetry/account-envelope.js +61 -0
  544. package/dist/telemetry/agent-client.d.ts +15 -0
  545. package/dist/telemetry/agent-client.js +57 -0
  546. package/dist/telemetry/app-instrumented.js +9 -2
  547. package/dist/telemetry/argument-shape.d.ts +7 -0
  548. package/dist/telemetry/argument-shape.js +86 -1
  549. package/dist/telemetry/automation-hint.d.ts +2 -3
  550. package/dist/telemetry/automation-hint.js +33 -8
  551. package/dist/telemetry/cli-telemetry.js +7 -2
  552. package/dist/telemetry/daemon-telemetry.js +3 -0
  553. package/dist/telemetry/error-fingerprint.d.ts +10 -1
  554. package/dist/telemetry/error-fingerprint.js +61 -5
  555. package/dist/telemetry/feedback-cli.d.ts +0 -13
  556. package/dist/telemetry/feedback-cli.js +0 -77
  557. package/dist/telemetry/feedback.d.ts +13 -0
  558. package/dist/telemetry/feedback.js +183 -17
  559. package/dist/telemetry/harness-run.d.ts +18 -0
  560. package/dist/telemetry/harness-run.js +80 -0
  561. package/dist/telemetry/hud-events.d.ts +16 -0
  562. package/dist/telemetry/hud-events.js +27 -0
  563. package/dist/telemetry/hud-metrics.d.ts +29 -6
  564. package/dist/telemetry/hud-metrics.js +116 -25
  565. package/dist/telemetry/init-telemetry.js +2 -2
  566. package/dist/telemetry/install-source.d.ts +13 -25
  567. package/dist/telemetry/install-source.js +44 -3
  568. package/dist/telemetry/mcp-connection.d.ts +0 -14
  569. package/dist/telemetry/mcp-connection.js +5 -1
  570. package/dist/telemetry/onboarding-firsts.d.ts +32 -0
  571. package/dist/telemetry/onboarding-firsts.js +81 -6
  572. package/dist/telemetry/platform-linked.d.ts +5 -0
  573. package/dist/telemetry/platform-linked.js +32 -0
  574. package/dist/telemetry/project-profile.js +5 -3
  575. package/dist/telemetry/proxy-telemetry.js +4 -1
  576. package/dist/telemetry/session-metrics.d.ts +15 -4
  577. package/dist/telemetry/session-metrics.js +88 -52
  578. package/dist/telemetry/telemetry.d.ts +38 -2
  579. package/dist/telemetry/telemetry.js +144 -34
  580. package/dist/telemetry/verification-of.d.ts +3 -1
  581. package/dist/telemetry/verification-of.js +13 -4
  582. package/dist/wire-journal.d.ts +2 -2
  583. package/dist/wire-journal.js +20 -6
  584. package/docs/README.md +3 -3
  585. package/docs/actions.mdx +6 -3
  586. package/docs/adapters.md +1 -1
  587. package/docs/agent-cheatsheet.md +25 -28
  588. package/docs/architecture.md +5 -5
  589. package/docs/autodrive.md +33 -28
  590. package/docs/benchmarks.md +5 -5
  591. package/docs/best-practices.mdx +27 -9
  592. package/docs/capabilities.mdx +14 -16
  593. package/docs/cli/affected.mdx +1 -1
  594. package/docs/cli/cloud.mdx +54 -75
  595. package/docs/cli/doctor.mdx +14 -3
  596. package/docs/cli/drive.mdx +20 -14
  597. package/docs/cli/feedback.mdx +3 -3
  598. package/docs/cli/gate.mdx +7 -2
  599. package/docs/cli/help.mdx +50 -55
  600. package/docs/cli/init.mdx +43 -28
  601. package/docs/cli/license.mdx +12 -8
  602. package/docs/cli/mcp.mdx +4 -4
  603. package/docs/cli/open.mdx +3 -3
  604. package/docs/cli/report.mdx +4 -2
  605. package/docs/cli/restart.mdx +2 -2
  606. package/docs/cli/rollback.mdx +14 -8
  607. package/docs/cli/serve.mdx +4 -4
  608. package/docs/cli/setup.mdx +23 -0
  609. package/docs/cli/status.mdx +18 -5
  610. package/docs/cli/stop.mdx +67 -8
  611. package/docs/cli/try.mdx +62 -0
  612. package/docs/cli/update.mdx +4 -3
  613. package/docs/cli/verify.mdx +17 -6
  614. package/docs/cli/version.mdx +5 -4
  615. package/docs/cli.mdx +111 -42
  616. package/docs/debugging.md +3 -3
  617. package/docs/deploy-checks.md +1 -1
  618. package/docs/desktop.mdx +9 -3
  619. package/docs/enterprise.md +11 -10
  620. package/docs/environment.mdx +7 -8
  621. package/docs/faq.mdx +3 -3
  622. package/docs/first-drive.md +5 -4
  623. package/docs/flows.md +35 -27
  624. package/docs/for-agents.md +4 -5
  625. package/docs/frameworks.mdx +32 -21
  626. package/docs/getting-started.md +65 -61
  627. package/docs/human-control.md +16 -16
  628. package/docs/index.mdx +15 -42
  629. package/docs/install-agentic.mdx +22 -37
  630. package/docs/install-manual.mdx +23 -13
  631. package/docs/instrumentation.mdx +5 -3
  632. package/docs/integration-patterns.md +7 -7
  633. package/docs/license-activation.mdx +1 -1
  634. package/docs/multi-agent-testing.md +24 -6
  635. package/docs/packages/babel-plugin.mdx +4 -2
  636. package/docs/packages/browser.mdx +16 -10
  637. package/docs/packages/core.mdx +12 -5
  638. package/docs/packages/electron.mdx +3 -2
  639. package/docs/packages/engine.mdx +1 -1
  640. package/docs/packages/eslint-plugin.mdx +18 -12
  641. package/docs/packages/next.mdx +8 -7
  642. package/docs/packages/open-verification.mdx +1 -1
  643. package/docs/packages/server.mdx +5 -5
  644. package/docs/packages/tauri.mdx +9 -9
  645. package/docs/packages/test.mdx +4 -10
  646. package/docs/packages/vite-plugin.mdx +32 -4
  647. package/docs/packages.mdx +11 -15
  648. package/docs/platform-integration.md +6 -5
  649. package/docs/predicates.mdx +40 -24
  650. package/docs/quickstart.mdx +69 -30
  651. package/docs/required-checks.md +8 -7
  652. package/docs/reticle-manual.md +15 -5
  653. package/docs/skill-file.mdx +17 -79
  654. package/docs/skill-setup.md +9 -9
  655. package/docs/skill.md +200 -0
  656. package/docs/system-map.md +7 -7
  657. package/docs/telemetry.md +23 -25
  658. package/docs/testing.md +4 -4
  659. package/docs/token-efficiency.md +12 -12
  660. package/docs/tools/act-and-wait.mdx +9 -2
  661. package/docs/tools/act-sequence.mdx +6 -7
  662. package/docs/tools/act.mdx +2 -2
  663. package/docs/tools/assert.mdx +18 -17
  664. package/docs/tools/console.mdx +9 -9
  665. package/docs/tools/inspect.mdx +16 -7
  666. package/docs/tools/look.mdx +24 -0
  667. package/docs/tools/navigate.mdx +5 -3
  668. package/docs/tools/network.mdx +2 -2
  669. package/docs/tools/observe.mdx +6 -6
  670. package/docs/tools/overview.mdx +34 -33
  671. package/docs/tools/query.mdx +5 -5
  672. package/docs/tools/session-and-feedback.mdx +22 -13
  673. package/docs/tools/sessions.mdx +8 -8
  674. package/docs/tools/snapshot.mdx +6 -5
  675. package/docs/tools/state.mdx +9 -9
  676. package/docs/tools/tools-and-run.mdx +26 -24
  677. package/docs/tools/verify.mdx +28 -0
  678. package/docs/tools/wait-for.mdx +8 -4
  679. package/docs/troubleshooting.mdx +21 -6
  680. package/docs/usage.md +55 -46
  681. package/docs/use-cases.mdx +3 -3
  682. package/docs/vs-chrome-devtools-mcp.mdx +9 -6
  683. package/docs/vs-playwright-mcp.mdx +3 -1
  684. package/docs/what-is-recorded.md +17 -5
  685. package/docs/what-is-reticle.mdx +5 -3
  686. package/docs/why-reticle.mdx +1 -1
  687. package/package.json +9 -12
  688. package/dist/command/cli/demo/demo-page.d.ts +0 -78
  689. package/dist/command/cli/demo/demo-page.js +0 -241
  690. package/dist/command/cli/demo/demo-run.d.ts +0 -38
  691. package/dist/command/cli/demo/demo-run.js +0 -138
  692. package/dist/features/harness/driver.d.ts +0 -50
  693. package/dist/features/harness/driver.js +0 -236
  694. package/dist/features/harness/jev-driver.d.ts +0 -188
  695. package/dist/features/harness/jev-driver.js +0 -678
  696. package/dist/features/harness/openai-driver.d.ts +0 -58
  697. package/dist/features/harness/openai-driver.js +0 -206
  698. package/dist/judgement/hunt/hunt-report.d.ts +0 -49
  699. package/dist/judgement/hunt/hunt-report.js +0 -84
  700. package/dist/language/flows/buddy-status.d.ts +0 -25
  701. package/dist/language/flows/buddy-status.js +0 -32
  702. package/dist/language/flows/change/watch-batcher.d.ts +0 -18
  703. package/dist/language/flows/change/watch-batcher.js +0 -19
  704. package/dist/memory/cloud/harness-offer.d.ts +0 -44
  705. package/dist/memory/cloud/harness-offer.js +0 -145
  706. package/dist/memory/project/dir/fill-value-store.d.ts +0 -32
  707. package/dist/memory/project/dir/fill-value-store.js +0 -88
  708. package/dist/surface/tools/feature-capture.d.ts +0 -151
  709. package/dist/surface/tools/feature-capture.js +0 -235
  710. package/dist/surface/tools/tool-hit-rate.d.ts +0 -87
  711. package/dist/surface/tools/tool-hit-rate.js +0 -90
  712. package/dist/telemetry/harness-drive.d.ts +0 -4
  713. package/dist/telemetry/harness-drive.js +0 -35
  714. package/dist/telemetry/identify.d.ts +0 -22
  715. package/dist/telemetry/identify.js +0 -73
  716. package/docs/cli/capsules.mdx +0 -70
  717. package/docs/cli/hunt.mdx +0 -73
  718. package/docs/cli/identify.mdx +0 -76
  719. package/docs/cli/kill.mdx +0 -91
  720. package/docs/cli/watch.mdx +0 -62
  721. package/docs/local-registry.md +0 -143
@@ -1,5 +1,6 @@
1
1
  import { EventType, PerfMetric, isDevToolingUrl } from '@reticlehq/core';
2
2
  import { routeOfEvent } from '@reticlehq/engine/question/predicate/predicate-route.js';
3
+ import { isCacheBookkeepingDiff } from '@reticlehq/engine/evidence/state-bookkeeping.js';
3
4
  /**
4
5
  * THE INVARIANT: every field of this summary has a bounded size that does not depend on how much the
5
6
  * app did. A verdict travels in the same payload as its evidence, so an unbounded evidence field is
@@ -57,12 +58,34 @@ function stateSettle(diffs) {
57
58
  const spread = Math.max(...times) - Math.min(...times);
58
59
  return spread > 0 ? { stateSettleMs: spread } : {};
59
60
  }
61
+ /** `METHOD /path STATUS` — what an agent recognises a call by. */
62
+ function requestLine(data) {
63
+ const raw = 'string' === typeof data['url'] ? data['url'] : '';
64
+ let path;
65
+ try {
66
+ path = new URL(raw, 'http://local.invalid').pathname;
67
+ }
68
+ catch {
69
+ path = raw.split('?')[0] ?? raw;
70
+ }
71
+ const method = 'string' === typeof data['method'] ? data['method'].toUpperCase() : 'GET';
72
+ const status = 'number' === typeof data['status'] ? String(data['status']) : 'pending';
73
+ return `${method} ${path} ${status}`;
74
+ }
75
+ /** The first line of a console error, capped. */
76
+ function firstLine(data) {
77
+ const text = ['message', 'text', 'error'].map((k) => data[k]).find((v) => 'string' === typeof v);
78
+ const line = ('string' === typeof text ? text : 'console error').split('\n')[0] ?? '';
79
+ return truncate(line);
80
+ }
60
81
  export function causalSummary(events, context = {}) {
61
82
  let netTotal = 0;
62
83
  let netErrors = 0;
63
84
  let ignoredDevTooling = 0;
64
85
  let headline;
65
86
  let consoleErrors = 0;
87
+ let firstConsoleError;
88
+ const requests = [];
66
89
  const statePathsChanged = [];
67
90
  const storageKeysChanged = [];
68
91
  const stateDiffs = [];
@@ -72,6 +95,7 @@ export function causalSummary(events, context = {}) {
72
95
  const fieldsChanged = [];
73
96
  let layoutShift;
74
97
  let longTasks = 0;
98
+ let ignoredBookkeeping = 0;
75
99
  for (const event of events) {
76
100
  const data = event.data;
77
101
  switch (event.type) {
@@ -82,6 +106,7 @@ export function causalSummary(events, context = {}) {
82
106
  }
83
107
  netTotal += 1;
84
108
  const status = data['status'];
109
+ requests.push(requestLine(data));
85
110
  const failed = false === data['ok'] || ('number' === typeof status && status >= 400);
86
111
  if (failed) {
87
112
  netErrors += 1;
@@ -93,6 +118,7 @@ export function causalSummary(events, context = {}) {
93
118
  case EventType.CONSOLE_ERROR:
94
119
  case EventType.ERROR_UNCAUGHT:
95
120
  consoleErrors += 1;
121
+ firstConsoleError ??= firstLine(data);
96
122
  break;
97
123
  case EventType.STATE_CHANGE: {
98
124
  pushUnique(statePathsChanged, data['name']);
@@ -103,6 +129,10 @@ export function causalSummary(events, context = {}) {
103
129
  const hasAfter = 'value' in data || 'new' in data;
104
130
  if ('string' === typeof path && path.length > 0 && ('old' in data || hasAfter)) {
105
131
  const after = 'value' in data ? data['value'] : data['new'];
132
+ if (isCacheBookkeepingDiff(data['old'], after)) {
133
+ ignoredBookkeeping += 1;
134
+ break;
135
+ }
106
136
  stateDiffs.push({
107
137
  path,
108
138
  from: capValue(data['old']),
@@ -160,9 +190,12 @@ export function causalSummary(events, context = {}) {
160
190
  ...(headline === undefined ? {} : { headline }),
161
191
  },
162
192
  consoleErrors,
193
+ ...(firstConsoleError === undefined ? {} : { firstConsoleError }),
194
+ ...(0 === requests.length ? {} : { requests: cap(requests, 'requests', elided) }),
163
195
  statePathsChanged: cap(statePathsChanged, 'statePathsChanged', elided),
164
196
  storageKeysChanged: cap(storageKeysChanged, 'storageKeysChanged', elided),
165
197
  stateDiffs: cap(stateDiffs, 'stateDiffs', elided),
198
+ ...(0 === ignoredBookkeeping ? {} : { ignoredBookkeeping }),
166
199
  ...settle,
167
200
  storageDiffs: cap(storageDiffs, 'storageDiffs', elided),
168
201
  ...(route === undefined ? {} : { route }),
@@ -25,7 +25,7 @@ export type VerificationRunInput = Omit<ReticleVerificationRun, 'schemaVersion'
25
25
  * reason those two values now survive into the artifact instead of being dropped at its door.
26
26
  * Confidence: nothing ran → LOW; an oracle-backed flow or any check ran → HIGH; only smoke → MEDIUM.
27
27
  */
28
- export declare function computeVerdict(input: VerificationRunInput): RunVerdict;
28
+ export declare function computeVerdict(raw: VerificationRunInput): RunVerdict;
29
29
  /**
30
30
  * Assemble the final, schema-valid ReticleVerificationRun. Stamps schemaVersion + createdAt (injected
31
31
  * clock) and computes the verdict; the result is parsed through the protocol schema so a malformed
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import { ReticleVerificationRunSchema, RUN_FILE_VERSION, Verified, RunConfidence, RunFlowStatus, VerdictStatus, } from '@reticlehq/core';
10
10
  import { redactForProfile } from './profile-redact.js';
11
+ import { supersededChecks } from '@reticlehq/engine/evidence/superseded-checks.js';
11
12
  /**
12
13
  * Compute the verdict deterministically from the run's flows, checks, and risks.
13
14
  * Rules (in order): a gated risk blocks → FAIL; mixed pass+fail → PARTIAL; any fail → FAIL;
@@ -18,11 +19,23 @@ import { redactForProfile } from './profile-redact.js';
18
19
  * reason those two values now survive into the artifact instead of being dropped at its door.
19
20
  * Confidence: nothing ran → LOW; an oracle-backed flow or any check ran → HIGH; only smoke → MEDIUM.
20
21
  */
21
- export function computeVerdict(input) {
22
+ export function computeVerdict(raw) {
23
+ // A passive check that read too early is superseded by the same claim holding later: the one
24
+ // rule every fold applies (superseded-checks.ts).
25
+ const superseded = supersededChecks(raw.checks.map((c) => ({
26
+ key: c.predicate,
27
+ passive: false === c.declaredBeforeActing,
28
+ held: Verified.YES === c.status,
29
+ failed: Verified.NO === c.status,
30
+ })));
31
+ const input = { ...raw, checks: raw.checks.filter((_, at) => !superseded.has(at)) };
22
32
  const passes = input.flows.filter((f) => f.status === RunFlowStatus.PASS || f.status === RunFlowStatus.HEALED)
23
33
  .length + input.checks.filter((c) => c.status === Verified.YES).length;
24
34
  const fails = input.flows.filter((f) => f.status === RunFlowStatus.FAIL).length +
25
35
  input.checks.filter((c) => c.status === Verified.NO).length;
36
+ const skippedFlows = input.flows.filter((f) => f.status === RunFlowStatus.SKIPPED).length;
37
+ // Ran and decided nothing, as the agent's own result block counts them: never part of a pass.
38
+ const undecidedChecks = input.checks.filter((c) => c.status !== Verified.YES && c.status !== Verified.NO).length;
26
39
  const blockingRisks = input.risks.filter((r) => r.gated).length;
27
40
  const reasons = [];
28
41
  for (const f of input.flows) {
@@ -31,6 +44,9 @@ export function computeVerdict(input) {
31
44
  ? `flow ${f.name}: ${f.failureReason}`
32
45
  : `flow ${f.name} failed`);
33
46
  }
47
+ else if (f.status === RunFlowStatus.SKIPPED && f.failureReason !== undefined) {
48
+ reasons.push(`flow ${f.name}: ${f.failureReason}`);
49
+ }
34
50
  }
35
51
  for (const c of input.checks) {
36
52
  if (c.status === Verified.NO)
@@ -43,10 +59,16 @@ export function computeVerdict(input) {
43
59
  let status;
44
60
  if (blockingRisks > 0)
45
61
  status = VerdictStatus.FAIL;
46
- else if (fails > 0 && passes > 0)
47
- status = VerdictStatus.PARTIAL;
62
+ // A failure beside things that passed is a fail, not a partial: the result block, the CLI and the
63
+ // platform's grade all call it that, and a "partial" beside "Reticle result: failed" was one run
64
+ // with two verdicts. A partial is only ever a pass with something skipped or undecided beside it.
48
65
  else if (fails > 0)
49
66
  status = VerdictStatus.FAIL;
67
+ else if ((skippedFlows > 0 || undecidedChecks > 0) && passes > 0) {
68
+ status = VerdictStatus.PARTIAL;
69
+ if (0 < undecidedChecks)
70
+ reasons.push(`${String(undecidedChecks)} check(s) undecided`);
71
+ }
50
72
  else if (0 === passes) {
51
73
  // Nothing passed and nothing failed, so nothing was proved -- an empty run, or one whose every
52
74
  // flow was skipped. Reporting that as PASS is the false green this whole file exists to prevent:
@@ -1,21 +1,3 @@
1
- /**
2
- * The gap, as a number the person who ran the session can see.
3
- *
4
- * Reticle's whole claim is that it measures the distance between what an agent believed happened
5
- * and what did. It measures that on every verdict, writes the answer into the journal, and shows it
6
- * to nobody: the counts exist, the reasons exist, the contradictions exist, and no surface anywhere
7
- * says "you made 14 claims, 9 held, 2 were false, 3 could not be decided, and here is who owns each
8
- * of those three". The value of the product is the one thing it never reports.
9
- *
10
- * A FOLD over the journal, never a second store — the rule `run-context.ts` next door states, for
11
- * the same reason: two ways to compute one number is worse than one way, because the day they
12
- * disagree the disagreement lands inside a verdict and a user finds it before we do.
13
- *
14
- * Nothing here sends anything anywhere, and that is deliberate rather than incidental. This is the
15
- * LOCAL half. Whether a fleet-wide version of the same number is worth collecting is a separate
16
- * decision with a separate owner, and building the local one first is what makes that decision
17
- * answerable from something other than a guess.
18
- */
19
1
  import { VerifiedReason, VerdictAttribution, type JournalAction } from '@reticlehq/core';
20
2
  /** One claim that did not hold, in the words it was made and the engine's reason for refusing it. */
21
3
  export interface GapFailure {
@@ -16,6 +16,7 @@
16
16
  * decision with a separate owner, and building the local one first is what makes that decision
17
17
  * answerable from something other than a guess.
18
18
  */
19
+ import { supersededChecks } from '@reticlehq/engine/evidence/superseded-checks.js';
19
20
  import { JournalVerdictEffectSchema, Verified, VerifiedReason, VerdictAttribution, verdictAttributionOf, } from '@reticlehq/core';
20
21
  /**
21
22
  * The reason, as the engine's own enum, or undefined.
@@ -48,9 +49,17 @@ export function gapSummary(actions) {
48
49
  falseGreensCaught: 0,
49
50
  failures: [],
50
51
  };
51
- for (const action of actions) {
52
- const verdict = verdictOf(action);
53
- if (verdict === undefined)
52
+ const verdicts = actions.map(verdictOf).filter((v) => v !== undefined);
53
+ // A passive check that read too early is not counted: the one rule every fold applies
54
+ // (superseded-checks.ts), so this block and the run's verdict cannot disagree.
55
+ const superseded = supersededChecks(verdicts.map((v) => ({
56
+ key: v.claim,
57
+ passive: false === v.declaredBeforeActing,
58
+ held: Verified.YES === v.verified,
59
+ failed: Verified.NO === v.verified,
60
+ })));
61
+ for (const [at, verdict] of verdicts.entries()) {
62
+ if (superseded.has(at))
54
63
  continue;
55
64
  summary.claims += 1;
56
65
  switch (verdict.verified) {
@@ -5,7 +5,7 @@
5
5
  * "why" is lifted from the replay's decision envelope (or its error) into failureReason.
6
6
  */
7
7
  import { ReplayStatus, RunFlowStatus, type FlowFile, type FlowReplayResult, type RunFlowResult } from '@reticlehq/core';
8
- /** OK → PASS; DRIFT/ERROR → FAIL (a healed flow is produced by the heal path, not plain replay). */
8
+ /** OK → PASS; UNVERIFIABLE → SKIPPED; DRIFT/ERROR → FAIL (a healed flow is produced by the heal path, not plain replay). */
9
9
  export declare function runFlowStatusOf(status: ReplayStatus): RunFlowStatus;
10
10
  /** Map one replay (plus its measured duration) into a RunFlowResult for the artifact's flows[]. */
11
11
  export declare function mapReplayToFlowResult(replay: FlowReplayResult, durationMs: number, flow?: FlowFile): RunFlowResult;
@@ -6,9 +6,13 @@
6
6
  */
7
7
  import { ReplayStatus, RUN_RECORDING_MAX_BYTES, RUN_STEP_RESULTS_MAX, RUN_TEXT_MAX, RunFlowStatus, } from '@reticlehq/core';
8
8
  import { SUCCESS_STEP_TOOL } from '../../../language/flows/flow-success.js';
9
- /** OK → PASS; DRIFT/ERROR → FAIL (a healed flow is produced by the heal path, not plain replay). */
9
+ /** OK → PASS; UNVERIFIABLE → SKIPPED; DRIFT/ERROR → FAIL (a healed flow is produced by the heal path, not plain replay). */
10
10
  export function runFlowStatusOf(status) {
11
- return status === ReplayStatus.OK ? RunFlowStatus.PASS : RunFlowStatus.FAIL;
11
+ if (status === ReplayStatus.OK)
12
+ return RunFlowStatus.PASS;
13
+ if (status === ReplayStatus.UNVERIFIABLE)
14
+ return RunFlowStatus.SKIPPED;
15
+ return RunFlowStatus.FAIL;
12
16
  }
13
17
  const clip = (text) => text.length > RUN_TEXT_MAX ? `${text.slice(0, RUN_TEXT_MAX - 1)}…` : text;
14
18
  /** One step as synced: what it did, where, and whether it held. */
@@ -37,25 +41,47 @@ function recordingOf(flow) {
37
41
  ? { recordingOmitted: true }
38
42
  : { recording };
39
43
  }
44
+ /** The first contradiction a replay recorded, on a step or across them. */
45
+ function firstContradiction(replay) {
46
+ for (const step of replay.steps) {
47
+ const found = step.contradictions?.[0];
48
+ if (found !== undefined)
49
+ return found;
50
+ }
51
+ return replay.crossStep?.[0];
52
+ }
40
53
  /** Map one replay (plus its measured duration) into a RunFlowResult for the artifact's flows[]. */
41
54
  export function mapReplayToFlowResult(replay, durationMs, flow) {
42
- // A replay that could not start returns OK with no steps. Nothing ran, so it is SKIPPED — which
43
- // every reader of a run (the verdict, the gate) already refuses to count as a pass.
44
- const status = replay.unverifiable === undefined ? runFlowStatusOf(replay.status) : RunFlowStatus.SKIPPED;
55
+ // A replay that could not start or complete returns UNVERIFIABLE (or carries an unverifiable caveat).
56
+ // Nothing was verified, so it is SKIPPED — which every reader of a run (the verdict, the gate)
57
+ // refuses to count as a pass.
58
+ // A pass whose channels disagreed is the suite's `unverifiable`, and the run says the same: the
59
+ // CLI printed "unverifiable" and exited 1 while the dashboard listed the run as Passed.
60
+ const disagreed = replay.status === ReplayStatus.OK ? firstContradiction(replay) : undefined;
61
+ const status = replay.status === ReplayStatus.UNVERIFIABLE ||
62
+ replay.unverifiable !== undefined ||
63
+ disagreed !== undefined
64
+ ? RunFlowStatus.SKIPPED
65
+ : runFlowStatusOf(replay.status);
45
66
  const failureReason = replay.unverifiable !== undefined
46
67
  ? replay.unverifiable.reason
47
- : status === RunFlowStatus.FAIL
48
- ? (replay.decision?.whatChanged ??
49
- replay.decision?.summary ??
50
- replay.error?.message ??
51
- 'flow failed')
52
- : undefined;
68
+ : disagreed !== undefined
69
+ ? clip(`a channel disagreed (${disagreed.kind}): ${disagreed.counter} — ${disagreed.detail}`)
70
+ : status === RunFlowStatus.FAIL
71
+ ? (replay.decision?.whatChanged ??
72
+ replay.decision?.summary ??
73
+ replay.error?.message ??
74
+ 'flow failed')
75
+ : status === RunFlowStatus.SKIPPED
76
+ ? 'flow could not be graded'
77
+ : undefined;
53
78
  // A flow with a success oracle gets a synthetic 'success' step appended by replay; surface its label
54
79
  // as the run's `oracle` so the verdict counts this flow as consequence-backed (→ HIGH confidence),
55
80
  // not a bare smoke click. Without this, an oracle-backed pass reads as MEDIUM and undersells itself.
56
81
  const oracle = replay.steps.find((s) => s.tool === SUCCESS_STEP_TOOL)?.anchor;
57
82
  return {
58
83
  name: replay.name,
84
+ ...(flow?.template === undefined ? {} : { template: flow.template }),
59
85
  status,
60
86
  steps: replay.steps.length,
61
87
  durationMs,
@@ -5,7 +5,7 @@
5
5
  * individual run to a deploy. The run is already clock-stamped by buildVerificationRun, so the store
6
6
  * needs no clock.
7
7
  */
8
- import { RunReadError, type ReticleVerificationRun, type RunId } from '@reticlehq/core';
8
+ import { RunReadError, type ReticleVerificationRun, type RunId, type RunScreenshot } from '@reticlehq/core';
9
9
  import type { FileSystemPort } from '../../../memory/project/fs/fs-port.js';
10
10
  /** Never-throws read result (mirrors ReadProjectResult). */
11
11
  export type ReadRunResult = {
@@ -38,7 +38,7 @@ export declare class RunStore {
38
38
  * Guards runId as a safe path segment BEFORE building the path — a runId can originate from a caller
39
39
  * (an OEM may set it), so an unsafe value must never escape .reticle/runs/ (mirrors the read guard).
40
40
  */
41
- write(run: ReticleVerificationRun): Promise<void>;
41
+ write(given: ReticleVerificationRun): Promise<void>;
42
42
  /** Never throws. Invalid id / missing → MISSING; bad JSON or failed schema → MALFORMED. */
43
43
  read(runId: RunId): Promise<ReadRunResult>;
44
44
  /** List run ids on disk (filenames minus.json). Empty when the runs dir is absent. */
@@ -51,4 +51,16 @@ export declare class RunStore {
51
51
  */
52
52
  latestTwo(): Promise<[ReticleVerificationRun, ReticleVerificationRun] | undefined>;
53
53
  }
54
+ /** Remember a capture that has not landed yet, so a run written now can wait for it. */
55
+ export declare function noteLanding(dir: string, land: Promise<void>): void;
56
+ /** Wait for this run's screenshots still landing, so a run written now can list them. Bounded. */
57
+ export declare function shotsLanded(root: string, runId: string): Promise<void>;
58
+ /** Every screenshot a run has landed, in the order they were taken (by seq). Never throws. */
59
+ export declare function readStepShots(fs: FileSystemPort, root: string, runId: string): Promise<RunScreenshot[]>;
60
+ /**
61
+ * The run with its screenshots: every one in `screenshots`, each replayed step's pinned to that
62
+ * step (matched as `<flow>#<step>`), and each verdict's to its check. Pure. A run with none comes
63
+ * back unchanged.
64
+ */
65
+ export declare function withScreenshots(run: ReticleVerificationRun, taken: readonly RunScreenshot[]): ReticleVerificationRun;
54
66
  export {};
@@ -5,11 +5,17 @@
5
5
  * individual run to a deploy. The run is already clock-stamped by buildVerificationRun, so the store
6
6
  * needs no clock.
7
7
  */
8
- import { asRunId, ReticleVerificationRunSchema, RUN_RETENTION, RUN_RETENTION_SLACK, RunReadError, } from '@reticlehq/core';
9
- import { reticleDirPaths, isValidRunId, runPath } from '../../../memory/project/dir/reticle-dir.js';
8
+ import { asRunId, ReticleVerificationRunSchema, RUN_RETENTION, RUN_RETENTION_SLACK, RunReadError, RunScreenshotSchema, STEP_SCREENSHOT, } from '@reticlehq/core';
9
+ import { PromptContextSchema } from '@reticlehq/core/artifacts';
10
+ import { reticleDirPaths, isValidRunId, runPath, stepShotDir, } from '../../../memory/project/dir/reticle-dir.js';
11
+ import { join } from 'node:path';
10
12
  const JSON_INDENT = 2;
11
13
  const JSON_EXT = '.json';
12
14
  const TMP_EXT = '.tmp';
15
+ /** A request older than this is about some other task, not the run being written now. */
16
+ const REQUEST_RELEVANT_MS = 6 * 60 * 60 * 1000;
17
+ /** Which run a recorded request was attached to, written into the request file. */
18
+ const REQUEST_RUN_KEY = 'answeredByRun';
13
19
  export class RunStore {
14
20
  #fs;
15
21
  #root;
@@ -28,11 +34,18 @@ export class RunStore {
28
34
  * Guards runId as a safe path segment BEFORE building the path — a runId can originate from a caller
29
35
  * (an OEM may set it), so an unsafe value must never escape .reticle/runs/ (mirrors the read guard).
30
36
  */
31
- async write(run) {
37
+ async write(given) {
38
+ let run = given;
32
39
  if (!isValidRunId(run.runId)) {
33
40
  throw new Error(`refusing to write run with unsafe runId: ${JSON.stringify(run.runId)}`);
34
41
  }
35
42
  await this.#fs.mkdir(reticleDirPaths(this.#root).runs);
43
+ const context = run.context ?? (await this.#recentRequest(run.createdAt, run.runId));
44
+ if (context !== undefined)
45
+ run = { ...run, context };
46
+ // The step screenshots taken for this run, the last of which may still be landing.
47
+ await shotsLanded(this.#root, run.runId);
48
+ run = withScreenshots(run, await readStepShots(this.#fs, this.#root, run.runId));
36
49
  // Atomic publish: write a temp file then rename, so a crash mid-write never leaves a half-written
37
50
  // artifact (a partial.json would otherwise read back as MALFORMED).
38
51
  const path = runPath(this.#root, run.runId);
@@ -49,6 +62,32 @@ export class RunStore {
49
62
  }
50
63
  await this.#pruneOld();
51
64
  }
65
+ /**
66
+ * The user's request this run answers, when the agent relayed one recently enough to be about it.
67
+ * Read from .reticle/intent/request.json (written by `reticle_intent { declare, request }`).
68
+ */
69
+ async #recentRequest(at, runId) {
70
+ try {
71
+ const path = reticleDirPaths(this.#root).request;
72
+ const raw = JSON.parse(await this.#fs.readFile(path));
73
+ const parsed = PromptContextSchema.safeParse(raw);
74
+ if (!parsed.success)
75
+ return undefined;
76
+ const given = parsed.data.at;
77
+ if (given === undefined || at - given < 0 || REQUEST_RELEVANT_MS < at - given)
78
+ return undefined;
79
+ // The first run written for a request answers it; a later run (the next agent session in the
80
+ // same tab) inherited it and showed a goal it never had. Its own rewrite keeps it.
81
+ const answeredBy = raw[REQUEST_RUN_KEY];
82
+ if ('string' === typeof answeredBy)
83
+ return answeredBy === runId ? parsed.data : undefined;
84
+ await this.#fs.writeFile(path, `${JSON.stringify({ ...raw, [REQUEST_RUN_KEY]: runId }, null, JSON_INDENT)}\n`);
85
+ return parsed.data;
86
+ }
87
+ catch {
88
+ return undefined; // no request recorded: the common case
89
+ }
90
+ }
52
91
  /**
53
92
  * Keep .reticle/runs/ bounded. Only acts once the count exceeds RUN_RETENTION + SLACK, then deletes the
54
93
  * oldest (by createdAt) back down to RUN_RETENTION — so the read-all is amortized, not per-write.
@@ -148,3 +187,156 @@ export class RunStore {
148
187
  return [previous, current];
149
188
  }
150
189
  }
190
+ /*
191
+ * A run's step screenshots, as its artifact records them. The images are written beside the run
192
+ * (`.reticle/visual/runs/<runId>/`) with one record line each in `shots.jsonl` by
193
+ * `features/visual/step-shots.ts`; this is the reading half.
194
+ */
195
+ /** How long a run write waits for screenshots still landing. A capture is never worth a stuck run. */
196
+ const LANDING_WAIT_MS = 10_000;
197
+ /** Captures still landing, per run directory. */
198
+ const landing = new Map();
199
+ /** Remember a capture that has not landed yet, so a run written now can wait for it. */
200
+ export function noteLanding(dir, land) {
201
+ const pending = landing.get(dir) ?? new Set();
202
+ landing.set(dir, pending);
203
+ pending.add(land);
204
+ void land.finally(() => pending.delete(land));
205
+ }
206
+ /** Wait for this run's screenshots still landing, so a run written now can list them. Bounded. */
207
+ export async function shotsLanded(root, runId) {
208
+ if (!isValidRunId(runId))
209
+ return;
210
+ const pending = landing.get(stepShotDir(root, runId));
211
+ if (pending === undefined || 0 === pending.size)
212
+ return;
213
+ let timer;
214
+ await Promise.race([
215
+ Promise.allSettled([...pending]),
216
+ new Promise((resolve) => {
217
+ timer = setTimeout(resolve, LANDING_WAIT_MS);
218
+ }),
219
+ ]);
220
+ if (timer !== undefined)
221
+ clearTimeout(timer);
222
+ }
223
+ /** One line of a run's record, read back; anything malformed is skipped. */
224
+ function parseLine(line) {
225
+ try {
226
+ const parsed = RunScreenshotSchema.safeParse(JSON.parse(line));
227
+ return parsed.success ? parsed.data : undefined;
228
+ }
229
+ catch {
230
+ return undefined;
231
+ }
232
+ }
233
+ /** Every screenshot a run has landed, in the order they were taken (by seq). Never throws. */
234
+ export async function readStepShots(fs, root, runId) {
235
+ if (!isValidRunId(runId))
236
+ return [];
237
+ try {
238
+ const text = await fs.readFile(join(stepShotDir(root, runId), STEP_SCREENSHOT.MANIFEST_FILE));
239
+ return (text
240
+ .split('\n')
241
+ .filter((line) => line.length > 0)
242
+ .map(parseLine)
243
+ .filter((shot) => shot !== undefined)
244
+ // In the order they were TAKEN: captures land in whatever order they finish.
245
+ .sort((a, b) => a.seq - b.seq));
246
+ }
247
+ catch {
248
+ return [];
249
+ }
250
+ }
251
+ /** The four facts a step records about its picture, out of the run-wide entry. */
252
+ function stepShotOf(shot) {
253
+ const { file, source, width, height, sha256 } = shot;
254
+ return { file, source, width, height, sha256 };
255
+ }
256
+ /** An id that occurs once in the list; a repeated one (a reload restarts the count) pairs nothing. */
257
+ function uniqueIds(ids) {
258
+ const seen = new Map();
259
+ for (const id of ids)
260
+ if (id !== undefined)
261
+ seen.set(id, (seen.get(id) ?? 0) + 1);
262
+ return new Set([...seen].filter(([, n]) => 1 === n).map(([id]) => id));
263
+ }
264
+ /**
265
+ * Pair by the journal action each was taken for, when both sides name it. A check that took no
266
+ * picture (a `steps` call, an answer refused as an error) then costs only its own picture, where the
267
+ * ordinal pairing below lost every picture in the run.
268
+ */
269
+ function pairByAction(run, shots) {
270
+ const verdictShots = shots.filter((shot) => true === shot.verdict && shot.actionId !== undefined);
271
+ if (0 === verdictShots.length || run.checks.every((check) => check.actionId === undefined))
272
+ return undefined;
273
+ const okChecks = uniqueIds(run.checks.map((check) => check.actionId));
274
+ const okShots = uniqueIds(verdictShots.map((shot) => shot.actionId));
275
+ const shotOf = new Map(verdictShots.flatMap((shot) => shot.actionId !== undefined && okShots.has(shot.actionId) && okChecks.has(shot.actionId)
276
+ ? [[shot.actionId, shot]]
277
+ : []));
278
+ const checkIdOf = new Map();
279
+ const checks = run.checks.map((check) => {
280
+ const shot = check.actionId === undefined ? undefined : shotOf.get(check.actionId);
281
+ if (shot === undefined)
282
+ return check;
283
+ if (check.checkId !== undefined)
284
+ checkIdOf.set(shot, check.checkId);
285
+ return { ...check, screenshot: stepShotOf(shot) };
286
+ });
287
+ return {
288
+ checks,
289
+ shots: shots.map((shot) => {
290
+ const checkId = checkIdOf.get(shot);
291
+ return checkId === undefined ? shot : { ...shot, checkId };
292
+ }),
293
+ };
294
+ }
295
+ /**
296
+ * Pair each verdict's picture with the check it produced: the n-th verdict picture is the n-th check,
297
+ * because both are written in the order the verdicts were given. Only when the counts agree — a
298
+ * verdict this run did not fold, or one taken while the capture failed, would shift every pairing
299
+ * after it, and an unpaired picture is better than one shown beside the wrong check.
300
+ */
301
+ function pairWithChecks(run, shots) {
302
+ const byAction = pairByAction(run, shots);
303
+ if (byAction !== undefined)
304
+ return byAction;
305
+ const verdictShots = shots.filter((shot) => true === shot.verdict);
306
+ if (0 === verdictShots.length ||
307
+ verdictShots.length !== run.checks.length ||
308
+ run.checks.some((check) => check.checkId === undefined))
309
+ return { checks: run.checks, shots: [...shots] };
310
+ const checkIdOf = new Map(verdictShots.map((shot, i) => [shot, run.checks[i]?.checkId]));
311
+ return {
312
+ checks: run.checks.map((check, i) => {
313
+ const shot = verdictShots[i];
314
+ return shot === undefined ? check : { ...check, screenshot: stepShotOf(shot) };
315
+ }),
316
+ shots: shots.map((shot) => {
317
+ const checkId = checkIdOf.get(shot);
318
+ return checkId === undefined ? shot : { ...shot, checkId };
319
+ }),
320
+ };
321
+ }
322
+ /**
323
+ * The run with its screenshots: every one in `screenshots`, each replayed step's pinned to that
324
+ * step (matched as `<flow>#<step>`), and each verdict's to its check. Pure. A run with none comes
325
+ * back unchanged.
326
+ */
327
+ export function withScreenshots(run, taken) {
328
+ if (0 === taken.length)
329
+ return run;
330
+ const { checks, shots } = pairWithChecks(run, taken);
331
+ const byStep = new Map(shots.flatMap((shot) => (shot.step === undefined ? [] : [[shot.step, shot]])));
332
+ const flows = run.flows.map((flow) => flow.stepResults === undefined
333
+ ? flow
334
+ : {
335
+ ...flow,
336
+ stepResults: flow.stepResults.map((result) => {
337
+ const shot = byStep.get(`${flow.name}#${String(result.step)}`);
338
+ return shot === undefined ? result : { ...result, screenshot: stepShotOf(shot) };
339
+ }),
340
+ });
341
+ return { ...run, checks, flows, screenshots: shots };
342
+ }