@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
@@ -5,14 +5,19 @@
5
5
  *
6
6
  * Headless by default — the pool exists for fault-tolerant headless multi-agent testing.
7
7
  */
8
+ import { startJsCoverage, takeJsCoverage } from '../input/js-coverage.js';
8
9
  import { BrowserLaunchKind } from '@reticlehq/core/telemetry';
9
10
  import { ActionType, HIDE_RETICLE_CHROME_CSS, RETICLE_OVERLAY_SELECTOR } from '@reticlehq/core';
10
11
  import { launchChromium } from '../../launch-chromium.js';
12
+ import { pageViewportOptions } from '../../chromium-launch-options.js';
11
13
  import { getSessionMetrics } from '../../telemetry/session-metrics.js';
12
14
  import { classifyConnectFailure } from '../../telemetry/connect-failure.js';
13
15
  import { chromiumInstallCommand, chromiumInstallDepsCommand, bundledPlaywrightVersion, } from '../../command/cli/doctor/browser/chromium-hint.js';
14
16
  import { installNetworkMocks } from '../input/network-mock.js';
15
- import { performGesture } from '../input/real-input.js';
17
+ import { performGesture, withChromePassThrough, } from '../input/real-input.js';
18
+ import { widenDocumentCsp } from './csp-widen.js';
19
+ import { contextEmulationOf } from './lease-emulation.js';
20
+ import { determinismConfigOf, installDeterminism } from './determinism.js';
16
21
  /** A key addresses focus, not a point; the gesture driver takes a box for every action. */
17
22
  const NO_BOX = { x: 0, y: 0, width: 0, height: 0 };
18
23
  const sleepFor = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -91,20 +96,48 @@ export function gotoOptions(timeoutMs) {
91
96
  ...(timeoutMs === undefined ? {} : { timeout: timeoutMs }),
92
97
  };
93
98
  }
94
- function wrapBrowser(browser) {
99
+ /**
100
+ * Reload with the cache ignored, as Cmd+Shift+R does (#1785).
101
+ *
102
+ * Playwright's `page.reload()` is a plain reload: a module with a fresh cache entry is not fetched
103
+ * again. The DevTools protocol's `Page.reload { ignoreCache: true }` is the browser's own hard
104
+ * reload. The pool launches Chromium, so the protocol is always there.
105
+ */
106
+ async function reloadIgnoringCache(page) {
107
+ const cdp = await page.context().newCDPSession(page);
108
+ try {
109
+ await cdp.send('Page.reload', { ignoreCache: true });
110
+ }
111
+ finally {
112
+ await cdp.detach();
113
+ }
114
+ }
115
+ function wrapBrowser(browser, headless) {
95
116
  return {
96
117
  isConnected: () => browser.isConnected(),
97
118
  newContext: async (opts) => {
98
- // Media and viewport ride on the context, so the first paint of the first page has them.
99
- const { ignoreHTTPSErrors, ...emulate } = opts ?? {};
100
- const contextOpts = {
119
+ // Media, viewport and pointer ride on the context, so the first paint of the first page has
120
+ // them. `pointer` becomes `hasTouch` here — see contextEmulationOf.
121
+ const { ignoreHTTPSErrors, jsCoverage, ...emulate } = opts ?? {};
122
+ const covering = new WeakSet();
123
+ // A deterministic context needs a fixed viewport: a density is not set on a window's own size.
124
+ const deterministic = emulate.deterministic;
125
+ const context = await browser.newContext({
101
126
  ...(true === ignoreHTTPSErrors ? { ignoreHTTPSErrors: true } : {}),
102
- ...emulate,
103
- };
104
- const context = await browser.newContext(0 < Object.keys(contextOpts).length ? contextOpts : undefined);
127
+ ...contextEmulationOf(emulate),
128
+ ...pageViewportOptions(headless || deterministic !== undefined, emulate.viewport),
129
+ });
130
+ // On the context, so every page and frame of the lease gets it before its first script.
131
+ if (deterministic !== undefined) {
132
+ await context.addInitScript(installDeterminism, determinismConfigOf(deterministic));
133
+ }
105
134
  return {
106
135
  newPage: async () => {
107
136
  const page = await context.newPage();
137
+ // Before the first navigation, so the code that runs while the page loads is counted.
138
+ if (true === jsCoverage) {
139
+ await startJsCoverage(page, covering);
140
+ }
108
141
  return {
109
142
  goto: (url, opts) => page.goto(url, gotoOptions(opts?.timeoutMs)),
110
143
  close: () => page.close(),
@@ -121,11 +154,13 @@ function wrapBrowser(browser) {
121
154
  },
122
155
  // Three moves, same as performGesture: a single move to the center can be a no-op if
123
156
  // the pointer was already there, and CSS :hover needs a native hit-test to apply.
124
- hover: async (x, y) => {
157
+ // Through Reticle's own UI, like every other real gesture (#992).
158
+ hover: (x, y) => withChromePassThrough(page, async () => {
125
159
  await page.mouse.move(x, y);
126
160
  await page.mouse.move(x + 1, y);
127
161
  await page.mouse.move(x, y);
128
- },
162
+ }),
163
+ reloadIgnoringCache: () => reloadIgnoringCache(page),
129
164
  // The same driver `reticle drive` presses with, so a held key and a chord read alike.
130
165
  emulateMedia: (media) => page.emulateMedia(media),
131
166
  press: (args) => performGesture(page, ActionType.PRESS, NO_BOX, args, sleepFor),
@@ -145,10 +180,24 @@ function wrapBrowser(browser) {
145
180
  });
146
181
  },
147
182
  setViewport: (size) => page.setViewportSize(size),
183
+ jsCoverage: {
184
+ start: () => startJsCoverage(page, covering),
185
+ take: () => covering.has(page) ? takeJsCoverage(page, covering) : Promise.resolve(undefined),
186
+ },
148
187
  bringToFront: () => page.bringToFront(),
149
188
  onCrash: (handler) => page.on('crash', handler),
150
189
  onConsole: (handler) => page.on('console', (msg) => handler(msg.text())),
151
- onDialog: (handler) => page.on('dialog', (dialog) => handler({ message: dialog.message(), dismiss: () => dialog.dismiss() })),
190
+ // Playwright's `pageerror` carries the full exception even when the page's own window
191
+ // listener never ran — the import-time throw that lands before any SDK is injected.
192
+ onPageError: (handler) => page.on('pageerror', (error) => handler({
193
+ message: error.message,
194
+ ...(error.stack === undefined ? {} : { stack: error.stack }),
195
+ })),
196
+ onDialog: (handler) => page.on('dialog', (dialog) => handler({
197
+ message: dialog.message(),
198
+ kind: dialog.type(),
199
+ dismiss: () => dialog.dismiss(),
200
+ })),
152
201
  addInitScript: async (script, arg) => {
153
202
  const handle = (await page.addInitScript(script, arg));
154
203
  const dispose = handle?.dispose;
@@ -162,6 +211,10 @@ function wrapBrowser(browser) {
162
211
  addCookies: (cookies) => context.addCookies(cookies),
163
212
  grantPermissions: (permissions, opts) => context.grantPermissions(permissions, opts),
164
213
  clearPermissions: () => context.clearPermissions(),
214
+ // On the context, so a page route that falls back still reaches it. See csp-widen.ts.
215
+ widenCsp: async (origin, onWidened) => {
216
+ await context.route(ANY_URL, (route) => widenDocumentCsp(route, origin, onWidened));
217
+ },
165
218
  close: () => context.close(),
166
219
  };
167
220
  },
@@ -203,11 +256,13 @@ function pathFromPlaywrightError(msg) {
203
256
  // Playwright puts the path at the end of the line, and a Windows path can hold a space
204
257
  // (for example C:\Users\Jo Doe). Read to the end of the line and trim the result.
205
258
  const found = /executable doesn.?t exist at (.+)$/im.exec(msg);
206
- if (null === found)
259
+ if (null === found) {
207
260
  return undefined;
261
+ }
208
262
  const captured = found[1];
209
- if (undefined === captured)
263
+ if (undefined === captured) {
210
264
  return undefined;
265
+ }
211
266
  const path = captured.trim();
212
267
  return '' === path ? undefined : path;
213
268
  }
@@ -233,7 +288,7 @@ export function playwrightLauncher(opts = {}) {
233
288
  // number that actually costs memory and the one that explains a slow machine.
234
289
  const settle = getSessionMetrics().recordConnectAttempt(BrowserLaunchKind.POOLED);
235
290
  try {
236
- const browser = wrapBrowser(await launchChromium(chromium, headless));
291
+ const browser = wrapBrowser(await launchChromium(chromium, headless), headless);
237
292
  settle();
238
293
  return browser;
239
294
  }
@@ -254,8 +309,9 @@ export function chromiumLaunchHint(msg) {
254
309
  // Checked FIRST: Playwright's host-requirement validation error also contains
255
310
  // "browserType.launch", so the generic check below would otherwise misdiagnose it as a
256
311
  // missing binary and send the user through a fix that changes nothing.
257
- if (/host system is missing dependencies/i.test(msg))
312
+ if (/host system is missing dependencies/i.test(msg)) {
258
313
  return CHROMIUM_MISSING_DEPS_HINT;
314
+ }
259
315
  if (/executable doesn.?t exist|playwright install|browsertype\.launch/i.test(msg)) {
260
316
  return chromiumMissingHint(pathFromPlaywrightError(msg));
261
317
  }
@@ -7,6 +7,14 @@
7
7
  */
8
8
  import type { RealInputArgs, RealInputResult } from '../input/real-input.js';
9
9
  import type { LeaseEmulation, LeaseMedia } from './lease-emulation.js';
10
+ import type { ScriptCoverage } from '../input/js-coverage.js';
11
+ /** JS coverage on one page: start it, and take what ran since the previous take. */
12
+ export interface PooledCoverage {
13
+ /** False when the page cannot measure coverage. */
14
+ start(): Promise<boolean>;
15
+ /** Undefined when coverage was not running; the first take does not start it. */
16
+ take(): Promise<ScriptCoverage[] | undefined>;
17
+ }
10
18
  /** The minimal page surface the pool drives. Real Playwright `Page` satisfies this. */
11
19
  export interface PooledPage {
12
20
  goto(url: string, opts?: {
@@ -21,6 +29,14 @@ export interface PooledPage {
21
29
  * "the page said nothing", never as "the page dialled correctly".
22
30
  */
23
31
  onConsole?(handler: (text: string) => void): void;
32
+ /**
33
+ * Fires for each error the page threw with no handler for it — an import-time module throw
34
+ * included. OPTIONAL like `onConsole`: a fake without it makes the pool hear nothing, which
35
+ * degrades to the old behaviour instead of inventing an error nobody reported. The handler must
36
+ * be installed BEFORE the first navigation — an import-time throw lands during `goto`, and a
37
+ * listener attached after it reads a broken page as healthy (#1966).
38
+ */
39
+ onPageError?(handler: (error: PooledPageError) => void): void;
24
40
  /**
25
41
  * Capture the page as a PNG, or a JPEG at `jpegQuality` (a live picture, where size matters more). OPTIONAL, like `onConsole`: a fake that does not implement it makes
26
42
  * the pool report "no provider", which is the correct degradation — an absent screenshotter must
@@ -39,6 +55,11 @@ export interface PooledPage {
39
55
  * page without it keeps the in-page dispatcher, whose synthetic Tab moves no focus.
40
56
  */
41
57
  press?(args: RealInputArgs): Promise<RealInputResult>;
58
+ /**
59
+ * Reload the page with the browser cache ignored for the document and every subresource, as
60
+ * Cmd+Shift+R does. OPTIONAL: without it a hard reload can only re-fetch the document (#1785).
61
+ */
62
+ reloadIgnoringCache?(): Promise<void>;
42
63
  /** Set prefers-color-scheme and prefers-reduced-motion. OPTIONAL: without it the media stay. */
43
64
  emulateMedia?(media: LeaseMedia): Promise<void>;
44
65
  /** Evaluate a script in the page's current document. OPTIONAL: without it no reader is injected. */
@@ -84,13 +105,28 @@ export interface PooledPage {
84
105
  * hidden, and a hidden tab throttles timers and rAF so nothing on it verifies (#1351).
85
106
  */
86
107
  bringToFront?(): Promise<void>;
108
+ /**
109
+ * JS coverage of this page. OPTIONAL, like `installMocks`: a page without it makes the
110
+ * coverage tool refuse rather than report that no code ran.
111
+ */
112
+ jsCoverage?: PooledCoverage;
87
113
  }
88
114
  /** A native dialog the page opened, handed to the pool so it can be dismissed instead of left blocking. */
89
115
  export interface PooledDialog {
90
116
  /** The dialog's message text — kept for diagnostics (`BrowserPool#lastDialogMessage`). */
91
117
  readonly message: string;
118
+ /** `alert`, `confirm`, `prompt` or `beforeunload`, as the engine names it. Absent: not known. */
119
+ readonly kind?: string;
92
120
  dismiss(): Promise<void>;
93
121
  }
122
+ /**
123
+ * One uncaught error the page threw, as the engine reported it. The message is the exception text
124
+ * without the console's `Uncaught ` prefix; the stack is present when the engine had one.
125
+ */
126
+ export interface PooledPageError {
127
+ readonly message: string;
128
+ readonly stack?: string;
129
+ }
94
130
  export interface InitScriptHandle {
95
131
  dispose(): Promise<void>;
96
132
  }
@@ -117,6 +153,8 @@ export interface PooledMockRule {
117
153
  contentType?: string;
118
154
  delayMs?: number;
119
155
  abort?: boolean;
156
+ /** Send the request on to this origin; the path and query stay (see network-mock.ts). */
157
+ forwardTo?: string;
120
158
  }
121
159
  /** An isolated browsing context (cookies/storage). Real Playwright `BrowserContext` satisfies this. */
122
160
  export interface PooledContext {
@@ -133,13 +171,23 @@ export interface PooledContext {
133
171
  }): Promise<void>;
134
172
  /** Drop every permission granted on this context. OPTIONAL, for the same reason. */
135
173
  clearPermissions?(): Promise<void>;
174
+ /**
175
+ * Add `origin` to the `connect-src` of each top document's CSP, and call `onWidened` when that
176
+ * changed a response (see `csp-widen.ts`). OPTIONAL: without it a deployed page with a strict CSP
177
+ * blocks the reader, and the lease says `sdk_never_dialled`, which is true.
178
+ */
179
+ widenCsp?(origin: string, onWidened: () => void): Promise<void>;
136
180
  }
137
181
  /** The launched browser. Real Playwright `Browser` satisfies this. */
138
182
  export interface PooledBrowser {
139
183
  isConnected(): boolean;
140
- /** `ignoreHTTPSErrors` accepts a self-signed or local-CA certificate for this context only. */
184
+ /**
185
+ * `ignoreHTTPSErrors` accepts a self-signed or local-CA certificate for this context only.
186
+ * `jsCoverage` starts JS coverage on each page before its first script runs.
187
+ */
141
188
  newContext(opts?: {
142
189
  ignoreHTTPSErrors?: boolean;
190
+ jsCoverage?: boolean;
143
191
  } & LeaseEmulation): Promise<PooledContext>;
144
192
  close(): Promise<void>;
145
193
  /** Fires when the browser process dies/crashes so the pool can relaunch on the next acquire. */
@@ -2,7 +2,37 @@
2
2
  * The pool's lease handle and lease record, its options, and its limits: the types and constants
3
3
  * `BrowserPool` is built from.
4
4
  */
5
- import type { InitScriptHandle, Launcher, PooledBrowser, PooledContext, PooledPage } from './pool-contract.js';
5
+ import type { InitScriptHandle, Launcher, PooledBrowser, PooledContext, PooledDialog, PooledPage, PooledPageError } from './pool-contract.js';
6
+ import type { SeedStorage } from '@reticlehq/core';
7
+ import type { LeaseEmulation } from './lease-emulation.js';
8
+ /** What one `BrowserPool#acquire` asks for. Every field is optional. */
9
+ export interface AcquireOptions {
10
+ signal?: AbortSignal;
11
+ /**
12
+ * `'wait'` (the default) queues behind the cap. `'refuse'` is for a caller that has a person
13
+ * or an agent waiting on the answer and no way to see a queue: it is told the pool is full.
14
+ */
15
+ whenFull?: 'wait' | 'refuse';
16
+ sessionId?: string;
17
+ seedStorage?: SeedStorage;
18
+ owner?: string;
19
+ /** In a browser with a window the person can watch. */
20
+ headed?: boolean;
21
+ /**
22
+ * JavaScript installed before any page script runs, for this lease only. A view built for a
23
+ * desktop shell calls bindings the shell injects (`window.go`, `window.runtime`, a preload
24
+ * object) on mount; a stub here is what lets it reach its data path in a leased tab.
25
+ */
26
+ initScript?: string;
27
+ /** Granted on the lease's origin before the first navigation, so the first render sees them. */
28
+ permissions?: readonly string[];
29
+ /** Accept a self-signed or local-CA dev certificate for this lease's context only (#1255). */
30
+ ignoreHTTPSErrors?: boolean;
31
+ /** Media and viewport set on the context, so the first paint already has them. */
32
+ emulate?: LeaseEmulation;
33
+ /** Start JS coverage before the page's first script, so load-time code is counted. */
34
+ jsCoverage?: boolean;
35
+ }
6
36
  /** A leased context+page for one flow. `release` frees the slot and closes the context. */
7
37
  export interface Lease {
8
38
  readonly sessionId: string;
@@ -46,8 +76,32 @@ export interface BrowserPoolOptions {
46
76
  /**
47
77
  * The zero-install reader, built where the daemon knows its own port and pairing token. A thunk so
48
78
  * the ~450KB build is only read if some page ever needs it; undefined when there is none to give.
79
+ * Called with the lease url, because a page off loopback gets its own nonce, not the token.
80
+ */
81
+ zeroInstallScript?: (url: string) => string | undefined;
82
+ /**
83
+ * The WebSocket origin the reader dials (`ws://localhost:<port>`). A lease on a page that is not
84
+ * on loopback adds it to the page's CSP `connect-src` (#2016). Absent: no page CSP is changed.
49
85
  */
50
- zeroInstallScript?: () => string | undefined;
86
+ daemonOrigin?: string;
87
+ /**
88
+ * Sink for uncaught page errors — an import-time throw the SDK was never installed in time to
89
+ * see (#1966). Called with the lease id, so the wiring can reach the session that connects for
90
+ * this lease later. Optional: without it the pool hears errors and drops them, which is the
91
+ * behaviour the repo had before the sink existed.
92
+ */
93
+ onPageError?: (leaseId: string, error: PooledPageError) => void;
94
+ /**
95
+ * Sink for lease release — manual release, the reaper, and a crash reclaim all funnel through
96
+ * it. Lets the wiring drop state it kept FOR that lease (the page-error buffer) instead of
97
+ * holding it for the life of the daemon. Optional: no sink, nothing to clean up.
98
+ */
99
+ onLeaseClosed?: (leaseId: string) => void;
100
+ /**
101
+ * Sink for each native dialog the pool dismissed, with the lease id. The dismissal is an answer
102
+ * of "no" on the app's behalf, so the wiring records it for the verdict (#1350). Optional.
103
+ */
104
+ onDialog?: (leaseId: string, dialog: Pick<PooledDialog, 'kind' | 'message'>) => void;
51
105
  /**
52
106
  * Launches a browser with a window, for a lease somebody wants to watch. Launched only when the
53
107
  * first headed lease is asked for. Absent: a headed lease is refused.
@@ -106,6 +160,8 @@ export interface ActiveLease {
106
160
  * context for "why did the page look frozen for a moment", not a log an agent needs to replay.
107
161
  */
108
162
  lastDialogMessage?: string;
163
+ /** Why the last screenshot of this lease failed, if it did. Cleared by the next one that works. */
164
+ captureError?: string;
109
165
  /**
110
166
  * The disposable handle of the caller's init script, when the lease was opened with one — a stub
111
167
  * of the bindings a desktop shell injects. Disposed with the lease, so a reload or a later
@@ -123,6 +179,18 @@ export interface ActiveLease {
123
179
  permissions: readonly string[];
124
180
  /** Whether its context accepts any TLS certificate (#1255). Fixed when the context is made. */
125
181
  ignoresHTTPSErrors: boolean;
182
+ /** `widenedFor`: the origin added to this page's CSP `connect-src`, once one was (#2016). */
183
+ csp: {
184
+ widenedFor?: string;
185
+ };
126
186
  }
127
187
  /** Whether the page's document has not finished loading. A page that cannot be asked counts as loaded. */
128
188
  export declare function pageLoading(page: PooledPage): Promise<boolean>;
189
+ /**
190
+ * The HTTP status a navigation ended on, or undefined when the page shape reports none.
191
+ *
192
+ * Real Playwright answers `goto` with a response object exposing `status()`; the fakes hand back
193
+ * whatever they like. A status accessor that THROWS says nothing usable, so it reads as absent
194
+ * rather than breaking the lease that is otherwise fine.
195
+ */
196
+ export declare function navStatusOf(navRes: unknown): number | undefined;
@@ -47,3 +47,26 @@ export async function pageLoading(page) {
47
47
  const state = await page.evaluate('document.readyState');
48
48
  return 'string' === typeof state && state !== 'complete';
49
49
  }
50
+ /**
51
+ * The HTTP status a navigation ended on, or undefined when the page shape reports none.
52
+ *
53
+ * Real Playwright answers `goto` with a response object exposing `status()`; the fakes hand back
54
+ * whatever they like. A status accessor that THROWS says nothing usable, so it reads as absent
55
+ * rather than breaking the lease that is otherwise fine.
56
+ */
57
+ export function navStatusOf(navRes) {
58
+ if (null === navRes || 'object' !== typeof navRes || !('status' in navRes)) {
59
+ return undefined;
60
+ }
61
+ const s = navRes.status;
62
+ if ('function' === typeof s) {
63
+ try {
64
+ const code = s.call(navRes);
65
+ return 'number' === typeof code ? code : undefined;
66
+ }
67
+ catch {
68
+ return undefined;
69
+ }
70
+ }
71
+ return 'number' === typeof s ? s : undefined;
72
+ }
@@ -25,6 +25,14 @@ export declare function zeroInstallScript(bundle: string, opts: InjectedConnect)
25
25
  export declare class NotHtmlDocumentError extends Error {
26
26
  constructor();
27
27
  }
28
+ /**
29
+ * Run the reader in a leased page now, and again before the page's own scripts on each later load.
30
+ * False when there is no reader or the page cannot run one; throws when the page is not HTML.
31
+ */
32
+ export declare function injectReaderInto(page: {
33
+ evaluate?(script: string): Promise<unknown>;
34
+ addInitScript?(script: string): unknown;
35
+ }, script: string | undefined): Promise<boolean>;
28
36
  /**
29
37
  * The single-file build, or undefined when this install has none.
30
38
  *
@@ -35,8 +35,84 @@ const HTML_CONTENT_TYPES = ['text/html', 'application/xhtml+xml'];
35
35
  * reads `document.contentType`, because an init script runs before the parser makes the root
36
36
  * element. The check binds no name, so it cannot collide with a name that the bundle declares.
37
37
  */
38
+ /*
39
+ * Run in the top frame only. Playwright runs an init script in every frame, and a rich-text editor's
40
+ * editing area is an iframe whose <body> IS the document being edited: the SDK mounted its HUD there,
41
+ * and saving the form stored the HUD markup in the app's data (Dolibarr product and project
42
+ * descriptions). The top frame's SDK already reads same-origin iframes, so a child frame needs nothing.
43
+ * A context with no `top` (a test sandbox) counts as the top frame.
44
+ */
45
+ const TOP_FRAME_ONLY = 'if (globalThis.top !== undefined && globalThis.self !== undefined && globalThis.top !== globalThis.self) return;';
38
46
  const NOT_HTML_GUARD = `if (globalThis.document !== undefined && !${JSON.stringify(HTML_CONTENT_TYPES)}.includes(globalThis.document.contentType)) ` +
39
47
  `return ${JSON.stringify(READER_NOT_HTML)};`;
48
+ /*
49
+ * Keep what the page says before the SDK's observers exist, and hand it to them after `connect()`.
50
+ *
51
+ * The observers install in `connect()`, which waits for DOMContentLoaded (below). The app's start-up
52
+ * scripts run before that, so a console error or an uncaught error while the page loaded was not
53
+ * seen, and a page that crashed at start-up gave a clean capture. Only the reader does this: it is
54
+ * installed before the page's scripts, and an app's own SDK connects from inside them.
55
+ *
56
+ * Kept in the order the page said it: `console.error` calls, uncaught script errors and unhandled
57
+ * rejections. After `connect()`, each console error is said again through the patched console with
58
+ * the native print off, so the console shows it once. Each error event is dispatched again on
59
+ * `window`, where the SDK listens. The app's own error listeners see a replayed error a second time.
60
+ * A resource that failed to load is not kept: the network observer reads it from resource timing.
61
+ */
62
+ const EARLY_KEEP = 'if ("function" === typeof globalThis.addEventListener && globalThis.console !== undefined) {\n' +
63
+ 'const early = { said: [], replaying: false };\n' +
64
+ 'globalThis.__reticleEarly = early;\n' +
65
+ 'const nativeError = globalThis.console.error;\n' +
66
+ 'globalThis.console.error = function (...args) {\n' +
67
+ ' if (early.said !== null) early.said.push(args);\n' +
68
+ ' if (!early.replaying) return nativeError.apply(this, args);\n' +
69
+ '};\n' +
70
+ 'early.keep = (e) => { if (early.said !== null && (e.type !== "error" || e instanceof globalThis.ErrorEvent)) early.said.push(e); };\n' +
71
+ 'globalThis.addEventListener("error", early.keep, true);\n' +
72
+ 'globalThis.addEventListener("unhandledrejection", early.keep);\n' +
73
+ '}';
74
+ const EARLY_REPLAY = 'const early = globalThis.__reticleEarly;\n' +
75
+ 'if (early !== undefined) {\n' +
76
+ ' globalThis.__reticleEarly = undefined;\n' +
77
+ ' globalThis.removeEventListener("error", early.keep, true);\n' +
78
+ ' globalThis.removeEventListener("unhandledrejection", early.keep);\n' +
79
+ ' const said = early.said;\n' +
80
+ ' early.said = null;\n' +
81
+ ' for (const item of said) {\n' +
82
+ ' if (Array.isArray(item)) {\n' +
83
+ ' early.replaying = true;\n' +
84
+ ' try { globalThis.console.error(...item); } finally { early.replaying = false; }\n' +
85
+ ' } else if ("error" === item.type) {\n' +
86
+ ' globalThis.dispatchEvent(new globalThis.ErrorEvent("error", { message: item.message, filename: item.filename, lineno: item.lineno, colno: item.colno, error: item.error }));\n' +
87
+ ' } else {\n' +
88
+ ' globalThis.dispatchEvent(new globalThis.PromiseRejectionEvent("unhandledrejection", { promise: item.promise, reason: item.reason }));\n' +
89
+ ' }\n' +
90
+ ' }\n' +
91
+ '}';
92
+ /*
93
+ * Connect once the DOM exists. The reader also runs as an init script on every later document of the
94
+ * lease, before the parser makes <head> and <body>. `connect()` mounts page UI before it dials the
95
+ * bridge, so it threw there and never dialled: every full navigation after the first page lost the
96
+ * lease's session (#1897). The bundle still loads at once, so the observers start early.
97
+ */
98
+ const CONNECT_WHEN_DOM_READY = (args) => `const connect = () => { globalThis.__reticleInstance.connect(${args}); ${EARLY_REPLAY} };\n` +
99
+ `if (globalThis.document !== undefined && 'loading' === globalThis.document.readyState) ` +
100
+ `globalThis.document.addEventListener('DOMContentLoaded', connect, { once: true });\n` +
101
+ `else connect();`;
102
+ /** Where every zod copy in a page keeps its shared settings (`z.config`). */
103
+ const ZOD_CONFIG = 'globalThis.__zod_globalConfig';
104
+ /*
105
+ * Turn zod `jitless` on for the page, unless the page set it itself.
106
+ *
107
+ * The reader is evaluated over CDP, where `new Function` works even on a page whose CSP forbids
108
+ * `unsafe-eval`. Zod's eval probe then answered true and cached it, and later parses compiled a fast
109
+ * path with `new Function` in the page: CSP threw, and the session stopped answering (#2016,
110
+ * nextjs.org). Zod reads `jitless` when a schema is made, and the SDK makes some schemas later, also
111
+ * inside a CDP evaluate. So the setting stays on.
112
+ * ponytail: the page's own zod then parses without its compiled fast path. Results are the same;
113
+ * only parse speed changes. Scope it to the bundle's own zod copy if that speed is ever seen.
114
+ */
115
+ const ZOD_JITLESS = `(${ZOD_CONFIG} ??= {}).jitless ??= true;`;
40
116
  /**
41
117
  * The script for a page: install the SDK if the page has none, then connect it to this daemon.
42
118
  *
@@ -47,7 +123,7 @@ const NOT_HTML_GUARD = `if (globalThis.document !== undefined && !${JSON.stringi
47
123
  */
48
124
  export function zeroInstallScript(bundle, opts) {
49
125
  const args = JSON.stringify(injectedConnectArgs(opts));
50
- return `(() => {\n${NOT_HTML_GUARD}\nif (!globalThis.__reticleInstance) {\n${bundle}\n}\nglobalThis.__reticleInstance.connect(${args});\n})();`;
126
+ return `(() => {\n${TOP_FRAME_ONLY}\n${NOT_HTML_GUARD}\nif (!globalThis.__reticleInstance) {\n${EARLY_KEEP}\n${ZOD_JITLESS}\n${bundle}\n}\n${CONNECT_WHEN_DOM_READY(args)}\n})();`;
51
127
  }
52
128
  /** The page is not an HTML document, so the lease did not give it the zero-install reader. */
53
129
  export class NotHtmlDocumentError extends Error {
@@ -56,6 +132,20 @@ export class NotHtmlDocumentError extends Error {
56
132
  this.name = 'NotHtmlDocumentError';
57
133
  }
58
134
  }
135
+ /**
136
+ * Run the reader in a leased page now, and again before the page's own scripts on each later load.
137
+ * False when there is no reader or the page cannot run one; throws when the page is not HTML.
138
+ */
139
+ export async function injectReaderInto(page, script) {
140
+ if (script === undefined || page.evaluate === undefined) {
141
+ return false;
142
+ }
143
+ await page.addInitScript?.(script);
144
+ if (READER_NOT_HTML === (await page.evaluate(script))) {
145
+ throw new NotHtmlDocumentError();
146
+ }
147
+ return true;
148
+ }
59
149
  let cached;
60
150
  /**
61
151
  * The single-file build, or undefined when this install has none.
@@ -19,6 +19,15 @@ export interface DevCommand {
19
19
  /** The app's directory, when it is not the project root. The caller must run the command there. */
20
20
  directory?: string;
21
21
  }
22
+ /**
23
+ * The direct child folders of `directory` that are apps with a dev command, sorted by name: the web
24
+ * apps when there are any, every dev-script folder when there are none (see `preferWebApps`).
25
+ *
26
+ * Only for a folder with no package.json of its own. A task folder holds the app one level down, and
27
+ * no workspace file lists it, so `workspacePackageDirs` never finds it. `node_modules`, hidden
28
+ * folders and folders with no dev script are never candidates.
29
+ */
30
+ export declare function childDevApps(directory: string, read?: (path: string) => string | undefined, listDirs?: (path: string) => readonly string[], writable?: (path: string) => boolean): readonly string[];
22
31
  /**
23
32
  * The dev command for the project in `directory`, or undefined when there is not one to be sure of.
24
33
  *
@@ -35,7 +44,7 @@ export declare function detectDevCommand(directory: string, read?: (path: string
35
44
  * init's own workspace listing answers which directories to consider; the root's lockfile picks the
36
45
  * package manager, because a workspace package usually has no lockfile of its own.
37
46
  */
38
- export declare function detectDevCommandInProject(directory: string, read?: (path: string) => string | undefined, listDirs?: (path: string) => readonly string[]): DevCommand | undefined;
47
+ export declare function detectDevCommandInProject(directory: string, read?: (path: string) => string | undefined, listDirs?: (path: string) => readonly string[], writable?: (path: string) => boolean): DevCommand | undefined;
39
48
  /**
40
49
  * The command that wires THIS project for good: `init`, in the app's own folder, through the
41
50
  * one-off runner the project's package manager ships.
@@ -44,4 +53,4 @@ export declare function detectDevCommandInProject(directory: string, read?: (pat
44
53
  * time: `init` run in a folder that is not the app stops on a missing package.json, and a runner the
45
54
  * machine does not have is "command not found". npx whenever there is doubt — it ships with Node.
46
55
  */
47
- export declare function initCommandIn(directory: string, read?: (path: string) => string | undefined, listDirs?: (path: string) => readonly string[]): string;
56
+ export declare function initCommandIn(directory: string, read?: (path: string) => string | undefined, listDirs?: (path: string) => readonly string[], writable?: (path: string) => boolean): string;