@reticlehq/server 3.4.0 → 3.6.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 (350) hide show
  1. package/README.md +1 -1
  2. package/SKILL.md +16 -8
  3. package/dist/chromium-launch-options.d.ts +3 -1
  4. package/dist/chromium-launch-options.js +2 -1
  5. package/dist/command/cli/adhoc-verdict.d.ts +1 -0
  6. package/dist/command/cli/adhoc-verdict.js +6 -3
  7. package/dist/command/cli/answers/open-note.d.ts +2 -0
  8. package/dist/command/cli/answers/open-note.js +22 -0
  9. package/dist/command/cli/auth/cloud-session.d.ts +4 -4
  10. package/dist/command/cli/auth/device-flow.d.ts +2 -2
  11. package/dist/command/cli/cli-flow-commands.js +4 -8
  12. package/dist/command/cli/cli-parse.d.ts +1 -1
  13. package/dist/command/cli/cli-parse.js +13 -11
  14. package/dist/command/cli/cli-verify.d.ts +1 -1
  15. package/dist/command/cli/cli-verify.js +35 -25
  16. package/dist/command/cli/cloud-cli.js +110 -12
  17. package/dist/command/cli/cloud-login.d.ts +9 -1
  18. package/dist/command/cli/cloud-login.js +43 -8
  19. package/dist/command/cli/demo/demo-page.js +11 -3
  20. package/dist/command/cli/doctor/browser/chromium-hint.d.ts +46 -0
  21. package/dist/command/cli/doctor/browser/chromium-hint.js +99 -1
  22. package/dist/command/cli/drive/drive-attach.d.ts +27 -2
  23. package/dist/command/cli/drive/drive-attach.js +71 -4
  24. package/dist/command/cli/drive/drive-command.d.ts +2 -1
  25. package/dist/command/cli/drive/drive-command.js +13 -7
  26. package/dist/command/cli/lifecycle/daemon-lifecycle.js +4 -1
  27. package/dist/command/cli/ports/port-holder.d.ts +10 -0
  28. package/dist/command/cli/ports/port-holder.js +24 -0
  29. package/dist/command/cli/setup-mcp-cli.js +15 -5
  30. package/dist/command/cli/tutorial.d.ts +2 -2
  31. package/dist/command/cli/tutorial.js +6 -9
  32. package/dist/command/cli.d.ts +6 -0
  33. package/dist/command/cli.js +45 -23
  34. package/dist/command/daemon/binding/daemon-status-probe.d.ts +2 -0
  35. package/dist/command/daemon/binding/daemon-status-probe.js +1 -0
  36. package/dist/command/daemon/daemon-resolve.d.ts +14 -0
  37. package/dist/command/daemon/daemon-resolve.js +33 -2
  38. package/dist/command/setup/agent-writer.d.ts +1 -1
  39. package/dist/command/setup/agent-writer.js +3 -2
  40. package/dist/command/setup/bringup/connect-lease.d.ts +1 -0
  41. package/dist/command/setup/bringup/connect-lease.js +1 -0
  42. package/dist/command/setup/bringup/dev-server-wait.d.ts +10 -0
  43. package/dist/command/setup/bringup/dev-server-wait.js +20 -1
  44. package/dist/command/setup/init/init-port.d.ts +4 -0
  45. package/dist/command/setup/init/init-port.js +10 -0
  46. package/dist/command/setup/init/init-runtime.d.ts +10 -0
  47. package/dist/command/setup/init/init-runtime.js +71 -9
  48. package/dist/command/setup/node-effects.js +8 -2
  49. package/dist/command/setup/remaining-steps.js +2 -1
  50. package/dist/command/setup/run-setup.d.ts +7 -0
  51. package/dist/command/setup/run-setup.js +38 -25
  52. package/dist/command/setup/setup-command.d.ts +2 -1
  53. package/dist/command/setup/setup-command.js +2 -0
  54. package/dist/command/setup/setup-mcp.d.ts +2 -0
  55. package/dist/command/setup/setup-mcp.js +14 -5
  56. package/dist/command/version/peer-announce.d.ts +6 -2
  57. package/dist/command/version/peer-announce.js +8 -6
  58. package/dist/command/version/version-nudge.d.ts +17 -3
  59. package/dist/command/version/version-nudge.js +25 -4
  60. package/dist/command/version/version-skew.js +11 -2
  61. package/dist/features/crawl/crawl-tools.js +4 -0
  62. package/dist/features/crawl/crawl.d.ts +6 -0
  63. package/dist/features/crawl/crawl.js +9 -1
  64. package/dist/features/exhaust/ledger.d.ts +7 -0
  65. package/dist/features/exhaust/ledger.js +35 -9
  66. package/dist/features/harness/app-findings.d.ts +2 -0
  67. package/dist/features/harness/app-findings.js +52 -0
  68. package/dist/features/harness/drive-report.d.ts +27 -1
  69. package/dist/features/harness/drive-report.js +162 -11
  70. package/dist/features/harness/drivers.d.ts +10 -14
  71. package/dist/features/harness/drivers.js +10 -14
  72. package/dist/features/harness/fill-values.d.ts +3 -69
  73. package/dist/features/harness/fill-values.js +3 -133
  74. package/dist/features/harness/goals.d.ts +21 -0
  75. package/dist/features/harness/goals.js +77 -0
  76. package/dist/features/harness/harness.d.ts +21 -0
  77. package/dist/features/harness/harness.js +69 -2
  78. package/dist/features/harness/platform/drive-target.d.ts +30 -0
  79. package/dist/features/harness/platform/drive-target.js +81 -0
  80. package/dist/features/harness/platform/local-apps.d.ts +94 -0
  81. package/dist/features/harness/platform/local-apps.js +204 -0
  82. package/dist/features/harness/platform/remote-drive.d.ts +180 -0
  83. package/dist/features/harness/platform/remote-drive.js +365 -0
  84. package/dist/features/harness/platform/script.d.ts +48 -0
  85. package/dist/features/harness/platform/script.js +128 -0
  86. package/dist/features/harness/platform/server-driver.d.ts +41 -0
  87. package/dist/features/harness/platform/server-driver.js +179 -0
  88. package/dist/features/harness/platform-config.d.ts +7 -0
  89. package/dist/features/harness/platform-config.js +14 -2
  90. package/dist/features/harness/script/app-controls.d.ts +5 -0
  91. package/dist/features/harness/script/app-controls.js +40 -0
  92. package/dist/features/harness/script/lane-ids.d.ts +14 -0
  93. package/dist/features/harness/script/lane-ids.js +16 -0
  94. package/dist/features/harness/script/script-run.d.ts +41 -0
  95. package/dist/features/harness/script/script-run.js +299 -0
  96. package/dist/features/license/license.d.ts +2 -2
  97. package/dist/features/visual/visual-tools.d.ts +10 -1
  98. package/dist/features/visual/visual-tools.js +40 -3
  99. package/dist/hooks/driven-by.d.ts +4 -0
  100. package/dist/hooks/driven-by.js +16 -0
  101. package/dist/hooks/hook-commands.js +15 -4
  102. package/dist/hooks/tool-log.d.ts +9 -0
  103. package/dist/hooks/tool-log.js +29 -0
  104. package/dist/index.d.ts +1 -0
  105. package/dist/index.js +91 -89
  106. package/dist/judgement/capsule/capsule-store.d.ts +4 -4
  107. package/dist/judgement/runs/artifact/build-verification-run.js +6 -0
  108. package/dist/judgement/runs/artifact/replay-mapping.d.ts +1 -1
  109. package/dist/judgement/runs/artifact/replay-mapping.js +16 -6
  110. package/dist/judgement/runs/artifact/run-store.d.ts +1 -1
  111. package/dist/judgement/runs/artifact/run-store.js +26 -1
  112. package/dist/judgement/runs/drive-run.d.ts +22 -0
  113. package/dist/judgement/runs/drive-run.js +99 -1
  114. package/dist/judgement/runs/repair-prompt.js +1 -1
  115. package/dist/judgement/runs/reticle-runner.js +8 -1
  116. package/dist/judgement/runs/verification-sync.d.ts +3 -2
  117. package/dist/judgement/runs/verification-sync.js +4 -3
  118. package/dist/language/flows/change/gate.d.ts +10 -0
  119. package/dist/language/flows/change/gate.js +22 -0
  120. package/dist/language/flows/decision.js +34 -0
  121. package/dist/language/flows/flow-anchor.d.ts +54 -8
  122. package/dist/language/flows/flow-anchor.js +88 -3
  123. package/dist/language/flows/flow-cross-step.d.ts +15 -0
  124. package/dist/language/flows/flow-cross-step.js +21 -0
  125. package/dist/language/flows/flow-learning.js +8 -11
  126. package/dist/language/flows/flow-mutate-tools.js +5 -3
  127. package/dist/language/flows/flow-replay-run.d.ts +23 -9
  128. package/dist/language/flows/flow-replay-run.js +101 -94
  129. package/dist/language/flows/flow-replay.d.ts +23 -1
  130. package/dist/language/flows/flow-replay.js +92 -19
  131. package/dist/language/flows/flow-scope.js +5 -1
  132. package/dist/language/flows/flow-step-runners.d.ts +20 -2
  133. package/dist/language/flows/flow-step-runners.js +236 -42
  134. package/dist/language/flows/flow-store-for-session.d.ts +2 -2
  135. package/dist/language/flows/flow-store-for-session.js +2 -2
  136. package/dist/language/flows/flow-tools.js +58 -34
  137. package/dist/language/flows/flows.js +5 -2
  138. package/dist/language/flows/heal-run.js +6 -4
  139. package/dist/language/flows/recording/flake.d.ts +2 -2
  140. package/dist/language/flows/recording/tape/recordings.d.ts +30 -4
  141. package/dist/language/flows/recording/tape/recordings.js +40 -8
  142. package/dist/language/flows/replay-from-hud.d.ts +20 -0
  143. package/dist/language/flows/replay-from-hud.js +51 -0
  144. package/dist/language/flows/replay.d.ts +9 -5
  145. package/dist/language/flows/replay.js +27 -9
  146. package/dist/language/flows/suite/suite-flakes.js +2 -0
  147. package/dist/language/flows/suite-selection.d.ts +2 -15
  148. package/dist/language/flows/suite-selection.js +4 -3
  149. package/dist/language/flows/verify-change-tools.js +8 -4
  150. package/dist/launch-chromium.d.ts +27 -5
  151. package/dist/launch-chromium.js +38 -8
  152. package/dist/memory/cloud/cloud-config.d.ts +12 -0
  153. package/dist/memory/cloud/cloud-config.js +15 -0
  154. package/dist/memory/cloud/cloud-sync.d.ts +17 -14
  155. package/dist/memory/cloud/cloud-sync.js +12 -1
  156. package/dist/memory/cloud/harness-config.d.ts +26 -1
  157. package/dist/memory/cloud/harness-config.js +99 -4
  158. package/dist/memory/cloud/hud-notices-source.d.ts +21 -0
  159. package/dist/memory/cloud/hud-notices-source.js +128 -0
  160. package/dist/memory/cloud/memory-scope.d.ts +144 -0
  161. package/dist/memory/cloud/memory-scope.js +205 -0
  162. package/dist/memory/cloud/sync-cycle.d.ts +21 -3
  163. package/dist/memory/cloud/sync-cycle.js +45 -5
  164. package/dist/memory/cloud/sync-daemon.js +7 -5
  165. package/dist/memory/cloud/sync-disk.d.ts +1 -1
  166. package/dist/memory/cloud/sync-disk.js +5 -8
  167. package/dist/memory/impact/account-watch.d.ts +19 -0
  168. package/dist/memory/impact/account-watch.js +34 -0
  169. package/dist/memory/impact/impact-recorder.d.ts +8 -0
  170. package/dist/memory/impact/impact-recorder.js +12 -2
  171. package/dist/memory/impact/impact-store.d.ts +16 -0
  172. package/dist/memory/impact/impact-store.js +142 -26
  173. package/dist/memory/intent/intent-shard.d.ts +2 -2
  174. package/dist/memory/intent/intent-tools.js +88 -5
  175. package/dist/memory/journal/envelope.d.ts +16 -16
  176. package/dist/memory/journal/journal-query.d.ts +14 -0
  177. package/dist/memory/journal/journal-query.js +15 -0
  178. package/dist/memory/journal/journal-recorder.js +7 -1
  179. package/dist/memory/journal/on-disk/retention.d.ts +3 -0
  180. package/dist/memory/journal/on-disk/retention.js +5 -0
  181. package/dist/memory/journal/on-disk/startup-maintenance.js +3 -1
  182. package/dist/memory/journal/on-disk/workspace-tiers.js +7 -4
  183. package/dist/memory/journal/session-end.js +6 -4
  184. package/dist/memory/project/artifact-root-resolver.d.ts +36 -1
  185. package/dist/memory/project/artifact-root-resolver.js +134 -26
  186. package/dist/memory/project/artifact-root.d.ts +42 -5
  187. package/dist/memory/project/artifact-root.js +87 -8
  188. package/dist/memory/project/dir/reticle-dir.d.ts +4 -2
  189. package/dist/memory/project/dir/reticle-dir.js +3 -1
  190. package/dist/memory/project/project-tools.js +22 -3
  191. package/dist/memory/project/session-root.d.ts +24 -1
  192. package/dist/memory/project/session-root.js +41 -5
  193. package/dist/memory/project/sync-status.d.ts +39 -0
  194. package/dist/memory/project/sync-status.js +90 -0
  195. package/dist/memory/recall/memory-tools.js +2 -0
  196. package/dist/memory/recall/project-memory.d.ts +19 -0
  197. package/dist/memory/recall/project-memory.js +45 -6
  198. package/dist/portal/bridge/bridge.d.ts +7 -4
  199. package/dist/portal/bridge/bridge.js +25 -3
  200. package/dist/portal/bridge/pairing-token.d.ts +9 -0
  201. package/dist/portal/bridge/pairing-token.js +17 -0
  202. package/dist/portal/input/real-input.d.ts +81 -10
  203. package/dist/portal/input/real-input.js +207 -22
  204. package/dist/portal/input/viewport-tools.js +19 -9
  205. package/dist/portal/pool/browser-pool.d.ts +22 -9
  206. package/dist/portal/pool/browser-pool.js +70 -35
  207. package/dist/portal/pool/playwright-launcher.d.ts +13 -0
  208. package/dist/portal/pool/playwright-launcher.js +17 -1
  209. package/dist/portal/pool/pool-contract.d.ts +7 -4
  210. package/dist/portal/session/command-payload.d.ts +8 -0
  211. package/dist/portal/session/command-payload.js +19 -0
  212. package/dist/portal/session/dev-server/dev-command.d.ts +12 -0
  213. package/dist/portal/session/dev-server/dev-command.js +61 -12
  214. package/dist/portal/session/facts/departure-note.d.ts +22 -0
  215. package/dist/portal/session/facts/departure-note.js +47 -0
  216. package/dist/portal/session/facts/session-replaced.d.ts +5 -0
  217. package/dist/portal/session/facts/session-replaced.js +5 -0
  218. package/dist/portal/session/first-run-wiring.d.ts +42 -0
  219. package/dist/portal/session/first-run-wiring.js +132 -0
  220. package/dist/portal/session/human/notes-ledger.d.ts +20 -0
  221. package/dist/portal/session/human/notes-ledger.js +55 -0
  222. package/dist/portal/session/human/review-store.d.ts +12 -0
  223. package/dist/portal/session/human/review-store.js +18 -10
  224. package/dist/portal/session/live-control-tools.d.ts +0 -13
  225. package/dist/portal/session/live-control-tools.js +28 -3
  226. package/dist/portal/session/no-session-diagnosis.d.ts +7 -0
  227. package/dist/portal/session/no-session-diagnosis.js +15 -0
  228. package/dist/portal/session/no-session-next-action.d.ts +11 -0
  229. package/dist/portal/session/no-session-next-action.js +31 -5
  230. package/dist/portal/session/no-session-watch.d.ts +14 -1
  231. package/dist/portal/session/no-session-watch.js +63 -10
  232. package/dist/portal/session/presence/session-mirror.js +3 -0
  233. package/dist/portal/session/serving-directory.d.ts +27 -0
  234. package/dist/portal/session/serving-directory.js +45 -0
  235. package/dist/portal/session/session-health.d.ts +7 -0
  236. package/dist/portal/session/session-health.js +6 -0
  237. package/dist/portal/session/session-info.d.ts +8 -1
  238. package/dist/portal/session/session-info.js +6 -0
  239. package/dist/portal/session/session-manager.d.ts +21 -0
  240. package/dist/portal/session/session-manager.js +44 -8
  241. package/dist/portal/session/session-reaper.js +4 -1
  242. package/dist/portal/session/session-successor.d.ts +5 -0
  243. package/dist/portal/session/session-tools.js +26 -3
  244. package/dist/portal/session/session.d.ts +12 -10
  245. package/dist/portal/session/session.js +30 -31
  246. package/dist/start-options.d.ts +6 -0
  247. package/dist/status-payload.d.ts +10 -0
  248. package/dist/status-payload.js +23 -0
  249. package/dist/surface/http-server.d.ts +1 -1
  250. package/dist/surface/http-server.js +15 -4
  251. package/dist/surface/mcp/mcp-proxy.d.ts +5 -0
  252. package/dist/surface/mcp/mcp-proxy.js +36 -5
  253. package/dist/surface/mcp/mcp.d.ts +11 -6
  254. package/dist/surface/mcp/mcp.js +28 -14
  255. package/dist/surface/mcp/proxy/proxy-log.js +3 -5
  256. package/dist/surface/mcp/server-instructions.d.ts +4 -2
  257. package/dist/surface/mcp/server-instructions.js +14 -4
  258. package/dist/surface/mcp/shared-params.js +2 -2
  259. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +8 -0
  260. package/dist/surface/tools/act/navigation/navigate-arrival.js +56 -2
  261. package/dist/surface/tools/act/settle-in-flight.js +25 -3
  262. package/dist/surface/tools/act-sequence-tool.js +2 -2
  263. package/dist/surface/tools/act-tools.js +25 -9
  264. package/dist/surface/tools/assert/assert-verdict.d.ts +1 -1
  265. package/dist/surface/tools/assert/assert-verdict.js +17 -2
  266. package/dist/surface/tools/browser-tools.js +8 -1
  267. package/dist/surface/tools/chat-drives.d.ts +26 -0
  268. package/dist/surface/tools/chat-drives.js +165 -0
  269. package/dist/surface/tools/dynamic-tools.js +29 -2
  270. package/dist/surface/tools/empty-session-list.d.ts +41 -0
  271. package/dist/surface/tools/empty-session-list.js +80 -0
  272. package/dist/surface/tools/error-recovery.d.ts +6 -0
  273. package/dist/surface/tools/error-recovery.js +38 -6
  274. package/dist/surface/tools/explore-tools.d.ts +10 -1
  275. package/dist/surface/tools/explore-tools.js +82 -13
  276. package/dist/surface/tools/feedback-tools.js +14 -0
  277. package/dist/surface/tools/harness-explore.d.ts +96 -14
  278. package/dist/surface/tools/harness-explore.js +227 -202
  279. package/dist/surface/tools/harness-plan.d.ts +12 -0
  280. package/dist/surface/tools/harness-plan.js +31 -0
  281. package/dist/surface/tools/harness-script.d.ts +8 -0
  282. package/dist/surface/tools/harness-script.js +342 -0
  283. package/dist/surface/tools/harness-toolset.d.ts +14 -1
  284. package/dist/surface/tools/harness-toolset.js +77 -6
  285. package/dist/surface/tools/invoke-tool.js +64 -9
  286. package/dist/surface/tools/lease-seed.d.ts +29 -0
  287. package/dist/surface/tools/lease-seed.js +123 -0
  288. package/dist/surface/tools/lease-tools.d.ts +3 -23
  289. package/dist/surface/tools/lease-tools.js +30 -131
  290. package/dist/surface/tools/live-call-text.js +2 -2
  291. package/dist/surface/tools/next-step.d.ts +19 -0
  292. package/dist/surface/tools/next-step.js +159 -0
  293. package/dist/surface/tools/observe-tools.js +2 -4
  294. package/dist/surface/tools/platform-moment.d.ts +12 -0
  295. package/dist/surface/tools/platform-moment.js +168 -0
  296. package/dist/surface/tools/query-hint-schema.d.ts +7 -0
  297. package/dist/surface/tools/query-hint-schema.js +10 -0
  298. package/dist/surface/tools/read-tools.js +8 -2
  299. package/dist/surface/tools/real-input-attempt.js +96 -13
  300. package/dist/surface/tools/tool-kit.d.ts +25 -1
  301. package/dist/surface/tools/tool-kit.js +4 -6
  302. package/dist/surface/tools/tools.js +20 -48
  303. package/dist/telemetry/argument-shape.js +1 -1
  304. package/dist/telemetry/hud-metrics.d.ts +2 -0
  305. package/dist/telemetry/hud-metrics.js +17 -0
  306. package/dist/telemetry/onboarding-firsts.d.ts +2 -2
  307. package/dist/telemetry/onboarding-firsts.js +2 -2
  308. package/dist/telemetry/telemetry.d.ts +12 -0
  309. package/dist/telemetry/telemetry.js +43 -14
  310. package/dist/telemetry/verification-of.js +1 -0
  311. package/dist/wire-journal.js +4 -1
  312. package/docs/README.md +1 -1
  313. package/docs/actions.mdx +1 -2
  314. package/docs/agent-cheatsheet.md +1 -1
  315. package/docs/autodrive.md +29 -25
  316. package/docs/cli/cloud.mdx +6 -4
  317. package/docs/cli/doctor.mdx +6 -0
  318. package/docs/cli/drive.mdx +8 -2
  319. package/docs/cli/init.mdx +11 -13
  320. package/docs/cli/status.mdx +5 -1
  321. package/docs/cli/version.mdx +3 -3
  322. package/docs/cli.mdx +14 -8
  323. package/docs/desktop.mdx +5 -1
  324. package/docs/environment.mdx +3 -7
  325. package/docs/getting-started.md +14 -2
  326. package/docs/human-control.md +1 -2
  327. package/docs/index.mdx +4 -3
  328. package/docs/install-agentic.mdx +1 -1
  329. package/docs/install-manual.mdx +2 -2
  330. package/docs/packages/next.mdx +3 -0
  331. package/docs/packages/tauri.mdx +2 -2
  332. package/docs/packages/vite-plugin.mdx +24 -1
  333. package/docs/packages.mdx +1 -1
  334. package/docs/quickstart.mdx +23 -11
  335. package/docs/telemetry.md +1 -1
  336. package/docs/tools/act.mdx +1 -1
  337. package/docs/tools/session-and-feedback.mdx +9 -9
  338. package/docs/usage.md +5 -3
  339. package/docs/what-is-recorded.md +13 -3
  340. package/docs/what-is-reticle.mdx +3 -1
  341. package/package.json +8 -12
  342. package/dist/features/harness/driver.d.ts +0 -50
  343. package/dist/features/harness/driver.js +0 -236
  344. package/dist/features/harness/jev-driver.d.ts +0 -188
  345. package/dist/features/harness/jev-driver.js +0 -678
  346. package/dist/features/harness/openai-driver.d.ts +0 -46
  347. package/dist/features/harness/openai-driver.js +0 -194
  348. package/dist/memory/project/dir/fill-value-store.d.ts +0 -32
  349. package/dist/memory/project/dir/fill-value-store.js +0 -88
  350. package/docs/local-registry.md +0 -143
@@ -12,11 +12,11 @@
12
12
  import { takeJsCoverage } from './js-coverage.js';
13
13
  import { stampedDriveUrl } from './drive-url-stamp.js';
14
14
  import { launchChromium } from '../../launch-chromium.js';
15
- import { chromiumLaunchHint, gotoOptions } from '../pool/playwright-launcher.js';
15
+ import { HIDE_RETICLE_CHROME_CSS, chromiumLaunchHint, gotoOptions, } from '../pool/playwright-launcher.js';
16
16
  import { BrowserLaunchKind } from '@reticlehq/core/telemetry';
17
17
  import { getSessionMetrics } from '../../telemetry/session-metrics.js';
18
18
  import { classifyConnectFailure } from '../../telemetry/connect-failure.js';
19
- import { ActionType, DriveErrorCode, DRIVE_PLAYWRIGHT_MISSING_MSG } from '@reticlehq/core';
19
+ import { ActionType, clampHoldMs, DriveErrorCode, DRIVE_PLAYWRIGHT_MISSING_MSG, explicitCodeFromArgs, InputMode, InputModeReason, pressKeyFromArgs, pressKeysFromArgs, pressModifiersFromArgs, } from '@reticlehq/core';
20
20
  import { installNetworkMocks } from './network-mock.js';
21
21
  import { attachNetworkDetail } from './network-detail.js';
22
22
  import { injectedConnectArgs } from '../pool/zero-install.js';
@@ -34,8 +34,8 @@ export function boxCenter(box) {
34
34
  return { cx: box.x + box.width / 2, cy: box.y + box.height / 2 };
35
35
  }
36
36
  /**
37
- * Which actions are driven by native pointer input. fill/type stay synthetic unless a
38
- * provider explicitly runs them.
37
+ * Which actions are driven by a native pointer. `press` is excluded on purpose — a key has no
38
+ * pointer, and widening this would change what every existing caller of it means.
39
39
  */
40
40
  export function isPointerAction(action) {
41
41
  return (action === ActionType.HOVER ||
@@ -43,37 +43,217 @@ export function isPointerAction(action) {
43
43
  action === ActionType.DBLCLICK ||
44
44
  action === ActionType.DRAG);
45
45
  }
46
+ /**
47
+ * The routing question `tryRealInput` asks: does this action have a real-input path at all? Wider
48
+ * than `isPointerAction` by `press`, which needs no coordinates.
49
+ */
50
+ export function isRealInputAction(action) {
51
+ return isPointerAction(action) || action === ActionType.PRESS;
52
+ }
53
+ /**
54
+ * A gesture that was NOT driven. No center for a key press — a zero would read as a real point.
55
+ *
56
+ * `inputMode` is SYNTHETIC: no real gesture ran, so this is the path the caller is about to take.
57
+ */
58
+ function undriven(action, box) {
59
+ const base = { performed: false, inputMode: InputMode.SYNTHETIC };
60
+ return action === ActionType.PRESS ? base : { ...base, center: boxCenter(box) };
61
+ }
46
62
  /** Settle delay after a native gesture so the reaction can begin to flush (named, not free). */
47
63
  const REAL_INPUT_SETTLE_MS = 16;
48
64
  /** Default number of interpolation steps for a native drag. */
49
65
  const DEFAULT_DRAG_STEPS = 8;
66
+ /**
67
+ * Drive a `press` with a real keyboard — coordinate-free; the key goes to whatever holds focus.
68
+ * Key and modifiers come from the same core helpers the synthetic dispatcher uses, so the two paths
69
+ * cannot read the same args differently.
70
+ *
71
+ * A `holdMs` splits the chord into down / wait / up, the same shape the page uses for a held key.
72
+ * `keyboard.press` would send it instantly instead, reporting a hold-to-confirm that never held.
73
+ * The one thing this cannot reproduce is the auto-repeat a held key emits: the driver sends a single
74
+ * keydown, where the in-page path sends the repeats a browser would. Named rather than papered over
75
+ * — an app that counts repeats needs the synthetic path, and a caller that sees a held key do
76
+ * nothing now has a reason to try it.
77
+ */
78
+ async function pressViaKeyboard(page, args, sleep, now) {
79
+ const key = pressKeyFromArgs(args);
80
+ const modifiers = pressModifiersFromArgs(args);
81
+ const chord = 0 < modifiers.length ? `${modifiers.join('+')}+${key}` : key;
82
+ const holdMs = clampHoldMs(args.holdMs);
83
+ if (0 === holdMs) {
84
+ // `press` DOES take a chord string ("Control+k"), so the tap path needs no splitting.
85
+ await page.keyboard.press(chord);
86
+ return 0;
87
+ }
88
+ /*
89
+ * `down`/`up` take ONE key each, unlike `press`: `down('Control+k')` throws
90
+ * `Unknown key: "Control+k"` — measured on a real Chromium, not assumed. The chord string the
91
+ * tap path uses therefore cannot express a hold, so the chord is split here: modifiers down in
92
+ * chord order, the key last, and released in reverse (key first, modifiers reversed), which is
93
+ * what a hand does and what an app's keyup bookkeeping expects.
94
+ *
95
+ * Without the split a held shortcut threw before a single key moved, the caller fell back to
96
+ * the synthetic path, and a real hold was impossible for any press with modifiers — the exact
97
+ * gesture `holdMs` exists for.
98
+ *
99
+ * ## Why every key that went down is tracked, and every exit path cleans up
100
+ *
101
+ * The down calls are the ones that MOVE the keyboard, and they can fail partway: `Control` goes
102
+ * down, the key after it rejects, and the driver's copy of `Control` is still held. That path
103
+ * used to fall straight to the caller's synthetic replay — which presses the same chord again on
104
+ * a keyboard that is already holding a modifier. Tracking what actually went down is what makes
105
+ * the cleanup below able to release the right keys, and only those: releasing a key that never
106
+ * went down is its own lie, and it would turn a clean failure into an unnecessary refusal.
107
+ */
108
+ const pressed = [];
109
+ const pressDown = async (k) => {
110
+ await page.keyboard.down(k);
111
+ pressed.push(k);
112
+ };
113
+ try {
114
+ for (const modifier of modifiers)
115
+ await pressDown(modifier);
116
+ await pressDown(key);
117
+ }
118
+ catch (error) {
119
+ // The chord is PARTIALLY down. Release what is held before reporting the failure; if that
120
+ // cannot be proved, `releaseKeys` throws RELEASE_FAILED and the caller refuses the replay —
121
+ // the same rule as a failed release on the ordinary path, for the same reason. Only when the
122
+ // cleanup DOES succeed is the original error safe to hand back.
123
+ await releaseKeys(page, pressed);
124
+ throw error;
125
+ }
126
+ const startedAt = now();
127
+ try {
128
+ await sleep(holdMs);
129
+ }
130
+ catch (error) {
131
+ // The wait failed, and the caller is about to run the synthetic path — which presses this SAME
132
+ // key a second time. If the driver's copy stays down, a held modifier then colours every later
133
+ // action for the rest of the run. Best-effort on purpose: whatever went wrong with the wait is
134
+ // the error worth reporting. A cleanup that cannot be proved is the exception — that one is a
135
+ // stuck key, and it must reach the caller as a refusal rather than be swallowed.
136
+ try {
137
+ await releaseKeys(page, pressed);
138
+ }
139
+ catch {
140
+ throw new DriveError(DriveErrorCode.RELEASE_FAILED, 'the wait failed and the keys it pressed could not be released, so they may still be held');
141
+ }
142
+ throw error;
143
+ }
144
+ // NOT best-effort: on the ordinary path a failed release is a real failure the caller must hear
145
+ // about, and swallowing it would report a press whose key is still down.
146
+ await releaseKeys(page, pressed);
147
+ return now() - startedAt;
148
+ }
149
+ /**
150
+ * Release the given keys, in reverse press order, and report a failure as one that leaves the
151
+ * keyboard UNKNOWN rather than as an ordinary provider error.
152
+ *
153
+ * Every release is attempted even after one fails: a stuck `Control` is worse than a stuck letter,
154
+ * so a failure on one key must not skip the rest. The first failure is what is thrown, since it is
155
+ * the one that happened first, and it is wrapped in `DriveError` so the caller can tell "this
156
+ * gesture failed" from "this gesture may have left a key down" — the difference between a safe
157
+ * synthetic replay and an unsafe one.
158
+ */
159
+ async function releaseKeys(page, pressed) {
160
+ let failure;
161
+ for (const k of [...pressed].reverse()) {
162
+ try {
163
+ await page.keyboard.up(k);
164
+ }
165
+ catch (error) {
166
+ failure ??= error;
167
+ }
168
+ }
169
+ if (failure !== undefined) {
170
+ throw new DriveError(DriveErrorCode.RELEASE_FAILED, `the key was pressed but could not be released, so it may still be held: ${describeFailure(failure)}`);
171
+ }
172
+ }
173
+ /**
174
+ * A thrown value as a line a reader can act on.
175
+ *
176
+ * Not `String(error)`: a non-Error thrown value (a rejected plain object, an SDK that throws a
177
+ * record) stringifies to `[object Object]`, which names nothing and hides the one fact the message
178
+ * exists to carry. Anything that is neither an Error nor a string says so rather than pretending.
179
+ */
180
+ function describeFailure(error) {
181
+ if (error instanceof Error)
182
+ return error.message;
183
+ return 'string' === typeof error ? error : 'an unknown error';
184
+ }
185
+ /**
186
+ * The `press`es this module will NOT drive: a chord that only the in-page dispatcher can express.
187
+ *
188
+ * `args.keys` asks for several keys held down TOGETHER, pressed in order and released in reverse.
189
+ * That is not a `page.keyboard.press` chord — a non-modifier key cannot appear before the last `+`
190
+ * — and a real keyboard cannot aim a key at a named element. `args.code` is the third: the driver
191
+ * presses by KEY name and offers no way to send a physical `code` that disagrees with it, so
192
+ * `{ text: 'z', code: 'KeyY' }` would strike a different key than the one asked for. All three are
193
+ * routed to the synthetic path by the caller, which reports the reason rather than pretending a
194
+ * different gesture happened.
195
+ *
196
+ * Ordered by how specifically the caller asked: `keys` then `code` name the KEY, `ref` names only
197
+ * the target. Two can apply at once, and the earlier one is the more unusual request — the reason
198
+ * should name that, not the generic "you passed a ref".
199
+ */
200
+ export function unspellablePressReason(ref, args) {
201
+ if (0 < pressKeysFromArgs(args).length) {
202
+ return InputModeReason.SYNTHETIC_MULTI_KEY_PRESS_PREFERRED;
203
+ }
204
+ if (explicitCodeFromArgs(args) !== undefined) {
205
+ return InputModeReason.SYNTHETIC_KEY_CODE_PRESS_PREFERRED;
206
+ }
207
+ if (0 < ref.length)
208
+ return InputModeReason.SYNTHETIC_ELEMENT_PRESS_PREFERRED;
209
+ return undefined;
210
+ }
50
211
  /**
51
212
  * Shared gesture executor: drive a native gesture on an already-resolved Page. Used by both the
52
213
  * CDP-attached and the launched (drive) providers so the pointer logic lives in one place.
53
214
  */
54
- export async function performGesture(page, action, box, args, sleep) {
215
+ export async function performGesture(page, action, box, args, sleep,
216
+ /** Injected so a test can assert the achieved hold deterministically; defaults to the real clock. */
217
+ now = Date.now) {
218
+ // Ahead of the box, not after it: a press addresses focus rather than a point, and the
219
+ // placeholder box its caller passes would otherwise be turned into a (0,0) that reads like a real
220
+ // location. The result reports NO `center` for the same reason.
221
+ if (action === ActionType.PRESS) {
222
+ const heldMs = await pressViaKeyboard(page, args, sleep, now);
223
+ return {
224
+ performed: true,
225
+ inputMode: InputMode.REAL,
226
+ // Omitted rather than 0 when there was no hold — see `RealInputResult.heldMs`.
227
+ ...(heldMs > 0 ? { heldMs } : {}),
228
+ };
229
+ }
55
230
  const center = boxCenter(box);
56
231
  const { cx, cy } = center;
232
+ const real = (performed) => ({
233
+ performed,
234
+ center,
235
+ inputMode: InputMode.REAL,
236
+ });
57
237
  if (action === ActionType.HOVER) {
58
238
  await page.mouse.move(cx, cy);
59
239
  await page.mouse.move(cx + 1, cy);
60
240
  await page.mouse.move(cx, cy);
61
241
  await sleep(REAL_INPUT_SETTLE_MS);
62
- return { performed: true, center };
242
+ return real(true);
63
243
  }
64
244
  if (action === ActionType.CLICK) {
65
245
  await page.mouse.move(cx, cy);
66
246
  await page.mouse.click(cx, cy);
67
- return { performed: true, center };
247
+ return real(true);
68
248
  }
69
249
  if (action === ActionType.DBLCLICK) {
70
250
  await page.mouse.move(cx, cy);
71
251
  await page.mouse.dblclick(cx, cy);
72
- return { performed: true, center };
252
+ return real(true);
73
253
  }
74
254
  if (action === ActionType.DRAG) {
75
255
  if (args.toBox === undefined)
76
- return { performed: false, center };
256
+ return real(false);
77
257
  const dst = boxCenter(args.toBox);
78
258
  const steps = args.steps ?? DEFAULT_DRAG_STEPS;
79
259
  await page.mouse.move(cx, cy);
@@ -84,14 +264,14 @@ export async function performGesture(page, action, box, args, sleep) {
84
264
  await page.mouse.move(px, py, { steps: 1 });
85
265
  }
86
266
  await page.mouse.up();
87
- return { performed: true, center };
267
+ return real(true);
88
268
  }
89
269
  if (action === ActionType.FILL || action === ActionType.TYPE) {
90
270
  await page.mouse.click(cx, cy);
91
271
  await page.keyboard.type(args.value ?? args.text ?? '');
92
- return { performed: true, center };
272
+ return real(true);
93
273
  }
94
- return { performed: false, center };
274
+ return real(false);
95
275
  }
96
276
  /**
97
277
  * Reticle paints its own dev overlay (presenter HUD + border glow) into the page. That chrome is
@@ -100,18 +280,19 @@ export async function performGesture(page, action, box, args, sleep) {
100
280
  * (Playwright applies this stylesheet only for the shot, then reverts) so visual baselines reflect
101
281
  * the app, not Reticle. Disabling animations settles any remaining transitions for determinism.
102
282
  */
103
- const HIDE_RETICLE_CHROME_CSS = '[data-reticle-overlay]{display:none !important}';
104
283
  const SCREENSHOT_DETERMINISM = { style: HIDE_RETICLE_CHROME_CSS, animations: 'disabled' };
105
284
  /**
106
285
  * Capture a PNG from a Playwright page. Shared by the CDP + launched providers so the
107
286
  * screenshot path lives in one place (mirrors performGesture). Returns the raw PNG bytes.
108
287
  */
109
288
  export async function capturePage(page, opts) {
110
- const buf = await page.screenshot(opts.clip !== undefined
111
- ? { ...SCREENSHOT_DETERMINISM, clip: opts.clip }
112
- : true === opts.fullPage
113
- ? { ...SCREENSHOT_DETERMINISM, fullPage: true }
114
- : { ...SCREENSHOT_DETERMINISM });
289
+ const buf = await page.screenshot(opts.jpegQuality !== undefined
290
+ ? { type: 'jpeg', quality: opts.jpegQuality }
291
+ : opts.clip !== undefined
292
+ ? { ...SCREENSHOT_DETERMINISM, clip: opts.clip }
293
+ : true === opts.fullPage
294
+ ? { ...SCREENSHOT_DETERMINISM, fullPage: true }
295
+ : { ...SCREENSHOT_DETERMINISM });
115
296
  return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
116
297
  }
117
298
  const nodeSleep = (ms) => new Promise((resolve) => {
@@ -138,6 +319,7 @@ const cdpConnect = async (url) => {
138
319
  export class CdpRealInputProvider {
139
320
  #cdpUrl;
140
321
  #sleep;
322
+ #now;
141
323
  #connect;
142
324
  #onNetworkDetail;
143
325
  /** Pages already listening. #pageFor resolves on EVERY call, so without this each action would add
@@ -149,6 +331,7 @@ export class CdpRealInputProvider {
149
331
  constructor(options) {
150
332
  this.#cdpUrl = options.cdpUrl;
151
333
  this.#sleep = options.sleep ?? nodeSleep;
334
+ this.#now = options.now ?? Date.now;
152
335
  this.#connect = options.connect ?? cdpConnect;
153
336
  this.#onNetworkDetail = options.onNetworkDetail;
154
337
  }
@@ -205,8 +388,8 @@ export class CdpRealInputProvider {
205
388
  async perform(sessionUrl, action, box, args) {
206
389
  const page = await this.#pageFor(sessionUrl);
207
390
  if (page === undefined)
208
- return { performed: false, center: boxCenter(box) };
209
- return performGesture(page, action, box, args, this.#sleep);
391
+ return undriven(action, box);
392
+ return performGesture(page, action, box, args, this.#sleep, this.#now);
210
393
  }
211
394
  /** PNG of the correlated page, or undefined if none matches. */
212
395
  async screenshot(sessionUrl, opts) {
@@ -309,6 +492,7 @@ export class LaunchedRealInputProvider {
309
492
  #driveUrl;
310
493
  #headless;
311
494
  #sleep;
495
+ #now;
312
496
  #launch;
313
497
  #injectConnect;
314
498
  #storageState;
@@ -321,6 +505,7 @@ export class LaunchedRealInputProvider {
321
505
  this.#driveUrl = options.driveUrl;
322
506
  this.#headless = options.headless;
323
507
  this.#sleep = options.sleep ?? nodeSleep;
508
+ this.#now = options.now ?? Date.now;
324
509
  this.#launch = options.launch ?? launchedChromium;
325
510
  this.#injectConnect = options.injectConnect;
326
511
  this.#storageState = options.storageState;
@@ -438,8 +623,8 @@ export class LaunchedRealInputProvider {
438
623
  perform(_sessionUrl, action, box, args) {
439
624
  const page = this.#livePage();
440
625
  if (page === undefined)
441
- return Promise.resolve({ performed: false, center: boxCenter(box) });
442
- return performGesture(page, action, box, args, this.#sleep);
626
+ return Promise.resolve(undriven(action, box));
627
+ return performGesture(page, action, box, args, this.#sleep, this.#now);
443
628
  }
444
629
  /** PNG of the owned page, or undefined before navigate / after dispose. */
445
630
  screenshot(_sessionUrl, opts) {
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { CDP_NO_PROVIDER_REASON, CDP_NO_PROVIDER_RECOMMENDATION } from '@reticlehq/core';
2
+ import { CDP_NO_PROVIDER_REASON, VIEWPORT_NO_PROVIDER_RECOMMENDATION } from '@reticlehq/core';
3
3
  import { ReticleTool } from '@reticlehq/core';
4
4
  import { sessionIdShape } from '../../surface/tools/tool-kit.js';
5
5
  import { MAX_VIEWPORT_PX, MIN_VIEWPORT_PX, viewportPxSchema, } from '../../surface/tools/args/numeric-bounds.js';
@@ -16,7 +16,7 @@ function viewportProvider(deps) {
16
16
  export const VIEWPORT_TOOLS = [
17
17
  {
18
18
  name: ReticleTool.VIEWPORT,
19
- description: 'Pin the DRIVEN page (needs `reticle drive`) to a fixed viewport size so a screenshot baseline is ' +
19
+ description: 'Pin the DRIVEN or LEASED page (needs `reticle drive`, or `reticle_lease` acquire when there is no CDP provider) to a fixed viewport size so a screenshot baseline is ' +
20
20
  'reproducible across machines — the missing piece of CI-stable visual regression, alongside ' +
21
21
  'reticle_visual_diff `masks` and a frozen clock (reticle_clock). Set it once before reticle_screenshot / ' +
22
22
  'reticle_visual_diff. Returns { applied, width, height } or the no-provider recommendation.',
@@ -34,8 +34,8 @@ export const VIEWPORT_TOOLS = [
34
34
  recommendation: z.string().optional(),
35
35
  },
36
36
  handler: async (deps, args) => {
37
- const width = clampDim(args['width']);
38
- const height = clampDim(args['height']);
37
+ const width = clampDim('width', args['width']);
38
+ const height = clampDim('height', args['height']);
39
39
  const session = deps.sessions.resolve(asString(args['sessionId']));
40
40
  const provider = viewportProvider(deps);
41
41
  if (provider !== undefined) {
@@ -60,13 +60,23 @@ export const VIEWPORT_TOOLS = [
60
60
  height: 0,
61
61
  ok: false,
62
62
  reason: CDP_NO_PROVIDER_REASON,
63
- recommendation: CDP_NO_PROVIDER_RECOMMENDATION,
63
+ recommendation: VIEWPORT_NO_PROVIDER_RECOMMENDATION,
64
64
  };
65
65
  },
66
66
  },
67
67
  ];
68
- /** Clamp a requested dimension into [MIN_DIM, MAX_DIM]; a missing/NaN value falls back to MIN_DIM. */
69
- function clampDim(value) {
70
- const n = 'number' === typeof value && Number.isFinite(value) ? Math.round(value) : MIN_DIM;
71
- return Math.max(MIN_DIM, Math.min(n, MAX_DIM));
68
+ /**
69
+ * Clamp a requested dimension into [MIN_DIM, MAX_DIM]; a missing value falls back to MIN_DIM.
70
+ *
71
+ * A value that is PRESENT but not a finite number is refused, not read as missing: a client that
72
+ * sent `"1440"` meant 1440, and answering with a 64px page it never asked for made every later
73
+ * snapshot, click and screenshot on that page read as broken (#1118).
74
+ */
75
+ function clampDim(key, value) {
76
+ if (value === undefined)
77
+ return MIN_DIM;
78
+ if ('number' !== typeof value || !Number.isFinite(value)) {
79
+ throw new Error(`${ReticleTool.VIEWPORT}: \`${key}\` must be a number of CSS px, got ${JSON.stringify(value)} — NOT applied`);
80
+ }
81
+ return Math.max(MIN_DIM, Math.min(Math.round(value), MAX_DIM));
72
82
  }
@@ -10,7 +10,7 @@
10
10
  * the thin Playwright adapter that satisfies these interfaces lives separately.
11
11
  */
12
12
  import { type SeedStorage } from '@reticlehq/core';
13
- import type { Launcher, PooledMockRule } from './pool-contract.js';
13
+ import type { Launcher, PooledMockRule, ScreenshotOptions } from './pool-contract.js';
14
14
  export type { InitScriptHandle, Launcher, PooledBrowser, PooledContext, PooledCookie, PooledDialog, PooledMockRule, PooledPage, } from './pool-contract.js';
15
15
  /** A leased context+page for one flow. `release` frees the slot and closes the context. */
16
16
  export interface Lease {
@@ -42,9 +42,17 @@ interface BrowserPoolOptions {
42
42
  * the ~450KB build is only read if some page ever needs it; undefined when there is none to give.
43
43
  */
44
44
  zeroInstallScript?: () => string | undefined;
45
+ /**
46
+ * Launches a browser with a window, for a lease somebody wants to watch. Launched only when the
47
+ * first headed lease is asked for. Absent: a headed lease is refused.
48
+ */
49
+ launchHeaded?: Launcher;
45
50
  }
51
+ /** What a headed lease is refused with where no window can be opened. */
52
+ export declare const NO_HEADED_BROWSER = "no headed browser can be opened here";
46
53
  /**
47
- * Owns a single browser and leases isolated contexts out of it, capped at `maxContexts`.
54
+ * Owns a headless browser (and, when asked, a headed one) and leases isolated contexts out of them,
55
+ * capped at `maxContexts` across both.
48
56
  * Not exported as a singleton — the daemon owns one instance.
49
57
  */
50
58
  export declare class BrowserPool {
@@ -60,15 +68,17 @@ export declare class BrowserPool {
60
68
  /** The sessionIds of every currently leased context — used to report/group leased sessions. */
61
69
  leasedSessionIds(): string[];
62
70
  /**
63
- * The public session id of an active lease on this origin, if we already hold one.
71
+ * The public session id of an active lease on this origin that `owner` took, if there is one.
64
72
  *
65
73
  * The lease TOOL reuses that id instead of minting a second context: a second acquire on the same
66
- * origin used to leave both tabs connected and poison default session resolution (#600). The pool's
67
- * own `acquire` still mints — the parallel suite needs isolation on purpose.
74
+ * origin used to leave both tabs connected and poison default session resolution (#600). Only the
75
+ * caller that took the lease gets it back: handing it to whoever asked put two agents in one tab,
76
+ * each one's verdicts resting on the other's actions (#1226). A caller with no owner cannot be told
77
+ * apart from another, so it always gets its own. The pool's own `acquire` still mints.
68
78
  *
69
79
  * Prefers the alias the agent was given, when the app registered under its own name.
70
80
  */
71
- leaseIdOnOrigin(origin: string): string | undefined;
81
+ leaseIdOnOrigin(origin: string, owner: string | undefined): string | undefined;
72
82
  /**
73
83
  * Release a lease by its sessionId (closes the context, frees the slot). No-op if unknown.
74
84
  *
@@ -106,9 +116,7 @@ export declare class BrowserPool {
106
116
  * Touches the lease like any other tool call, so capturing keeps it alive rather than letting the
107
117
  * reaper take it out from under a diff.
108
118
  */
109
- screenshotLease(sessionId: string, opts?: {
110
- fullPage?: boolean;
111
- }): Promise<Uint8Array | undefined>;
119
+ screenshotLease(sessionId: string, opts?: ScreenshotOptions): Promise<Uint8Array | undefined>;
112
120
  /**
113
121
  * Move the real pointer on a leased page, or false when this session is not a lease or cannot
114
122
  * hover. Same optional-capability contract as screenshotLease: absence must read as "could not
@@ -167,6 +175,9 @@ export declare class BrowserPool {
167
175
  signal?: AbortSignal;
168
176
  sessionId?: string;
169
177
  seedStorage?: SeedStorage;
178
+ owner?: string;
179
+ /** In a browser with a window the person can watch. */
180
+ headed?: boolean;
170
181
  }): Promise<Lease>;
171
182
  /**
172
183
  * The websocket address this lease's page reported it could not reach, if it reported one.
@@ -181,4 +192,6 @@ export declare class BrowserPool {
181
192
  lastDialogMessage(sessionId: string): string | undefined;
182
193
  /** Close every context and the browser. Pending waiters are rejected (the pool is terminal now). */
183
194
  shutdown(): Promise<void>;
195
+ /** Whether this lease lives in the headed browser. */
196
+ isHeaded(sessionId: string): boolean;
184
197
  }