@reticlehq/server 3.2.0 → 3.4.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 (437) hide show
  1. package/LICENSE-ENTERPRISE +1 -1
  2. package/README.md +3 -3
  3. package/SKILL.md +23 -22
  4. package/dist/chromium-launch-options.d.ts +4 -3
  5. package/dist/chromium-launch-options.js +6 -2
  6. package/dist/command/cli/adhoc-suite.d.ts +41 -0
  7. package/dist/command/cli/adhoc-suite.js +159 -0
  8. package/dist/command/cli/adhoc-verdict.d.ts +58 -2
  9. package/dist/command/cli/adhoc-verdict.js +108 -13
  10. package/dist/command/cli/answers/gate-hook-message.d.ts +6 -0
  11. package/dist/command/cli/answers/gate-hook-message.js +6 -0
  12. package/dist/command/cli/auth/cloud-keystore.d.ts +0 -2
  13. package/dist/command/cli/auth/cloud-keystore.js +0 -3
  14. package/dist/command/cli/auth/cloud-session.d.ts +4 -0
  15. package/dist/command/cli/auth/cloud-session.js +2 -0
  16. package/dist/command/cli/cli-doctor.js +30 -8
  17. package/dist/command/cli/cli-flow-commands.d.ts +3 -6
  18. package/dist/command/cli/cli-flow-commands.js +67 -4
  19. package/dist/command/cli/cli-parse-grammar.d.ts +7 -0
  20. package/dist/command/cli/cli-parse-grammar.js +7 -0
  21. package/dist/command/cli/cli-parse-verify.d.ts +2 -5
  22. package/dist/command/cli/cli-parse-verify.js +86 -13
  23. package/dist/command/cli/cli-parse.d.ts +14 -1
  24. package/dist/command/cli/cli-parse.js +54 -8
  25. package/dist/command/cli/cli-update-commands.js +8 -1
  26. package/dist/command/cli/cli-verify.d.ts +80 -0
  27. package/dist/command/cli/cli-verify.js +181 -26
  28. package/dist/command/cli/cloud-cli.js +5 -2
  29. package/dist/command/cli/cloud-kit.d.ts +0 -2
  30. package/dist/command/cli/cloud-kit.js +3 -5
  31. package/dist/command/cli/cloud-login.js +21 -3
  32. package/dist/command/cli/demo/demo-page.js +6 -3
  33. package/dist/command/cli/doctor/browser/chromium-hint.d.ts +5 -0
  34. package/dist/command/cli/doctor/browser/chromium-hint.js +5 -0
  35. package/dist/command/cli/doctor/doctor-sessions-line.d.ts +2 -1
  36. package/dist/command/cli/launch/cli-launch.d.ts +9 -29
  37. package/dist/command/cli/launch/cli-launch.js +27 -49
  38. package/dist/command/cli/launch/sdk-version-match.d.ts +84 -0
  39. package/dist/command/cli/launch/sdk-version-match.js +206 -0
  40. package/dist/command/cli/lifecycle/daemon-lifecycle.js +2 -16
  41. package/dist/command/cli/ports/resolve/cli-port.d.ts +38 -0
  42. package/dist/command/cli/ports/resolve/cli-port.js +169 -15
  43. package/dist/command/cli/report-command.d.ts +16 -0
  44. package/dist/command/cli/report-command.js +97 -0
  45. package/dist/command/cli/setup-mcp-cli.js +13 -13
  46. package/dist/command/cli/tutorial.d.ts +2 -2
  47. package/dist/command/cli/tutorial.js +21 -7
  48. package/dist/command/cli.js +67 -10
  49. package/dist/command/daemon/binding/daemon-status-probe.d.ts +44 -2
  50. package/dist/command/daemon/binding/daemon-status-probe.js +79 -6
  51. package/dist/command/daemon/binding/port-presence.d.ts +1 -1
  52. package/dist/command/daemon/daemon-resolve.d.ts +9 -0
  53. package/dist/command/daemon/daemon-resolve.js +1 -1
  54. package/dist/command/daemon/idle-shutdown.d.ts +2 -1
  55. package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +7 -1
  56. package/dist/command/daemon/lifetime/daemon-usefulness.js +30 -7
  57. package/dist/command/dev/stale-issue-guard.d.ts +3 -4
  58. package/dist/command/dev/stale-issue-guard.js +8 -8
  59. package/dist/command/setup/bringup/connect-lease.d.ts +17 -0
  60. package/dist/command/setup/bringup/connect-lease.js +38 -0
  61. package/dist/command/setup/bringup/dev-server-files.d.ts +68 -0
  62. package/dist/command/setup/bringup/dev-server-files.js +131 -0
  63. package/dist/command/setup/bringup/dev-server-log-cap.d.ts +35 -0
  64. package/dist/command/setup/bringup/dev-server-log-cap.js +121 -0
  65. package/dist/command/setup/bringup/ensure-daemon.d.ts +65 -4
  66. package/dist/command/setup/bringup/ensure-daemon.js +135 -16
  67. package/dist/command/setup/bringup/static-page-server.d.ts +35 -0
  68. package/dist/command/setup/bringup/static-page-server.js +151 -0
  69. package/dist/command/setup/desktop-shape.d.ts +4 -0
  70. package/dist/command/setup/desktop-shape.js +18 -2
  71. package/dist/command/setup/init/init-host.js +8 -0
  72. package/dist/command/setup/init/init-port.d.ts +15 -0
  73. package/dist/command/setup/init/init-port.js +44 -0
  74. package/dist/command/setup/init/init-runtime.d.ts +1 -1
  75. package/dist/command/setup/init/init-runtime.js +39 -2
  76. package/dist/command/setup/node-effects.d.ts +27 -14
  77. package/dist/command/setup/node-effects.js +80 -44
  78. package/dist/command/setup/probe/loopback-probe-urls.d.ts +7 -0
  79. package/dist/command/setup/probe/loopback-probe-urls.js +40 -0
  80. package/dist/command/setup/probe/page-probe.d.ts +13 -2
  81. package/dist/command/setup/probe/page-probe.js +18 -3
  82. package/dist/command/setup/run-setup.d.ts +26 -1
  83. package/dist/command/setup/run-setup.js +96 -13
  84. package/dist/command/setup/session-pick.d.ts +13 -0
  85. package/dist/command/setup/session-pick.js +20 -0
  86. package/dist/command/setup/setup-command.d.ts +2 -14
  87. package/dist/command/setup/setup-command.js +105 -31
  88. package/dist/command/setup/setup-mcp.js +3 -3
  89. package/dist/command/setup/terminal/wait-progress.d.ts +8 -0
  90. package/dist/command/setup/terminal/wait-progress.js +17 -0
  91. package/dist/features/crawl/crawl-empty.js +1 -1
  92. package/dist/features/crawl/crawl-tools.d.ts +6 -0
  93. package/dist/features/crawl/crawl-tools.js +57 -0
  94. package/dist/features/crawl/crawl.d.ts +2 -0
  95. package/dist/features/crawl/crawl.js +171 -156
  96. package/dist/features/exhaust/app-coverage.d.ts +33 -0
  97. package/dist/features/exhaust/app-coverage.js +31 -0
  98. package/dist/features/exhaust/code-coverage.d.ts +47 -0
  99. package/dist/features/exhaust/code-coverage.js +77 -0
  100. package/dist/features/exhaust/exhaust-run.d.ts +33 -0
  101. package/dist/features/exhaust/exhaust-run.js +82 -0
  102. package/dist/features/exhaust/explorer.d.ts +103 -0
  103. package/dist/features/exhaust/explorer.js +195 -0
  104. package/dist/features/exhaust/failure-branches.d.ts +33 -0
  105. package/dist/features/exhaust/failure-branches.js +92 -0
  106. package/dist/features/exhaust/ledger.d.ts +202 -0
  107. package/dist/features/exhaust/ledger.js +252 -0
  108. package/dist/features/exhaust/session-fold.d.ts +31 -0
  109. package/dist/features/exhaust/session-fold.js +79 -0
  110. package/dist/features/exhaust/session-port.d.ts +36 -0
  111. package/dist/features/exhaust/session-port.js +102 -0
  112. package/dist/features/harness/drive-report.d.ts +0 -9
  113. package/dist/features/harness/drive-report.js +18 -0
  114. package/dist/features/harness/driver.js +4 -7
  115. package/dist/features/harness/fill-values.d.ts +6 -0
  116. package/dist/features/harness/fill-values.js +3 -0
  117. package/dist/features/harness/jev-driver.js +36 -22
  118. package/dist/features/harness/openai-driver.js +4 -7
  119. package/dist/features/harness/platform-config.d.ts +10 -0
  120. package/dist/features/harness/platform-config.js +13 -6
  121. package/dist/index.d.ts +10 -1
  122. package/dist/index.js +78 -104
  123. package/dist/judgement/capsule/capsule-store.d.ts +31 -2
  124. package/dist/judgement/capsule/capsule-store.js +58 -6
  125. package/dist/judgement/capsule/capsule.js +5 -0
  126. package/dist/judgement/capsule/causal-summary.d.ts +13 -1
  127. package/dist/judgement/capsule/causal-summary.js +7 -0
  128. package/dist/judgement/domain/domain-model.js +40 -9
  129. package/dist/judgement/oracles/self-instrument.js +4 -2
  130. package/dist/judgement/outcome/assertion-integrity.d.ts +3 -3
  131. package/dist/judgement/runs/artifact/gap-report.d.ts +17 -0
  132. package/dist/judgement/runs/artifact/gap-report.js +46 -0
  133. package/dist/judgement/runs/artifact/gap-summary.d.ts +58 -0
  134. package/dist/judgement/runs/artifact/gap-summary.js +85 -0
  135. package/dist/judgement/runs/artifact/render-report.js +4 -1
  136. package/dist/judgement/runs/artifact/replay-mapping.d.ts +2 -2
  137. package/dist/judgement/runs/artifact/replay-mapping.js +44 -9
  138. package/dist/judgement/runs/artifact/to-artifact.d.ts +7 -2
  139. package/dist/judgement/runs/artifact/to-artifact.js +1 -1
  140. package/dist/judgement/runs/context-tools.js +21 -3
  141. package/dist/judgement/runs/drive-run.js +7 -2
  142. package/dist/judgement/runs/verification-sync.d.ts +3 -1
  143. package/dist/judgement/runs/verification-sync.js +1 -1
  144. package/dist/language/flows/annotate-notes/annotate.d.ts +0 -15
  145. package/dist/language/flows/annotate-notes/annotate.js +66 -18
  146. package/dist/language/flows/change/affected.d.ts +9 -0
  147. package/dist/language/flows/change/affected.js +35 -0
  148. package/dist/language/flows/change/gate.d.ts +20 -0
  149. package/dist/language/flows/change/gate.js +12 -1
  150. package/dist/language/flows/flow-anchor.d.ts +12 -0
  151. package/dist/language/flows/flow-anchor.js +20 -0
  152. package/dist/language/flows/flow-author.d.ts +7 -0
  153. package/dist/language/flows/flow-author.js +19 -0
  154. package/dist/language/flows/flow-expect-grammar.d.ts +2 -2
  155. package/dist/language/flows/flow-expect-grammar.js +92 -11
  156. package/dist/language/flows/flow-intent.js +1 -1
  157. package/dist/language/flows/flow-journey.d.ts +54 -0
  158. package/dist/language/flows/flow-journey.js +119 -0
  159. package/dist/language/flows/flow-learning.d.ts +3 -0
  160. package/dist/language/flows/flow-learning.js +39 -8
  161. package/dist/language/flows/flow-replay-run.d.ts +33 -12
  162. package/dist/language/flows/flow-replay-run.js +131 -52
  163. package/dist/language/flows/flow-replay-types.d.ts +9 -0
  164. package/dist/language/flows/flow-replay.d.ts +27 -12
  165. package/dist/language/flows/flow-replay.js +127 -111
  166. package/dist/language/flows/flow-result.d.ts +2 -0
  167. package/dist/language/flows/flow-result.js +25 -0
  168. package/dist/language/flows/flow-step-runners.d.ts +26 -10
  169. package/dist/language/flows/flow-step-runners.js +20 -4
  170. package/dist/language/flows/flow-success.d.ts +21 -6
  171. package/dist/language/flows/flow-success.js +50 -138
  172. package/dist/language/flows/flow-tools.js +17 -5
  173. package/dist/language/flows/flows.d.ts +18 -5
  174. package/dist/language/flows/flows.js +101 -16
  175. package/dist/language/flows/heal.d.ts +9 -1
  176. package/dist/language/flows/heal.js +24 -2
  177. package/dist/language/flows/learned-sources.d.ts +21 -0
  178. package/dist/language/flows/learned-sources.js +84 -0
  179. package/dist/language/flows/recording/recording-backtrack.d.ts +0 -7
  180. package/dist/language/flows/recording/recording-backtrack.js +1 -1
  181. package/dist/language/flows/recording/replay-halt.d.ts +2 -1
  182. package/dist/language/flows/recording/replay-halt.js +3 -1
  183. package/dist/language/flows/recording/tape/recordings.d.ts +31 -2
  184. package/dist/language/flows/recording/tape/recordings.js +55 -1
  185. package/dist/language/flows/replay.d.ts +19 -0
  186. package/dist/language/flows/replay.js +53 -13
  187. package/dist/language/flows/stores/annotation-store.d.ts +5 -5
  188. package/dist/language/flows/stores/assertion-tiers-store.js +2 -3
  189. package/dist/language/flows/stores/flake-store.js +2 -3
  190. package/dist/language/flows/suite/coverage.d.ts +1 -1
  191. package/dist/language/flows/suite/parallel-suite.d.ts +2 -1
  192. package/dist/language/flows/verify-change-tools.js +19 -2
  193. package/dist/launch-chromium.d.ts +80 -0
  194. package/dist/launch-chromium.js +218 -0
  195. package/dist/memory/cloud/cloud-config.d.ts +11 -2
  196. package/dist/memory/cloud/cloud-config.js +47 -7
  197. package/dist/memory/cloud/cloud-sync.d.ts +4 -3
  198. package/dist/memory/cloud/cloud-sync.js +7 -10
  199. package/dist/memory/cloud/harness-config.d.ts +2 -0
  200. package/dist/memory/cloud/harness-offer.js +5 -6
  201. package/dist/memory/cloud/harness-switch.js +5 -6
  202. package/dist/memory/cloud/sync-cycle.d.ts +78 -1
  203. package/dist/memory/cloud/sync-cycle.js +321 -53
  204. package/dist/memory/cloud/sync-daemon.d.ts +13 -0
  205. package/dist/memory/cloud/sync-daemon.js +45 -20
  206. package/dist/memory/cloud/sync-disk.js +27 -8
  207. package/dist/memory/impact/impact-store.js +6 -0
  208. package/dist/memory/intent/inline-intent.js +8 -3
  209. package/dist/memory/intent/intent-shard-store.d.ts +33 -47
  210. package/dist/memory/intent/intent-shard-store.js +252 -140
  211. package/dist/memory/intent/intent-shard.d.ts +0 -23
  212. package/dist/memory/intent/intent-shard.js +1 -11
  213. package/dist/memory/intent/intent-store.d.ts +13 -8
  214. package/dist/memory/intent/intent-store.js +46 -90
  215. package/dist/memory/intent/intent-tools.js +34 -23
  216. package/dist/memory/journal/ambient-store.js +2 -3
  217. package/dist/memory/journal/deviation-report.js +4 -1
  218. package/dist/memory/journal/deviation-service.js +10 -2
  219. package/dist/memory/journal/drive-flow.d.ts +19 -14
  220. package/dist/memory/journal/drive-flow.js +65 -48
  221. package/dist/memory/journal/envelope-store.js +2 -3
  222. package/dist/memory/journal/journal-recorder.d.ts +21 -0
  223. package/dist/memory/journal/on-disk/retain-policy.d.ts +34 -0
  224. package/dist/memory/journal/on-disk/retain-policy.js +44 -0
  225. package/dist/memory/journal/on-disk/retention.d.ts +14 -10
  226. package/dist/memory/journal/on-disk/retention.js +13 -12
  227. package/dist/memory/journal/on-disk/startup-maintenance.d.ts +42 -0
  228. package/dist/memory/journal/on-disk/startup-maintenance.js +14 -0
  229. package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +0 -11
  230. package/dist/memory/journal/on-disk/workspace-gitignore.js +6 -45
  231. package/dist/memory/journal/on-disk/workspace-tiers.d.ts +52 -0
  232. package/dist/memory/journal/on-disk/workspace-tiers.js +90 -0
  233. package/dist/memory/journal/route-template.d.ts +22 -0
  234. package/dist/memory/journal/route-template.js +44 -0
  235. package/dist/memory/journal/session-end.d.ts +13 -2
  236. package/dist/memory/journal/session-end.js +88 -18
  237. package/dist/memory/journal/session-journal.d.ts +8 -1
  238. package/dist/memory/journal/session-journal.js +10 -0
  239. package/dist/memory/project/baselines.d.ts +1 -1
  240. package/dist/memory/project/dir/reticle-dir.d.ts +3 -1
  241. package/dist/memory/project/dir/reticle-dir.js +1 -0
  242. package/dist/memory/project/fs/fs-port.js +44 -5
  243. package/dist/memory/project/fs/write-atomic.d.ts +26 -0
  244. package/dist/memory/project/fs/write-atomic.js +48 -0
  245. package/dist/memory/project/project-tools.js +3 -1
  246. package/dist/memory/recall/prior/connection-memory.d.ts +6 -0
  247. package/dist/memory/recall/prior/connection-memory.js +8 -0
  248. package/dist/memory/recall/registered-projects.d.ts +2 -1
  249. package/dist/portal/bridge/auth-failure-reason.d.ts +1 -1
  250. package/dist/portal/bridge/auth-failure-reason.js +9 -4
  251. package/dist/portal/bridge/bridge.d.ts +8 -0
  252. package/dist/portal/bridge/bridge.js +43 -2
  253. package/dist/portal/input/js-coverage.d.ts +25 -0
  254. package/dist/portal/input/js-coverage.js +30 -0
  255. package/dist/portal/input/real-input.d.ts +11 -0
  256. package/dist/portal/input/real-input.js +31 -5
  257. package/dist/portal/pool/browser-pool.d.ts +10 -0
  258. package/dist/portal/pool/browser-pool.js +10 -0
  259. package/dist/portal/pool/playwright-launcher.d.ts +6 -0
  260. package/dist/portal/pool/playwright-launcher.js +21 -13
  261. package/dist/portal/pool/pool-contract.d.ts +2 -0
  262. package/dist/portal/pool/storage-seed.d.ts +2 -1
  263. package/dist/portal/pool/zero-install.d.ts +27 -0
  264. package/dist/portal/pool/zero-install.js +54 -0
  265. package/dist/portal/realm/web-realm.js +6 -0
  266. package/dist/portal/session/dev-server/dev-command.d.ts +2 -2
  267. package/dist/portal/session/dev-server/dev-command.js +30 -12
  268. package/dist/portal/session/dev-server/dev-server-probe.d.ts +2 -1
  269. package/dist/portal/session/dev-server/dev-server-probe.js +17 -1
  270. package/dist/portal/session/dev-server/route-status-probe.d.ts +24 -0
  271. package/dist/portal/session/dev-server/route-status-probe.js +57 -0
  272. package/dist/portal/session/dev-server/served-document.d.ts +21 -0
  273. package/dist/portal/session/dev-server/served-document.js +57 -0
  274. package/dist/portal/session/facts/background-traffic.d.ts +9 -0
  275. package/dist/portal/session/facts/background-traffic.js +25 -0
  276. package/dist/portal/session/facts/observed-state.d.ts +11 -0
  277. package/dist/portal/session/facts/observed-state.js +34 -0
  278. package/dist/portal/session/live-control-tools.js +48 -3
  279. package/dist/portal/session/no-session-diagnosis.d.ts +29 -0
  280. package/dist/portal/session/no-session-diagnosis.js +62 -5
  281. package/dist/portal/session/no-session-next-action.d.ts +13 -0
  282. package/dist/portal/session/no-session-next-action.js +48 -9
  283. package/dist/portal/session/no-session-watch.d.ts +18 -0
  284. package/dist/portal/session/no-session-watch.js +88 -2
  285. package/dist/portal/session/presence/attachment-history.d.ts +13 -2
  286. package/dist/portal/session/session-health.d.ts +61 -0
  287. package/dist/portal/session/session-health.js +43 -3
  288. package/dist/portal/session/session-info.d.ts +6 -0
  289. package/dist/portal/session/session-manager.d.ts +29 -6
  290. package/dist/portal/session/session-manager.js +42 -5
  291. package/dist/portal/session/session-reaper.d.ts +28 -0
  292. package/dist/portal/session/session-reaper.js +49 -1
  293. package/dist/portal/session/session-successor.d.ts +11 -0
  294. package/dist/portal/session/session-successor.js +14 -1
  295. package/dist/portal/session/session-verdict-facts.d.ts +28 -0
  296. package/dist/portal/session/session-verdict-facts.js +15 -0
  297. package/dist/portal/session/session.d.ts +10 -0
  298. package/dist/portal/session/session.js +34 -26
  299. package/dist/surface/http-server.d.ts +2 -1
  300. package/dist/surface/http-server.js +4 -2
  301. package/dist/surface/mcp/mcp-proxy.d.ts +2 -2
  302. package/dist/surface/mcp/mcp-proxy.js +5 -5
  303. package/dist/surface/mcp/mcp.js +4 -2
  304. package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +13 -1
  305. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +27 -2
  306. package/dist/surface/mcp/proxy-idle-exit.d.ts +2 -1
  307. package/dist/surface/mcp/server-instructions.js +21 -8
  308. package/dist/surface/tools/act/after-match.d.ts +17 -0
  309. package/dist/surface/tools/act/after-match.js +30 -0
  310. package/dist/surface/tools/act/already-true.d.ts +40 -0
  311. package/dist/surface/tools/act/already-true.js +36 -0
  312. package/dist/surface/tools/act/durable.d.ts +69 -0
  313. package/dist/surface/tools/act/durable.js +139 -0
  314. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +19 -6
  315. package/dist/surface/tools/act/navigation/navigate-arrival.js +60 -10
  316. package/dist/surface/tools/act/navigation/navigate-result.d.ts +1 -12
  317. package/dist/surface/tools/act/navigation/navigate-result.js +21 -3
  318. package/dist/surface/tools/act/proved-controls.d.ts +9 -0
  319. package/dist/surface/tools/act/proved-controls.js +11 -0
  320. package/dist/surface/tools/act/sequence-grade.d.ts +5 -0
  321. package/dist/surface/tools/act/sequence-grade.js +32 -1
  322. package/dist/surface/tools/act/settle-in-flight.d.ts +6 -2
  323. package/dist/surface/tools/act/settle-in-flight.js +29 -6
  324. package/dist/surface/tools/act-capsule.d.ts +7 -0
  325. package/dist/surface/tools/act-capsule.js +68 -8
  326. package/dist/surface/tools/act-sequence-tool.js +25 -8
  327. package/dist/surface/tools/act-tools.js +51 -74
  328. package/dist/surface/tools/args/numeric-bounds.d.ts +15 -2
  329. package/dist/surface/tools/args/numeric-bounds.js +30 -3
  330. package/dist/surface/tools/assert/assert-grade.js +26 -3
  331. package/dist/surface/tools/assert/assert-verdict.js +32 -6
  332. package/dist/surface/tools/browser-tools.js +17 -4
  333. package/dist/surface/tools/coverage-tools.js +27 -1
  334. package/dist/surface/tools/dynamic-tools.js +6 -0
  335. package/dist/surface/tools/error-recovery.js +4 -4
  336. package/dist/surface/tools/feedback-invite.js +6 -4
  337. package/dist/surface/tools/feedback-tools.d.ts +2 -1
  338. package/dist/surface/tools/feedback-tools.js +1 -1
  339. package/dist/surface/tools/harness-explore.d.ts +3 -2
  340. package/dist/surface/tools/harness-explore.js +7 -6
  341. package/dist/surface/tools/invoke-tool.js +17 -4
  342. package/dist/surface/tools/lease-hint.d.ts +8 -0
  343. package/dist/surface/tools/lease-hint.js +10 -0
  344. package/dist/surface/tools/lease-tools.d.ts +16 -28
  345. package/dist/surface/tools/lease-tools.js +68 -11
  346. package/dist/surface/tools/lineage-tools.js +1 -1
  347. package/dist/surface/tools/live-call-text.js +4 -1
  348. package/dist/surface/tools/observe-tools.js +23 -7
  349. package/dist/surface/tools/real-input-attempt.d.ts +0 -5
  350. package/dist/surface/tools/real-input-attempt.js +1 -1
  351. package/dist/surface/tools/tool-kit.d.ts +5 -0
  352. package/dist/surface/tools/tool-kit.js +6 -1
  353. package/dist/surface/tools/tool-surface.js +17 -5
  354. package/dist/surface/tools/tools.js +68 -29
  355. package/dist/telemetry/argument-shape.d.ts +0 -2
  356. package/dist/telemetry/argument-shape.js +0 -4
  357. package/dist/telemetry/error-class.d.ts +2 -3
  358. package/dist/telemetry/error-class.js +2 -3
  359. package/dist/telemetry/feedback-local.d.ts +1 -0
  360. package/dist/telemetry/feedback-local.js +1 -3
  361. package/dist/telemetry/feedback.d.ts +1 -1
  362. package/dist/telemetry/harness-drive.d.ts +0 -2
  363. package/dist/telemetry/harness-drive.js +0 -4
  364. package/dist/telemetry/hud-metrics.d.ts +32 -0
  365. package/dist/telemetry/hud-metrics.js +95 -0
  366. package/dist/telemetry/session-metrics.d.ts +5 -0
  367. package/dist/telemetry/session-metrics.js +15 -1
  368. package/dist/wire-journal.d.ts +34 -0
  369. package/dist/wire-journal.js +104 -0
  370. package/dist/workspace-packages.d.ts +0 -2
  371. package/dist/workspace-packages.js +1 -9
  372. package/docs/README.md +5 -2
  373. package/docs/actions.mdx +3 -3
  374. package/docs/agent-cheatsheet.md +4 -4
  375. package/docs/architecture.md +6 -6
  376. package/docs/best-practices.mdx +1 -1
  377. package/docs/capabilities.mdx +32 -1
  378. package/docs/cli/cloud.mdx +21 -9
  379. package/docs/cli/doctor.mdx +4 -0
  380. package/docs/cli/feedback.mdx +2 -2
  381. package/docs/cli/gate.mdx +9 -4
  382. package/docs/cli/init.mdx +1 -0
  383. package/docs/cli/report.mdx +44 -0
  384. package/docs/cli/update.mdx +10 -0
  385. package/docs/cli.mdx +9 -0
  386. package/docs/desktop.mdx +14 -10
  387. package/docs/environment.mdx +87 -0
  388. package/docs/faq.mdx +18 -16
  389. package/docs/first-drive.md +5 -13
  390. package/docs/flows.md +32 -2
  391. package/docs/frameworks.mdx +140 -9
  392. package/docs/getting-started.md +3 -3
  393. package/docs/http-transport.md +6 -3
  394. package/docs/human-control.md +2 -2
  395. package/docs/index.mdx +16 -6
  396. package/docs/install-agentic.mdx +37 -1
  397. package/docs/install-manual.mdx +1 -1
  398. package/docs/integration-patterns.md +3 -3
  399. package/docs/multi-agent-testing.md +1 -1
  400. package/docs/packages/babel-plugin.mdx +1 -1
  401. package/docs/packages/browser.mdx +2 -2
  402. package/docs/packages/react.mdx +2 -2
  403. package/docs/packages/tauri.mdx +1 -1
  404. package/docs/packages/vite-plugin.mdx +2 -2
  405. package/docs/packages.mdx +9 -9
  406. package/docs/predicates.mdx +176 -7
  407. package/docs/quickstart.mdx +2 -2
  408. package/docs/recipes.mdx +2 -2
  409. package/docs/state-management.mdx +2 -2
  410. package/docs/system-map.md +1 -1
  411. package/docs/telemetry.md +1 -1
  412. package/docs/token-efficiency.md +3 -3
  413. package/docs/tools/act-and-wait.mdx +1 -0
  414. package/docs/tools/act-sequence.mdx +1 -1
  415. package/docs/tools/console.mdx +1 -1
  416. package/docs/tools/inspect.mdx +1 -1
  417. package/docs/tools/network.mdx +1 -1
  418. package/docs/tools/query.mdx +11 -11
  419. package/docs/tools/sessions.mdx +1 -1
  420. package/docs/tools/snapshot.mdx +1 -1
  421. package/docs/tools/state.mdx +1 -1
  422. package/docs/tools/wait-for.mdx +1 -1
  423. package/docs/usage.md +8 -7
  424. package/docs/use-cases.mdx +157 -0
  425. package/docs/vs-screenshots.mdx +3 -3
  426. package/docs/what-is-recorded.md +62 -0
  427. package/docs/what-is-reticle.mdx +17 -20
  428. package/docs/why-reticle.mdx +14 -21
  429. package/package.json +11 -10
  430. package/dist/judgement/capsule/minimize.d.ts +0 -12
  431. package/dist/judgement/capsule/minimize.js +0 -22
  432. package/dist/judgement/outcome/predicate-to-expect.d.ts +0 -44
  433. package/dist/judgement/outcome/predicate-to-expect.js +0 -148
  434. package/dist/judgement/phenomena/phenomena.d.ts +0 -26
  435. package/dist/judgement/phenomena/phenomena.js +0 -101
  436. package/dist/language/flows/flow-report.d.ts +0 -22
  437. package/dist/language/flows/flow-report.js +0 -106
@@ -4,7 +4,7 @@
4
4
  * A daemon left running by one project answers the next project's app and rejects it on token, and
5
5
  * the SDK printed `bridge refused the connection: authentication failed`. That sends someone to
6
6
  * check a token which is perfectly correct — it is simply a DIFFERENT project's token. The two cases
7
- * need opposite fixes: "your token is wrong" versus "that daemon is not yours, stop it".
7
+ * need opposite fixes: "your token is wrong" versus "that daemon is not yours, use your own port".
8
8
  *
9
9
  * The discriminator is EVIDENCE, not derivation. The daemon and the SDK derive project ids by
10
10
  * different schemes (the SDK from its Vite root, the daemon from its own cwd), so comparing those
@@ -4,7 +4,7 @@
4
4
  * A daemon left running by one project answers the next project's app and rejects it on token, and
5
5
  * the SDK printed `bridge refused the connection: authentication failed`. That sends someone to
6
6
  * check a token which is perfectly correct — it is simply a DIFFERENT project's token. The two cases
7
- * need opposite fixes: "your token is wrong" versus "that daemon is not yours, stop it".
7
+ * need opposite fixes: "your token is wrong" versus "that daemon is not yours, use your own port".
8
8
  *
9
9
  * The discriminator is EVIDENCE, not derivation. The daemon and the SDK derive project ids by
10
10
  * different schemes (the SDK from its Vite root, the daemon from its own cwd), so comparing those
@@ -28,8 +28,11 @@ const PLAIN = 'authentication failed';
28
28
  * before `~/.reticle` was replaced. Both need the same first move: ask `status`, which can say which.
29
29
  */
30
30
  const WRONG_TOKEN = 'authentication failed: wrong pairing token — run `reticle status` for the cause';
31
- /** A paste-in snippet or a Next config that never saw a token. Reload cannot mint one. */
32
- const NO_TOKEN = 'authentication failed: no pairing token on the page';
31
+ /**
32
+ * A paste-in snippet or a Next config that never saw a token. Reload cannot mint one; restarting the
33
+ * dev server re-runs the substitution that should have put it there (#1047).
34
+ */
35
+ const NO_TOKEN = 'authentication failed: no pairing token on the page; the build did not substitute it, so restart the dev server';
33
36
  /** WebSocket close reasons are capped at 123 bytes; a longer one throws and closes with nothing. */
34
37
  const MAX_REASON_BYTES = 123;
35
38
  const DIFFERENT_PROJECT_PREFIX = 'this daemon serves a different project';
@@ -59,7 +62,9 @@ export function authFailureReason(servedProjects, helloProject, helloToken) {
59
62
  if (helloProject !== undefined &&
60
63
  1 === servedProjects.size &&
61
64
  !servedProjects.has(helloProject)) {
62
- const reason = `${DIFFERENT_PROJECT_PREFIX} — run \`reticle stop\` and retry`;
65
+ // Not "stop it": that daemon is serving somebody else's app. This project needs its own port,
66
+ // which the CLI and the build plugins both read from `.reticle.json`.
67
+ const reason = `${DIFFERENT_PROJECT_PREFIX} — set a free "port" in .reticle.json, then restart the dev server`;
63
68
  return Buffer.byteLength(reason, 'utf8') <= MAX_REASON_BYTES ? reason : PLAIN;
64
69
  }
65
70
  if (helloToken === undefined || 0 === helloToken.length)
@@ -38,6 +38,14 @@ export declare const WS_CLOSE_REASON: {
38
38
  * refusal on this path: nothing about the app is wrong and retrying is the correct response.
39
39
  */
40
40
  readonly HANDSHAKE_POOL_FULL: string;
41
+ /**
42
+ * A page's HELLO failed the wire schema for a reason other than its protocol number — the SDK and
43
+ * this daemon are different releases whose contracts no longer agree. The socket is still closed
44
+ * with the short `invalid message` the SDK already prints; this is the sentence the no-session
45
+ * diagnosis records, because "never dialled the bridge" was what `init` said about a page this
46
+ * daemon had just turned away. Same `cause — fix` shape as the protocol-skew reasons.
47
+ */
48
+ readonly INVALID_HELLO: string;
41
49
  };
42
50
  interface BridgeOptions {
43
51
  port: number;
@@ -69,6 +69,16 @@ export const WS_CLOSE_REASON = {
69
69
  'this dial never got to identify itself. Nothing is wrong with the app; the pool drains on its ' +
70
70
  'own and reloading the page reconnects. If it persists, something else on this machine is ' +
71
71
  'opening sockets to this port.',
72
+ /**
73
+ * A page's HELLO failed the wire schema for a reason other than its protocol number — the SDK and
74
+ * this daemon are different releases whose contracts no longer agree. The socket is still closed
75
+ * with the short `invalid message` the SDK already prints; this is the sentence the no-session
76
+ * diagnosis records, because "never dialled the bridge" was what `init` said about a page this
77
+ * daemon had just turned away. Same `cause — fix` shape as the protocol-skew reasons.
78
+ */
79
+ INVALID_HELLO: "invalid message: the page's hello does not match this daemon's wire contract — put " +
80
+ '@reticlehq/browser, the build plugin and @reticlehq/server on one release, run `reticle stop`, ' +
81
+ 'then restart the dev server',
72
82
  };
73
83
  /**
74
84
  * A dial turned away at the ORIGIN gate, in words the reader can act on.
@@ -179,6 +189,25 @@ function helloProtocolMismatch(text) {
179
189
  }
180
190
  return null;
181
191
  }
192
+ /**
193
+ * What a HELLO says about the page it came from, read loosely enough to survive the schema failing.
194
+ * Null when the message is not a hello at all — only an SDK sends one, so only then is a refusal
195
+ * evidence about an app.
196
+ */
197
+ function peekHelloPage(text) {
198
+ try {
199
+ const json = JSON.parse(text);
200
+ if (json.kind !== MessageKind.HELLO)
201
+ return null;
202
+ return {
203
+ ...('string' === typeof json.url ? { url: json.url } : {}),
204
+ ...('string' === typeof json.projectId ? { projectId: json.projectId } : {}),
205
+ };
206
+ }
207
+ catch {
208
+ return null;
209
+ }
210
+ }
182
211
  /** Normalize ws RawData (string | Buffer | Buffer[] | ArrayBuffer) into a UTF-8 string. */
183
212
  function rawToString(raw) {
184
213
  if ('string' === typeof raw)
@@ -436,10 +465,19 @@ export class Bridge {
436
465
  // Told to the AGENT too, not only to the SDK that is about to stop retrying. Without this
437
466
  // the next tool call answers "no browser session connected", which reads as "no app is
438
467
  // running" — so an SDK too old to connect is invisible.
439
- this.sessions.noteClosure(reason, this.#clock());
468
+ this.sessions.noteClosure(reason, this.#clock(), peekHelloPage(text) ?? {});
440
469
  socket.close(WS_CLOSE.PROTOCOL_MISMATCH[0], reason);
441
470
  return;
442
471
  }
472
+ // Recorded only for a HELLO on a socket that has none yet: that is a page being turned
473
+ // away, and it used to leave no trace, so `init` reported "never dialled the bridge" about
474
+ // a page this daemon had just refused. A malformed frame on a live session is a different
475
+ // failure and says nothing about whether the app can connect.
476
+ const refused = undefined === session ? peekHelloPage(text) : null;
477
+ if (null !== refused) {
478
+ log('hello_invalid', { ...refused });
479
+ this.sessions.noteClosure(WS_CLOSE_REASON.INVALID_HELLO, this.#clock(), refused);
480
+ }
443
481
  socket.close(...WS_CLOSE.INVALID_MESSAGE);
444
482
  return;
445
483
  }
@@ -498,7 +536,10 @@ export class Bridge {
498
536
  presented: parsed.token !== undefined && 0 < parsed.token.length,
499
537
  tokenSource: this.#tokenSource,
500
538
  });
501
- this.sessions.noteClosure(reason, this.#clock());
539
+ this.sessions.noteClosure(reason, this.#clock(), {
540
+ url: parsed.url,
541
+ ...(parsed.projectId === undefined ? {} : { projectId: parsed.projectId }),
542
+ });
502
543
  socket.close(WS_CLOSE.AUTH_FAILED[0], reason);
503
544
  return;
504
545
  }
@@ -0,0 +1,25 @@
1
+ import type { Page } from 'playwright';
2
+ /**
3
+ * V8 JS coverage on a page Reticle drives — the raw half of "what of the app ever ran".
4
+ *
5
+ * Started once per page with `resetOnNavigation: false`, so a reload keeps counting instead of
6
+ * starting over. A take stops and immediately restarts: the counts it returns are since the last
7
+ * take, and the reader folds them as a union (see features/exhaust/code-coverage.ts).
8
+ *
9
+ * Chromium only. Anything else — or a page that closed — answers false/undefined rather than
10
+ * throwing: coverage is an addition to a drive, never a reason for one to fail.
11
+ */
12
+ /** One script's coverage — the shape `stopJSCoverage` returns, narrowed to what is read. */
13
+ export interface ScriptCoverage {
14
+ url: string;
15
+ functions: {
16
+ functionName: string;
17
+ ranges: {
18
+ startOffset: number;
19
+ endOffset: number;
20
+ count: number;
21
+ }[];
22
+ }[];
23
+ }
24
+ export declare function startJsCoverage(page: Page, covering: WeakSet<Page>): Promise<boolean>;
25
+ export declare function takeJsCoverage(page: Page, covering: WeakSet<Page>): Promise<ScriptCoverage[] | undefined>;
@@ -0,0 +1,30 @@
1
+ export async function startJsCoverage(page, covering) {
2
+ if (covering.has(page))
3
+ return true;
4
+ try {
5
+ await page.coverage.startJSCoverage({ resetOnNavigation: false });
6
+ covering.add(page);
7
+ return true;
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ }
13
+ export async function takeJsCoverage(page, covering) {
14
+ // Nothing collects until something asks: collection slows every script on the page. The first
15
+ // take starts it and has nothing to report yet.
16
+ if (!covering.has(page)) {
17
+ await startJsCoverage(page, covering);
18
+ return undefined;
19
+ }
20
+ try {
21
+ const entries = await page.coverage.stopJSCoverage();
22
+ covering.delete(page);
23
+ await startJsCoverage(page, covering);
24
+ return entries;
25
+ }
26
+ catch {
27
+ covering.delete(page);
28
+ return undefined;
29
+ }
30
+ }
@@ -9,6 +9,7 @@
9
9
  * Node-only. Playwright is loaded via DYNAMIC `import('playwright')` so non-CDP users never
10
10
  * pay for it; the type-only import is elided by `tsc`, so the build stays green without it.
11
11
  */
12
+ import { type ScriptCoverage } from './js-coverage.js';
12
13
  import type { Browser, Page } from 'playwright';
13
14
  import { ActionType, DriveErrorCode } from '@reticlehq/core';
14
15
  import { type MockRule } from './network-mock.js';
@@ -77,6 +78,14 @@ export interface RealInputProvider {
77
78
  * Optional: a provider with no owned browser simply omits it.
78
79
  */
79
80
  setMocks?(sessionUrl: string, rules: MockRule[]): Promise<boolean>;
81
+ /**
82
+ * What of the app's own code ran since the last take (V8 coverage, Chromium only), or undefined
83
+ * when no driven page matches or collection had not started. The first call starts collecting,
84
+ * because collection slows every script on the page and a slower page can let a console error land
85
+ * after a clean-console check passed. Optional: a provider with no owned browser cannot see the
86
+ * engine's counters.
87
+ */
88
+ takeCodeCoverage?(sessionUrl: string): Promise<ScriptCoverage[] | undefined>;
80
89
  /**
81
90
  * Pin the correlated page's viewport to fixed pixel dimensions so a screenshot baseline is
82
91
  * reproducible across machines (the missing piece of CI-stable visual regression, alongside masks
@@ -144,6 +153,7 @@ interface CdpProviderOptions {
144
153
  export declare class CdpRealInputProvider implements RealInputProvider {
145
154
  #private;
146
155
  constructor(options: CdpProviderOptions);
156
+ takeCodeCoverage(sessionUrl: string): Promise<ScriptCoverage[] | undefined>;
147
157
  isAvailableFor(sessionUrl: string): Promise<boolean>;
148
158
  perform(sessionUrl: string, action: ActionType, box: ElementBox, args: RealInputArgs): Promise<RealInputResult>;
149
159
  /** PNG of the correlated page, or undefined if none matches. */
@@ -236,6 +246,7 @@ export declare class LaunchedRealInputProvider implements OwnedRealInputProvider
236
246
  width: number;
237
247
  height: number;
238
248
  }): Promise<boolean>;
249
+ takeCodeCoverage(_sessionUrl: string): Promise<ScriptCoverage[] | undefined>;
239
250
  /** Apply network-mock rules to the owned page; false before navigate / after dispose. */
240
251
  setMocks(_sessionUrl: string, rules: MockRule[]): Promise<boolean>;
241
252
  /** Close the owned browser once. Idempotent and safe before navigate. */
@@ -1,12 +1,25 @@
1
+ /**
2
+ * Optional CDP/Playwright real-input mode.
3
+ *
4
+ * Synthetic `dispatchEvent` cannot drive native hover/pointer state (an onMouseEnter never
5
+ * fires, hit-testing never runs). When a CDP endpoint is configured, this module connects a
6
+ * Playwright `Browser` over CDP and drives REAL pointer/keyboard input against the element box
7
+ * the SDK resolves (viewport CSS px from getBoundingClientRect).
8
+ *
9
+ * Node-only. Playwright is loaded via DYNAMIC `import('playwright')` so non-CDP users never
10
+ * pay for it; the type-only import is elided by `tsc`, so the build stays green without it.
11
+ */
12
+ import { takeJsCoverage } from './js-coverage.js';
1
13
  import { stampedDriveUrl } from './drive-url-stamp.js';
2
- import { chromiumLaunchOptions } from '../../chromium-launch-options.js';
3
- import { gotoOptions } from '../pool/playwright-launcher.js';
14
+ import { launchChromium } from '../../launch-chromium.js';
15
+ import { chromiumLaunchHint, gotoOptions } from '../pool/playwright-launcher.js';
4
16
  import { BrowserLaunchKind } from '@reticlehq/core/telemetry';
5
17
  import { getSessionMetrics } from '../../telemetry/session-metrics.js';
6
18
  import { classifyConnectFailure } from '../../telemetry/connect-failure.js';
7
19
  import { ActionType, DriveErrorCode, DRIVE_PLAYWRIGHT_MISSING_MSG } from '@reticlehq/core';
8
20
  import { installNetworkMocks } from './network-mock.js';
9
21
  import { attachNetworkDetail } from './network-detail.js';
22
+ import { injectedConnectArgs } from '../pool/zero-install.js';
10
23
  /** Structured, code-tagged failure so callers branch on cause, not message text. */
11
24
  export class DriveError extends Error {
12
25
  code;
@@ -130,6 +143,8 @@ export class CdpRealInputProvider {
130
143
  /** Pages already listening. #pageFor resolves on EVERY call, so without this each action would add
131
144
  * another listener and every response would be emitted once per action taken so far. */
132
145
  #listening = new WeakSet();
146
+ /** Pages collecting V8 coverage — see js-coverage.ts. */
147
+ #covering = new WeakSet();
133
148
  #browser;
134
149
  constructor(options) {
135
150
  this.#cdpUrl = options.cdpUrl;
@@ -175,6 +190,10 @@ export class CdpRealInputProvider {
175
190
  this.#listen(page);
176
191
  return page;
177
192
  }
193
+ async takeCodeCoverage(sessionUrl) {
194
+ const page = await this.#pageFor(sessionUrl);
195
+ return page === undefined ? undefined : takeJsCoverage(page, this.#covering);
196
+ }
178
197
  async isAvailableFor(sessionUrl) {
179
198
  try {
180
199
  return (await this.#pageFor(sessionUrl)) !== undefined;
@@ -272,13 +291,14 @@ export const launchedChromium = async (headless) => {
272
291
  }
273
292
  const settle = getSessionMetrics().recordConnectAttempt(BrowserLaunchKind.LAUNCHED);
274
293
  try {
275
- const browser = await mod.chromium.launch(chromiumLaunchOptions(headless));
294
+ const browser = await launchChromium(mod.chromium, headless);
276
295
  settle();
277
296
  return browser;
278
297
  }
279
298
  catch (e) {
280
299
  settle(classifyConnectFailure(e));
281
- throw new DriveError(DriveErrorCode.LAUNCH_FAILED, e instanceof Error ? e.message : String(e));
300
+ const msg = e instanceof Error ? e.message : String(e);
301
+ throw new DriveError(DriveErrorCode.LAUNCH_FAILED, chromiumLaunchHint(msg) ?? msg);
282
302
  }
283
303
  };
284
304
  /**
@@ -295,6 +315,8 @@ export class LaunchedRealInputProvider {
295
315
  #onNetworkDetail;
296
316
  #browser;
297
317
  #page;
318
+ /** Pages collecting V8 coverage — see js-coverage.ts. */
319
+ #covering = new WeakSet();
298
320
  constructor(options) {
299
321
  this.#driveUrl = options.driveUrl;
300
322
  this.#headless = options.headless;
@@ -338,7 +360,7 @@ export class LaunchedRealInputProvider {
338
360
  await page.waitForFunction('!!globalThis.__reticleInstance', {
339
361
  timeout: INJECT_CONNECT_WAIT_MS,
340
362
  });
341
- const arg = JSON.stringify({ allowNonLocalhost: true, token: opts.token, url: opts.url });
363
+ const arg = JSON.stringify(injectedConnectArgs(opts));
342
364
  await page.evaluate(`globalThis.__reticleInstance.connect(${arg})`);
343
365
  }
344
366
  catch {
@@ -441,6 +463,10 @@ export class LaunchedRealInputProvider {
441
463
  await page.setViewportSize({ width: size.width, height: size.height });
442
464
  return true;
443
465
  }
466
+ takeCodeCoverage(_sessionUrl) {
467
+ const page = this.#livePage();
468
+ return page === undefined ? Promise.resolve(undefined) : takeJsCoverage(page, this.#covering);
469
+ }
444
470
  /** Apply network-mock rules to the owned page; false before navigate / after dispose. */
445
471
  async setMocks(_sessionUrl, rules) {
446
472
  const page = this.#livePage();
@@ -18,6 +18,11 @@ export interface Lease {
18
18
  readonly url: string;
19
19
  readonly navStatus?: number;
20
20
  release(): Promise<void>;
21
+ /**
22
+ * Hand the page the zero-install reader: evaluated in the live document, and added ahead of every
23
+ * document this lease loads next. False when there is no reader, or the page cannot run one.
24
+ */
25
+ injectReader?(): Promise<boolean>;
21
26
  }
22
27
  /** Default lease time-to-live: a lease untouched for this long is presumed orphaned and reclaimed. */
23
28
  export declare const DEFAULT_LEASE_TTL_MS: number;
@@ -32,6 +37,11 @@ interface BrowserPoolOptions {
32
37
  leaseTtlMs?: number;
33
38
  /** Per-lease navigation timeout — a page that won't load fails its own lease, never blocks a slot. */
34
39
  navTimeoutMs?: number;
40
+ /**
41
+ * The zero-install reader, built where the daemon knows its own port and pairing token. A thunk so
42
+ * the ~450KB build is only read if some page ever needs it; undefined when there is none to give.
43
+ */
44
+ zeroInstallScript?: () => string | undefined;
35
45
  }
36
46
  /**
37
47
  * Owns a single browser and leases isolated contexts out of it, capped at `maxContexts`.
@@ -30,6 +30,7 @@ export class BrowserPool {
30
30
  #genId;
31
31
  #now;
32
32
  #ttl;
33
+ #zeroInstall;
33
34
  #navTimeout;
34
35
  #browser;
35
36
  #launching;
@@ -70,6 +71,7 @@ export class BrowserPool {
70
71
  this.#now = opts.now ?? (() => Date.now());
71
72
  this.#ttl = opts.leaseTtlMs ?? DEFAULT_LEASE_TTL_MS;
72
73
  this.#navTimeout = opts.navTimeoutMs ?? DEFAULT_NAV_TIMEOUT_MS;
74
+ this.#zeroInstall = opts.zeroInstallScript;
73
75
  }
74
76
  /** The TTL configured for leases — how long an untouched lease lives before the reaper reclaims it. */
75
77
  leaseTtlMs() {
@@ -405,6 +407,14 @@ export class BrowserPool {
405
407
  url,
406
408
  ...(navStatus !== undefined ? { navStatus } : {}),
407
409
  release: () => this.#release(sessionId),
410
+ injectReader: async () => {
411
+ const script = this.#zeroInstall?.();
412
+ if (script === undefined || page.evaluate === undefined)
413
+ return false;
414
+ await page.addInitScript?.(script);
415
+ await page.evaluate(script);
416
+ return true;
417
+ },
408
418
  };
409
419
  }
410
420
  catch (err) {
@@ -25,6 +25,12 @@ export declare function gotoOptions(timeoutMs: number | undefined): {
25
25
  export declare function playwrightLauncher(opts?: {
26
26
  headless?: boolean;
27
27
  }): Launcher;
28
+ /**
29
+ * Turn Playwright's raw launch error into the one command that fixes it, or undefined when it is
30
+ * not a missing-browser failure. Shared by the pooled and the drive launch, so `reticle verify` on
31
+ * a fresh machine gets the same advice as a lease.
32
+ */
33
+ export declare function chromiumLaunchHint(msg: string): string | undefined;
28
34
  /**
29
35
  * Resolve the pool's concurrency cap. An explicit RETICLE_MAX_CONTEXTS wins (clamped to
30
36
  * [1, hard ceiling]); otherwise scale with the machine but never above the CPU-derived ceiling.
@@ -6,7 +6,7 @@
6
6
  * Headless by default — the pool exists for fault-tolerant headless multi-agent testing.
7
7
  */
8
8
  import { BrowserLaunchKind } from '@reticlehq/core/telemetry';
9
- import { chromiumLaunchOptions } from '../../chromium-launch-options.js';
9
+ import { launchChromium } from '../../launch-chromium.js';
10
10
  import { getSessionMetrics } from '../../telemetry/session-metrics.js';
11
11
  import { classifyConnectFailure } from '../../telemetry/connect-failure.js';
12
12
  import { chromiumInstallCommand, chromiumInstallDepsCommand, bundledPlaywrightVersion, } from '../../command/cli/doctor/browser/chromium-hint.js';
@@ -41,6 +41,7 @@ function wrapBrowser(browser) {
41
41
  return {
42
42
  goto: (url, opts) => page.goto(url, gotoOptions(opts?.timeoutMs)),
43
43
  close: () => page.close(),
44
+ evaluate: (script) => page.evaluate(script),
44
45
  // Playwright returns a Buffer; Uint8Array is what the visual store and differ take.
45
46
  screenshot: async (opts) => new Uint8Array(await page.screenshot({ fullPage: true === opts?.fullPage })),
46
47
  // Three moves, same as performGesture: a single move to the center can be a no-op if
@@ -104,27 +105,34 @@ export function playwrightLauncher(opts = {}) {
104
105
  // number that actually costs memory and the one that explains a slow machine.
105
106
  const settle = getSessionMetrics().recordConnectAttempt(BrowserLaunchKind.POOLED);
106
107
  try {
107
- const browser = wrapBrowser(await chromium.launch(chromiumLaunchOptions(headless)));
108
+ const browser = wrapBrowser(await launchChromium(chromium, headless));
108
109
  settle();
109
110
  return browser;
110
111
  }
111
112
  catch (err) {
112
113
  settle(classifyConnectFailure(err));
113
- // Turn Playwright's raw "Executable doesn't exist" into the one command that fixes it.
114
114
  const msg = err instanceof Error ? err.message : String(err);
115
- // Checked FIRST: Playwright's host-requirement validation error also contains
116
- // "browserType.launch", so the generic check below would otherwise misdiagnose it as a
117
- // missing binary and send the user through a fix that changes nothing.
118
- if (/host system is missing dependencies/i.test(msg)) {
119
- throw new Error(CHROMIUM_MISSING_DEPS_HINT);
120
- }
121
- if (/executable doesn.?t exist|playwright install|browsertype\.launch/i.test(msg)) {
122
- throw new Error(CHROMIUM_MISSING_HINT);
123
- }
124
- throw err;
115
+ const hint = chromiumLaunchHint(msg);
116
+ throw hint !== undefined ? new Error(hint) : err;
125
117
  }
126
118
  };
127
119
  }
120
+ /**
121
+ * Turn Playwright's raw launch error into the one command that fixes it, or undefined when it is
122
+ * not a missing-browser failure. Shared by the pooled and the drive launch, so `reticle verify` on
123
+ * a fresh machine gets the same advice as a lease.
124
+ */
125
+ export function chromiumLaunchHint(msg) {
126
+ // Checked FIRST: Playwright's host-requirement validation error also contains
127
+ // "browserType.launch", so the generic check below would otherwise misdiagnose it as a
128
+ // missing binary and send the user through a fix that changes nothing.
129
+ if (/host system is missing dependencies/i.test(msg))
130
+ return CHROMIUM_MISSING_DEPS_HINT;
131
+ if (/executable doesn.?t exist|playwright install|browsertype\.launch/i.test(msg)) {
132
+ return CHROMIUM_MISSING_HINT;
133
+ }
134
+ return undefined;
135
+ }
128
136
  const MAX_CONTEXTS_CEILING = 8;
129
137
  const MAX_CONTEXTS_FLOOR = 1;
130
138
  /**
@@ -34,6 +34,8 @@ export interface PooledPage {
34
34
  * reports dispatched/settled while the styles never ran.
35
35
  */
36
36
  hover?(x: number, y: number): Promise<void>;
37
+ /** Evaluate a script in the page's current document. OPTIONAL: without it no reader is injected. */
38
+ evaluate?(script: string): Promise<unknown>;
37
39
  /** Add an init script to run after document creation but before any page scripts run. */
38
40
  addInitScript?<Arg>(script: ((arg: Arg) => void) | string, arg?: Arg): Promise<InitScriptHandle | void>;
39
41
  /**
@@ -2,7 +2,7 @@ import { type SeedStorage } from '@reticlehq/core';
2
2
  import type { InitScriptHandle, PooledContext, PooledCookie, PooledPage } from './pool-contract.js';
3
3
  export declare function targetOriginOf(navUrl: string): string | undefined;
4
4
  export declare function normalizeCookies(cookies: SeedStorage['cookies'], navUrl: string): PooledCookie[];
5
- export interface StorageSeedResult {
5
+ interface StorageSeedResult {
6
6
  handle?: InitScriptHandle;
7
7
  checkError?: () => void;
8
8
  }
@@ -21,3 +21,4 @@ export interface StorageSeedResult {
21
21
  * has resolved, ensuring one-time semantics (reloads or future navigations do not reapply the seed).
22
22
  */
23
23
  export declare function seedStorageInto(context: PooledContext, page: PooledPage, targetUrl: string, seed: SeedStorage): Promise<StorageSeedResult | void>;
24
+ export {};
@@ -0,0 +1,27 @@
1
+ export interface InjectedConnect {
2
+ url: string;
3
+ /** Absent when this daemon runs without a pairing token; the bridge then asks for none. */
4
+ token?: string;
5
+ }
6
+ /**
7
+ * The connect options a page is given when WE supply the connection rather than the app.
8
+ *
9
+ * One builder for both injection paths — this one, and re-pointing an SDK a hosted preview already
10
+ * ships (`real-input.ts`) — so the two cannot come to disagree about what a daemon-driven page needs.
11
+ */
12
+ export declare function injectedConnectArgs(opts: InjectedConnect): Record<string, unknown>;
13
+ /**
14
+ * The script for a page: install the SDK if the page has none, then connect it to this daemon.
15
+ *
16
+ * The guard is on the SINGLETON, not on a timer: a page that loaded its own SDK already holds
17
+ * `__reticleInstance`, and evaluating a second copy would register a second session for one tab.
18
+ * `connect` is a no-op once connected, so calling it on the page's own instance is safe.
19
+ */
20
+ export declare function zeroInstallScript(bundle: string, opts: InjectedConnect): string;
21
+ /**
22
+ * The single-file build, or undefined when this install has none.
23
+ *
24
+ * Read once and kept: it is ~450KB and identical for every lease. Absent means an older browser
25
+ * package or a broken install, and the caller then behaves exactly as it did before this existed.
26
+ */
27
+ export declare function readReaderBundle(): string | undefined;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The zero-install reader: how a page whose app never ran `init` still reaches a verdict.
3
+ *
4
+ * `@reticlehq/browser` builds itself into one file (`dist/reticle-inject.js`). The daemon reads that
5
+ * file as TEXT and evaluates it in a leased page that never connected, so the server never imports DOM
6
+ * code and the page needs no build step. What comes back is an ordinary session that reports no
7
+ * framework adapter and no source mapping, which is the honest description of what it can see.
8
+ */
9
+ import { readFileSync } from 'node:fs';
10
+ import { createRequire } from 'node:module';
11
+ /** The subpath `@reticlehq/browser` exports its single-file build under. */
12
+ const READER_SPECIFIER = '@reticlehq/browser/inject';
13
+ /**
14
+ * The connect options a page is given when WE supply the connection rather than the app.
15
+ *
16
+ * One builder for both injection paths — this one, and re-pointing an SDK a hosted preview already
17
+ * ships (`real-input.ts`) — so the two cannot come to disagree about what a daemon-driven page needs.
18
+ */
19
+ export function injectedConnectArgs(opts) {
20
+ return {
21
+ allowNonLocalhost: true,
22
+ ...(opts.token === undefined ? {} : { token: opts.token }),
23
+ url: opts.url,
24
+ };
25
+ }
26
+ /**
27
+ * The script for a page: install the SDK if the page has none, then connect it to this daemon.
28
+ *
29
+ * The guard is on the SINGLETON, not on a timer: a page that loaded its own SDK already holds
30
+ * `__reticleInstance`, and evaluating a second copy would register a second session for one tab.
31
+ * `connect` is a no-op once connected, so calling it on the page's own instance is safe.
32
+ */
33
+ export function zeroInstallScript(bundle, opts) {
34
+ const args = JSON.stringify(injectedConnectArgs(opts));
35
+ return `(() => {\nif (!globalThis.__reticleInstance) {\n${bundle}\n}\nglobalThis.__reticleInstance.connect(${args});\n})();`;
36
+ }
37
+ let cached;
38
+ /**
39
+ * The single-file build, or undefined when this install has none.
40
+ *
41
+ * Read once and kept: it is ~450KB and identical for every lease. Absent means an older browser
42
+ * package or a broken install, and the caller then behaves exactly as it did before this existed.
43
+ */
44
+ export function readReaderBundle() {
45
+ if (cached === undefined) {
46
+ try {
47
+ cached = readFileSync(createRequire(import.meta.url).resolve(READER_SPECIFIER), 'utf8');
48
+ }
49
+ catch {
50
+ cached = null;
51
+ }
52
+ }
53
+ return cached ?? undefined;
54
+ }
@@ -93,6 +93,11 @@ export const CHANNEL_OF_PREFIX = {
93
93
  // channel at all.
94
94
  anim: ProtocolChannel.UI,
95
95
  dialog: ProtocolChannel.UI,
96
+ // A form field's value is on the subject's surface in exactly the sense `ui` means: it is what
97
+ // the person is looking at and typing into. The protocol has no `input` channel and does not
98
+ // want one — a field is a rendered thing, and the observation carries the field's NAME and
99
+ // length, never its contents for a password or a card.
100
+ field: ProtocolChannel.UI,
96
101
  focus: ProtocolChannel.UI,
97
102
  render: ProtocolChannel.UI,
98
103
  reveal: ProtocolChannel.UI,
@@ -124,6 +129,7 @@ export const NOT_EVIDENCE = {
124
129
  context: "Reticle's own context tool opening, not something the application did",
125
130
  flow: 'a flow being recorded by the tool',
126
131
  human: 'a person driving the HUD: pause, resume, a mark. The operator, not the subject',
132
+ hud: "usage telemetry about Reticle's own panel, taken off before the buffer. The tool, not the subject",
127
133
  page: "the SDK's own health report about the page it is inside",
128
134
  sdk: 'the SDK itself failing, which is a fact about the observer',
129
135
  transport: "the tool's own buffer overflowing",
@@ -12,8 +12,8 @@
12
12
  export interface DevCommand {
13
13
  /** The literal shell command, e.g. `pnpm run dev`. */
14
14
  command: string;
15
- /** The package.json script it runs. */
16
- script: string;
15
+ /** The package.json script it runs. Absent when the command runs a CLI directly (`npx tauri dev`). */
16
+ script?: string;
17
17
  /** The port the script PINS, when it pins one. Absent means the tool picks — never a guess. */
18
18
  port?: number;
19
19
  }