@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.
- package/LICENSE +201 -104
- package/NOTICE +5 -0
- package/README.md +1 -1
- package/SKILL.md +13 -12
- package/bin/launch.js +13 -0
- package/bin/package.json +3 -0
- package/bin/reticle.js +66 -8
- package/dist/chromium-launch-options.d.ts +25 -0
- package/dist/chromium-launch-options.js +21 -1
- package/dist/command/cli/adhoc-suite.js +2 -0
- package/dist/command/cli/adhoc-verdict.d.ts +2 -43
- package/dist/command/cli/adhoc-verdict.js +50 -160
- package/dist/command/cli/answers/gate-exit.d.ts +6 -2
- package/dist/command/cli/answers/gate-exit.js +12 -2
- package/dist/command/cli/answers/mcp-connection-hint.d.ts +2 -0
- package/dist/command/cli/answers/mcp-connection-hint.js +6 -0
- package/dist/command/cli/ci-hint.d.ts +44 -0
- package/dist/command/cli/ci-hint.js +72 -0
- package/dist/command/cli/cli-doctor.d.ts +6 -1
- package/dist/command/cli/cli-doctor.js +46 -5
- package/dist/command/cli/cli-flow-commands.d.ts +7 -1
- package/dist/command/cli/cli-flow-commands.js +39 -24
- package/dist/command/cli/cli-kill.d.ts +21 -0
- package/dist/command/cli/cli-kill.js +47 -4
- package/dist/command/cli/cli-parse-compare.d.ts +22 -0
- package/dist/command/cli/cli-parse-compare.js +75 -0
- package/dist/command/cli/cli-parse-grade.d.ts +36 -0
- package/dist/command/cli/cli-parse-grade.js +75 -0
- package/dist/command/cli/cli-parse-grammar.d.ts +2 -0
- package/dist/command/cli/cli-parse-grammar.js +18 -20
- package/dist/command/cli/cli-parse-verify.d.ts +10 -0
- package/dist/command/cli/cli-parse-verify.js +63 -14
- package/dist/command/cli/cli-parse.d.ts +22 -17
- package/dist/command/cli/cli-parse.js +54 -32
- package/dist/command/cli/cli-update-commands.d.ts +1 -1
- package/dist/command/cli/cli-update-commands.js +29 -20
- package/dist/command/cli/cli-usage.js +61 -31
- package/dist/command/cli/cli-verify.d.ts +17 -3
- package/dist/command/cli/cli-verify.js +59 -21
- package/dist/command/cli/cloud-cli.js +2 -119
- package/dist/command/cli/daemon-link/daemon-client.d.ts +45 -0
- package/dist/command/cli/daemon-link/daemon-client.js +205 -0
- package/dist/command/cli/doctor/browser/chromium-hint.d.ts +6 -1
- package/dist/command/cli/doctor/browser/chromium-hint.js +11 -5
- package/dist/command/cli/doctor/doctor-daemon-line.js +6 -3
- package/dist/command/cli/doctor/doctor-fix.d.ts +44 -0
- package/dist/command/cli/doctor/doctor-fix.js +89 -0
- package/dist/command/cli/doctor/doctor-launcher-line.d.ts +23 -0
- package/dist/command/cli/doctor/doctor-launcher-line.js +60 -0
- package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
- package/dist/command/cli/doctor/doctor-rows.js +4 -0
- package/dist/command/cli/doctor-repairs.d.ts +64 -0
- package/dist/command/cli/doctor-repairs.js +214 -0
- package/dist/command/cli/drive/drive-command.js +3 -7
- package/dist/command/cli/ensure-daemon.d.ts +26 -0
- package/dist/command/cli/ensure-daemon.js +57 -0
- package/dist/command/cli/finished-run/grade-command.d.ts +23 -0
- package/dist/command/cli/finished-run/grade-command.js +180 -0
- package/dist/command/cli/first-use-checks.d.ts +41 -0
- package/dist/command/cli/first-use-checks.js +127 -0
- package/dist/command/cli/first-verdict-node.d.ts +3 -0
- package/dist/command/cli/first-verdict-node.js +189 -0
- package/dist/command/cli/first-verdict.d.ts +126 -0
- package/dist/command/cli/first-verdict.js +267 -0
- package/dist/command/cli/launch/sdk-version-match.d.ts +3 -2
- package/dist/command/cli/launch/sdk-version-match.js +3 -2
- package/dist/command/cli/lifecycle/daemon-lifecycle.d.ts +1 -1
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +7 -6
- package/dist/command/cli/mcp-command.js +13 -4
- package/dist/command/cli/ports/port-holder.d.ts +11 -0
- package/dist/command/cli/ports/port-holder.js +36 -4
- package/dist/command/cli/setup-mcp-cli.d.ts +27 -1
- package/dist/command/cli/setup-mcp-cli.js +98 -23
- package/dist/command/cli/status/status-lines.d.ts +2 -0
- package/dist/command/cli/status/status-lines.js +72 -17
- package/dist/command/cli/status-fields.d.ts +5 -1
- package/dist/command/cli/status-fields.js +24 -6
- package/dist/command/cli/try-command.d.ts +7 -0
- package/dist/command/cli/try-command.js +11 -3
- package/dist/command/cli/two-builds/compare-command.d.ts +48 -0
- package/dist/command/cli/two-builds/compare-command.js +314 -0
- package/dist/command/cli/verify-against.d.ts +61 -0
- package/dist/command/cli/verify-against.js +187 -0
- package/dist/command/cli/verify-no-session.d.ts +2 -0
- package/dist/command/cli/verify-no-session.js +13 -0
- package/dist/command/cli/verify-results.d.ts +35 -2
- package/dist/command/cli/verify-results.js +76 -10
- package/dist/command/cli.js +112 -70
- package/dist/command/daemon/binding/daemon-status-probe.d.ts +3 -1
- package/dist/command/daemon/binding/daemon-status-probe.js +4 -2
- package/dist/command/daemon/daemon-argv.d.ts +9 -0
- package/dist/command/daemon/daemon-argv.js +11 -0
- package/dist/command/daemon/daemon-resolve.d.ts +8 -1
- package/dist/command/daemon/daemon-resolve.js +27 -1
- package/dist/command/daemon/daemon.d.ts +22 -4
- package/dist/command/daemon/daemon.js +52 -10
- package/dist/command/daemon/lifetime/daemon-exit.d.ts +24 -0
- package/dist/command/daemon/lifetime/daemon-exit.js +39 -0
- package/dist/command/daemon/lifetime/death-cause.d.ts +15 -0
- package/dist/command/daemon/lifetime/death-cause.js +149 -0
- package/dist/command/daemon/lifetime/heartbeat.d.ts +7 -15
- package/dist/command/daemon/lifetime/heartbeat.js +11 -15
- package/dist/command/daemon/lifetime/startup-failure.d.ts +29 -0
- package/dist/command/daemon/lifetime/startup-failure.js +62 -0
- package/dist/command/daemon/port-state.d.ts +14 -0
- package/dist/command/daemon/port-state.js +31 -0
- package/dist/command/setup/agent-configs.d.ts +2 -0
- package/dist/command/setup/agent-configs.js +42 -15
- package/dist/command/setup/agent-next-steps.d.ts +77 -0
- package/dist/command/setup/agent-next-steps.js +284 -0
- package/dist/command/setup/agent-writer.js +11 -6
- package/dist/command/setup/bringup/dev-server-files.d.ts +9 -0
- package/dist/command/setup/bringup/dev-server-files.js +17 -0
- package/dist/command/setup/bringup/static-page-server.d.ts +14 -2
- package/dist/command/setup/bringup/static-page-server.js +43 -9
- package/dist/command/setup/init/init-host.js +2 -0
- package/dist/command/setup/init/init-runtime.d.ts +6 -1
- package/dist/command/setup/init/init-runtime.js +63 -21
- package/dist/command/setup/mcp-launcher.d.ts +3 -0
- package/dist/command/setup/mcp-launcher.js +11 -0
- package/dist/command/setup/node-effects.d.ts +3 -2
- package/dist/command/setup/node-effects.js +9 -3
- package/dist/command/setup/remaining-steps.d.ts +8 -0
- package/dist/command/setup/remaining-steps.js +10 -0
- package/dist/command/setup/run-setup.d.ts +2 -0
- package/dist/command/setup/run-setup.js +9 -1
- package/dist/command/setup/setup-command.js +36 -15
- package/dist/command/setup/setup-mcp.d.ts +8 -0
- package/dist/command/setup/setup-mcp.js +47 -20
- package/dist/command/setup/start-dev-server.d.ts +8 -0
- package/dist/command/setup/start-dev-server.js +43 -0
- package/dist/command/update/updater.js +6 -0
- package/dist/command/version/identity/server-version.d.ts +2 -0
- package/dist/command/version/identity/server-version.js +2 -0
- package/dist/command/version/version-skew.d.ts +7 -0
- package/dist/command/version/version-skew.js +14 -3
- package/dist/features/compare/action-plan.d.ts +260 -0
- package/dist/features/compare/action-plan.js +543 -0
- package/dist/features/compare/behaviour-compare.d.ts +24 -0
- package/dist/features/compare/behaviour-compare.js +85 -0
- package/dist/features/compare/behaviour-diff.d.ts +97 -0
- package/dist/features/compare/behaviour-diff.js +202 -0
- package/dist/features/compare/behaviour-report.d.ts +40 -0
- package/dist/features/compare/behaviour-report.js +128 -0
- package/dist/features/compare/build-readings.d.ts +106 -0
- package/dist/features/compare/build-readings.js +250 -0
- package/dist/features/compare/compare-diff.d.ts +62 -0
- package/dist/features/compare/compare-diff.js +177 -0
- package/dist/features/compare/compare-report-html.d.ts +6 -0
- package/dist/features/compare/compare-report-html.js +102 -0
- package/dist/features/compare/compare-report.d.ts +15 -0
- package/dist/features/compare/compare-report.js +73 -0
- package/dist/features/compare/compare-run.d.ts +60 -0
- package/dist/features/compare/compare-run.js +123 -0
- package/dist/features/compare/outside/effect-lines.d.ts +26 -0
- package/dist/features/compare/outside/effect-lines.js +103 -0
- package/dist/features/compare/outside/state-sources.d.ts +76 -0
- package/dist/features/compare/outside/state-sources.js +164 -0
- package/dist/features/compare/outside/value-dictionary.d.ts +51 -0
- package/dist/features/compare/outside/value-dictionary.js +227 -0
- package/dist/features/compare/visible-content.d.ts +20 -0
- package/dist/features/compare/visible-content.js +125 -0
- package/dist/features/crawl/crawl-empty.js +2 -1
- package/dist/features/crawl/crawl-exhaustive.d.ts +55 -0
- package/dist/features/crawl/crawl-exhaustive.js +138 -0
- package/dist/features/crawl/crawl-tools.d.ts +9 -2
- package/dist/features/crawl/crawl-tools.js +28 -12
- package/dist/features/crawl/crawl.d.ts +8 -9
- package/dist/features/crawl/crawl.js +61 -65
- package/dist/features/exhaust/app-coverage.d.ts +5 -1
- package/dist/features/exhaust/app-coverage.js +3 -1
- package/dist/features/exhaust/code-coverage.js +8 -4
- package/dist/features/exhaust/edge-cases.d.ts +133 -0
- package/dist/features/exhaust/edge-cases.js +310 -0
- package/dist/features/exhaust/edges/edge-drive.d.ts +42 -0
- package/dist/features/exhaust/edges/edge-drive.js +364 -0
- package/dist/features/exhaust/edges/edge-run.d.ts +59 -0
- package/dist/features/exhaust/edges/edge-run.js +169 -0
- package/dist/features/exhaust/explorer.d.ts +87 -14
- package/dist/features/exhaust/explorer.js +159 -25
- package/dist/features/exhaust/failure-branches.d.ts +5 -0
- package/dist/features/exhaust/failure-branches.js +29 -11
- package/dist/features/exhaust/invariants.d.ts +112 -0
- package/dist/features/exhaust/invariants.js +188 -0
- package/dist/features/exhaust/ledger.d.ts +68 -0
- package/dist/features/exhaust/ledger.js +121 -13
- package/dist/features/exhaust/session-fold.d.ts +10 -0
- package/dist/features/exhaust/session-fold.js +46 -3
- package/dist/features/exhaust/session-port.d.ts +3 -1
- package/dist/features/exhaust/session-port.js +97 -28
- package/dist/features/grade/grade-answer.d.ts +99 -0
- package/dist/features/grade/grade-answer.js +112 -0
- package/dist/features/grade/grade-noise.d.ts +27 -0
- package/dist/features/grade/grade-noise.js +55 -0
- package/dist/features/grade/grade-renumber.d.ts +12 -0
- package/dist/features/grade/grade-renumber.js +86 -0
- package/dist/features/grade/grade-state.d.ts +50 -0
- package/dist/features/grade/grade-state.js +93 -0
- package/dist/features/grade/grade-suggest.d.ts +33 -0
- package/dist/features/grade/grade-suggest.js +98 -0
- package/dist/features/license/license.d.ts +11 -71
- package/dist/features/license/license.js +43 -136
- package/dist/features/visual/desktop-capture.d.ts +33 -0
- package/dist/features/visual/desktop-capture.js +94 -0
- package/dist/features/visual/step-shots.js +139 -35
- package/dist/features/visual/visual-tools.d.ts +0 -18
- package/dist/features/visual/visual-tools.js +67 -99
- package/dist/import-graph.js +5 -6
- package/dist/index.d.ts +3 -1
- package/dist/index.js +19 -7
- package/dist/judgement/capsule/causal-summary.js +9 -2
- package/dist/judgement/runs/artifact/replay-mapping.d.ts +13 -1
- package/dist/judgement/runs/artifact/replay-mapping.js +1 -1
- package/dist/judgement/runs/reticle-runner.js +16 -2
- package/dist/judgement/runs/run-ledger.d.ts +7 -5
- package/dist/judgement/runs/run-ledger.js +98 -69
- package/dist/judgement/runs/runner-port.d.ts +2 -0
- package/dist/judgement/runs/runner-port.js +23 -5
- package/dist/judgement/runs/verification-sync.d.ts +6 -3
- package/dist/judgement/runs/verification-sync.js +21 -10
- package/dist/language/flows/affected-tools.d.ts +1 -1
- package/dist/language/flows/affected-tools.js +49 -30
- package/dist/language/flows/change/git-changed.d.ts +2 -1
- package/dist/language/flows/change/git-changed.js +19 -2
- package/dist/language/flows/fields/flow-secret-field.d.ts +1 -13
- package/dist/language/flows/fields/flow-secret-field.js +77 -21
- package/dist/language/flows/flow-anchor.d.ts +60 -2
- package/dist/language/flows/flow-anchor.js +125 -20
- package/dist/language/flows/flow-classify.d.ts +20 -0
- package/dist/language/flows/flow-classify.js +90 -12
- package/dist/language/flows/flow-cross-step.d.ts +7 -1
- package/dist/language/flows/flow-cross-step.js +25 -1
- package/dist/language/flows/flow-journey.d.ts +38 -4
- package/dist/language/flows/flow-journey.js +138 -8
- package/dist/language/flows/flow-replay-run.d.ts +0 -16
- package/dist/language/flows/flow-replay-run.js +76 -14
- package/dist/language/flows/flow-replay-types.d.ts +4 -2
- package/dist/language/flows/flow-replay.d.ts +19 -1
- package/dist/language/flows/flow-replay.js +169 -52
- package/dist/language/flows/flow-replayable.js +7 -1
- package/dist/language/flows/flow-start-path.d.ts +34 -5
- package/dist/language/flows/flow-start-path.js +202 -15
- package/dist/language/flows/flow-step-runners.d.ts +14 -13
- package/dist/language/flows/flow-step-runners.js +184 -109
- package/dist/language/flows/flow-store-for-session.d.ts +26 -25
- package/dist/language/flows/flow-store-for-session.js +51 -5
- package/dist/language/flows/flow-tools.js +46 -33
- package/dist/language/flows/flows.js +176 -76
- package/dist/language/flows/recording/tape/recordings.d.ts +21 -16
- package/dist/language/flows/recording/tape/recordings.js +112 -49
- package/dist/language/flows/replay.d.ts +36 -12
- package/dist/language/flows/replay.js +193 -50
- package/dist/language/flows/steps/page-steps.d.ts +68 -0
- package/dist/language/flows/steps/page-steps.js +198 -0
- package/dist/language/flows/suite/sequential-run.d.ts +68 -0
- package/dist/language/flows/suite/sequential-run.js +96 -0
- package/dist/language/flows/verify-change-tools.js +26 -15
- package/dist/launch-chromium.d.ts +1 -0
- package/dist/launch-chromium.js +49 -12
- package/dist/memory/cloud/background-sync.d.ts +13 -0
- package/dist/memory/cloud/background-sync.js +24 -3
- package/dist/memory/cloud/sync-daemon.js +26 -27
- package/dist/memory/cloud/sync-screenshots.js +6 -1
- package/dist/memory/journal/attach-journal.js +2 -1
- package/dist/memory/journal/drive-flow.d.ts +7 -0
- package/dist/memory/journal/drive-flow.js +44 -13
- package/dist/memory/journal/journal-recorder.d.ts +4 -2
- package/dist/memory/journal/session-journal.d.ts +7 -0
- package/dist/memory/journal/session-journal.js +58 -10
- package/dist/memory/project/root-claims.d.ts +9 -0
- package/dist/memory/project/root-claims.js +9 -4
- package/dist/portal/bridge/bridge.d.ts +13 -4
- package/dist/portal/bridge/bridge.js +10 -9
- package/dist/portal/input/download-capture.d.ts +7 -0
- package/dist/portal/input/download-capture.js +92 -0
- package/dist/portal/input/network-detail.d.ts +6 -0
- package/dist/portal/input/network-detail.js +12 -1
- package/dist/portal/input/network-mock-tools.js +49 -13
- package/dist/portal/input/network-mock.d.ts +8 -0
- package/dist/portal/input/network-mock.js +30 -10
- package/dist/portal/input/page-capture.d.ts +24 -0
- package/dist/portal/input/page-capture.js +33 -0
- package/dist/portal/input/real-input.d.ts +35 -18
- package/dist/portal/input/real-input.js +99 -33
- package/dist/portal/input/viewport-tools.d.ts +8 -0
- package/dist/portal/input/viewport-tools.js +81 -21
- package/dist/portal/pool/browser-pool.d.ts +16 -30
- package/dist/portal/pool/browser-pool.js +64 -52
- package/dist/portal/pool/context-permissions.d.ts +34 -17
- package/dist/portal/pool/context-permissions.js +94 -1
- package/dist/portal/pool/csp-widen.d.ts +62 -0
- package/dist/portal/pool/csp-widen.js +132 -0
- package/dist/portal/pool/determinism.d.ts +52 -0
- package/dist/portal/pool/determinism.js +259 -0
- package/dist/portal/pool/lease-emulation.d.ts +34 -1
- package/dist/portal/pool/lease-emulation.js +18 -0
- package/dist/portal/pool/lease-marker-stamp.d.ts +6 -0
- package/dist/portal/pool/lease-marker-stamp.js +15 -1
- package/dist/portal/pool/lease-page-error.d.ts +56 -0
- package/dist/portal/pool/lease-page-error.js +160 -0
- package/dist/portal/pool/page-error-journal.d.ts +63 -0
- package/dist/portal/pool/page-error-journal.js +208 -0
- package/dist/portal/pool/playwright-launcher.js +71 -15
- package/dist/portal/pool/pool-contract.d.ts +49 -1
- package/dist/portal/pool/pool-lease.d.ts +70 -2
- package/dist/portal/pool/pool-lease.js +23 -0
- package/dist/portal/pool/zero-install.d.ts +8 -0
- package/dist/portal/pool/zero-install.js +91 -1
- package/dist/portal/session/dev-server/dev-command.d.ts +11 -2
- package/dist/portal/session/dev-server/dev-command.js +110 -16
- package/dist/portal/session/dev-server/dev-server-probe.d.ts +7 -0
- package/dist/portal/session/dev-server/dev-server-probe.js +9 -0
- package/dist/portal/session/dev-server/project-ports.d.ts +21 -0
- package/dist/portal/session/dev-server/project-ports.js +62 -0
- package/dist/portal/session/facts/departed-network.d.ts +66 -0
- package/dist/portal/session/facts/departed-network.js +142 -0
- package/dist/portal/session/no-session-diagnosis.d.ts +9 -0
- package/dist/portal/session/no-session-diagnosis.js +76 -27
- package/dist/portal/session/no-session-next-action.d.ts +14 -0
- package/dist/portal/session/no-session-next-action.js +56 -7
- package/dist/portal/session/no-session-watch.d.ts +6 -0
- package/dist/portal/session/no-session-watch.js +41 -4
- package/dist/portal/session/page-commands/undeclared-command.d.ts +9 -3
- package/dist/portal/session/page-commands/undeclared-command.js +16 -7
- package/dist/portal/session/recorded-gaps.d.ts +1 -1
- package/dist/portal/session/recorded-gaps.js +5 -2
- package/dist/portal/session/serving-directory.d.ts +10 -0
- package/dist/portal/session/serving-directory.js +39 -8
- package/dist/portal/session/session-manager.d.ts +10 -0
- package/dist/portal/session/session-manager.js +211 -81
- package/dist/portal/session/session.js +4 -3
- package/dist/portal/session/zero-install-first-call.d.ts +20 -1
- package/dist/portal/session/zero-install-first-call.js +34 -2
- package/dist/start-wiring.d.ts +30 -2
- package/dist/start-wiring.js +74 -9
- package/dist/surface/mcp/mcp-proxy.js +10 -2
- package/dist/surface/mcp/mcp.js +8 -5
- package/dist/surface/mcp/peer/agents-connected.d.ts +6 -0
- package/dist/surface/mcp/peer/agents-connected.js +58 -0
- package/dist/surface/mcp/proxy/proxy-daemon-probe.js +17 -5
- package/dist/surface/mcp/shared-params.d.ts +2 -0
- package/dist/surface/mcp/shared-params.js +31 -0
- package/dist/surface/tools/act/act-observation.d.ts +40 -2
- package/dist/surface/tools/act/act-observation.js +118 -12
- package/dist/surface/tools/act/act-preflight.js +38 -18
- package/dist/surface/tools/act/act-sequence-retry.d.ts +23 -2
- package/dist/surface/tools/act/act-sequence-retry.js +61 -5
- package/dist/surface/tools/act/act-target.js +3 -1
- package/dist/surface/tools/act/after-match.d.ts +10 -0
- package/dist/surface/tools/act/after-match.js +40 -0
- package/dist/surface/tools/act/already-true.js +1 -1
- package/dist/surface/tools/act/navigation/reload-result.d.ts +12 -1
- package/dist/surface/tools/act/navigation/reload-result.js +25 -2
- package/dist/surface/tools/act/resolve-target.d.ts +17 -1
- package/dist/surface/tools/act/resolve-target.js +59 -9
- package/dist/surface/tools/act/sequence-grade.d.ts +15 -1
- package/dist/surface/tools/act/sequence-grade.js +45 -27
- package/dist/surface/tools/act/settle-in-flight.js +27 -15
- package/dist/surface/tools/act-command.d.ts +23 -0
- package/dist/surface/tools/act-command.js +50 -0
- package/dist/surface/tools/act-sequence-tool.js +81 -50
- package/dist/surface/tools/act-tools.d.ts +1 -13
- package/dist/surface/tools/act-tools.js +83 -95
- package/dist/surface/tools/agent/build-staleness.d.ts +1 -1
- package/dist/surface/tools/agent/build-staleness.js +1 -1
- package/dist/surface/tools/assert/assert-verdict.js +18 -12
- package/dist/surface/tools/browser-tools.js +87 -13
- package/dist/surface/tools/compare-tools.d.ts +11 -0
- package/dist/surface/tools/compare-tools.js +94 -0
- package/dist/surface/tools/coverage-tools.js +1 -1
- package/dist/surface/tools/dynamic-tools.js +11 -3
- package/dist/surface/tools/empty-session-list.d.ts +2 -0
- package/dist/surface/tools/empty-session-list.js +4 -2
- package/dist/surface/tools/error-recovery.d.ts +12 -1
- package/dist/surface/tools/error-recovery.js +131 -40
- package/dist/surface/tools/explore-tools.js +1 -1
- package/dist/surface/tools/invoke-tool.js +29 -21
- package/dist/surface/tools/lease-coverage-tools.d.ts +49 -0
- package/dist/surface/tools/lease-coverage-tools.js +128 -0
- package/dist/surface/tools/lease-hint.d.ts +42 -1
- package/dist/surface/tools/lease-hint.js +52 -3
- package/dist/surface/tools/lease-readiness.d.ts +47 -0
- package/dist/surface/tools/lease-readiness.js +126 -0
- package/dist/surface/tools/lease-seed.d.ts +16 -1
- package/dist/surface/tools/lease-seed.js +37 -4
- package/dist/surface/tools/lease-tools.d.ts +3 -41
- package/dist/surface/tools/lease-tools.js +104 -124
- package/dist/surface/tools/lease-url-identity.d.ts +46 -0
- package/dist/surface/tools/lease-url-identity.js +97 -0
- package/dist/surface/tools/merge-tools.js +99 -2
- package/dist/surface/tools/merged-name-redirect.js +5 -1
- package/dist/surface/tools/observe-tools.js +15 -9
- package/dist/surface/tools/read/console-pre-attach.d.ts +19 -0
- package/dist/surface/tools/read/console-pre-attach.js +23 -0
- package/dist/surface/tools/read-tools.js +33 -30
- package/dist/surface/tools/real-input-attempt.d.ts +0 -8
- package/dist/surface/tools/real-input-attempt.js +143 -28
- package/dist/surface/tools/repeat-hint.d.ts +40 -0
- package/dist/surface/tools/repeat-hint.js +171 -0
- package/dist/surface/tools/run-report.d.ts +2 -2
- package/dist/surface/tools/run-report.js +27 -15
- package/dist/surface/tools/session-ports.d.ts +14 -0
- package/dist/surface/tools/session-ports.js +53 -0
- package/dist/surface/tools/tool-kit.d.ts +18 -0
- package/dist/surface/tools/tool-kit.js +9 -3
- package/dist/surface/tools/tool-surface.js +0 -1
- package/dist/surface/tools/tools.js +54 -18
- package/dist/surface/tools/type-spelling.d.ts +13 -0
- package/dist/surface/tools/type-spelling.js +36 -0
- package/dist/telemetry/agent-client.d.ts +6 -0
- package/dist/telemetry/agent-client.js +10 -0
- package/dist/telemetry/argument-shape.js +17 -7
- package/dist/telemetry/cli-telemetry.d.ts +10 -1
- package/dist/telemetry/cli-telemetry.js +15 -0
- package/dist/telemetry/init-telemetry.d.ts +2 -1
- package/dist/telemetry/init-telemetry.js +47 -2
- package/dist/telemetry/install-trace.js +23 -4
- package/dist/telemetry/onboarding-funnel.d.ts +19 -2
- package/dist/telemetry/onboarding-funnel.js +25 -3
- package/dist/telemetry/proxy-telemetry.d.ts +2 -1
- package/dist/telemetry/proxy-telemetry.js +2 -2
- package/dist/telemetry/session-metrics.d.ts +1 -1
- package/dist/telemetry/session-metrics.js +67 -27
- package/dist/telemetry/telemetry.d.ts +3 -1
- package/dist/telemetry/telemetry.js +60 -28
- package/dist/telemetry/tool-refused.d.ts +6 -3
- package/dist/telemetry/tool-refused.js +15 -3
- package/docs/actions.mdx +3 -3
- package/docs/agent-cheatsheet.md +1 -1
- package/docs/architecture.md +3 -6
- package/docs/capabilities.mdx +61 -1
- package/docs/cli/affected.mdx +9 -7
- package/docs/cli/cloud.mdx +3 -3
- package/docs/cli/compare.mdx +94 -0
- package/docs/cli/doctor.mdx +41 -2
- package/docs/cli/grade.mdx +97 -0
- package/docs/cli/help.mdx +4 -2
- package/docs/cli/license.mdx +13 -12
- package/docs/cli/restart.mdx +7 -5
- package/docs/cli/rollback.mdx +5 -5
- package/docs/cli/setup.mdx +13 -2
- package/docs/cli/status.mdx +4 -0
- package/docs/cli/stop.mdx +3 -3
- package/docs/cli/update.mdx +2 -2
- package/docs/cli/verify.mdx +23 -1
- package/docs/cli.mdx +34 -24
- package/docs/deploy-checks.md +25 -0
- package/docs/desktop.mdx +1 -1
- package/docs/enterprise.md +17 -22
- package/docs/environment.mdx +1 -0
- package/docs/first-drive.md +1 -1
- package/docs/flows.md +11 -1
- package/docs/frameworks.mdx +9 -9
- package/docs/getting-started.md +1 -1
- package/docs/install-manual.mdx +16 -1
- package/docs/license-activation.mdx +3 -3
- package/docs/packages/engine.mdx +1 -1
- package/docs/packages/server.mdx +1 -1
- package/docs/packages/tauri.mdx +1 -1
- package/docs/packages/test.mdx +1 -1
- package/docs/packages.mdx +1 -1
- package/docs/platform-integration.md +1 -1
- package/docs/predicates.mdx +1 -1
- package/docs/quickstart.mdx +68 -49
- package/docs/skill-setup.md +1 -1
- package/docs/skill.md +14 -13
- package/docs/telemetry.md +6 -4
- package/docs/tools/navigate.mdx +1 -1
- package/docs/tools/verify.mdx +4 -1
- package/docs/troubleshooting.mdx +1 -1
- package/docs/usage.md +17 -14
- package/package.json +18 -14
- package/LICENSE-ENTERPRISE +0 -37
- package/dist/features/ee/audit-log.d.ts +0 -14
- package/dist/features/ee/audit-log.js +0 -11
- package/dist/features/exhaust/exhaust-run.d.ts +0 -33
- 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
|
-
|
|
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
|
|
99
|
-
|
|
100
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
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
|
-
|
|
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}\
|
|
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;
|