@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.
- package/README.md +1 -1
- package/SKILL.md +16 -8
- package/dist/chromium-launch-options.d.ts +3 -1
- package/dist/chromium-launch-options.js +2 -1
- package/dist/command/cli/adhoc-verdict.d.ts +1 -0
- package/dist/command/cli/adhoc-verdict.js +6 -3
- package/dist/command/cli/answers/open-note.d.ts +2 -0
- package/dist/command/cli/answers/open-note.js +22 -0
- package/dist/command/cli/auth/cloud-session.d.ts +4 -4
- package/dist/command/cli/auth/device-flow.d.ts +2 -2
- package/dist/command/cli/cli-flow-commands.js +4 -8
- package/dist/command/cli/cli-parse.d.ts +1 -1
- package/dist/command/cli/cli-parse.js +13 -11
- package/dist/command/cli/cli-verify.d.ts +1 -1
- package/dist/command/cli/cli-verify.js +35 -25
- package/dist/command/cli/cloud-cli.js +110 -12
- package/dist/command/cli/cloud-login.d.ts +9 -1
- package/dist/command/cli/cloud-login.js +43 -8
- package/dist/command/cli/demo/demo-page.js +11 -3
- package/dist/command/cli/doctor/browser/chromium-hint.d.ts +46 -0
- package/dist/command/cli/doctor/browser/chromium-hint.js +99 -1
- package/dist/command/cli/drive/drive-attach.d.ts +27 -2
- package/dist/command/cli/drive/drive-attach.js +71 -4
- package/dist/command/cli/drive/drive-command.d.ts +2 -1
- package/dist/command/cli/drive/drive-command.js +13 -7
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +4 -1
- package/dist/command/cli/ports/port-holder.d.ts +10 -0
- package/dist/command/cli/ports/port-holder.js +24 -0
- package/dist/command/cli/setup-mcp-cli.js +15 -5
- package/dist/command/cli/tutorial.d.ts +2 -2
- package/dist/command/cli/tutorial.js +6 -9
- package/dist/command/cli.d.ts +6 -0
- package/dist/command/cli.js +45 -23
- package/dist/command/daemon/binding/daemon-status-probe.d.ts +2 -0
- package/dist/command/daemon/binding/daemon-status-probe.js +1 -0
- package/dist/command/daemon/daemon-resolve.d.ts +14 -0
- package/dist/command/daemon/daemon-resolve.js +33 -2
- package/dist/command/setup/agent-writer.d.ts +1 -1
- package/dist/command/setup/agent-writer.js +3 -2
- package/dist/command/setup/bringup/connect-lease.d.ts +1 -0
- package/dist/command/setup/bringup/connect-lease.js +1 -0
- package/dist/command/setup/bringup/dev-server-wait.d.ts +10 -0
- package/dist/command/setup/bringup/dev-server-wait.js +20 -1
- package/dist/command/setup/init/init-port.d.ts +4 -0
- package/dist/command/setup/init/init-port.js +10 -0
- package/dist/command/setup/init/init-runtime.d.ts +10 -0
- package/dist/command/setup/init/init-runtime.js +71 -9
- package/dist/command/setup/node-effects.js +8 -2
- package/dist/command/setup/remaining-steps.js +2 -1
- package/dist/command/setup/run-setup.d.ts +7 -0
- package/dist/command/setup/run-setup.js +38 -25
- package/dist/command/setup/setup-command.d.ts +2 -1
- package/dist/command/setup/setup-command.js +2 -0
- package/dist/command/setup/setup-mcp.d.ts +2 -0
- package/dist/command/setup/setup-mcp.js +14 -5
- package/dist/command/version/peer-announce.d.ts +6 -2
- package/dist/command/version/peer-announce.js +8 -6
- package/dist/command/version/version-nudge.d.ts +17 -3
- package/dist/command/version/version-nudge.js +25 -4
- package/dist/command/version/version-skew.js +11 -2
- package/dist/features/crawl/crawl-tools.js +4 -0
- package/dist/features/crawl/crawl.d.ts +6 -0
- package/dist/features/crawl/crawl.js +9 -1
- package/dist/features/exhaust/ledger.d.ts +7 -0
- package/dist/features/exhaust/ledger.js +35 -9
- package/dist/features/harness/app-findings.d.ts +2 -0
- package/dist/features/harness/app-findings.js +52 -0
- package/dist/features/harness/drive-report.d.ts +27 -1
- package/dist/features/harness/drive-report.js +162 -11
- package/dist/features/harness/drivers.d.ts +10 -14
- package/dist/features/harness/drivers.js +10 -14
- package/dist/features/harness/fill-values.d.ts +3 -69
- package/dist/features/harness/fill-values.js +3 -133
- package/dist/features/harness/goals.d.ts +21 -0
- package/dist/features/harness/goals.js +77 -0
- package/dist/features/harness/harness.d.ts +21 -0
- package/dist/features/harness/harness.js +69 -2
- package/dist/features/harness/platform/drive-target.d.ts +30 -0
- package/dist/features/harness/platform/drive-target.js +81 -0
- package/dist/features/harness/platform/local-apps.d.ts +94 -0
- package/dist/features/harness/platform/local-apps.js +204 -0
- package/dist/features/harness/platform/remote-drive.d.ts +180 -0
- package/dist/features/harness/platform/remote-drive.js +365 -0
- package/dist/features/harness/platform/script.d.ts +48 -0
- package/dist/features/harness/platform/script.js +128 -0
- package/dist/features/harness/platform/server-driver.d.ts +41 -0
- package/dist/features/harness/platform/server-driver.js +179 -0
- package/dist/features/harness/platform-config.d.ts +7 -0
- package/dist/features/harness/platform-config.js +14 -2
- package/dist/features/harness/script/app-controls.d.ts +5 -0
- package/dist/features/harness/script/app-controls.js +40 -0
- package/dist/features/harness/script/lane-ids.d.ts +14 -0
- package/dist/features/harness/script/lane-ids.js +16 -0
- package/dist/features/harness/script/script-run.d.ts +41 -0
- package/dist/features/harness/script/script-run.js +299 -0
- package/dist/features/license/license.d.ts +2 -2
- package/dist/features/visual/visual-tools.d.ts +10 -1
- package/dist/features/visual/visual-tools.js +40 -3
- package/dist/hooks/driven-by.d.ts +4 -0
- package/dist/hooks/driven-by.js +16 -0
- package/dist/hooks/hook-commands.js +15 -4
- package/dist/hooks/tool-log.d.ts +9 -0
- package/dist/hooks/tool-log.js +29 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +91 -89
- package/dist/judgement/capsule/capsule-store.d.ts +4 -4
- package/dist/judgement/runs/artifact/build-verification-run.js +6 -0
- package/dist/judgement/runs/artifact/replay-mapping.d.ts +1 -1
- package/dist/judgement/runs/artifact/replay-mapping.js +16 -6
- package/dist/judgement/runs/artifact/run-store.d.ts +1 -1
- package/dist/judgement/runs/artifact/run-store.js +26 -1
- package/dist/judgement/runs/drive-run.d.ts +22 -0
- package/dist/judgement/runs/drive-run.js +99 -1
- package/dist/judgement/runs/repair-prompt.js +1 -1
- package/dist/judgement/runs/reticle-runner.js +8 -1
- package/dist/judgement/runs/verification-sync.d.ts +3 -2
- package/dist/judgement/runs/verification-sync.js +4 -3
- package/dist/language/flows/change/gate.d.ts +10 -0
- package/dist/language/flows/change/gate.js +22 -0
- package/dist/language/flows/decision.js +34 -0
- package/dist/language/flows/flow-anchor.d.ts +54 -8
- package/dist/language/flows/flow-anchor.js +88 -3
- package/dist/language/flows/flow-cross-step.d.ts +15 -0
- package/dist/language/flows/flow-cross-step.js +21 -0
- package/dist/language/flows/flow-learning.js +8 -11
- package/dist/language/flows/flow-mutate-tools.js +5 -3
- package/dist/language/flows/flow-replay-run.d.ts +23 -9
- package/dist/language/flows/flow-replay-run.js +101 -94
- package/dist/language/flows/flow-replay.d.ts +23 -1
- package/dist/language/flows/flow-replay.js +92 -19
- package/dist/language/flows/flow-scope.js +5 -1
- package/dist/language/flows/flow-step-runners.d.ts +20 -2
- package/dist/language/flows/flow-step-runners.js +236 -42
- package/dist/language/flows/flow-store-for-session.d.ts +2 -2
- package/dist/language/flows/flow-store-for-session.js +2 -2
- package/dist/language/flows/flow-tools.js +58 -34
- package/dist/language/flows/flows.js +5 -2
- package/dist/language/flows/heal-run.js +6 -4
- package/dist/language/flows/recording/flake.d.ts +2 -2
- package/dist/language/flows/recording/tape/recordings.d.ts +30 -4
- package/dist/language/flows/recording/tape/recordings.js +40 -8
- package/dist/language/flows/replay-from-hud.d.ts +20 -0
- package/dist/language/flows/replay-from-hud.js +51 -0
- package/dist/language/flows/replay.d.ts +9 -5
- package/dist/language/flows/replay.js +27 -9
- package/dist/language/flows/suite/suite-flakes.js +2 -0
- package/dist/language/flows/suite-selection.d.ts +2 -15
- package/dist/language/flows/suite-selection.js +4 -3
- package/dist/language/flows/verify-change-tools.js +8 -4
- package/dist/launch-chromium.d.ts +27 -5
- package/dist/launch-chromium.js +38 -8
- package/dist/memory/cloud/cloud-config.d.ts +12 -0
- package/dist/memory/cloud/cloud-config.js +15 -0
- package/dist/memory/cloud/cloud-sync.d.ts +17 -14
- package/dist/memory/cloud/cloud-sync.js +12 -1
- package/dist/memory/cloud/harness-config.d.ts +26 -1
- package/dist/memory/cloud/harness-config.js +99 -4
- package/dist/memory/cloud/hud-notices-source.d.ts +21 -0
- package/dist/memory/cloud/hud-notices-source.js +128 -0
- package/dist/memory/cloud/memory-scope.d.ts +144 -0
- package/dist/memory/cloud/memory-scope.js +205 -0
- package/dist/memory/cloud/sync-cycle.d.ts +21 -3
- package/dist/memory/cloud/sync-cycle.js +45 -5
- package/dist/memory/cloud/sync-daemon.js +7 -5
- package/dist/memory/cloud/sync-disk.d.ts +1 -1
- package/dist/memory/cloud/sync-disk.js +5 -8
- package/dist/memory/impact/account-watch.d.ts +19 -0
- package/dist/memory/impact/account-watch.js +34 -0
- package/dist/memory/impact/impact-recorder.d.ts +8 -0
- package/dist/memory/impact/impact-recorder.js +12 -2
- package/dist/memory/impact/impact-store.d.ts +16 -0
- package/dist/memory/impact/impact-store.js +142 -26
- package/dist/memory/intent/intent-shard.d.ts +2 -2
- package/dist/memory/intent/intent-tools.js +88 -5
- package/dist/memory/journal/envelope.d.ts +16 -16
- package/dist/memory/journal/journal-query.d.ts +14 -0
- package/dist/memory/journal/journal-query.js +15 -0
- package/dist/memory/journal/journal-recorder.js +7 -1
- package/dist/memory/journal/on-disk/retention.d.ts +3 -0
- package/dist/memory/journal/on-disk/retention.js +5 -0
- package/dist/memory/journal/on-disk/startup-maintenance.js +3 -1
- package/dist/memory/journal/on-disk/workspace-tiers.js +7 -4
- package/dist/memory/journal/session-end.js +6 -4
- package/dist/memory/project/artifact-root-resolver.d.ts +36 -1
- package/dist/memory/project/artifact-root-resolver.js +134 -26
- package/dist/memory/project/artifact-root.d.ts +42 -5
- package/dist/memory/project/artifact-root.js +87 -8
- package/dist/memory/project/dir/reticle-dir.d.ts +4 -2
- package/dist/memory/project/dir/reticle-dir.js +3 -1
- package/dist/memory/project/project-tools.js +22 -3
- package/dist/memory/project/session-root.d.ts +24 -1
- package/dist/memory/project/session-root.js +41 -5
- package/dist/memory/project/sync-status.d.ts +39 -0
- package/dist/memory/project/sync-status.js +90 -0
- package/dist/memory/recall/memory-tools.js +2 -0
- package/dist/memory/recall/project-memory.d.ts +19 -0
- package/dist/memory/recall/project-memory.js +45 -6
- package/dist/portal/bridge/bridge.d.ts +7 -4
- package/dist/portal/bridge/bridge.js +25 -3
- package/dist/portal/bridge/pairing-token.d.ts +9 -0
- package/dist/portal/bridge/pairing-token.js +17 -0
- package/dist/portal/input/real-input.d.ts +81 -10
- package/dist/portal/input/real-input.js +207 -22
- package/dist/portal/input/viewport-tools.js +19 -9
- package/dist/portal/pool/browser-pool.d.ts +22 -9
- package/dist/portal/pool/browser-pool.js +70 -35
- package/dist/portal/pool/playwright-launcher.d.ts +13 -0
- package/dist/portal/pool/playwright-launcher.js +17 -1
- package/dist/portal/pool/pool-contract.d.ts +7 -4
- package/dist/portal/session/command-payload.d.ts +8 -0
- package/dist/portal/session/command-payload.js +19 -0
- package/dist/portal/session/dev-server/dev-command.d.ts +12 -0
- package/dist/portal/session/dev-server/dev-command.js +61 -12
- package/dist/portal/session/facts/departure-note.d.ts +22 -0
- package/dist/portal/session/facts/departure-note.js +47 -0
- package/dist/portal/session/facts/session-replaced.d.ts +5 -0
- package/dist/portal/session/facts/session-replaced.js +5 -0
- package/dist/portal/session/first-run-wiring.d.ts +42 -0
- package/dist/portal/session/first-run-wiring.js +132 -0
- package/dist/portal/session/human/notes-ledger.d.ts +20 -0
- package/dist/portal/session/human/notes-ledger.js +55 -0
- package/dist/portal/session/human/review-store.d.ts +12 -0
- package/dist/portal/session/human/review-store.js +18 -10
- package/dist/portal/session/live-control-tools.d.ts +0 -13
- package/dist/portal/session/live-control-tools.js +28 -3
- package/dist/portal/session/no-session-diagnosis.d.ts +7 -0
- package/dist/portal/session/no-session-diagnosis.js +15 -0
- package/dist/portal/session/no-session-next-action.d.ts +11 -0
- package/dist/portal/session/no-session-next-action.js +31 -5
- package/dist/portal/session/no-session-watch.d.ts +14 -1
- package/dist/portal/session/no-session-watch.js +63 -10
- package/dist/portal/session/presence/session-mirror.js +3 -0
- package/dist/portal/session/serving-directory.d.ts +27 -0
- package/dist/portal/session/serving-directory.js +45 -0
- package/dist/portal/session/session-health.d.ts +7 -0
- package/dist/portal/session/session-health.js +6 -0
- package/dist/portal/session/session-info.d.ts +8 -1
- package/dist/portal/session/session-info.js +6 -0
- package/dist/portal/session/session-manager.d.ts +21 -0
- package/dist/portal/session/session-manager.js +44 -8
- package/dist/portal/session/session-reaper.js +4 -1
- package/dist/portal/session/session-successor.d.ts +5 -0
- package/dist/portal/session/session-tools.js +26 -3
- package/dist/portal/session/session.d.ts +12 -10
- package/dist/portal/session/session.js +30 -31
- package/dist/start-options.d.ts +6 -0
- package/dist/status-payload.d.ts +10 -0
- package/dist/status-payload.js +23 -0
- package/dist/surface/http-server.d.ts +1 -1
- package/dist/surface/http-server.js +15 -4
- package/dist/surface/mcp/mcp-proxy.d.ts +5 -0
- package/dist/surface/mcp/mcp-proxy.js +36 -5
- package/dist/surface/mcp/mcp.d.ts +11 -6
- package/dist/surface/mcp/mcp.js +28 -14
- package/dist/surface/mcp/proxy/proxy-log.js +3 -5
- package/dist/surface/mcp/server-instructions.d.ts +4 -2
- package/dist/surface/mcp/server-instructions.js +14 -4
- package/dist/surface/mcp/shared-params.js +2 -2
- package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +8 -0
- package/dist/surface/tools/act/navigation/navigate-arrival.js +56 -2
- package/dist/surface/tools/act/settle-in-flight.js +25 -3
- package/dist/surface/tools/act-sequence-tool.js +2 -2
- package/dist/surface/tools/act-tools.js +25 -9
- package/dist/surface/tools/assert/assert-verdict.d.ts +1 -1
- package/dist/surface/tools/assert/assert-verdict.js +17 -2
- package/dist/surface/tools/browser-tools.js +8 -1
- package/dist/surface/tools/chat-drives.d.ts +26 -0
- package/dist/surface/tools/chat-drives.js +165 -0
- package/dist/surface/tools/dynamic-tools.js +29 -2
- package/dist/surface/tools/empty-session-list.d.ts +41 -0
- package/dist/surface/tools/empty-session-list.js +80 -0
- package/dist/surface/tools/error-recovery.d.ts +6 -0
- package/dist/surface/tools/error-recovery.js +38 -6
- package/dist/surface/tools/explore-tools.d.ts +10 -1
- package/dist/surface/tools/explore-tools.js +82 -13
- package/dist/surface/tools/feedback-tools.js +14 -0
- package/dist/surface/tools/harness-explore.d.ts +96 -14
- package/dist/surface/tools/harness-explore.js +227 -202
- package/dist/surface/tools/harness-plan.d.ts +12 -0
- package/dist/surface/tools/harness-plan.js +31 -0
- package/dist/surface/tools/harness-script.d.ts +8 -0
- package/dist/surface/tools/harness-script.js +342 -0
- package/dist/surface/tools/harness-toolset.d.ts +14 -1
- package/dist/surface/tools/harness-toolset.js +77 -6
- package/dist/surface/tools/invoke-tool.js +64 -9
- package/dist/surface/tools/lease-seed.d.ts +29 -0
- package/dist/surface/tools/lease-seed.js +123 -0
- package/dist/surface/tools/lease-tools.d.ts +3 -23
- package/dist/surface/tools/lease-tools.js +30 -131
- package/dist/surface/tools/live-call-text.js +2 -2
- package/dist/surface/tools/next-step.d.ts +19 -0
- package/dist/surface/tools/next-step.js +159 -0
- package/dist/surface/tools/observe-tools.js +2 -4
- package/dist/surface/tools/platform-moment.d.ts +12 -0
- package/dist/surface/tools/platform-moment.js +168 -0
- package/dist/surface/tools/query-hint-schema.d.ts +7 -0
- package/dist/surface/tools/query-hint-schema.js +10 -0
- package/dist/surface/tools/read-tools.js +8 -2
- package/dist/surface/tools/real-input-attempt.js +96 -13
- package/dist/surface/tools/tool-kit.d.ts +25 -1
- package/dist/surface/tools/tool-kit.js +4 -6
- package/dist/surface/tools/tools.js +20 -48
- package/dist/telemetry/argument-shape.js +1 -1
- package/dist/telemetry/hud-metrics.d.ts +2 -0
- package/dist/telemetry/hud-metrics.js +17 -0
- package/dist/telemetry/onboarding-firsts.d.ts +2 -2
- package/dist/telemetry/onboarding-firsts.js +2 -2
- package/dist/telemetry/telemetry.d.ts +12 -0
- package/dist/telemetry/telemetry.js +43 -14
- package/dist/telemetry/verification-of.js +1 -0
- package/dist/wire-journal.js +4 -1
- package/docs/README.md +1 -1
- package/docs/actions.mdx +1 -2
- package/docs/agent-cheatsheet.md +1 -1
- package/docs/autodrive.md +29 -25
- package/docs/cli/cloud.mdx +6 -4
- package/docs/cli/doctor.mdx +6 -0
- package/docs/cli/drive.mdx +8 -2
- package/docs/cli/init.mdx +11 -13
- package/docs/cli/status.mdx +5 -1
- package/docs/cli/version.mdx +3 -3
- package/docs/cli.mdx +14 -8
- package/docs/desktop.mdx +5 -1
- package/docs/environment.mdx +3 -7
- package/docs/getting-started.md +14 -2
- package/docs/human-control.md +1 -2
- package/docs/index.mdx +4 -3
- package/docs/install-agentic.mdx +1 -1
- package/docs/install-manual.mdx +2 -2
- package/docs/packages/next.mdx +3 -0
- package/docs/packages/tauri.mdx +2 -2
- package/docs/packages/vite-plugin.mdx +24 -1
- package/docs/packages.mdx +1 -1
- package/docs/quickstart.mdx +23 -11
- package/docs/telemetry.md +1 -1
- package/docs/tools/act.mdx +1 -1
- package/docs/tools/session-and-feedback.mdx +9 -9
- package/docs/usage.md +5 -3
- package/docs/what-is-recorded.md +13 -3
- package/docs/what-is-reticle.mdx +3 -1
- package/package.json +8 -12
- package/dist/features/harness/driver.d.ts +0 -50
- package/dist/features/harness/driver.js +0 -236
- package/dist/features/harness/jev-driver.d.ts +0 -188
- package/dist/features/harness/jev-driver.js +0 -678
- package/dist/features/harness/openai-driver.d.ts +0 -46
- package/dist/features/harness/openai-driver.js +0 -194
- package/dist/memory/project/dir/fill-value-store.d.ts +0 -32
- package/dist/memory/project/dir/fill-value-store.js +0 -88
- 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
|
|
38
|
-
*
|
|
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
|
|
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
|
|
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
|
|
252
|
+
return real(true);
|
|
73
253
|
}
|
|
74
254
|
if (action === ActionType.DRAG) {
|
|
75
255
|
if (args.toBox === undefined)
|
|
76
|
-
return
|
|
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
|
|
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
|
|
272
|
+
return real(true);
|
|
93
273
|
}
|
|
94
|
-
return
|
|
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.
|
|
111
|
-
? {
|
|
112
|
-
:
|
|
113
|
-
? { ...SCREENSHOT_DETERMINISM,
|
|
114
|
-
:
|
|
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
|
|
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(
|
|
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,
|
|
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:
|
|
63
|
+
recommendation: VIEWPORT_NO_PROVIDER_RECOMMENDATION,
|
|
64
64
|
};
|
|
65
65
|
},
|
|
66
66
|
},
|
|
67
67
|
];
|
|
68
|
-
/**
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
|
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
|
|
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).
|
|
67
|
-
*
|
|
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
|
}
|