@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
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
* Replay's arrival at a flow's start page: navigate (or reload) before step 1, wait for the session
|
|
3
3
|
* the SDK reconnects as, and say what happened when it does not.
|
|
4
4
|
*/
|
|
5
|
-
import { EventType, ReticleCommand, } from '@reticlehq/core';
|
|
6
|
-
import { establishedState, samePath, startPathBudgetMs } from './flow-journey.js';
|
|
5
|
+
import { AnchorKind, EventType, ReticleCommand, } from '@reticlehq/core';
|
|
6
|
+
import { declaredRoute, establishedState, fillRouteParams, isRoutePattern, onRoute, samePath, startPathBudgetMs, unmetRouteClaim, } from './flow-journey.js';
|
|
7
7
|
import { asRecord } from '@reticlehq/core';
|
|
8
8
|
import { navigablePath, routeOfEvent, routeOfUrl, } from '@reticlehq/engine/question/predicate/predicate-route.js';
|
|
9
9
|
import { carryReticleIdentity } from '../../surface/tools/lease-tools.js';
|
|
10
10
|
import { anchorPrecondition, anchorQueryArgs } from './flow-step-runners.js';
|
|
11
11
|
import { queryRefs } from './replay.js';
|
|
12
|
+
import { refFor } from './flow-anchor.js';
|
|
12
13
|
import { isDocumentGoneError } from '../../portal/session/facts/session-replaced.js';
|
|
13
14
|
/**
|
|
14
15
|
* The route the tab is on now: the last observed route.change, falling back to the pathname of the
|
|
@@ -136,12 +137,20 @@ async function firstStepResolvesHere(session, flow) {
|
|
|
136
137
|
return false;
|
|
137
138
|
}
|
|
138
139
|
try {
|
|
139
|
-
|
|
140
|
+
// THE control the recording meant, by the same rule replay applies to the step: one match, or
|
|
141
|
+
// the recorded position among exactly as many namesakes. A name that also appears elsewhere
|
|
142
|
+
// (30 "Edit" links on another page, 10 where the flow was recorded) is not "step 1 starts here".
|
|
143
|
+
return (refFor(first.anchor, queryRefs(await session.command(ReticleCommand.QUERY, args))) !==
|
|
144
|
+
undefined);
|
|
140
145
|
}
|
|
141
146
|
catch {
|
|
142
147
|
return false;
|
|
143
148
|
}
|
|
144
149
|
}
|
|
150
|
+
/** An anchor that is the app's own name for one control (a testid, a component): the same on every page. */
|
|
151
|
+
function namesTheControl(anchor) {
|
|
152
|
+
return AnchorKind.TESTID === anchor?.kind || AnchorKind.COMPONENT === anchor?.kind;
|
|
153
|
+
}
|
|
145
154
|
/** The replay result, with how long replay waited for its start page when that went past the budget. */
|
|
146
155
|
export function withStartPageWait(result, arrival) {
|
|
147
156
|
return arrival.wait === undefined ? result : { ...result, startPageWait: arrival.wait };
|
|
@@ -150,6 +159,20 @@ export function withStartPageWait(result, arrival) {
|
|
|
150
159
|
function waitOf(outcome) {
|
|
151
160
|
return outcome.wait === undefined ? {} : { wait: outcome.wait };
|
|
152
161
|
}
|
|
162
|
+
/*
|
|
163
|
+
* The page each tab was on when its last replay ended, by session id. A page load gives the tab a
|
|
164
|
+
* new id, so an entry still matches only when nothing loaded since: the query on that page is what
|
|
165
|
+
* the last flow left, not what the caller chose.
|
|
166
|
+
* ponytail: one entry per replayed tab, never pruned; prune on session close if tabs ever churn.
|
|
167
|
+
*/
|
|
168
|
+
const leftByReplay = new Map();
|
|
169
|
+
/** Record where a replay left the tab, so the next reset does not keep that flow's query. */
|
|
170
|
+
export function noteReplayEnded(session) {
|
|
171
|
+
const path = currentPathOf(session);
|
|
172
|
+
if (path !== undefined) {
|
|
173
|
+
leftByReplay.set(session.id, path);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
153
176
|
/**
|
|
154
177
|
* Replay's half of the FlowFile contract: put the tab on the flow's `startPath` before step 1, and
|
|
155
178
|
* RELOAD it if it is already there.
|
|
@@ -164,6 +187,10 @@ function waitOf(outcome) {
|
|
|
164
187
|
* or from the wrong page. Silence is not an opt-out: a flow that depends on leftovers without
|
|
165
188
|
* saying so is a flow whose green means nothing on a fresh machine, and CI is a fresh machine.
|
|
166
189
|
*
|
|
190
|
+
* A route in `requires` is not an opt-out. It is the page the flow needs, and replay goes there:
|
|
191
|
+
* see `arriveAtDeclaredRoute`. A suite ran such a flow on the page the previous flow left open,
|
|
192
|
+
* and its anchors then failed, or matched ambiguously, on an unrelated page (#2034).
|
|
193
|
+
*
|
|
167
194
|
* A full-page load tears down the session socket, so the navigation must happen here — before any
|
|
168
195
|
* step runs — and the replay continues on the session the SDK reconnects as (found via the same
|
|
169
196
|
* tombstone rebind that lets `resolve(oldId)` answer after any navigation). Best-effort by design:
|
|
@@ -174,6 +201,16 @@ function waitOf(outcome) {
|
|
|
174
201
|
export async function arriveAtStartPath(sessions, session, flow, timeoutMs = startPathBudgetMs(flow), clock = REAL_ARRIVAL_CLOCK,
|
|
175
202
|
/** Whether the tab is still loading. Replay passes one for a pool lease, the only tab it can ask. */
|
|
176
203
|
stillLoading, loadingCapMs = START_PATH_LOADING_CAP_MS) {
|
|
204
|
+
const move = {
|
|
205
|
+
timeoutMs,
|
|
206
|
+
clock,
|
|
207
|
+
loadingCapMs,
|
|
208
|
+
...(stillLoading === undefined ? {} : { stillLoading }),
|
|
209
|
+
};
|
|
210
|
+
const route = declaredRoute(flow);
|
|
211
|
+
if (route !== undefined) {
|
|
212
|
+
return arriveAtDeclaredRoute(sessions, session, flow, route, move);
|
|
213
|
+
}
|
|
177
214
|
const target = flow.startPath;
|
|
178
215
|
if (target === undefined || 0 === target.length) {
|
|
179
216
|
return {};
|
|
@@ -190,30 +227,50 @@ stillLoading, loadingCapMs = START_PATH_LOADING_CAP_MS) {
|
|
|
190
227
|
// A route mismatch that step 1 can start from anyway is not worth a page load: navigating away
|
|
191
228
|
// from a persistent anchor could only hurt, and did. Arriving is the goal; resetting a tab that is
|
|
192
229
|
// ALREADY here is a different decision, taken above, and this must not override it.
|
|
193
|
-
|
|
230
|
+
// Only for an anchor that names the control itself (a testid, a component): a role and a name
|
|
231
|
+
// found on another page can be that page's own control, and step 1 then acts on the wrong one.
|
|
232
|
+
if (!here &&
|
|
233
|
+
namesTheControl(flow.steps?.[0]?.anchor) &&
|
|
234
|
+
(await firstStepResolvesHere(session, flow))) {
|
|
194
235
|
return {};
|
|
195
236
|
}
|
|
237
|
+
// A refused navigation left the tab untouched, and replay goes on with the connected session.
|
|
238
|
+
return (await moveTo(sessions, session, flow, target, here, current, move)) ?? {};
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Navigate (or reload, when `here`) to `target` and say what came back. Undefined when the tab was
|
|
242
|
+
* not moved at all: no usable base URL, or the browser refused the navigation.
|
|
243
|
+
*/
|
|
244
|
+
async function moveTo(sessions, session, flow, target, here, current, move) {
|
|
196
245
|
let destination;
|
|
197
246
|
try {
|
|
198
247
|
// startPath is a pathname (a host belongs to the machine, not the journey) — resolve it
|
|
199
248
|
// against the tab's own URL to get something the browser can be sent to. Already HERE, the
|
|
200
249
|
// reset reloads the page the tab is on: `samePath` ignored a query the flow did not record, and
|
|
201
250
|
// navigating to `target` would strip it, so the replay would test a different page than the one
|
|
202
|
-
// it just agreed it was on.
|
|
203
|
-
|
|
251
|
+
// it just agreed it was on. A query that the last replay left is not kept: it is the previous
|
|
252
|
+
// flow's state, and keeping it gave the next flow a filtered page that it never recorded.
|
|
253
|
+
const keepQuery = here && leftByReplay.get(session.id) !== current;
|
|
254
|
+
destination = new URL(keepQuery ? current : target, session.url).toString();
|
|
204
255
|
}
|
|
205
256
|
catch {
|
|
206
|
-
return
|
|
257
|
+
return undefined; // no usable base URL — nowhere to navigate from
|
|
207
258
|
}
|
|
208
259
|
// Measured either side of the reset, and only when the reset is a reload: reachable before and
|
|
209
260
|
// gone after is the reload's doing, not the flow file's. Without this, an app holding its session
|
|
210
261
|
// in memory comes back signed out and step 1 blames a component that is completely fine.
|
|
211
262
|
const resolvedBefore = here && (await firstStepResolvesHere(session, flow));
|
|
212
|
-
const outcome = await navigateAndAwait(sessions, session, destination, target, timeoutMs, clock,
|
|
263
|
+
const outcome = await navigateAndAwait(sessions, session, destination, target, move.timeoutMs, move.clock, {
|
|
264
|
+
isReload: here,
|
|
265
|
+
...(move.stillLoading === undefined ? {} : { stillLoading: move.stillLoading }),
|
|
266
|
+
loadingCapMs: move.loadingCapMs,
|
|
267
|
+
});
|
|
213
268
|
if ('lost' === outcome.kind) {
|
|
214
269
|
const why = outcome.stillLoading
|
|
215
270
|
? 'The page was still loading when replay stopped waiting: check that the app finishes loading, then replay'
|
|
216
|
-
: 'A
|
|
271
|
+
: 'A dev server that compiles on the first load can take longer than that: raise the wait with ' +
|
|
272
|
+
'`timeoutMs` on step 1 or `signalTimeoutMs` in the flow file, then replay. A backgrounded tab ' +
|
|
273
|
+
'can also be slow: bring it to the front';
|
|
217
274
|
return {
|
|
218
275
|
lost: `replay ${here ? 'reloaded' : 'navigated to'} ${target} before step 1 and no page was connected ` +
|
|
219
276
|
`after ${String(outcome.waitedMs)}ms, so the session it was driving is gone and nothing ran. ${why}`,
|
|
@@ -221,7 +278,7 @@ stillLoading, loadingCapMs = START_PATH_LOADING_CAP_MS) {
|
|
|
221
278
|
};
|
|
222
279
|
}
|
|
223
280
|
if ('refused' === outcome.kind) {
|
|
224
|
-
return
|
|
281
|
+
return undefined;
|
|
225
282
|
}
|
|
226
283
|
if ('redirected' === outcome.kind) {
|
|
227
284
|
const path = currentPathOf(outcome.session) ?? 'another route';
|
|
@@ -241,6 +298,107 @@ stillLoading, loadingCapMs = START_PATH_LOADING_CAP_MS) {
|
|
|
241
298
|
...waitOf(outcome),
|
|
242
299
|
};
|
|
243
300
|
}
|
|
301
|
+
/**
|
|
302
|
+
* The arrival for a replay that continues at a step and so does not move the tab. A declared route
|
|
303
|
+
* claim must still hold where the tab is, as it did when it was a precondition the run checked.
|
|
304
|
+
*/
|
|
305
|
+
export function routeClaimsWhereTheTabIs(flow, session) {
|
|
306
|
+
const route = declaredRoute(flow);
|
|
307
|
+
if (route === undefined) {
|
|
308
|
+
return {};
|
|
309
|
+
}
|
|
310
|
+
const current = currentPathOf(session);
|
|
311
|
+
const unmet = current === undefined
|
|
312
|
+
? 'replay cannot see which page it is on'
|
|
313
|
+
: unmetRouteClaim(flow, current);
|
|
314
|
+
if (unmet === undefined) {
|
|
315
|
+
return {};
|
|
316
|
+
}
|
|
317
|
+
return {
|
|
318
|
+
unreached: unreachedReason(route, current, `replay continues mid-flow there, and ${unmet}`),
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Replay's arrival for a flow that declares the route it needs in `requires` (#2034).
|
|
323
|
+
*
|
|
324
|
+
* The tab goes to that route before step 1, the same way it goes to a `startPath`, and the same
|
|
325
|
+
* reset applies once it is there. Two differences, both because the flow SAID where it must be:
|
|
326
|
+
*
|
|
327
|
+
* - A route with an entity id (`/cases/:id/notes`) keeps the id of the page the tab is on when that
|
|
328
|
+
* page matches. The recorded address names one record, and that record can be deleted since: a
|
|
329
|
+
* replay sent there ran a generic flow on a fixture that no longer existed and answered `unknown`.
|
|
330
|
+
* - When replay cannot put the tab on the route, it says so and nothing runs. Running anyway gave a
|
|
331
|
+
* verdict about another page, reported as a missing or ambiguous anchor.
|
|
332
|
+
*/
|
|
333
|
+
async function arriveAtDeclaredRoute(sessions, session, flow, route, move) {
|
|
334
|
+
const current = currentPathOf(session);
|
|
335
|
+
if (current === undefined) {
|
|
336
|
+
return {
|
|
337
|
+
unreached: unreachedReason(route, undefined, 'replay cannot see which page it is on'),
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
const here = onRoute(current, route);
|
|
341
|
+
// The opt-out keeps the tab as it is. It does not make another page the right one.
|
|
342
|
+
if (0 < establishedState(flow).length) {
|
|
343
|
+
if (unmetRouteClaim(flow, current) === undefined) {
|
|
344
|
+
return {};
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
unreached: unreachedReason(route, current, 'the flow also declares state that a page load would discard, so replay does not move the tab'),
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
const target = routeTarget(flow, route, current, here);
|
|
351
|
+
if (target === undefined) {
|
|
352
|
+
return {
|
|
353
|
+
unreached: unreachedReason(route, current, 'the route names an entity id, and the flow records no address on that route to open'),
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
const moved = await moveTo(sessions, session, flow, target, samePath(current, target), current, move);
|
|
357
|
+
if (moved === undefined) {
|
|
358
|
+
return { unreached: unreachedReason(route, current, `the page refused to open ${target}`) };
|
|
359
|
+
}
|
|
360
|
+
const landed = moved.session === undefined ? current : currentPathOf(moved.session);
|
|
361
|
+
// Every declared route claim, its `contains` too, is checked on the page replay arrived at.
|
|
362
|
+
const unmet = landed === undefined ? 'replay cannot see which page it is on' : unmetRouteClaim(flow, landed);
|
|
363
|
+
if (unmet === undefined) {
|
|
364
|
+
return moved;
|
|
365
|
+
}
|
|
366
|
+
const { redirected, ...rest } = moved;
|
|
367
|
+
const why = redirected === undefined
|
|
368
|
+
? `replay opened ${target}, and ${unmet}`
|
|
369
|
+
: `replay opened ${target}, and the app sent the tab to another page`;
|
|
370
|
+
return { ...rest, unreached: unreachedReason(route, landed, why) };
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Where replay sends the tab for a declared route.
|
|
374
|
+
*
|
|
375
|
+
* A pattern that the tab already matches: the tab's own page, so its id is kept. A pattern whose
|
|
376
|
+
* ids the tab can give (another section of the same case): the route with those ids. Else the
|
|
377
|
+
* flow's `startPath` when it is on the route, because it is the page the journey was recorded on.
|
|
378
|
+
* Else the route itself when it is a plain path. A pattern with no address to open has no target.
|
|
379
|
+
*/
|
|
380
|
+
function routeTarget(flow, route, current, here) {
|
|
381
|
+
const pattern = isRoutePattern(route);
|
|
382
|
+
if (here && pattern) {
|
|
383
|
+
// Without its query: `moveTo` keeps the query unless the previous replay left it.
|
|
384
|
+
return current.replace(/\?[^#]*/, '');
|
|
385
|
+
}
|
|
386
|
+
const filled = pattern ? fillRouteParams(route, current) : undefined;
|
|
387
|
+
if (filled !== undefined) {
|
|
388
|
+
return filled;
|
|
389
|
+
}
|
|
390
|
+
const start = flow.startPath;
|
|
391
|
+
if (start !== undefined && 0 < start.length && onRoute(start, route)) {
|
|
392
|
+
return start;
|
|
393
|
+
}
|
|
394
|
+
return pattern ? undefined : route;
|
|
395
|
+
}
|
|
396
|
+
/** Why a flow with a declared route did not run, and the one move that lets it. */
|
|
397
|
+
function unreachedReason(route, current, why) {
|
|
398
|
+
const where = current ?? 'a page replay cannot see';
|
|
399
|
+
return (`this flow declares that it starts on ${route}, but the tab is on ${where}: ${why}. ` +
|
|
400
|
+
`Nothing ran and nothing was proved. Open a page on ${route} (reticle_navigate), then replay`);
|
|
401
|
+
}
|
|
244
402
|
/**
|
|
245
403
|
* Why step 1 failed after the reset, and the one line that opts the flow out.
|
|
246
404
|
*
|
|
@@ -256,11 +414,32 @@ function resetCostHint(flow, target) {
|
|
|
256
414
|
return (`replay reloaded ${target} before step 1 and the first anchor did not come back — this flow ` +
|
|
257
415
|
`starts from state a page load discards. ${optOut}, or record it from a cold page`);
|
|
258
416
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
417
|
+
/**
|
|
418
|
+
* Whether assigning `to` from `from` is a jump within the same document. That is the case when the
|
|
419
|
+
* URLs differ at most in the fragment and `to` has a fragment; a browser then loads no page. Without
|
|
420
|
+
* a fragment, the same URL reloads by itself. Undefined or unparsable URLs are not a jump.
|
|
421
|
+
*/
|
|
422
|
+
export function isFragmentJump(from, to) {
|
|
423
|
+
if (from === undefined) {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
try {
|
|
427
|
+
const a = new URL(from);
|
|
428
|
+
const b = new URL(to);
|
|
429
|
+
if (0 === b.hash.length) {
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
a.hash = '';
|
|
433
|
+
b.hash = '';
|
|
434
|
+
return a.href === b.href;
|
|
435
|
+
}
|
|
436
|
+
catch {
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
export async function navigateAndAwait(sessions, session, destination, expectedPath, timeoutMs, clock = REAL_ARRIVAL_CLOCK, options = {}) {
|
|
441
|
+
const { isReload = false, stillLoading, acceptRedirect = false } = options;
|
|
442
|
+
const loadingCapMs = options.loadingCapMs ?? START_PATH_LOADING_CAP_MS;
|
|
264
443
|
// A leased tab is addressed by URL params, so navigating without them would strand the lease.
|
|
265
444
|
const url = carryReticleIdentity(session.url, destination);
|
|
266
445
|
try {
|
|
@@ -268,6 +447,11 @@ stillLoading, loadingCapMs = START_PATH_LOADING_CAP_MS) {
|
|
|
268
447
|
if (!outcome.ok || true !== asRecord(outcome.result)['ok']) {
|
|
269
448
|
return { kind: 'refused' };
|
|
270
449
|
}
|
|
450
|
+
// A same-document URL with a fragment loads no page: the browser only jumps within it. Ask for
|
|
451
|
+
// the load this function waits for. A hash-routed app's replay never started without it.
|
|
452
|
+
if (isFragmentJump(session.url, url)) {
|
|
453
|
+
await session.command(ReticleCommand.REFRESH, {});
|
|
454
|
+
}
|
|
271
455
|
}
|
|
272
456
|
catch (error) {
|
|
273
457
|
// A navigation that unloads the page rejects the very command that asked for it — the transport
|
|
@@ -291,6 +475,9 @@ stillLoading, loadingCapMs = START_PATH_LOADING_CAP_MS) {
|
|
|
291
475
|
if (true === arrived?.matches) {
|
|
292
476
|
return { kind: 'arrived', session: arrived.session, ...extendedWait() };
|
|
293
477
|
}
|
|
478
|
+
if (acceptRedirect && arrived !== undefined) {
|
|
479
|
+
return { kind: 'redirected', session: arrived.session, ...extendedWait() };
|
|
480
|
+
}
|
|
294
481
|
if (clock.now() >= deadline) {
|
|
295
482
|
// A live redirect is a different result from no SDK reconnection at all.
|
|
296
483
|
if (arrived !== undefined) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AnchorKind, type Drift, type FlowAnchor, type FlowReplayResult, type FlowStep, type FlowStepResult, type Predicate } from '@reticlehq/core';
|
|
2
2
|
import type { FlowReplaySession, Sleep } from './flow-replay-types.js';
|
|
3
3
|
import { type Reresolved } from './flow-anchor.js';
|
|
4
|
+
import { type Baselines } from '@reticlehq/engine/evidence/baseline.js';
|
|
4
5
|
/** The live act_sequence tool gives each step this transport budget when none was supplied. */
|
|
5
6
|
export declare const DEFAULT_SEQUENCE_STEP_TIMEOUT_MS = 8000;
|
|
6
7
|
export declare function runRoleStep(session: FlowReplaySession, step: FlowStep, index: number, anchor: Extract<FlowAnchor, {
|
|
@@ -83,7 +84,15 @@ export declare function anchorPrecondition(anchor: FlowAnchor): Predicate | unde
|
|
|
83
84
|
* Left alone, so the ordinary verdict stands, when anything else is in the run: a drifted anchor is
|
|
84
85
|
* drift whatever else happened, and a failure that is not staleness is a failure.
|
|
85
86
|
*/
|
|
86
|
-
export declare function staleTargetResult(name: string, steps: readonly FlowStepResult[]
|
|
87
|
+
export declare function staleTargetResult(name: string, steps: readonly FlowStepResult[],
|
|
88
|
+
/**
|
|
89
|
+
* `startControlRequired`: replay loaded the start page itself, with no redirect, and the caller
|
|
90
|
+
* asked that a missing step 1 control fail. Then the miss means the app does not offer the control
|
|
91
|
+
* the journey starts with (#2061), so it stays drift. Without it, the miss is not proved.
|
|
92
|
+
*/
|
|
93
|
+
options?: {
|
|
94
|
+
startControlRequired?: boolean;
|
|
95
|
+
}): FlowReplayResult | undefined;
|
|
87
96
|
/**
|
|
88
97
|
* The honest answer when a step acted on a target no person could have clicked (covered, of no
|
|
89
98
|
* size, off screen). The replay stopped there, and nothing about the app was decided: undecided as a
|
|
@@ -93,19 +102,11 @@ export declare function staleTargetResult(name: string, steps: readonly FlowStep
|
|
|
93
102
|
export declare function unreachableTargetResult(name: string, steps: readonly FlowStepResult[]): FlowReplayResult | undefined;
|
|
94
103
|
/**
|
|
95
104
|
* Run an act_sequence step: resolve every sub-step's OWN anchor, then dispatch the whole thing as one
|
|
96
|
-
* ACT_SEQUENCE
|
|
97
|
-
* execute identically.
|
|
98
|
-
*
|
|
99
|
-
* `replayFlow` had no sequence branch at all. It dispatches on `anchor.kind`, so a saved sequence fell
|
|
100
|
-
* to the testid runner and ran ONE act with `action: ''` (a saved sequence carries no top-level
|
|
101
|
-
* action) — sub-steps 2..n never executed. Fixing the anchor without this would have turned a visible
|
|
102
|
-
* drift into a silent partial replay reporting ok.
|
|
105
|
+
* ACT_SEQUENCE, the shape `replayProgram` uses, so a recorded sequence and a saved one run the same.
|
|
103
106
|
*/
|
|
104
107
|
export declare function runSequenceStep(session: FlowReplaySession, step: FlowStep, index: number, subs: readonly FlowStep[], confirmDangerous: boolean, sleep: Sleep,
|
|
105
108
|
/** Testids whose presence is deliberately NOT asserted — the LLM-output case. */
|
|
106
109
|
dynamic?: ReadonlySet<string>,
|
|
107
|
-
/**
|
|
108
|
-
*
|
|
109
|
-
|
|
110
|
-
*/
|
|
111
|
-
judge?: (expectation: Predicate, since: number) => Promise<Drift | undefined>): Promise<FlowStepResult>;
|
|
110
|
+
/** Judge a sub-step's `expect` from `since`, just before its dispatch, against the `before`
|
|
111
|
+
* reading; omitted for a setup step, whose consequences are not checked. */
|
|
112
|
+
judge?: (expectation: Predicate, since: number, before?: Baselines) => Promise<Drift | undefined>): Promise<FlowStepResult>;
|