@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,4 +1,5 @@
1
- import { ActionType, DANGEROUS_ACTION_CONFIRM_ARG, NATIVE_INPUT_ARG, isDangerousActionText, } from '@reticlehq/core';
1
+ import { ActionType, DANGEROUS_ACTION_CONFIRM_ARG, NATIVE_INPUT_ARG, isDangerousActionText, outwardActionOf, outwardRefusal, } from '@reticlehq/core';
2
+ import { currentDrivenBy, harnessOutwardAllowed } from '../../../hooks/driven-by.js';
2
3
  import { asRecord, asString } from '@reticlehq/core';
3
4
  /**
4
5
  * Refuse to drive a money-moving or destructive control by accident.
@@ -29,9 +30,21 @@ function descriptorRole(value) {
29
30
  function isDestructiveDescriptor(value) {
30
31
  return isDangerousActionText(descriptorText(value), descriptorRole(value));
31
32
  }
33
+ /** A Harness call presses an outward control only when its journey asked (`harnessOutwardAllowed`). */
34
+ function assertOutwardAllowed(...descriptors) {
35
+ const allowed = harnessOutwardAllowed();
36
+ if (allowed === undefined)
37
+ return;
38
+ for (const descriptor of descriptors) {
39
+ const kind = outwardActionOf(descriptorText(descriptor), descriptorRole(descriptor));
40
+ if (kind !== undefined && !allowed.includes(kind))
41
+ throw new Error(outwardRefusal(kind));
42
+ }
43
+ }
32
44
  export function assertNotDestructive(action, innerArgs, inspected) {
33
45
  if (action !== ActionType.CLICK && action !== ActionType.DBLCLICK)
34
46
  return;
47
+ assertOutwardAllowed(inspected);
35
48
  if (true === innerArgs[DANGEROUS_ACTION_CONFIRM_ARG])
36
49
  return;
37
50
  if (!isDestructiveDescriptor(inspected))
@@ -44,6 +57,7 @@ export function assertNotDestructive(action, innerArgs, inspected) {
44
57
  * option dragged onto Save is not a payment.
45
58
  */
46
59
  export function assertDragNotDestructive(innerArgs, from, to) {
60
+ assertOutwardAllowed(from, to);
47
61
  if (true === innerArgs[DANGEROUS_ACTION_CONFIRM_ARG])
48
62
  return;
49
63
  if (!isDestructiveDescriptor(from) && !isDestructiveDescriptor(to))
@@ -67,3 +81,26 @@ export function assertNativeInputSupported(innerArgs) {
67
81
  if (true === innerArgs[NATIVE_INPUT_ARG])
68
82
  throw new Error(NATIVE_INPUT_UNSUPPORTED);
69
83
  }
84
+ /**
85
+ * The agent's own declaration counts as the confirmation, for that one control.
86
+ *
87
+ * `reticle_act_and_wait { target: { role: "button", name: "Place order" }, until }` names the
88
+ * control by the very words the guard flags AND names the consequence before acting: asking again
89
+ * for `confirmDangerous` cost a round trip per step on a shop's ordinary path and protected nothing.
90
+ * A `ref` or `testid` does not count — neither says what the control does, and a stale ref is
91
+ * exactly how the wrong button gets pressed. A Harness call never takes this path: its outward
92
+ * guard decides alone.
93
+ */
94
+ export function confirmedByDeclaration(innerArgs, target, declared) {
95
+ if (!declared || true === innerArgs[DANGEROUS_ACTION_CONFIRM_ARG])
96
+ return innerArgs;
97
+ if (currentDrivenBy() !== undefined)
98
+ return innerArgs;
99
+ const named = asRecord(target);
100
+ // The words must themselves be the dangerous ones: naming "Continue" on a button whose form posts
101
+ // to /delete-account consents to nothing, and the guard still reads the whole control.
102
+ const words = ['name', 'text', 'label'].map((key) => asString(named[key]) ?? '').join(' ');
103
+ return isDangerousActionText(words, asString(named['role']))
104
+ ? { ...innerArgs, [DANGEROUS_ACTION_CONFIRM_ARG]: true }
105
+ : innerArgs;
106
+ }
@@ -10,6 +10,7 @@
10
10
  * used from the two points where observation can be lost: a write rejected at dispatch, and a wait
11
11
  * cut off mid-predicate.
12
12
  */
13
+ import { type ReticleEvent } from '@reticlehq/core';
13
14
  import type { Session } from '../../../portal/session/session.js';
14
15
  import { type SuccessorRegistry } from '../../../portal/session/session-successor.js';
15
16
  import type { EvalResult } from '@reticlehq/engine/question/predicate/predicate-eval.js';
@@ -39,4 +40,36 @@ interface FollowedOutcome {
39
40
  * `awaitDocumentSuccessor` refuses to guess — a wrong follow drives somebody else's app.
40
41
  */
41
42
  export declare function followLostObservation(input: FollowSuccessor): Promise<FollowedOutcome>;
43
+ /** Why a consequence that did not follow a click on a disabled control is not the app's failure. */
44
+ export declare const DISABLED_TARGET_NOTE: string;
45
+ /**
46
+ * The page reports `enabled: false` on an act whose target was disabled at dispatch. A missed
47
+ * consequence then says nothing about the app, so the verdict is undecided rather than "no".
48
+ */
49
+ export declare function disabledTargetNote(pass: boolean, actResult: unknown): string | undefined;
50
+ /**
51
+ * The requests of a failed check's window, as its record carries them: method, url, status and the
52
+ * start of the response body (redacted in the page before it was ever sent). Dev tooling is left out.
53
+ */
54
+ /**
55
+ * The requests a check keeps: on a miss, the window's calls that explain it; on a held network check,
56
+ * the request that answered it, so a share page can name "a POST to /api/…", not "a request was seen".
57
+ */
58
+ export declare function checkNet(verdict: {
59
+ pass: boolean;
60
+ evidence?: unknown;
61
+ }, events: readonly ReticleEvent[]): {
62
+ net?: {
63
+ method: string;
64
+ url: string;
65
+ status?: number;
66
+ body?: string;
67
+ }[];
68
+ };
69
+ export declare function windowNet(events: readonly ReticleEvent[]): {
70
+ method: string;
71
+ url: string;
72
+ status?: number;
73
+ body?: string;
74
+ }[];
42
75
  export {};
@@ -10,6 +10,7 @@
10
10
  * used from the two points where observation can be lost: a write rejected at dispatch, and a wait
11
11
  * cut off mid-predicate.
12
12
  */
13
+ import { EventType, asRecord, asString, isDevToolingUrl } from '@reticlehq/core';
13
14
  import { awaitDocumentSuccessor, } from '../../../portal/session/session-successor.js';
14
15
  /**
15
16
  * Follow the unique same-origin successor and re-ask there, or leave the verdict untouched.
@@ -34,3 +35,59 @@ export async function followLostObservation(input) {
34
35
  return { session: next, verdict, followed: true };
35
36
  return { session: next, verdict: await reevaluate(next, leftover), followed: true };
36
37
  }
38
+ /** Why a consequence that did not follow a click on a disabled control is not the app's failure. */
39
+ export const DISABLED_TARGET_NOTE = 'the control was disabled when it was acted on, so nothing a user could do there would have ' +
40
+ 'caused the declared consequence. Check why it was disabled (an empty required field, a save ' +
41
+ 'that already happened) before calling this a defect.';
42
+ /**
43
+ * The page reports `enabled: false` on an act whose target was disabled at dispatch. A missed
44
+ * consequence then says nothing about the app, so the verdict is undecided rather than "no".
45
+ */
46
+ export function disabledTargetNote(pass, actResult) {
47
+ if (pass)
48
+ return undefined;
49
+ return false === asRecord(actResult)['enabled'] ? DISABLED_TARGET_NOTE : undefined;
50
+ }
51
+ /** Calls quoted on a failed check, and how much of each response body. */
52
+ const MAX_NET_CALLS = 5;
53
+ const MAX_BODY_CHARS = 300;
54
+ /**
55
+ * The requests of a failed check's window, as its record carries them: method, url, status and the
56
+ * start of the response body (redacted in the page before it was ever sent). Dev tooling is left out.
57
+ */
58
+ /**
59
+ * The requests a check keeps: on a miss, the window's calls that explain it; on a held network check,
60
+ * the request that answered it, so a share page can name "a POST to /api/…", not "a request was seen".
61
+ */
62
+ export function checkNet(verdict, events) {
63
+ if (!verdict.pass)
64
+ return { net: windowNet(events) };
65
+ const seen = asRecord(verdict.evidence);
66
+ const method = asString(seen['method']);
67
+ const url = asString(seen['url']);
68
+ if (method === undefined || url === undefined)
69
+ return {};
70
+ const status = seen['status'];
71
+ return { net: [{ method, url, ...('number' === typeof status ? { status } : {}) }] };
72
+ }
73
+ export function windowNet(events) {
74
+ const out = [];
75
+ for (const event of events) {
76
+ if (EventType.NET_REQUEST !== event.type)
77
+ continue;
78
+ const url = asString(event.data['url']);
79
+ if (url === undefined || isDevToolingUrl(url))
80
+ continue;
81
+ const status = event.data['status'];
82
+ const body = asString(event.data['responseBody']);
83
+ out.push({
84
+ method: (asString(event.data['method']) ?? 'GET').toUpperCase(),
85
+ url,
86
+ ...('number' === typeof status ? { status } : {}),
87
+ ...(body === undefined ? {} : { body: body.slice(0, MAX_BODY_CHARS) }),
88
+ });
89
+ if (MAX_NET_CALLS <= out.length)
90
+ break;
91
+ }
92
+ return out;
93
+ }
@@ -11,7 +11,7 @@
11
11
  * outcome than "unknown".
12
12
  */
13
13
  import { PredicateSchema } from '@reticlehq/engine/question/predicate/predicate-schema.js';
14
- import { isGlobalPressCall } from '@reticlehq/core';
14
+ import { SESSION_REF, isGlobalPressCall, unissuedRefRefusal } from '@reticlehq/core';
15
15
  import { SessionReplacedError } from '../../../portal/session/page-commands/pending-commands.js';
16
16
  import { assertNativeInputSupported } from './act-danger.js';
17
17
  import { unevaluablePredicateReason, vacuousPredicateReason, } from '@reticlehq/engine/question/predicate/predicate-precheck.js';
@@ -80,6 +80,19 @@ export function sequenceStepArgs(step) {
80
80
  flat[key] = value;
81
81
  }
82
82
  const nested = step['args'];
83
+ if ('string' === typeof nested) {
84
+ let parsed;
85
+ try {
86
+ parsed = JSON.parse(nested);
87
+ }
88
+ catch {
89
+ throw new Error(`step.args is a string that is not valid JSON — pass an object, not a string. Got: ${nested.slice(0, 120)}`);
90
+ }
91
+ if (null === parsed || 'object' !== typeof parsed || Array.isArray(parsed)) {
92
+ throw new Error(`step.args is a JSON string but not an object — pass an object, not ${null === parsed ? 'null' : typeof parsed}. Got: ${nested.slice(0, 120)}`);
93
+ }
94
+ return { ...flat, ...parsed };
95
+ }
83
96
  return { ...flat, ...(null !== nested && 'object' === typeof nested ? nested : {}) };
84
97
  }
85
98
  export function assertSequenceSteps(steps) {
@@ -113,8 +126,18 @@ export function assertSequenceSteps(steps) {
113
126
  'Refused rather than dropped, because a step whose declaration was discarded reports ' +
114
127
  'as a step that declared nothing. Nothing was acted on.');
115
128
  }
116
- if ('string' === typeof step['ref'] && step['ref'].length > 0)
129
+ if ('string' === typeof step['args']) {
130
+ sequenceStepArgs(step);
131
+ }
132
+ if ('string' === typeof step['ref'] && step['ref'].length > 0) {
133
+ // The same shape check `resolveActTarget` makes, moved ahead of the first step: left there, a
134
+ // malformed ref in step three is only found after steps one and two have already acted.
135
+ if (!SESSION_REF.test(step['ref'])) {
136
+ throw new Error(`step ${String(i)}: ${unissuedRefRefusal(step['ref'])} ` +
137
+ 'Nothing was acted on — the whole sequence is refused so a bad step cannot leave the earlier ones half-applied.');
138
+ }
117
139
  return;
140
+ }
118
141
  if (step['target'] !== undefined)
119
142
  return;
120
143
  if (isGlobalPressCall(step))
@@ -7,7 +7,7 @@
7
7
  * dispatch out of the file that opens the window would have weakened a real invariant to satisfy a
8
8
  * line count. This resolves a TARGET and dispatches only QUERY, so that guard is untouched.
9
9
  */
10
- import { ReticleCommand, isGlobalPressCall } from '@reticlehq/core';
10
+ import { ReticleCommand, SESSION_REF, isGlobalPressCall, unissuedRefRefusal, } from '@reticlehq/core';
11
11
  import { normalizeQueryArgs } from '../read/query-shape.js';
12
12
  import { resolveTargetRef } from './resolve-target.js';
13
13
  import { asRecord, asString, asNumber } from '@reticlehq/core';
@@ -49,8 +49,13 @@ export async function resolveActTarget(session, args,
49
49
  */
50
50
  appearanceMs) {
51
51
  const ref = asString(args['ref']);
52
- if (ref !== undefined && ref.length > 0)
52
+ if (ref !== undefined && ref.length > 0) {
53
+ // Refused here, at the boundary, and never re-read as a `target`: guessing what an arbitrary
54
+ // string meant is the silent re-resolution the stale-ref refusal exists to prevent.
55
+ if (!SESSION_REF.test(ref))
56
+ return { kind: 'error', message: unissuedRefRefusal(ref) };
53
57
  return { kind: 'ref', ref };
58
+ }
54
59
  const target = args['target'];
55
60
  if (target === undefined) {
56
61
  if (isGlobalPressCall(args))
@@ -94,7 +99,7 @@ appearanceMs) {
94
99
  // One match, or an ambiguity: both are answered by the existing resolver, which already ranks
95
100
  // candidates inside its refusal so the next turn needs no snapshot.
96
101
  if ('wait' !== decision.do)
97
- return resolveTargetRef(found);
102
+ return resolveTargetRef(found, asRecord(out.result)['hint']);
98
103
  await new Promise((resolve) => setTimeout(resolve, decision.waitMs));
99
104
  }
100
105
  }
@@ -59,6 +59,14 @@ export interface ArrivalScope {
59
59
  * "the app redirected the newly arrived document somewhere else."
60
60
  */
61
61
  navigatedFrom: string;
62
+ /**
63
+ * The DOCUMENT the session was on when the navigation was dispatched.
64
+ *
65
+ * A navigation to the page already shown replaces the document without changing the URL, so the
66
+ * old document is still the connected one until the replacement reports (#1320). Only a different
67
+ * document identity proves the replacement; `undefined` on both sides proves nothing and waits.
68
+ */
69
+ navigatedFromDocumentId?: string;
62
70
  /** Sessions already on the target before dispatch cannot prove this navigation arrived. */
63
71
  priorIds: ReadonlySet<string>;
64
72
  }
@@ -42,6 +42,21 @@ function samePage(a, b) {
42
42
  return false;
43
43
  }
44
44
  }
45
+ /**
46
+ * Same origin and path, different fragment: the browser changes the URL WITHOUT replacing the
47
+ * document. There is no replacement to wait for on this path, so it must not be treated as a
48
+ * same-page navigation (#1320).
49
+ */
50
+ function sameDocumentFragmentChange(a, b) {
51
+ if (!samePage(a, b))
52
+ return false;
53
+ try {
54
+ return new URL(a).hash !== new URL(b).hash;
55
+ }
56
+ catch {
57
+ return false;
58
+ }
59
+ }
45
60
  /**
46
61
  * The navigation target as an absolute URL, resolved against the tab being navigated — the same
47
62
  * resolution the browser applies. An agent passes a path (`/orders?id=4`) as often as a full URL,
@@ -70,13 +85,39 @@ export function idsAtTarget(sessions, target) {
70
85
  }
71
86
  return ids;
72
87
  }
88
+ /**
89
+ * Whether `current` is a different document from the one the navigation was dispatched on.
90
+ *
91
+ * A new Session object under the same id is not enough: the SDK also reopens its socket in place,
92
+ * and that replaces the Session while the page stays exactly where it was. What a real unload
93
+ * changes is the document id — the one sampled before dispatch (`navigatedFromDocumentId`) against
94
+ * the one the live session is reporting (`currentDocumentId`). Either side not having reported one
95
+ * yet is "cannot tell", which is never reported as a new document.
96
+ */
97
+ function documentUnloaded(scope, current) {
98
+ const before = scope.navigatedFromDocumentId;
99
+ const after = current.currentDocumentId;
100
+ return before !== undefined && after !== undefined && before !== after;
101
+ }
73
102
  function findArrival(sessions, target, scope, currentSession) {
74
103
  let arrived = null;
75
- for (const s of sessions.all()) {
104
+ // One snapshot for the whole look, so "is the driven session still connected?" and "has a
105
+ // replacement reported?" are answered from the same moment.
106
+ const snapshot = sessions.all();
107
+ const drivenPresent = snapshot.some((s) => s.id === currentSession.id);
108
+ // Navigating to the page already shown replaces its document without moving the URL, so the
109
+ // OLD document is still the connected one at the first looks; its presence there is not
110
+ // arrival until the replacement reports a different document identity (#1320). A fragment-only
111
+ // change keeps the document, so it is an arrival as soon as the URL matches.
112
+ const replacesDocument = samePage(scope.navigatedFrom, target) &&
113
+ !sameDocumentFragmentChange(scope.navigatedFrom, target);
114
+ for (const s of snapshot) {
76
115
  // The currently tracked document gets priority because it is the strongest
77
116
  // evidence of where this navigation went.
78
117
  if (s.id === currentSession.id) {
79
118
  if (samePage(s.url, target)) {
119
+ if (replacesDocument && s.currentDocumentId === scope.navigatedFromDocumentId)
120
+ continue;
80
121
  return { sessionId: s.id };
81
122
  }
82
123
  // Intermediate routes are not necessarily redirects. Keep polling so
@@ -87,6 +128,12 @@ function findArrival(sessions, target, scope, currentSession) {
87
128
  // navigation arrived.
88
129
  if (scope.priorIds.has(s.id))
89
130
  continue;
131
+ // While the replaced document is still connected, a DIFFERENT session at the target is an
132
+ // unrelated arrival (a second tab, a neighbour app): the replacement this navigation waits
133
+ // for has not reported yet, and letting the newcomer stand in would confirm too early and
134
+ // name the wrong session (#1320).
135
+ if (replacesDocument && drivenPresent)
136
+ continue;
90
137
  if (samePage(s.url, target)) {
91
138
  if (null === arrived)
92
139
  arrived = { sessionId: s.id };
@@ -122,7 +169,11 @@ export async function awaitArrival(sessions, target, scope, timeoutMs = ARRIVAL_
122
169
  // landed when the target was never observed.
123
170
  const current = sessions.get(scope.navigatedSession.id);
124
171
  if (current !== undefined) {
125
- if (!samePage(current.url, scope.navigatedFrom) && !samePage(current.url, target)) {
172
+ // Sitting on `navigatedFrom` means two different things: a tab that has not moved, or a page
173
+ // that unloaded and came back here (an auth guard bouncing `/checkout` to `/login` while the
174
+ // tab started on `/login`). Only a document that is provably new tells them apart.
175
+ if (!samePage(current.url, target) &&
176
+ (!samePage(current.url, scope.navigatedFrom) || documentUnloaded(scope, current))) {
126
177
  return {
127
178
  sessionId: current.id,
128
179
  landedOn: current.url,
@@ -131,6 +182,9 @@ export async function awaitArrival(sessions, target, scope, timeoutMs = ARRIVAL_
131
182
  return null;
132
183
  }
133
184
  const successor = await awaitDocumentSuccessor(sessions, scope.navigatedSession, 0, clock);
185
+ // A successor under another id is only "unique at the origin", which a tab opened by someone else
186
+ // after the driven one went away satisfies equally. On the starting page that guess cannot be told
187
+ // from a redirect, so it is not reported as one.
134
188
  if (successor !== null &&
135
189
  !samePage(successor.url, target) &&
136
190
  !samePage(successor.url, scope.navigatedFrom)) {
@@ -29,4 +29,4 @@ export type TargetResolution = {
29
29
  * When several remain, they are ranked (in-viewport, then role) inside the refusal only — so the
30
30
  * agent can pass the top ref on the next turn without a snapshot. Ranking is never acted on here.
31
31
  */
32
- export declare function resolveTargetRef(candidates: readonly unknown[]): TargetResolution;
32
+ export declare function resolveTargetRef(candidates: readonly unknown[], hint?: unknown): TargetResolution;
@@ -61,6 +61,21 @@ function formatCandidate(c, anyInViewport) {
61
61
  const head = name.length > 0 ? `${ref} (${role} "${name}"` : `${ref} (${role}`;
62
62
  return `${head}; ${where})`;
63
63
  }
64
+ /**
65
+ * The names that role really has, when an exact role + name query just missed (the browser's
66
+ * `nameNearMiss` hint). Names are matched exactly, so one that carries a changing part — "billing
67
+ * Last run 1 minute ago" — is unreachable by name; `testid` or a `text` match is the durable way.
68
+ */
69
+ function nearNamesClause(hint) {
70
+ const near = asRecord(hint)['nameNearMiss'];
71
+ const names = Array.isArray(near) ? near.filter((n) => 'string' === typeof n) : [];
72
+ if (0 === names.length) {
73
+ return 'widen the query, or take a reticle_snapshot to see what is actually on the page.';
74
+ }
75
+ return (`names are matched exactly, and that role is called ${names.map((n) => `"${n}"`).join(', ')}. ` +
76
+ 'Use that name, or — when the name carries a part that changes, like a time — target it by ' +
77
+ '`testid` or by `text` (a contained match).');
78
+ }
64
79
  /**
65
80
  * Turn a target QUERY into the single ref an action can be performed on.
66
81
  *
@@ -81,15 +96,15 @@ function formatCandidate(c, anyInViewport) {
81
96
  * When several remain, they are ranked (in-viewport, then role) inside the refusal only — so the
82
97
  * agent can pass the top ref on the next turn without a snapshot. Ranking is never acted on here.
83
98
  */
84
- export function resolveTargetRef(candidates) {
99
+ export function resolveTargetRef(candidates, hint) {
85
100
  const all = candidates.map((c) => asRecord(c));
86
101
  const visible = all.filter((c) => c.visible !== false);
87
102
  const usable = visible.length > 0 ? visible : all;
88
103
  if (0 === usable.length) {
89
104
  return {
90
105
  kind: 'error',
91
- message: 'target matched no element. Nothing was acted on and no verdict is possible — widen the ' +
92
- 'query, or take a reticle_snapshot to see what is actually on the page.',
106
+ message: 'target matched no element. Nothing was acted on and no verdict is possible — ' +
107
+ nearNamesClause(hint),
93
108
  };
94
109
  }
95
110
  if (usable.length > 1) {
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The opt-in screen/request check, wired: after an act_and_wait, compare what the window's write
3
+ * requests carried with the values the page's form controls show (engine: screen-request.ts).
4
+ *
5
+ * OPT-IN (`RETICLE_SCREEN_REQUEST_CHECK=1`) and ADVISORY. It ships behind the flag until its
6
+ * false-alarm rate is measured at zero on the e2e battery, the benchmark and the persona fixtures;
7
+ * until then it must cost nothing for anyone who did not ask. It runs AFTER the verdict is decided
8
+ * and is appended to `contradictions` as an advisory kind, so it can never move a verdict.
9
+ */
10
+ import { type Contradiction, type ReticleEvent } from '@reticlehq/core';
11
+ import type { Session } from '../../../portal/session/session.js';
12
+ export declare const SCREEN_REQUEST_CHECK_ENV = "RETICLE_SCREEN_REQUEST_CHECK";
13
+ export interface SentBody {
14
+ method: string;
15
+ url: string;
16
+ /** The request body as sent (JSON text). */
17
+ body: string;
18
+ }
19
+ export interface ShownControl {
20
+ /** `name` or `id` attribute — the only link from a control to a field. */
21
+ field: string;
22
+ /** The control's current value (a select's selected option value, an input's text). */
23
+ value: string;
24
+ /** What the user sees, when it differs from the value (a select's option label). */
25
+ label?: string | undefined;
26
+ ref?: string | undefined;
27
+ }
28
+ export declare function screenRequestMismatches(sent: readonly SentBody[], controls: readonly ShownControl[]): Contradiction[];
29
+ /** Advisory findings for this window, or none when the check is off or nothing was written. */
30
+ export declare function screenRequestFindings(session: Session, windowEvents: readonly ReticleEvent[]): Promise<Contradiction[]>;
31
+ /** The `contradictions` field: the verdict's own, then any advisory ones; omitted when both are empty. */
32
+ export declare function withAdvisories(decided: readonly Contradiction[], advisory: readonly Contradiction[]): {
33
+ contradictions?: Contradiction[];
34
+ };
@@ -0,0 +1,113 @@
1
+ /**
2
+ * The opt-in screen/request check, wired: after an act_and_wait, compare what the window's write
3
+ * requests carried with the values the page's form controls show (engine: screen-request.ts).
4
+ *
5
+ * OPT-IN (`RETICLE_SCREEN_REQUEST_CHECK=1`) and ADVISORY. It ships behind the flag until its
6
+ * false-alarm rate is measured at zero on the e2e battery, the benchmark and the persona fixtures;
7
+ * until then it must cost nothing for anyone who did not ask. It runs AFTER the verdict is decided
8
+ * and is appended to `contradictions` as an advisory kind, so it can never move a verdict.
9
+ */
10
+ import { ContradictionKind, EventType, REDACTED_VALUE, ReticleCommand, } from '@reticlehq/core';
11
+ export const SCREEN_REQUEST_CHECK_ENV = 'RETICLE_SCREEN_REQUEST_CHECK';
12
+ const READ_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
13
+ /** The form controls whose value a request can carry. */
14
+ const CONTROL_ROLES = ['combobox', 'listbox', 'textbox', 'spinbutton'];
15
+ function primitiveFields(body) {
16
+ const out = new Map();
17
+ try {
18
+ const parsed = JSON.parse(body);
19
+ if ('object' !== typeof parsed || null === parsed || Array.isArray(parsed))
20
+ return out;
21
+ for (const [key, value] of Object.entries(parsed)) {
22
+ if ('string' === typeof value || 'number' === typeof value || 'boolean' === typeof value) {
23
+ out.set(key.toLowerCase(), String(value));
24
+ }
25
+ }
26
+ }
27
+ catch {
28
+ // Not JSON: nothing comparable, so nothing reported.
29
+ }
30
+ return out;
31
+ }
32
+ function pathOf(url) {
33
+ try {
34
+ return new URL(url, 'http://local.invalid').pathname;
35
+ }
36
+ catch {
37
+ return url;
38
+ }
39
+ }
40
+ export function screenRequestMismatches(sent, controls) {
41
+ const out = [];
42
+ for (const request of sent) {
43
+ const fields = primitiveFields(request.body);
44
+ if (0 === fields.size)
45
+ continue;
46
+ for (const control of controls) {
47
+ const key = control.field.toLowerCase();
48
+ const carried = fields.get(key);
49
+ if (carried === undefined || carried === control.value)
50
+ continue;
51
+ const shown = control.label !== undefined && control.label !== control.value
52
+ ? `"${control.label}" (value "${control.value}")`
53
+ : `"${control.value}"`;
54
+ out.push({
55
+ kind: ContradictionKind.SCREEN_REQUEST_MISMATCH,
56
+ claim: `the screen's "${control.field}" control shows ${shown}`,
57
+ counter: `${request.method.toUpperCase()} ${pathOf(request.url)} sent ${control.field}=${JSON.stringify(carried)}`,
58
+ detail: `${control.ref === undefined ? '' : `${control.ref} `}${control.field}: shown ${shown}, sent ${JSON.stringify(carried)}`,
59
+ });
60
+ }
61
+ }
62
+ return out;
63
+ }
64
+ function sentBodies(events) {
65
+ return events.flatMap((event) => {
66
+ if (EventType.NET_REQUEST !== event.type)
67
+ return [];
68
+ const raw = event.data['method'];
69
+ const method = ('string' === typeof raw ? raw : 'GET').toUpperCase();
70
+ const body = event.data['requestBody'];
71
+ const url = event.data['url'];
72
+ if (READ_METHODS.has(method) || 'string' !== typeof body || 'string' !== typeof url)
73
+ return [];
74
+ return [{ method, url, body }];
75
+ });
76
+ }
77
+ async function shownControls(session) {
78
+ const out = [];
79
+ for (const role of CONTROL_ROLES) {
80
+ const res = await session.command(ReticleCommand.MATCH, {
81
+ query: { role, attrs: ['name', 'id'] },
82
+ });
83
+ if (!res.ok)
84
+ continue;
85
+ for (const el of res.result?.elements ?? []) {
86
+ const field = el.attrs?.['name'] ?? el.attrs?.['id'];
87
+ // No value read, or a redacted one: nothing to compare, so nothing is guessed.
88
+ if (field === undefined || el.value === undefined || REDACTED_VALUE === el.value)
89
+ continue;
90
+ out.push({ field, value: el.value, ref: el.ref });
91
+ }
92
+ }
93
+ return out;
94
+ }
95
+ /** Advisory findings for this window, or none when the check is off or nothing was written. */
96
+ export async function screenRequestFindings(session, windowEvents) {
97
+ if ('1' !== process.env[SCREEN_REQUEST_CHECK_ENV])
98
+ return [];
99
+ const sent = sentBodies(windowEvents);
100
+ if (0 === sent.length)
101
+ return [];
102
+ try {
103
+ return screenRequestMismatches(sent, await shownControls(session));
104
+ }
105
+ catch {
106
+ return [];
107
+ }
108
+ }
109
+ /** The `contradictions` field: the verdict's own, then any advisory ones; omitted when both are empty. */
110
+ export function withAdvisories(decided, advisory) {
111
+ const all = [...decided, ...advisory];
112
+ return 0 === all.length ? {} : { contradictions: all };
113
+ }
@@ -40,6 +40,12 @@ export interface StepExpectation {
40
40
  * filter act_and_wait applies. A held step with one is a UI that advanced over a failed write.
41
41
  */
42
42
  contradicted?: readonly string[];
43
+ /**
44
+ * Why this step could not be judged at all: its target was missing (nothing was acted on), the
45
+ * page left the app and the observation went with it, or the predicate could not be read. Such a
46
+ * step is undecided, never a miss — `unknown`, as act_and_wait says.
47
+ */
48
+ undecided?: string;
43
49
  }
44
50
  export interface SequenceGrade {
45
51
  verified: Verified;
@@ -80,5 +86,7 @@ export declare function gradeSequence(steps: readonly StepExpectation[], plan?:
80
86
  * two-of-twelve plan as a regression flow is a reasonable thing to do and a bad thing to do without
81
87
  * knowing it.
82
88
  */
89
+ /** The stopped recording a proved journey is held under, so the `keep` offer can be taken. */
90
+ export declare const JOURNEY_RECORDING = "last-journey";
83
91
  export declare function offerToKeep(grade: SequenceGrade): string | undefined;
84
92
  export {};
@@ -29,7 +29,7 @@ export function gradeSequence(steps, plan = { planned: steps.length, dispatched:
29
29
  const declared = declaring.length;
30
30
  // `held: false` on an undeclared step means it could not be performed at all — the journey broke
31
31
  // there whether or not anything was declared about it.
32
- const missed = steps.find((step) => (step.declared ? true !== step.held : false === step.held));
32
+ const missed = steps.find((step) => step.undecided === undefined && (step.declared ? true !== step.held : false === step.held));
33
33
  // A miss decides the grade before coverage does. How much of the plan declared nothing is
34
34
  // context on a red, never a softening of it.
35
35
  if (missed !== undefined) {
@@ -52,6 +52,15 @@ export function gradeSequence(steps, plan = { planned: steps.length, dispatched:
52
52
  because: `step ${String(contradictedAt + 1)}: channels disagree about this action (${kinds}) even though it went on`,
53
53
  };
54
54
  }
55
+ // Nothing failed that was seen: a step nobody could judge leaves the plan undecided, saying why.
56
+ const unjudged = steps.find((step) => step.undecided !== undefined);
57
+ if (unjudged !== undefined)
58
+ return {
59
+ verified: Verified.UNKNOWN,
60
+ declared,
61
+ total,
62
+ because: `a step could not be judged — ${unjudged.undecided ?? ''}`,
63
+ };
55
64
  /*
56
65
  * `unknown` rather than `no-fault`, and the distinction is load-bearing.
57
66
  *
@@ -125,11 +134,13 @@ export function gradeSequence(steps, plan = { planned: steps.length, dispatched:
125
134
  * two-of-twelve plan as a regression flow is a reasonable thing to do and a bad thing to do without
126
135
  * knowing it.
127
136
  */
137
+ /** The stopped recording a proved journey is held under, so the `keep` offer can be taken. */
138
+ export const JOURNEY_RECORDING = 'last-journey';
128
139
  export function offerToKeep(grade) {
129
140
  if (grade.verified !== Verified.YES || 0 === grade.declared)
130
141
  return undefined;
131
142
  return (`this plan proved something (${String(grade.declared)} of ${String(grade.total)} steps declared a ` +
132
143
  'consequence and every one held) — keep it as a regression flow with ' +
133
- 'reticle_flow_save { saveAs: "<name>" }, and the steps that declared nothing will replay ' +
144
+ `reticle_flow_save { flowName: "${JOURNEY_RECORDING}", saveAs: "<name>" }, and the steps that declared nothing will replay ` +
134
145
  'without proving anything, exactly as they did here');
135
146
  }