@reticlehq/server 3.8.2 → 3.10.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 (477) hide show
  1. package/LICENSE +201 -104
  2. package/NOTICE +5 -0
  3. package/README.md +1 -1
  4. package/SKILL.md +13 -12
  5. package/bin/launch.js +13 -0
  6. package/bin/package.json +3 -0
  7. package/bin/reticle.js +66 -8
  8. package/dist/chromium-launch-options.d.ts +25 -0
  9. package/dist/chromium-launch-options.js +21 -1
  10. package/dist/command/cli/adhoc-suite.js +2 -0
  11. package/dist/command/cli/adhoc-verdict.d.ts +2 -43
  12. package/dist/command/cli/adhoc-verdict.js +50 -160
  13. package/dist/command/cli/answers/gate-exit.d.ts +6 -2
  14. package/dist/command/cli/answers/gate-exit.js +12 -2
  15. package/dist/command/cli/answers/mcp-connection-hint.d.ts +2 -0
  16. package/dist/command/cli/answers/mcp-connection-hint.js +6 -0
  17. package/dist/command/cli/ci-hint.d.ts +44 -0
  18. package/dist/command/cli/ci-hint.js +72 -0
  19. package/dist/command/cli/cli-doctor.d.ts +6 -1
  20. package/dist/command/cli/cli-doctor.js +46 -5
  21. package/dist/command/cli/cli-flow-commands.d.ts +7 -1
  22. package/dist/command/cli/cli-flow-commands.js +39 -24
  23. package/dist/command/cli/cli-kill.d.ts +21 -0
  24. package/dist/command/cli/cli-kill.js +47 -4
  25. package/dist/command/cli/cli-parse-compare.d.ts +22 -0
  26. package/dist/command/cli/cli-parse-compare.js +75 -0
  27. package/dist/command/cli/cli-parse-grade.d.ts +36 -0
  28. package/dist/command/cli/cli-parse-grade.js +75 -0
  29. package/dist/command/cli/cli-parse-grammar.d.ts +2 -0
  30. package/dist/command/cli/cli-parse-grammar.js +18 -20
  31. package/dist/command/cli/cli-parse-verify.d.ts +10 -0
  32. package/dist/command/cli/cli-parse-verify.js +63 -14
  33. package/dist/command/cli/cli-parse.d.ts +22 -17
  34. package/dist/command/cli/cli-parse.js +54 -32
  35. package/dist/command/cli/cli-update-commands.d.ts +1 -1
  36. package/dist/command/cli/cli-update-commands.js +29 -20
  37. package/dist/command/cli/cli-usage.js +61 -31
  38. package/dist/command/cli/cli-verify.d.ts +17 -3
  39. package/dist/command/cli/cli-verify.js +59 -21
  40. package/dist/command/cli/cloud-cli.js +2 -119
  41. package/dist/command/cli/daemon-link/daemon-client.d.ts +45 -0
  42. package/dist/command/cli/daemon-link/daemon-client.js +205 -0
  43. package/dist/command/cli/doctor/browser/chromium-hint.d.ts +6 -1
  44. package/dist/command/cli/doctor/browser/chromium-hint.js +11 -5
  45. package/dist/command/cli/doctor/doctor-daemon-line.js +6 -3
  46. package/dist/command/cli/doctor/doctor-fix.d.ts +44 -0
  47. package/dist/command/cli/doctor/doctor-fix.js +89 -0
  48. package/dist/command/cli/doctor/doctor-launcher-line.d.ts +23 -0
  49. package/dist/command/cli/doctor/doctor-launcher-line.js +60 -0
  50. package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
  51. package/dist/command/cli/doctor/doctor-rows.js +4 -0
  52. package/dist/command/cli/doctor-repairs.d.ts +64 -0
  53. package/dist/command/cli/doctor-repairs.js +214 -0
  54. package/dist/command/cli/drive/drive-command.js +3 -7
  55. package/dist/command/cli/ensure-daemon.d.ts +26 -0
  56. package/dist/command/cli/ensure-daemon.js +57 -0
  57. package/dist/command/cli/finished-run/grade-command.d.ts +23 -0
  58. package/dist/command/cli/finished-run/grade-command.js +180 -0
  59. package/dist/command/cli/first-use-checks.d.ts +41 -0
  60. package/dist/command/cli/first-use-checks.js +127 -0
  61. package/dist/command/cli/first-verdict-node.d.ts +3 -0
  62. package/dist/command/cli/first-verdict-node.js +189 -0
  63. package/dist/command/cli/first-verdict.d.ts +126 -0
  64. package/dist/command/cli/first-verdict.js +267 -0
  65. package/dist/command/cli/launch/sdk-version-match.d.ts +3 -2
  66. package/dist/command/cli/launch/sdk-version-match.js +3 -2
  67. package/dist/command/cli/lifecycle/daemon-lifecycle.d.ts +1 -1
  68. package/dist/command/cli/lifecycle/daemon-lifecycle.js +7 -6
  69. package/dist/command/cli/mcp-command.js +13 -4
  70. package/dist/command/cli/ports/port-holder.d.ts +11 -0
  71. package/dist/command/cli/ports/port-holder.js +36 -4
  72. package/dist/command/cli/setup-mcp-cli.d.ts +27 -1
  73. package/dist/command/cli/setup-mcp-cli.js +98 -23
  74. package/dist/command/cli/status/status-lines.d.ts +2 -0
  75. package/dist/command/cli/status/status-lines.js +72 -17
  76. package/dist/command/cli/status-fields.d.ts +5 -1
  77. package/dist/command/cli/status-fields.js +24 -6
  78. package/dist/command/cli/try-command.d.ts +7 -0
  79. package/dist/command/cli/try-command.js +11 -3
  80. package/dist/command/cli/two-builds/compare-command.d.ts +48 -0
  81. package/dist/command/cli/two-builds/compare-command.js +314 -0
  82. package/dist/command/cli/verify-against.d.ts +61 -0
  83. package/dist/command/cli/verify-against.js +187 -0
  84. package/dist/command/cli/verify-no-session.d.ts +2 -0
  85. package/dist/command/cli/verify-no-session.js +13 -0
  86. package/dist/command/cli/verify-results.d.ts +35 -2
  87. package/dist/command/cli/verify-results.js +76 -10
  88. package/dist/command/cli.js +112 -70
  89. package/dist/command/daemon/binding/daemon-status-probe.d.ts +3 -1
  90. package/dist/command/daemon/binding/daemon-status-probe.js +4 -2
  91. package/dist/command/daemon/daemon-argv.d.ts +9 -0
  92. package/dist/command/daemon/daemon-argv.js +11 -0
  93. package/dist/command/daemon/daemon-resolve.d.ts +8 -1
  94. package/dist/command/daemon/daemon-resolve.js +27 -1
  95. package/dist/command/daemon/daemon.d.ts +22 -4
  96. package/dist/command/daemon/daemon.js +52 -10
  97. package/dist/command/daemon/lifetime/daemon-exit.d.ts +24 -0
  98. package/dist/command/daemon/lifetime/daemon-exit.js +39 -0
  99. package/dist/command/daemon/lifetime/death-cause.d.ts +15 -0
  100. package/dist/command/daemon/lifetime/death-cause.js +149 -0
  101. package/dist/command/daemon/lifetime/heartbeat.d.ts +7 -15
  102. package/dist/command/daemon/lifetime/heartbeat.js +11 -15
  103. package/dist/command/daemon/lifetime/startup-failure.d.ts +29 -0
  104. package/dist/command/daemon/lifetime/startup-failure.js +62 -0
  105. package/dist/command/daemon/port-state.d.ts +14 -0
  106. package/dist/command/daemon/port-state.js +31 -0
  107. package/dist/command/setup/agent-configs.d.ts +2 -0
  108. package/dist/command/setup/agent-configs.js +42 -15
  109. package/dist/command/setup/agent-next-steps.d.ts +77 -0
  110. package/dist/command/setup/agent-next-steps.js +284 -0
  111. package/dist/command/setup/agent-writer.js +11 -6
  112. package/dist/command/setup/bringup/dev-server-files.d.ts +9 -0
  113. package/dist/command/setup/bringup/dev-server-files.js +17 -0
  114. package/dist/command/setup/bringup/static-page-server.d.ts +14 -2
  115. package/dist/command/setup/bringup/static-page-server.js +43 -9
  116. package/dist/command/setup/init/init-host.js +2 -0
  117. package/dist/command/setup/init/init-runtime.d.ts +6 -1
  118. package/dist/command/setup/init/init-runtime.js +63 -21
  119. package/dist/command/setup/mcp-launcher.d.ts +3 -0
  120. package/dist/command/setup/mcp-launcher.js +11 -0
  121. package/dist/command/setup/node-effects.d.ts +3 -2
  122. package/dist/command/setup/node-effects.js +9 -3
  123. package/dist/command/setup/remaining-steps.d.ts +8 -0
  124. package/dist/command/setup/remaining-steps.js +10 -0
  125. package/dist/command/setup/run-setup.d.ts +2 -0
  126. package/dist/command/setup/run-setup.js +9 -1
  127. package/dist/command/setup/setup-command.js +36 -15
  128. package/dist/command/setup/setup-mcp.d.ts +8 -0
  129. package/dist/command/setup/setup-mcp.js +47 -20
  130. package/dist/command/setup/start-dev-server.d.ts +8 -0
  131. package/dist/command/setup/start-dev-server.js +43 -0
  132. package/dist/command/update/updater.js +6 -0
  133. package/dist/command/version/identity/server-version.d.ts +2 -0
  134. package/dist/command/version/identity/server-version.js +2 -0
  135. package/dist/command/version/version-skew.d.ts +7 -0
  136. package/dist/command/version/version-skew.js +14 -3
  137. package/dist/features/compare/action-plan.d.ts +260 -0
  138. package/dist/features/compare/action-plan.js +543 -0
  139. package/dist/features/compare/behaviour-compare.d.ts +24 -0
  140. package/dist/features/compare/behaviour-compare.js +85 -0
  141. package/dist/features/compare/behaviour-diff.d.ts +97 -0
  142. package/dist/features/compare/behaviour-diff.js +202 -0
  143. package/dist/features/compare/behaviour-report.d.ts +40 -0
  144. package/dist/features/compare/behaviour-report.js +128 -0
  145. package/dist/features/compare/build-readings.d.ts +106 -0
  146. package/dist/features/compare/build-readings.js +250 -0
  147. package/dist/features/compare/compare-diff.d.ts +62 -0
  148. package/dist/features/compare/compare-diff.js +177 -0
  149. package/dist/features/compare/compare-report-html.d.ts +6 -0
  150. package/dist/features/compare/compare-report-html.js +102 -0
  151. package/dist/features/compare/compare-report.d.ts +15 -0
  152. package/dist/features/compare/compare-report.js +73 -0
  153. package/dist/features/compare/compare-run.d.ts +60 -0
  154. package/dist/features/compare/compare-run.js +123 -0
  155. package/dist/features/compare/outside/effect-lines.d.ts +26 -0
  156. package/dist/features/compare/outside/effect-lines.js +103 -0
  157. package/dist/features/compare/outside/state-sources.d.ts +76 -0
  158. package/dist/features/compare/outside/state-sources.js +164 -0
  159. package/dist/features/compare/outside/value-dictionary.d.ts +51 -0
  160. package/dist/features/compare/outside/value-dictionary.js +227 -0
  161. package/dist/features/compare/visible-content.d.ts +20 -0
  162. package/dist/features/compare/visible-content.js +125 -0
  163. package/dist/features/crawl/crawl-empty.js +2 -1
  164. package/dist/features/crawl/crawl-exhaustive.d.ts +55 -0
  165. package/dist/features/crawl/crawl-exhaustive.js +138 -0
  166. package/dist/features/crawl/crawl-tools.d.ts +9 -2
  167. package/dist/features/crawl/crawl-tools.js +28 -12
  168. package/dist/features/crawl/crawl.d.ts +8 -9
  169. package/dist/features/crawl/crawl.js +61 -65
  170. package/dist/features/exhaust/app-coverage.d.ts +5 -1
  171. package/dist/features/exhaust/app-coverage.js +3 -1
  172. package/dist/features/exhaust/code-coverage.js +8 -4
  173. package/dist/features/exhaust/edge-cases.d.ts +133 -0
  174. package/dist/features/exhaust/edge-cases.js +310 -0
  175. package/dist/features/exhaust/edges/edge-drive.d.ts +42 -0
  176. package/dist/features/exhaust/edges/edge-drive.js +364 -0
  177. package/dist/features/exhaust/edges/edge-run.d.ts +59 -0
  178. package/dist/features/exhaust/edges/edge-run.js +169 -0
  179. package/dist/features/exhaust/explorer.d.ts +87 -14
  180. package/dist/features/exhaust/explorer.js +159 -25
  181. package/dist/features/exhaust/failure-branches.d.ts +5 -0
  182. package/dist/features/exhaust/failure-branches.js +29 -11
  183. package/dist/features/exhaust/invariants.d.ts +112 -0
  184. package/dist/features/exhaust/invariants.js +188 -0
  185. package/dist/features/exhaust/ledger.d.ts +68 -0
  186. package/dist/features/exhaust/ledger.js +121 -13
  187. package/dist/features/exhaust/session-fold.d.ts +10 -0
  188. package/dist/features/exhaust/session-fold.js +46 -3
  189. package/dist/features/exhaust/session-port.d.ts +3 -1
  190. package/dist/features/exhaust/session-port.js +97 -28
  191. package/dist/features/grade/grade-answer.d.ts +99 -0
  192. package/dist/features/grade/grade-answer.js +112 -0
  193. package/dist/features/grade/grade-noise.d.ts +27 -0
  194. package/dist/features/grade/grade-noise.js +55 -0
  195. package/dist/features/grade/grade-renumber.d.ts +12 -0
  196. package/dist/features/grade/grade-renumber.js +86 -0
  197. package/dist/features/grade/grade-state.d.ts +50 -0
  198. package/dist/features/grade/grade-state.js +93 -0
  199. package/dist/features/grade/grade-suggest.d.ts +33 -0
  200. package/dist/features/grade/grade-suggest.js +98 -0
  201. package/dist/features/license/license.d.ts +11 -71
  202. package/dist/features/license/license.js +43 -136
  203. package/dist/features/visual/desktop-capture.d.ts +33 -0
  204. package/dist/features/visual/desktop-capture.js +94 -0
  205. package/dist/features/visual/step-shots.js +139 -35
  206. package/dist/features/visual/visual-tools.d.ts +0 -18
  207. package/dist/features/visual/visual-tools.js +67 -99
  208. package/dist/import-graph.js +5 -6
  209. package/dist/index.d.ts +3 -1
  210. package/dist/index.js +19 -7
  211. package/dist/judgement/capsule/causal-summary.js +9 -2
  212. package/dist/judgement/runs/artifact/replay-mapping.d.ts +13 -1
  213. package/dist/judgement/runs/artifact/replay-mapping.js +1 -1
  214. package/dist/judgement/runs/reticle-runner.js +16 -2
  215. package/dist/judgement/runs/run-ledger.d.ts +7 -5
  216. package/dist/judgement/runs/run-ledger.js +98 -69
  217. package/dist/judgement/runs/runner-port.d.ts +2 -0
  218. package/dist/judgement/runs/runner-port.js +23 -5
  219. package/dist/judgement/runs/verification-sync.d.ts +6 -3
  220. package/dist/judgement/runs/verification-sync.js +21 -10
  221. package/dist/language/flows/affected-tools.d.ts +1 -1
  222. package/dist/language/flows/affected-tools.js +49 -30
  223. package/dist/language/flows/change/git-changed.d.ts +2 -1
  224. package/dist/language/flows/change/git-changed.js +19 -2
  225. package/dist/language/flows/fields/flow-secret-field.d.ts +1 -13
  226. package/dist/language/flows/fields/flow-secret-field.js +77 -21
  227. package/dist/language/flows/flow-anchor.d.ts +60 -2
  228. package/dist/language/flows/flow-anchor.js +125 -20
  229. package/dist/language/flows/flow-classify.d.ts +20 -0
  230. package/dist/language/flows/flow-classify.js +90 -12
  231. package/dist/language/flows/flow-cross-step.d.ts +7 -1
  232. package/dist/language/flows/flow-cross-step.js +25 -1
  233. package/dist/language/flows/flow-journey.d.ts +38 -4
  234. package/dist/language/flows/flow-journey.js +138 -8
  235. package/dist/language/flows/flow-replay-run.d.ts +0 -16
  236. package/dist/language/flows/flow-replay-run.js +76 -14
  237. package/dist/language/flows/flow-replay-types.d.ts +4 -2
  238. package/dist/language/flows/flow-replay.d.ts +19 -1
  239. package/dist/language/flows/flow-replay.js +169 -52
  240. package/dist/language/flows/flow-replayable.js +7 -1
  241. package/dist/language/flows/flow-start-path.d.ts +34 -5
  242. package/dist/language/flows/flow-start-path.js +202 -15
  243. package/dist/language/flows/flow-step-runners.d.ts +14 -13
  244. package/dist/language/flows/flow-step-runners.js +184 -109
  245. package/dist/language/flows/flow-store-for-session.d.ts +26 -25
  246. package/dist/language/flows/flow-store-for-session.js +51 -5
  247. package/dist/language/flows/flow-tools.js +46 -33
  248. package/dist/language/flows/flows.js +176 -76
  249. package/dist/language/flows/recording/tape/recordings.d.ts +21 -16
  250. package/dist/language/flows/recording/tape/recordings.js +112 -49
  251. package/dist/language/flows/replay.d.ts +36 -12
  252. package/dist/language/flows/replay.js +193 -50
  253. package/dist/language/flows/steps/page-steps.d.ts +68 -0
  254. package/dist/language/flows/steps/page-steps.js +198 -0
  255. package/dist/language/flows/suite/sequential-run.d.ts +68 -0
  256. package/dist/language/flows/suite/sequential-run.js +96 -0
  257. package/dist/language/flows/verify-change-tools.js +26 -15
  258. package/dist/launch-chromium.d.ts +1 -0
  259. package/dist/launch-chromium.js +49 -12
  260. package/dist/memory/cloud/background-sync.d.ts +13 -0
  261. package/dist/memory/cloud/background-sync.js +24 -3
  262. package/dist/memory/cloud/sync-daemon.js +26 -27
  263. package/dist/memory/cloud/sync-screenshots.js +6 -1
  264. package/dist/memory/journal/attach-journal.js +2 -1
  265. package/dist/memory/journal/drive-flow.d.ts +7 -0
  266. package/dist/memory/journal/drive-flow.js +44 -13
  267. package/dist/memory/journal/journal-recorder.d.ts +4 -2
  268. package/dist/memory/journal/session-journal.d.ts +7 -0
  269. package/dist/memory/journal/session-journal.js +58 -10
  270. package/dist/memory/project/root-claims.d.ts +9 -0
  271. package/dist/memory/project/root-claims.js +9 -4
  272. package/dist/portal/bridge/bridge.d.ts +13 -4
  273. package/dist/portal/bridge/bridge.js +10 -9
  274. package/dist/portal/input/download-capture.d.ts +7 -0
  275. package/dist/portal/input/download-capture.js +92 -0
  276. package/dist/portal/input/network-detail.d.ts +6 -0
  277. package/dist/portal/input/network-detail.js +12 -1
  278. package/dist/portal/input/network-mock-tools.js +49 -13
  279. package/dist/portal/input/network-mock.d.ts +8 -0
  280. package/dist/portal/input/network-mock.js +30 -10
  281. package/dist/portal/input/page-capture.d.ts +24 -0
  282. package/dist/portal/input/page-capture.js +33 -0
  283. package/dist/portal/input/real-input.d.ts +35 -18
  284. package/dist/portal/input/real-input.js +99 -33
  285. package/dist/portal/input/viewport-tools.d.ts +8 -0
  286. package/dist/portal/input/viewport-tools.js +81 -21
  287. package/dist/portal/pool/browser-pool.d.ts +16 -30
  288. package/dist/portal/pool/browser-pool.js +64 -52
  289. package/dist/portal/pool/context-permissions.d.ts +34 -17
  290. package/dist/portal/pool/context-permissions.js +94 -1
  291. package/dist/portal/pool/csp-widen.d.ts +62 -0
  292. package/dist/portal/pool/csp-widen.js +132 -0
  293. package/dist/portal/pool/determinism.d.ts +52 -0
  294. package/dist/portal/pool/determinism.js +259 -0
  295. package/dist/portal/pool/lease-emulation.d.ts +34 -1
  296. package/dist/portal/pool/lease-emulation.js +18 -0
  297. package/dist/portal/pool/lease-marker-stamp.d.ts +6 -0
  298. package/dist/portal/pool/lease-marker-stamp.js +15 -1
  299. package/dist/portal/pool/lease-page-error.d.ts +56 -0
  300. package/dist/portal/pool/lease-page-error.js +160 -0
  301. package/dist/portal/pool/page-error-journal.d.ts +63 -0
  302. package/dist/portal/pool/page-error-journal.js +208 -0
  303. package/dist/portal/pool/playwright-launcher.js +71 -15
  304. package/dist/portal/pool/pool-contract.d.ts +49 -1
  305. package/dist/portal/pool/pool-lease.d.ts +70 -2
  306. package/dist/portal/pool/pool-lease.js +23 -0
  307. package/dist/portal/pool/zero-install.d.ts +8 -0
  308. package/dist/portal/pool/zero-install.js +91 -1
  309. package/dist/portal/session/dev-server/dev-command.d.ts +11 -2
  310. package/dist/portal/session/dev-server/dev-command.js +110 -16
  311. package/dist/portal/session/dev-server/dev-server-probe.d.ts +7 -0
  312. package/dist/portal/session/dev-server/dev-server-probe.js +9 -0
  313. package/dist/portal/session/dev-server/project-ports.d.ts +21 -0
  314. package/dist/portal/session/dev-server/project-ports.js +62 -0
  315. package/dist/portal/session/facts/departed-network.d.ts +66 -0
  316. package/dist/portal/session/facts/departed-network.js +142 -0
  317. package/dist/portal/session/no-session-diagnosis.d.ts +9 -0
  318. package/dist/portal/session/no-session-diagnosis.js +76 -27
  319. package/dist/portal/session/no-session-next-action.d.ts +14 -0
  320. package/dist/portal/session/no-session-next-action.js +56 -7
  321. package/dist/portal/session/no-session-watch.d.ts +6 -0
  322. package/dist/portal/session/no-session-watch.js +41 -4
  323. package/dist/portal/session/page-commands/undeclared-command.d.ts +9 -3
  324. package/dist/portal/session/page-commands/undeclared-command.js +16 -7
  325. package/dist/portal/session/recorded-gaps.d.ts +1 -1
  326. package/dist/portal/session/recorded-gaps.js +5 -2
  327. package/dist/portal/session/serving-directory.d.ts +10 -0
  328. package/dist/portal/session/serving-directory.js +39 -8
  329. package/dist/portal/session/session-manager.d.ts +10 -0
  330. package/dist/portal/session/session-manager.js +211 -81
  331. package/dist/portal/session/session.js +4 -3
  332. package/dist/portal/session/zero-install-first-call.d.ts +20 -1
  333. package/dist/portal/session/zero-install-first-call.js +34 -2
  334. package/dist/start-wiring.d.ts +30 -2
  335. package/dist/start-wiring.js +74 -9
  336. package/dist/surface/mcp/mcp-proxy.js +10 -2
  337. package/dist/surface/mcp/mcp.js +8 -5
  338. package/dist/surface/mcp/peer/agents-connected.d.ts +6 -0
  339. package/dist/surface/mcp/peer/agents-connected.js +58 -0
  340. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +17 -5
  341. package/dist/surface/mcp/shared-params.d.ts +2 -0
  342. package/dist/surface/mcp/shared-params.js +31 -0
  343. package/dist/surface/tools/act/act-observation.d.ts +40 -2
  344. package/dist/surface/tools/act/act-observation.js +118 -12
  345. package/dist/surface/tools/act/act-preflight.js +38 -18
  346. package/dist/surface/tools/act/act-sequence-retry.d.ts +23 -2
  347. package/dist/surface/tools/act/act-sequence-retry.js +61 -5
  348. package/dist/surface/tools/act/act-target.js +3 -1
  349. package/dist/surface/tools/act/after-match.d.ts +10 -0
  350. package/dist/surface/tools/act/after-match.js +40 -0
  351. package/dist/surface/tools/act/already-true.js +1 -1
  352. package/dist/surface/tools/act/navigation/reload-result.d.ts +12 -1
  353. package/dist/surface/tools/act/navigation/reload-result.js +25 -2
  354. package/dist/surface/tools/act/resolve-target.d.ts +17 -1
  355. package/dist/surface/tools/act/resolve-target.js +59 -9
  356. package/dist/surface/tools/act/sequence-grade.d.ts +15 -1
  357. package/dist/surface/tools/act/sequence-grade.js +45 -27
  358. package/dist/surface/tools/act/settle-in-flight.js +27 -15
  359. package/dist/surface/tools/act-command.d.ts +23 -0
  360. package/dist/surface/tools/act-command.js +50 -0
  361. package/dist/surface/tools/act-sequence-tool.js +81 -50
  362. package/dist/surface/tools/act-tools.d.ts +1 -13
  363. package/dist/surface/tools/act-tools.js +83 -95
  364. package/dist/surface/tools/agent/build-staleness.d.ts +1 -1
  365. package/dist/surface/tools/agent/build-staleness.js +1 -1
  366. package/dist/surface/tools/assert/assert-verdict.js +18 -12
  367. package/dist/surface/tools/browser-tools.js +87 -13
  368. package/dist/surface/tools/compare-tools.d.ts +11 -0
  369. package/dist/surface/tools/compare-tools.js +94 -0
  370. package/dist/surface/tools/coverage-tools.js +1 -1
  371. package/dist/surface/tools/dynamic-tools.js +11 -3
  372. package/dist/surface/tools/empty-session-list.d.ts +2 -0
  373. package/dist/surface/tools/empty-session-list.js +4 -2
  374. package/dist/surface/tools/error-recovery.d.ts +12 -1
  375. package/dist/surface/tools/error-recovery.js +131 -40
  376. package/dist/surface/tools/explore-tools.js +1 -1
  377. package/dist/surface/tools/invoke-tool.js +29 -21
  378. package/dist/surface/tools/lease-coverage-tools.d.ts +49 -0
  379. package/dist/surface/tools/lease-coverage-tools.js +128 -0
  380. package/dist/surface/tools/lease-hint.d.ts +42 -1
  381. package/dist/surface/tools/lease-hint.js +52 -3
  382. package/dist/surface/tools/lease-readiness.d.ts +47 -0
  383. package/dist/surface/tools/lease-readiness.js +126 -0
  384. package/dist/surface/tools/lease-seed.d.ts +16 -1
  385. package/dist/surface/tools/lease-seed.js +37 -4
  386. package/dist/surface/tools/lease-tools.d.ts +3 -41
  387. package/dist/surface/tools/lease-tools.js +104 -124
  388. package/dist/surface/tools/lease-url-identity.d.ts +46 -0
  389. package/dist/surface/tools/lease-url-identity.js +97 -0
  390. package/dist/surface/tools/merge-tools.js +99 -2
  391. package/dist/surface/tools/merged-name-redirect.js +5 -1
  392. package/dist/surface/tools/observe-tools.js +15 -9
  393. package/dist/surface/tools/read/console-pre-attach.d.ts +19 -0
  394. package/dist/surface/tools/read/console-pre-attach.js +23 -0
  395. package/dist/surface/tools/read-tools.js +33 -30
  396. package/dist/surface/tools/real-input-attempt.d.ts +0 -8
  397. package/dist/surface/tools/real-input-attempt.js +143 -28
  398. package/dist/surface/tools/repeat-hint.d.ts +40 -0
  399. package/dist/surface/tools/repeat-hint.js +171 -0
  400. package/dist/surface/tools/run-report.d.ts +2 -2
  401. package/dist/surface/tools/run-report.js +27 -15
  402. package/dist/surface/tools/session-ports.d.ts +14 -0
  403. package/dist/surface/tools/session-ports.js +53 -0
  404. package/dist/surface/tools/tool-kit.d.ts +18 -0
  405. package/dist/surface/tools/tool-kit.js +9 -3
  406. package/dist/surface/tools/tool-surface.js +0 -1
  407. package/dist/surface/tools/tools.js +54 -18
  408. package/dist/surface/tools/type-spelling.d.ts +13 -0
  409. package/dist/surface/tools/type-spelling.js +36 -0
  410. package/dist/telemetry/agent-client.d.ts +6 -0
  411. package/dist/telemetry/agent-client.js +10 -0
  412. package/dist/telemetry/argument-shape.js +17 -7
  413. package/dist/telemetry/cli-telemetry.d.ts +10 -1
  414. package/dist/telemetry/cli-telemetry.js +15 -0
  415. package/dist/telemetry/init-telemetry.d.ts +2 -1
  416. package/dist/telemetry/init-telemetry.js +47 -2
  417. package/dist/telemetry/install-trace.js +23 -4
  418. package/dist/telemetry/onboarding-funnel.d.ts +19 -2
  419. package/dist/telemetry/onboarding-funnel.js +25 -3
  420. package/dist/telemetry/proxy-telemetry.d.ts +2 -1
  421. package/dist/telemetry/proxy-telemetry.js +2 -2
  422. package/dist/telemetry/session-metrics.d.ts +1 -1
  423. package/dist/telemetry/session-metrics.js +67 -27
  424. package/dist/telemetry/telemetry.d.ts +3 -1
  425. package/dist/telemetry/telemetry.js +60 -28
  426. package/dist/telemetry/tool-refused.d.ts +6 -3
  427. package/dist/telemetry/tool-refused.js +15 -3
  428. package/docs/actions.mdx +3 -3
  429. package/docs/agent-cheatsheet.md +1 -1
  430. package/docs/architecture.md +3 -6
  431. package/docs/capabilities.mdx +61 -1
  432. package/docs/cli/affected.mdx +9 -7
  433. package/docs/cli/cloud.mdx +3 -3
  434. package/docs/cli/compare.mdx +94 -0
  435. package/docs/cli/doctor.mdx +41 -2
  436. package/docs/cli/grade.mdx +97 -0
  437. package/docs/cli/help.mdx +4 -2
  438. package/docs/cli/license.mdx +13 -12
  439. package/docs/cli/restart.mdx +7 -5
  440. package/docs/cli/rollback.mdx +5 -5
  441. package/docs/cli/setup.mdx +13 -2
  442. package/docs/cli/status.mdx +4 -0
  443. package/docs/cli/stop.mdx +3 -3
  444. package/docs/cli/update.mdx +2 -2
  445. package/docs/cli/verify.mdx +23 -1
  446. package/docs/cli.mdx +34 -24
  447. package/docs/deploy-checks.md +25 -0
  448. package/docs/desktop.mdx +1 -1
  449. package/docs/enterprise.md +17 -22
  450. package/docs/environment.mdx +1 -0
  451. package/docs/first-drive.md +1 -1
  452. package/docs/flows.md +11 -1
  453. package/docs/frameworks.mdx +9 -9
  454. package/docs/getting-started.md +1 -1
  455. package/docs/install-manual.mdx +16 -1
  456. package/docs/license-activation.mdx +3 -3
  457. package/docs/packages/engine.mdx +1 -1
  458. package/docs/packages/server.mdx +1 -1
  459. package/docs/packages/tauri.mdx +1 -1
  460. package/docs/packages/test.mdx +1 -1
  461. package/docs/packages.mdx +1 -1
  462. package/docs/platform-integration.md +1 -1
  463. package/docs/predicates.mdx +1 -1
  464. package/docs/quickstart.mdx +68 -49
  465. package/docs/skill-setup.md +1 -1
  466. package/docs/skill.md +14 -13
  467. package/docs/telemetry.md +6 -4
  468. package/docs/tools/navigate.mdx +1 -1
  469. package/docs/tools/verify.mdx +4 -1
  470. package/docs/troubleshooting.mdx +1 -1
  471. package/docs/usage.md +17 -14
  472. package/package.json +18 -14
  473. package/LICENSE-ENTERPRISE +0 -37
  474. package/dist/features/ee/audit-log.d.ts +0 -14
  475. package/dist/features/ee/audit-log.js +0 -11
  476. package/dist/features/exhaust/exhaust-run.d.ts +0 -33
  477. package/dist/features/exhaust/exhaust-run.js +0 -82
@@ -1,4 +1,5 @@
1
- import { asRecord, ElementState } from '@reticlehq/core';
1
+ import * as z from 'zod';
2
+ import { asRecord, ElementState, NearestTargetSchema } from '@reticlehq/core';
2
3
  /**
3
4
  * Roles that usually name the control an agent meant, ahead of a wrapping `generic` that
4
5
  * happened to inherit the same accessible name (header CTA vs empty-state CTA).
@@ -17,8 +18,9 @@ const ROLE_RANK = {
17
18
  searchbox: 10,
18
19
  };
19
20
  function roleRank(role) {
20
- if ('string' !== typeof role)
21
+ if ('string' !== typeof role) {
21
22
  return 100;
23
+ }
22
24
  return ROLE_RANK[role] ?? 50;
23
25
  }
24
26
  function statesOf(c) {
@@ -35,8 +37,9 @@ function inViewport(c) {
35
37
  */
36
38
  function compareCandidates(a, b) {
37
39
  const viewport = Number(inViewport(b)) - Number(inViewport(a));
38
- if (0 !== viewport)
40
+ if (0 !== viewport) {
39
41
  return viewport;
42
+ }
40
43
  return roleRank(a.role) - roleRank(b.role);
41
44
  }
42
45
  /**
@@ -50,14 +53,18 @@ function formatCandidate(c, anyInViewport) {
50
53
  const ref = 'string' === typeof c.ref ? c.ref : '?';
51
54
  const visible = false !== c.visible;
52
55
  let where;
53
- if (!visible)
56
+ if (!visible) {
54
57
  where = 'hidden';
55
- else if (inViewport(c))
58
+ }
59
+ else if (inViewport(c)) {
56
60
  where = 'in-viewport';
57
- else if (anyInViewport)
61
+ }
62
+ else if (anyInViewport) {
58
63
  where = 'off-screen';
59
- else
64
+ }
65
+ else {
60
66
  where = 'visible';
67
+ }
61
68
  const head = name.length > 0 ? `${ref} (${role} "${name}"` : `${ref} (${role}`;
62
69
  return `${head}; ${where})`;
63
70
  }
@@ -76,6 +83,42 @@ function nearNamesClause(hint) {
76
83
  'Use that name, or — when the name carries a part that changes, like a time — target it by ' +
77
84
  '`testid` or by `text` (a contained match).');
78
85
  }
86
+ /**
87
+ * What a result says when every match was hidden and the action used the hidden one. It does not
88
+ * say that a person could not reach it: a hidden input with a visible label is reached through the
89
+ * label, and the reach check after the action decides that.
90
+ */
91
+ export function hiddenTargetNote(ref) {
92
+ return (`every element that matched the target is hidden, so the action used the hidden match ${ref}. ` +
93
+ 'If a person reaches it through a visible label, this is correct. If not, target the control ' +
94
+ 'a person can see.');
95
+ }
96
+ /** The `hiddenTarget` field for a tool result, or nothing when the action used a visible match. */
97
+ export function hiddenTargetField(resolution) {
98
+ if ('ref' !== resolution.kind || resolution.hiddenTarget === undefined) {
99
+ return {};
100
+ }
101
+ return { hiddenTarget: resolution.hiddenTarget };
102
+ }
103
+ const NearestTargetsSchema = z.array(NearestTargetSchema).min(1);
104
+ /** The words before the nearest-target list in a no_match refusal. The repeat hint reads after it. */
105
+ export const NEAREST_TARGETS_LEAD = ' The nearest targets on the page, most similar first: ';
106
+ /**
107
+ * The browser's `nearest` hint as a sentence: the targets most like the one asked for, with refs,
108
+ * so the retry is one call and not a snapshot loop. Empty when there is no list. It is advice
109
+ * only: the action stays refused, and nothing here picks a target.
110
+ */
111
+ function nearestClause(hint) {
112
+ const parsed = NearestTargetsSchema.safeParse(asRecord(hint)['nearest']);
113
+ if (!parsed.success) {
114
+ return '';
115
+ }
116
+ const listed = parsed.data
117
+ .map((t) => `${t.ref} (${t.role} "${t.name}${true === t.nameTruncated ? '…' : ''}")`)
118
+ .join(', ');
119
+ return (`${NEAREST_TARGETS_LEAD}${listed}. If one of them is the ` +
120
+ 'element you meant, pass its ref as `ref`.');
121
+ }
79
122
  /**
80
123
  * Turn a target QUERY into the single ref an action can be performed on.
81
124
  *
@@ -91,7 +134,9 @@ function nearNamesClause(hint) {
91
134
  *
92
135
  * Invisible matches are filtered before counting: a hidden duplicate is a common way for a
93
136
  * legitimately unambiguous query to look ambiguous, and refusing on it would push callers back to
94
- * the two-turn path for no gain.
137
+ * the two-turn path for no gain. When every match is hidden, the one hidden match is used and the
138
+ * resolution names it in `hiddenTarget`. It is not refused: a hidden input is often clicked through
139
+ * its visible label.
95
140
  *
96
141
  * When several remain, they are ranked (in-viewport, then role) inside the refusal only — so the
97
142
  * agent can pass the top ref on the next turn without a snapshot. Ranking is never acted on here.
@@ -104,7 +149,8 @@ export function resolveTargetRef(candidates, hint) {
104
149
  return {
105
150
  kind: 'error',
106
151
  message: 'target matched no element. Nothing was acted on and no verdict is possible — ' +
107
- nearNamesClause(hint),
152
+ nearNamesClause(hint) +
153
+ nearestClause(hint),
108
154
  };
109
155
  }
110
156
  if (usable.length > 1) {
@@ -126,5 +172,9 @@ export function resolveTargetRef(candidates, hint) {
126
172
  if ('string' !== typeof ref || 0 === ref.length) {
127
173
  return { kind: 'error', message: 'target matched an element with no usable ref.' };
128
174
  }
175
+ // Every match was hidden, so the action uses a hidden one. Rule 11: say so, never silently.
176
+ if (0 === visible.length) {
177
+ return { kind: 'ref', ref, hiddenTarget: hiddenTargetNote(ref) };
178
+ }
129
179
  return { kind: 'ref', ref };
130
180
  }
@@ -14,7 +14,7 @@
14
14
  * is verified FOR THOSE THREE and silent about nine, and `because` says so — reporting it as "25%
15
15
  * verified" would be the arithmetic that hides the nine.
16
16
  */
17
- import { Verified } from '@reticlehq/core';
17
+ import { Verified, VerifiedReason } from '@reticlehq/core';
18
18
  /**
19
19
  * What to do when a step's declared consequence does not hold.
20
20
  *
@@ -46,9 +46,21 @@ export interface StepExpectation {
46
46
  * step is undecided, never a miss — `unknown`, as act_and_wait says.
47
47
  */
48
48
  undecided?: string;
49
+ /** The step's action (`click`, `fill`), so a plan that could not judge a step can name it. */
50
+ action?: string;
51
+ /** A real frame flushed after this step's action, as `settled` on its act result says. */
52
+ settled?: boolean;
53
+ /**
54
+ * Absence-derived contradiction kinds seen in this step's window (a request that never settled,
55
+ * for example). They do not decide a miss, but they stop a plan from claiming no channel saw a
56
+ * problem.
57
+ */
58
+ doubted?: readonly string[];
49
59
  }
50
60
  export interface SequenceGrade {
51
61
  verified: Verified;
62
+ /** The deciding clause, from core's list, so a sequence verdict is counted by reason like any other. */
63
+ reason: VerifiedReason;
52
64
  /** Steps that declared a consequence. */
53
65
  declared: number;
54
66
  total: number;
@@ -67,6 +79,8 @@ interface SequencePlan {
67
79
  readonly planned: number;
68
80
  /** Whether anything actually reached the page. */
69
81
  readonly dispatched: boolean;
82
+ /** The capture lost events inside the plan's window, so no channel saw all of it. */
83
+ readonly captureLost?: boolean;
70
84
  }
71
85
  export declare function gradeSequence(steps: readonly StepExpectation[], plan?: SequencePlan): SequenceGrade;
72
86
  /**
@@ -14,7 +14,7 @@
14
14
  * is verified FOR THOSE THREE and silent about nine, and `because` says so — reporting it as "25%
15
15
  * verified" would be the arithmetic that hides the nine.
16
16
  */
17
- import { Verified } from '@reticlehq/core';
17
+ import { Verified, VerifiedReason } from '@reticlehq/core';
18
18
  /**
19
19
  * What to do when a step's declared consequence does not hold.
20
20
  *
@@ -23,6 +23,23 @@ import { Verified } from '@reticlehq/core';
23
23
  * sweep of independent controls, where stopping at the first would hide the other thirteen.
24
24
  */
25
25
  export const DeviationMode = { HALT: 'halt', CONTINUE: 'continue' };
26
+ /** The sentence for a plan whose steps declared nothing. */
27
+ function undeclaredBecause(total, dispatched) {
28
+ if (0 === total) {
29
+ return 'the plan had no steps, so nothing was driven and nothing was proved';
30
+ }
31
+ // A step refused before dispatch is a malformed call: telling its author to add an `expect`
32
+ // sends them to the wrong thing.
33
+ if (!dispatched) {
34
+ return `nothing was dispatched, so none of the ${String(total)} step(s) ran — read the per-step \`error\` for the one that was refused, and fix that before adding an \`expect\``;
35
+ }
36
+ return `all ${String(total)} step(s) declared nothing, so the app was driven but not verified — give each step an \`expect\` naming the consequence it causes`;
37
+ }
38
+ /** A step as a sentence names it: its number, counted from 1, and its action when it has one. */
39
+ function stepName(index, action) {
40
+ const number = `step ${String(index + 1)}`;
41
+ return action === undefined ? number : `${number} (${action})`;
42
+ }
26
43
  export function gradeSequence(steps, plan = { planned: steps.length, dispatched: true }) {
27
44
  const total = Math.max(plan.planned, steps.length);
28
45
  const declaring = steps.filter((step) => step.declared);
@@ -36,6 +53,7 @@ export function gradeSequence(steps, plan = { planned: steps.length, dispatched:
36
53
  const observed = missed.observed ?? 'nothing that matched';
37
54
  return {
38
55
  verified: Verified.NO,
56
+ reason: VerifiedReason.ASSERTION_FAILED,
39
57
  declared,
40
58
  total,
41
59
  because: `a declared consequence did not hold — observed ${observed}`,
@@ -47,47 +65,43 @@ export function gradeSequence(steps, plan = { planned: steps.length, dispatched:
47
65
  const kinds = (steps[contradictedAt]?.contradicted ?? []).join(', ');
48
66
  return {
49
67
  verified: Verified.NO,
68
+ reason: VerifiedReason.CONTRADICTED,
50
69
  declared,
51
70
  total,
52
71
  because: `step ${String(contradictedAt + 1)}: channels disagree about this action (${kinds}) even though it went on`,
53
72
  };
54
73
  }
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)
74
+ // Nothing failed that was seen: a step nobody could judge leaves the plan undecided. The sentence
75
+ // names the step and what was missing, so the agent knows which step to change (#2204).
76
+ const unjudgedAt = steps.findIndex((step) => step.undecided !== undefined);
77
+ if (unjudgedAt >= 0) {
78
+ const unjudged = steps[unjudgedAt];
58
79
  return {
59
80
  verified: Verified.UNKNOWN,
81
+ reason: VerifiedReason.INCONCLUSIVE,
60
82
  declared,
61
83
  total,
62
- because: `a step could not be judged — ${unjudged.undecided ?? ''}`,
84
+ because: `${stepName(unjudgedAt, unjudged?.action)} could not be judged: ${unjudged?.undecided ?? ''}`,
63
85
  };
86
+ }
64
87
  /*
65
- * `unknown` rather than `no-fault`, and the distinction is load-bearing.
66
- *
67
- * "Nothing was declared" is what `no-fault` means for a single action -- but the engine only says
68
- * it over a SETTLED window, because no-fault claims the whole window was observed. Nothing on
69
- * this path observes settledness: the caller tracks dispatch and stalls, never settle. Saying
70
- * `no-fault` here would claim evidence nobody collected, in the one place this product cannot
71
- * afford to overclaim.
72
- *
73
- * So the enum stays conservative and the SENTENCE carries the whole answer: it names declaring a
74
- * consequence as the next move, which is what an agent reading `no-fault` would have done.
75
- * Upgrading means plumbing `settled` from the act results through `SequencePlan`.
88
+ * Nothing declared is `no-fault` over a quiet plan and `unknown` otherwise. This is the rule a
89
+ * single action follows (`engine/src/evidence/verified.ts`): no-fault claims the whole window was
90
+ * observed, so every step must report a settled frame, no step may carry an absence-derived
91
+ * finding, and the capture must be whole. `unknown` sends an agent to look again with better
92
+ * coverage. When the plan was quiet, that cannot help: the fix is to declare a consequence.
76
93
  */
77
94
  if (0 === declared) {
95
+ const quiet = plan.dispatched &&
96
+ true !== plan.captureLost &&
97
+ steps.length > 0 &&
98
+ steps.every((step) => true === step.settled && 0 === (step.doubted ?? []).length);
78
99
  return {
79
- verified: Verified.UNKNOWN,
100
+ verified: quiet ? Verified.NO_FAULT : Verified.UNKNOWN,
101
+ reason: VerifiedReason.NOTHING_DECLARED,
80
102
  declared,
81
103
  total,
82
- because: 0 === total
83
- ? 'the plan had no steps, so nothing was driven and nothing was proved'
84
- : // "the app was driven" was said unconditionally, including on a call whose own
85
- // `dispatched` was false in the same object. A step refused before dispatch is a
86
- // malformed call, and telling its author to add an `expect` sends them at the wrong
87
- // thing entirely.
88
- plan.dispatched
89
- ? `all ${String(total)} step(s) declared nothing, so the app was driven but not verified — give each step an \`expect\` naming the consequence it causes`
90
- : `nothing was dispatched, so none of the ${String(total)} step(s) ran — read the per-step \`error\` for the one that was refused, and fix that before adding an \`expect\``,
104
+ because: undeclaredBecause(total, plan.dispatched),
91
105
  };
92
106
  }
93
107
  // A journey is proved at its END. Declaring only early steps checks that it started, and a yes
@@ -95,6 +109,7 @@ export function gradeSequence(steps, plan = { planned: steps.length, dispatched:
95
109
  if (steps.length < total) {
96
110
  return {
97
111
  verified: Verified.UNKNOWN,
112
+ reason: VerifiedReason.EVIDENCE_INCOMPLETE,
98
113
  declared,
99
114
  total,
100
115
  because: `only ${String(steps.length)} of ${String(total)} steps ran, so the journey never reached its end`,
@@ -103,6 +118,7 @@ export function gradeSequence(steps, plan = { planned: steps.length, dispatched:
103
118
  if (true !== steps.at(-1)?.declared) {
104
119
  return {
105
120
  verified: Verified.UNKNOWN,
121
+ reason: VerifiedReason.EVIDENCE_INCOMPLETE,
106
122
  declared,
107
123
  total,
108
124
  because: `the last step, where the journey ends, declared nothing — give it an \`expect\` naming the end state (${String(declared)} of ${String(total)} steps declared one)`,
@@ -110,6 +126,7 @@ export function gradeSequence(steps, plan = { planned: steps.length, dispatched:
110
126
  }
111
127
  return {
112
128
  verified: Verified.YES,
129
+ reason: VerifiedReason.PROVED,
113
130
  declared,
114
131
  total,
115
132
  because: declared === total
@@ -137,8 +154,9 @@ export function gradeSequence(steps, plan = { planned: steps.length, dispatched:
137
154
  /** The stopped recording a proved journey is held under, so the `keep` offer can be taken. */
138
155
  export const JOURNEY_RECORDING = 'last-journey';
139
156
  export function offerToKeep(grade) {
140
- if (grade.verified !== Verified.YES || 0 === grade.declared)
157
+ if (grade.verified !== Verified.YES || 0 === grade.declared) {
141
158
  return undefined;
159
+ }
142
160
  return (`this plan proved something (${String(grade.declared)} of ${String(grade.total)} steps declared a ` +
143
161
  'consequence and every one held) — keep it as a regression flow with ' +
144
162
  `reticle_flow_save { flowName: "${JOURNEY_RECORDING}", saveAs: "<name>" }, and the steps that declared nothing will replay ` +
@@ -27,7 +27,7 @@
27
27
  * - still in flight when the budget genuinely runs out → `unsettled`, as before, but now an honest
28
28
  * limit instead of an early exit.
29
29
  */
30
- import { EventType, NetInitiator, isDevToolingUrl, isForeignTraffic, urlForMatch, } from '@reticlehq/core';
30
+ import { EventType, isDevToolingUrl, isForeignTraffic, neverAnswered, urlForMatch, } from '@reticlehq/core';
31
31
  /**
32
32
  * What a URL is matched against, as opposed to what is shown.
33
33
  *
@@ -81,10 +81,11 @@ const isForeign = (data, appOrigin, background) => isForeignTraffic(matchUrlOf(d
81
81
  * NET_REQUEST, so counting it as outstanding would mean no page containing an outbound link or a
82
82
  * download button ever settles again. See `NetInitiator.NAVIGATION`.
83
83
  *
84
- * The `settled` predicate asks the same question in `evalSettled`; it spells it against this same
85
- * constant rather than against a string, which is what keeps the two answers one vocabulary.
84
+ * The `settled` predicate asks the same question in `evalSettled`. Both read core's `neverAnswered`,
85
+ * which keeps the two answers one rule. It also covers a request whose page unloaded before its
86
+ * answer arrived (#1944).
86
87
  */
87
- const isDeparture = (data) => data['initiator'] === NetInitiator.NAVIGATION;
88
+ const isDeparture = neverAnswered;
88
89
  /** How often to re-read the buffer. Short enough to return promptly, long enough not to spin. */
89
90
  const POLL_MS = 50;
90
91
  const idOf = (data) => 'string' === typeof data['id'] ? data['id'] : undefined;
@@ -98,21 +99,26 @@ const idOf = (data) => 'string' === typeof data['id'] ? data['id'] : undefined;
98
99
  export function inFlightRequestIds(events, appOrigin, background = []) {
99
100
  const settled = new Set();
100
101
  for (const e of events) {
101
- if (e.type !== EventType.NET_REQUEST)
102
+ if (e.type !== EventType.NET_REQUEST) {
102
103
  continue;
104
+ }
103
105
  const id = idOf(e.data);
104
- if (id !== undefined)
106
+ if (id !== undefined) {
105
107
  settled.add(id);
108
+ }
106
109
  }
107
110
  const open = [];
108
111
  for (const e of events) {
109
- if (e.type !== EventType.NET_PENDING || isDevTooling(e.data) || isDeparture(e.data))
112
+ if (e.type !== EventType.NET_PENDING || isDevTooling(e.data) || isDeparture(e.data)) {
110
113
  continue;
111
- if (isForeign(e.data, appOrigin, background))
114
+ }
115
+ if (isForeign(e.data, appOrigin, background)) {
112
116
  continue;
117
+ }
113
118
  const id = idOf(e.data);
114
- if (id !== undefined && !settled.has(id) && !open.includes(id))
119
+ if (id !== undefined && !settled.has(id) && !open.includes(id)) {
115
120
  open.push(id);
121
+ }
116
122
  }
117
123
  return open;
118
124
  }
@@ -128,11 +134,13 @@ export function inFlightRequestLabels(events, appOrigin, background = []) {
128
134
  const open = new Set(inFlightRequestIds(events, appOrigin, background));
129
135
  const labels = [];
130
136
  for (const e of events) {
131
- if (e.type !== EventType.NET_PENDING)
137
+ if (e.type !== EventType.NET_PENDING) {
132
138
  continue;
139
+ }
133
140
  const id = idOf(e.data);
134
- if (id === undefined || !open.has(id))
141
+ if (id === undefined || !open.has(id)) {
135
142
  continue;
143
+ }
136
144
  open.delete(id); // one label per request, however many times its start was recorded
137
145
  const method = 'string' === typeof e.data['method'] ? e.data['method'] : 'request';
138
146
  const url = 'string' === typeof e.data['url'] ? e.data['url'] : 'an unreported url';
@@ -158,8 +166,9 @@ const MIN_REPEATS = 2;
158
166
  export function repeatedRequestLabels(events) {
159
167
  const counts = new Map();
160
168
  for (const e of events) {
161
- if (e.type !== EventType.NET_REQUEST || isDevTooling(e.data))
169
+ if (e.type !== EventType.NET_REQUEST || isDevTooling(e.data)) {
162
170
  continue;
171
+ }
163
172
  const method = 'string' === typeof e.data['method'] ? e.data['method'] : 'request';
164
173
  const url = 'string' === typeof e.data['url'] ? e.data['url'] : 'an unreported url';
165
174
  const key = `${method} ${url}`;
@@ -182,17 +191,20 @@ export async function waitForInFlight(session, since, budgetMs, opts) {
182
191
  // The verdict's own scope: waiting on a request the verdict will not count is latency for nothing.
183
192
  const outstanding = () => inFlightRequestIds(session.eventsSince(since), session.url, session.background);
184
193
  let open = outstanding();
185
- if (0 === open.length)
194
+ if (0 === open.length) {
186
195
  return { settled: true, stillInFlight: [] };
187
- if (budgetMs <= 0)
196
+ }
197
+ if (budgetMs <= 0) {
188
198
  return { settled: false, stillInFlight: open };
199
+ }
189
200
  const deadline = session.elapsed() + budgetMs;
190
201
  while (session.elapsed() < deadline) {
191
202
  // Never overshoot the budget: the last sleep is trimmed to whatever is actually left.
192
203
  await opts.sleep(Math.min(POLL_MS, deadline - session.elapsed()));
193
204
  open = outstanding();
194
- if (0 === open.length)
205
+ if (0 === open.length) {
195
206
  return { settled: true, stillInFlight: [] };
207
+ }
196
208
  }
197
209
  return { settled: false, stillInFlight: open };
198
210
  }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The single dispatch point for every ACT and ACT_SEQUENCE command, extracted from
3
+ * act-tools.ts at the 1000-line cap.
4
+ *
5
+ * Attribution: this dispatch does NOT open its own window — the CALLER wraps it in
6
+ * `session.beginAction` / `finishAction` with the tool it serves (act, act_and_wait, act_sequence
7
+ * pass their own `command`), so the window covers the whole flow around the dispatch, not just
8
+ * the send.
9
+ */
10
+ import { ReticleCommand } from '@reticlehq/core';
11
+ import type { Session } from '../../portal/session/session.js';
12
+ import type { ToolDeps } from './tool-kit.js';
13
+ /**
14
+ * Single dispatch point for every ACT and ACT_SEQUENCE command.
15
+ *
16
+ * reticle_act, act_and_wait and act_sequence rewrite uploads here, once. The path resolves against
17
+ * the session's project, not the daemon's folder, so a worktree uploads its own fixture (#1769).
18
+ *
19
+ * captureAct is called AFTER this, so the flow-recording captures the pre-rewrite args (the path
20
+ * the agent actually wrote) rather than the base64 blob — replay would otherwise send 750 KiB of
21
+ * base64 to the browser as if it were an inline content call.
22
+ */
23
+ export declare function actCommand(deps: ToolDeps, session: Session, command: ReticleCommand, rawActArgs: Record<string, unknown>, timeoutMs?: number, realTried?: boolean): Promise<import('@reticlehq/core').CommandResult>;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * The single dispatch point for every ACT and ACT_SEQUENCE command, extracted from
3
+ * act-tools.ts at the 1000-line cap.
4
+ *
5
+ * Attribution: this dispatch does NOT open its own window — the CALLER wraps it in
6
+ * `session.beginAction` / `finishAction` with the tool it serves (act, act_and_wait, act_sequence
7
+ * pass their own `command`), so the window covers the whole flow around the dispatch, not just
8
+ * the send.
9
+ */
10
+ import { ActionType, ReticleCommand, asRecord, asString } from '@reticlehq/core';
11
+ import { rewriteUploadArgs, tryRealInput, HOVER_NEEDS_POINTER_MSG } from './real-input-attempt.js';
12
+ import { sessionRoot } from '../../memory/project/session-root.js';
13
+ import { normalizeTypeSpelling } from './type-spelling.js';
14
+ /**
15
+ * Single dispatch point for every ACT and ACT_SEQUENCE command.
16
+ *
17
+ * reticle_act, act_and_wait and act_sequence rewrite uploads here, once. The path resolves against
18
+ * the session's project, not the daemon's folder, so a worktree uploads its own fixture (#1769).
19
+ *
20
+ * captureAct is called AFTER this, so the flow-recording captures the pre-rewrite args (the path
21
+ * the agent actually wrote) rather than the base64 blob — replay would otherwise send 750 KiB of
22
+ * base64 to the browser as if it were an inline content call.
23
+ */
24
+ export async function actCommand(deps, session, command, rawActArgs, timeoutMs, realTried = false) {
25
+ const actArgs = normalizeTypeSpelling(rawActArgs);
26
+ const rewritten = await rewriteUploadArgs({ fs: deps.fs, reticleRoot: sessionRoot(deps, session.id) }, 'string' === typeof actArgs['action'] ? actArgs['action'] : '', asRecord(actArgs['args']));
27
+ // Sequence and act_and_wait dispatch through here without the ACT handler's tryRealInput.
28
+ // A synthetic hover reports dispatched/settled while CSS :hover never applies — drive a real
29
+ // pointer when one is available, otherwise refuse rather than lie. A press on a lease takes its
30
+ // real keyboard, as reticle_act does: a synthetic Tab moves no focus.
31
+ const hover = ActionType.HOVER === actArgs['action'];
32
+ if (!realTried && (hover || ActionType.PRESS === actArgs['action'])) {
33
+ const ref = asString(actArgs['ref']);
34
+ if (hover && ref === undefined) {
35
+ throw new Error(HOVER_NEEDS_POINTER_MSG);
36
+ }
37
+ const action = hover ? ActionType.HOVER : ActionType.PRESS;
38
+ const real = await tryRealInput(deps, session, ref ?? '', action, actArgs);
39
+ if (hover && real.result === undefined) {
40
+ throw new Error(HOVER_NEEDS_POINTER_MSG);
41
+ }
42
+ if (real.result !== undefined) {
43
+ const result = { dispatched: true, settled: real.settled, ...asRecord(real.result) };
44
+ return { kind: 'command_result', id: action, ok: true, result };
45
+ }
46
+ }
47
+ const bridgeArgs = { ...actArgs, args: rewritten };
48
+ // What the acted element shows (test id, source) is noted in `Session.command`, Harness acts too.
49
+ return session.command(command, bridgeArgs, timeoutMs);
50
+ }