@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
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { SECRET_FIELD_ARG, SECRET_NAME_ARG, secretKeyForFill, secretValue, } from './fields/flow-secret-field.js';
|
|
2
|
-
import { EventType, FlowPredicateSchema, MUTATING_METHODS,
|
|
2
|
+
import { EventType, FlowPredicateSchema, MUTATING_METHODS, isDevToolingUrl, } from '@reticlehq/core';
|
|
3
3
|
import { DANGEROUS_ACTION_CONFIRM_ARG, DOCUMENT_ANCHOR_ROLE, ReticleCommand, QueryBy, isGlobalPressCall, } from '@reticlehq/core';
|
|
4
4
|
import { ReticleTool, invokedFlowMissing } from '@reticlehq/core';
|
|
5
5
|
import { formatStepAddress } from 'open-verification';
|
|
6
6
|
import { refFor } from './flow-anchor.js';
|
|
7
|
+
import { navigablePath, routeOfUrl } from '@reticlehq/engine/question/predicate/predicate-route.js';
|
|
7
8
|
import { asRecord, asString } from '@reticlehq/core';
|
|
8
9
|
/**
|
|
9
10
|
* The note attached when a testid resolves to multiple live elements (the first match is used).
|
|
@@ -21,9 +22,36 @@ function ambiguousRoleNote(role, name) {
|
|
|
21
22
|
* replay engines (replayProgram + flow-replay's step runner) so element extraction — the core of anchor
|
|
22
23
|
* resolution — can't drift between them.
|
|
23
24
|
*/
|
|
25
|
+
/**
|
|
26
|
+
* The refs of a role query's matches that have NO accessible name, in page order.
|
|
27
|
+
*
|
|
28
|
+
* A role query without a name returns every control of the role, named ones included. A nameless
|
|
29
|
+
* anchor's recorded position (`nth` of `of`) counts only the nameless ones — an icon-only edit
|
|
30
|
+
* button is the 2nd nameless button of its row, not the 5th button — so the named ones are dropped
|
|
31
|
+
* before the position is read.
|
|
32
|
+
*/
|
|
33
|
+
export function namelessRefs(result) {
|
|
34
|
+
if (!result.ok) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
const elements = asRecord(result.result)['elements'];
|
|
38
|
+
if (!Array.isArray(elements)) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
const refs = [];
|
|
42
|
+
for (const element of elements) {
|
|
43
|
+
const e = asRecord(element);
|
|
44
|
+
const ref = asString(e['ref']);
|
|
45
|
+
if (0 === (asString(e['name']) ?? '').trim().length && ref !== undefined) {
|
|
46
|
+
refs.push(ref);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return refs;
|
|
50
|
+
}
|
|
24
51
|
export function queryRefs(result) {
|
|
25
|
-
if (!result.ok)
|
|
52
|
+
if (!result.ok) {
|
|
26
53
|
return [];
|
|
54
|
+
}
|
|
27
55
|
const payload = asRecord(result.result);
|
|
28
56
|
const elements = Array.isArray(payload['elements']) ? payload['elements'] : [];
|
|
29
57
|
return elements.map((e) => asString(asRecord(e)['ref']) ?? '').filter((r) => r.length > 0);
|
|
@@ -47,12 +75,14 @@ export function replayActionArgs(value, confirmDangerous = false, field) {
|
|
|
47
75
|
const key = field === undefined ? undefined : secretKeyForFill(args, field);
|
|
48
76
|
delete args[SECRET_NAME_ARG];
|
|
49
77
|
delete args[SECRET_FIELD_ARG];
|
|
50
|
-
if (confirmDangerous)
|
|
78
|
+
if (confirmDangerous) {
|
|
51
79
|
args[DANGEROUS_ACTION_CONFIRM_ARG] = true;
|
|
80
|
+
}
|
|
52
81
|
if (key !== undefined) {
|
|
53
82
|
const supplied = secretValue(key, process.env);
|
|
54
|
-
if (supplied !== undefined && supplied.length > 0)
|
|
83
|
+
if (supplied !== undefined && supplied.length > 0) {
|
|
55
84
|
args['value'] = supplied;
|
|
85
|
+
}
|
|
56
86
|
}
|
|
57
87
|
return args;
|
|
58
88
|
}
|
|
@@ -62,37 +92,52 @@ export function replayActionArgs(value, confirmDangerous = false, field) {
|
|
|
62
92
|
*/
|
|
63
93
|
function recordedFieldName(step) {
|
|
64
94
|
const by = asString(step['by']);
|
|
65
|
-
if (QueryBy.TESTID === by)
|
|
95
|
+
if (QueryBy.TESTID === by) {
|
|
66
96
|
return asString(step['value']);
|
|
67
|
-
|
|
97
|
+
}
|
|
98
|
+
if (QueryBy.ROLE === by) {
|
|
68
99
|
return asString(step['name']);
|
|
100
|
+
}
|
|
69
101
|
return undefined;
|
|
70
102
|
}
|
|
71
103
|
/** The element's source location from an action result, when the framework stamped one. */
|
|
72
104
|
function sourceFromResult(res) {
|
|
73
105
|
const source = asRecord(res['source']);
|
|
74
|
-
if (typeof source['file'] !== 'string' || typeof source['line'] !== 'number')
|
|
106
|
+
if (typeof source['file'] !== 'string' || typeof source['line'] !== 'number') {
|
|
75
107
|
return undefined;
|
|
108
|
+
}
|
|
76
109
|
const out = { file: source['file'], line: source['line'] };
|
|
77
|
-
if ('number' === typeof source['column'])
|
|
110
|
+
if ('number' === typeof source['column']) {
|
|
78
111
|
out['column'] = source['column'];
|
|
112
|
+
}
|
|
79
113
|
return out;
|
|
80
114
|
}
|
|
81
115
|
/**
|
|
82
|
-
* The
|
|
116
|
+
* The page a session's live url is on, as a NAVIGABLE path: pathname + query + hash, with
|
|
117
|
+
* Reticle's own params dropped. Undefined when the session has no url yet.
|
|
83
118
|
*
|
|
84
|
-
*
|
|
85
|
-
* a
|
|
119
|
+
* Every recorded page comes from here: a step's page, the route a tape is cut on, and the
|
|
120
|
+
* `startPath` and route `requires` of a saved flow. The pathname alone dropped the query, so a
|
|
121
|
+
* journey leased on `/?showModal=login` saved `startPath: "/"`, and its replay asserted "the modal
|
|
122
|
+
* is absent" on a page where the modal never opens. Under a hash router it dropped the hash too,
|
|
123
|
+
* which made every page `/` (#1411).
|
|
86
124
|
*/
|
|
87
|
-
export
|
|
125
|
+
export function pageOf(url) {
|
|
126
|
+
if (url === undefined) {
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
const parts = routeOfUrl(url);
|
|
130
|
+
return parts === undefined ? undefined : navigablePath(parts);
|
|
131
|
+
}
|
|
88
132
|
/**
|
|
89
133
|
* Did the app send a write request in this window? A step that did is saved `writes: true`, so a
|
|
90
134
|
* replay does not repeat it unasked. The dev server's own traffic is not the app's.
|
|
91
135
|
*/
|
|
92
136
|
export function wroteIn(events) {
|
|
93
137
|
return events.some((event) => {
|
|
94
|
-
if (EventType.NET_REQUEST !== event.type)
|
|
138
|
+
if (EventType.NET_REQUEST !== event.type) {
|
|
95
139
|
return false;
|
|
140
|
+
}
|
|
96
141
|
const method = asString(event.data['method'])?.toUpperCase() ?? '';
|
|
97
142
|
return MUTATING_METHODS.includes(method) && !isDevToolingUrl(asString(event.data['url']));
|
|
98
143
|
});
|
|
@@ -122,7 +167,9 @@ route,
|
|
|
122
167
|
/** The session that acted: only recordings it started take the step. */
|
|
123
168
|
session,
|
|
124
169
|
/** The act's window sent a write request; see `wroteIn`. */
|
|
125
|
-
wrote = false
|
|
170
|
+
wrote = false,
|
|
171
|
+
/** The act as the ambient tape keeps it, when that differs. See RecordingStore.capture. */
|
|
172
|
+
ambientArgs) {
|
|
126
173
|
// NO `active()` gate. `RecordingStore.capture` opens the AMBIENT tape on its first step, and that
|
|
127
174
|
// branch was unreachable from here: this returned early whenever nothing was open, and the only
|
|
128
175
|
// thing that opened anything was `reticle_record { action: "start" }`. So the comment on `capture`
|
|
@@ -134,8 +181,15 @@ wrote = false) {
|
|
|
134
181
|
// recorded cannot contribute to either.
|
|
135
182
|
// A click on Reticle's own panel (the HUD exposed) is not a step of the app's journey: saved, the
|
|
136
183
|
// app's flow pressed Run Harness on replay, a paid drive, under an intent that never named it.
|
|
137
|
-
if (true === asRecord(res)['reticleUi'])
|
|
184
|
+
if (true === asRecord(res)['reticleUi']) {
|
|
138
185
|
return;
|
|
186
|
+
}
|
|
187
|
+
const step = capturedStep(args, res, route, wrote);
|
|
188
|
+
const ambient = ambientArgs === undefined ? undefined : capturedStep(ambientArgs, res, route, wrote);
|
|
189
|
+
recordings.capture(step, route, session, ambient);
|
|
190
|
+
}
|
|
191
|
+
/** One act as a recorded step, with the claim the agent declared on it. */
|
|
192
|
+
function capturedStep(args, res, route, wrote) {
|
|
139
193
|
const step = compileActStep(args, res);
|
|
140
194
|
// Keep the assertion the agent actually made. `act_and_wait { until }` IS the agent saying what
|
|
141
195
|
// success means — the large majority of calls carry one — and dropping it produced a flow graded
|
|
@@ -143,36 +197,50 @@ wrote = false) {
|
|
|
143
197
|
// story failing at its last step. See enforceableExpect below.
|
|
144
198
|
const declared = args['until'] ?? args['predicate'];
|
|
145
199
|
const expect = enforceableExpect(declared);
|
|
146
|
-
if (expect !== undefined)
|
|
200
|
+
if (expect !== undefined) {
|
|
147
201
|
step.expect = expect;
|
|
148
|
-
|
|
202
|
+
}
|
|
203
|
+
else if (declared !== undefined) {
|
|
149
204
|
step.unkeptExpect = UNKEPT_EXPECT;
|
|
150
|
-
|
|
205
|
+
}
|
|
206
|
+
if (route !== undefined) {
|
|
151
207
|
step.page = route;
|
|
208
|
+
}
|
|
152
209
|
const intent = asString(args['intent'])?.trim();
|
|
153
|
-
if (intent !== undefined && intent.length > 0)
|
|
210
|
+
if (intent !== undefined && intent.length > 0) {
|
|
154
211
|
step.intent = intent;
|
|
155
|
-
|
|
212
|
+
}
|
|
213
|
+
if (wrote) {
|
|
156
214
|
step.writes = true;
|
|
157
|
-
|
|
215
|
+
}
|
|
216
|
+
return step;
|
|
158
217
|
}
|
|
159
218
|
/**
|
|
160
|
-
* Capture an act_and_wait once its verdict is known
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
219
|
+
* Capture an act_and_wait once its verdict is known.
|
|
220
|
+
*
|
|
221
|
+
* The rule act_sequence keeps (#988). A recording somebody opened keeps every claim the agent
|
|
222
|
+
* declared, held or not: dropping a refuted one saved a flow that replayed green on the defect it
|
|
223
|
+
* had caught. The ambient tape keeps a claim only if the action made it hold (`held`), so a flow cut
|
|
224
|
+
* from it never replays a claim that was never once true because of the action. The action is
|
|
225
|
+
* always recorded: replay needs it to reach the next step.
|
|
226
|
+
*
|
|
227
|
+
* Keyed on `held`, not on `verified: yes`. A claim the action made hold under an `unknown` or a
|
|
228
|
+
* contradicted verdict is still what the agent proved about the page, and dropping it left the
|
|
229
|
+
* replay with no check at all. One function decides both tapes: a second rule that took the claim off the tape
|
|
230
|
+
* after the fact ran before this capture, so it took the PREVIOUS step's claim, which had passed.
|
|
164
231
|
*/
|
|
165
|
-
export function captureVerdictedAct(recordings, args, res, route,
|
|
232
|
+
export function captureVerdictedAct(recordings, args, res, route, held, session,
|
|
166
233
|
/** The act's window sent a write request; see `wroteIn`. */
|
|
167
234
|
wrote = false) {
|
|
168
235
|
const { until: _until, predicate: _predicate, ...unproved } = args;
|
|
169
|
-
captureAct(recordings,
|
|
236
|
+
captureAct(recordings, args, res, route, session, wrote, held ? undefined : unproved);
|
|
170
237
|
}
|
|
171
238
|
/** Fold a PASSING standalone assertion into the step it proved. See RecordingStore.attachExpect. */
|
|
172
239
|
export function captureAssertion(recordings, raw, session) {
|
|
173
240
|
const expect = enforceableExpect(raw);
|
|
174
|
-
if (expect !== undefined)
|
|
241
|
+
if (expect !== undefined) {
|
|
175
242
|
recordings.attachExpect(expect, session);
|
|
243
|
+
}
|
|
176
244
|
}
|
|
177
245
|
/**
|
|
178
246
|
* A declared predicate, as a recorded expectation — or nothing.
|
|
@@ -186,8 +254,9 @@ export function captureAssertion(recordings, raw, session) {
|
|
|
186
254
|
* Every one of those was a claim the agent made and the file did not keep.
|
|
187
255
|
*/
|
|
188
256
|
function enforceableExpect(raw) {
|
|
189
|
-
if (raw === undefined)
|
|
257
|
+
if (raw === undefined) {
|
|
190
258
|
return undefined;
|
|
259
|
+
}
|
|
191
260
|
// The flow file's own schema, so capture keeps exactly what a load would accept — a predicate
|
|
192
261
|
// holding a session ref is refused by both, rather than recorded here and rejected on read.
|
|
193
262
|
const parsed = FlowPredicateSchema.safeParse(raw);
|
|
@@ -232,8 +301,9 @@ function compileAnchorArgs(r, ref, action, actArgs) {
|
|
|
232
301
|
const compiled = anchorArgs(r, ref, action, actArgs);
|
|
233
302
|
// The SDK says the target holds a secret (a password input, whatever its label). Carried beside
|
|
234
303
|
// the anchor so the saved flow redacts the fill by what the field IS, not by what it is called.
|
|
235
|
-
if (true === r['secret'])
|
|
304
|
+
if (true === r['secret']) {
|
|
236
305
|
compiled.args[SECRET_FIELD_ARG] = true;
|
|
306
|
+
}
|
|
237
307
|
return compiled;
|
|
238
308
|
}
|
|
239
309
|
function anchorArgs(r, ref, action, actArgs) {
|
|
@@ -262,10 +332,15 @@ function anchorArgs(r, ref, action, actArgs) {
|
|
|
262
332
|
action,
|
|
263
333
|
args: actArgs,
|
|
264
334
|
};
|
|
265
|
-
if (source !== undefined)
|
|
335
|
+
if (source !== undefined) {
|
|
266
336
|
testidArgs['source'] = source;
|
|
267
|
-
|
|
337
|
+
}
|
|
338
|
+
if (testidOf !== undefined) {
|
|
268
339
|
testidArgs['of'] = testidOf;
|
|
340
|
+
if ('number' === typeof r['testidNth'] && 0 <= r['testidNth']) {
|
|
341
|
+
testidArgs['nth'] = r['testidNth'];
|
|
342
|
+
}
|
|
343
|
+
}
|
|
269
344
|
return { args: testidArgs, stable: true };
|
|
270
345
|
}
|
|
271
346
|
// Role + NAME before component: a component/source anchor names the JSX site, so every row's copy
|
|
@@ -282,21 +357,64 @@ function anchorArgs(r, ref, action, actArgs) {
|
|
|
282
357
|
action,
|
|
283
358
|
args: actArgs,
|
|
284
359
|
};
|
|
285
|
-
if (source !== undefined)
|
|
360
|
+
if (source !== undefined) {
|
|
286
361
|
roleArgs['source'] = source;
|
|
362
|
+
}
|
|
287
363
|
if ('number' === typeof r['nth'] && 'number' === typeof r['of']) {
|
|
288
364
|
roleArgs['nth'] = r['nth'];
|
|
289
365
|
roleArgs['of'] = r['of'];
|
|
290
366
|
}
|
|
367
|
+
if (Array.isArray(r['within'])) {
|
|
368
|
+
roleArgs['within'] = r['within'];
|
|
369
|
+
}
|
|
291
370
|
return { args: roleArgs, stable: true };
|
|
292
371
|
}
|
|
372
|
+
// A role and NO accessible name (an icon-only button): the role plus the control's position among
|
|
373
|
+
// the nameless controls of that role. Without this branch the step fell to a component anchor or
|
|
374
|
+
// to the stale ref, and a replay on a fresh page could not find the control again.
|
|
375
|
+
if (role !== undefined &&
|
|
376
|
+
role !== 'generic' &&
|
|
377
|
+
name === undefined &&
|
|
378
|
+
asString(r['component']) === undefined) {
|
|
379
|
+
const namelessArgs = {
|
|
380
|
+
by: QueryBy.ROLE,
|
|
381
|
+
value: role,
|
|
382
|
+
action,
|
|
383
|
+
args: actArgs,
|
|
384
|
+
};
|
|
385
|
+
if (source !== undefined) {
|
|
386
|
+
namelessArgs['source'] = source;
|
|
387
|
+
}
|
|
388
|
+
if ('number' === typeof r['nth'] && 'number' === typeof r['of']) {
|
|
389
|
+
namelessArgs['nth'] = r['nth'];
|
|
390
|
+
namelessArgs['of'] = r['of'];
|
|
391
|
+
}
|
|
392
|
+
return { args: namelessArgs, stable: true };
|
|
393
|
+
}
|
|
293
394
|
const component = asString(r['component']);
|
|
294
395
|
if (component !== undefined || source !== undefined) {
|
|
295
396
|
const componentArgs = { by: QueryBy.COMPONENT, action, args: actArgs };
|
|
296
|
-
if (component !== undefined)
|
|
397
|
+
if (component !== undefined) {
|
|
297
398
|
componentArgs['component'] = component;
|
|
298
|
-
|
|
399
|
+
}
|
|
400
|
+
if (source !== undefined) {
|
|
299
401
|
componentArgs['source'] = source;
|
|
402
|
+
}
|
|
403
|
+
// Which of the elements this anchor matches was acted on: a list renders every item from one site.
|
|
404
|
+
// The element's own words, when it has no accessible name: they survive a change of layout.
|
|
405
|
+
const ownText = asString(r['ownText']);
|
|
406
|
+
if (ownText !== undefined && ownText.length > 0) {
|
|
407
|
+
componentArgs['text'] = ownText;
|
|
408
|
+
}
|
|
409
|
+
// The role, too: a nameless control with no own words has no other identity a layout keeps.
|
|
410
|
+
const role = asString(r['role']);
|
|
411
|
+
if (role !== undefined && role.length > 0) {
|
|
412
|
+
componentArgs['role'] = role;
|
|
413
|
+
}
|
|
414
|
+
if ('number' === typeof r['componentNth'] && 'number' === typeof r['componentOf']) {
|
|
415
|
+
componentArgs['nth'] = r['componentNth'];
|
|
416
|
+
componentArgs['of'] = r['componentOf'];
|
|
417
|
+
}
|
|
300
418
|
return { args: componentArgs, stable: true };
|
|
301
419
|
}
|
|
302
420
|
return { args: { ref, action, args: actArgs }, stable: false };
|
|
@@ -312,26 +430,38 @@ export function compileSequenceStep(args, res) {
|
|
|
312
430
|
? asRecord(res)['steps']
|
|
313
431
|
: [];
|
|
314
432
|
let stable = inputSteps.length > 0;
|
|
433
|
+
// A declared `expect` that a flow cannot keep (a session ref), said on save as for a single act (#2188).
|
|
434
|
+
let unkept = false;
|
|
315
435
|
const subSteps = inputSteps.flatMap((raw, i) => {
|
|
316
436
|
// A step on Reticle's own panel is not a step of the app's journey, as for a single act.
|
|
317
|
-
if (true === asRecord(resolved[i])['reticleUi'])
|
|
437
|
+
if (true === asRecord(resolved[i])['reticleUi']) {
|
|
318
438
|
return [];
|
|
439
|
+
}
|
|
319
440
|
const step = asRecord(raw);
|
|
320
441
|
const compiled = compileAnchorArgs(asRecord(resolved[i]), asString(step['ref']) ?? '', asString(step['action']) ?? '', replayActionArgs(step['args']));
|
|
321
|
-
if (!compiled.stable)
|
|
442
|
+
if (!compiled.stable) {
|
|
322
443
|
stable = false;
|
|
444
|
+
}
|
|
323
445
|
// Each sub-step keeps its OWN declared consequence. A sequence records one step and replays as
|
|
324
446
|
// one batch, but what each step CLAIMED is per step -- folding them together would let one
|
|
325
447
|
// signal answer for every click in the journey.
|
|
326
448
|
const expect = enforceableExpect(step['expect']);
|
|
449
|
+
if (expect === undefined && step['expect'] !== undefined) {
|
|
450
|
+
unkept = true;
|
|
451
|
+
}
|
|
327
452
|
return [expect === undefined ? compiled.args : { ...compiled.args, expect }];
|
|
328
453
|
});
|
|
329
454
|
const timeoutMs = explicitTimeoutMs(args);
|
|
455
|
+
// The pace is part of what the sequence did: replay at the default settle answered differently (#2130).
|
|
456
|
+
const burst = args['burst'];
|
|
457
|
+
const burstMs = 'number' === typeof burst && Number.isFinite(burst) && 0 <= burst ? burst : undefined;
|
|
330
458
|
return {
|
|
331
459
|
tool: ReticleTool.ACT_SEQUENCE,
|
|
332
460
|
stable,
|
|
333
461
|
args: { steps: subSteps },
|
|
334
462
|
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
463
|
+
...(burstMs === undefined ? {} : { burstMs }),
|
|
464
|
+
...(unkept ? { unkeptExpect: UNKEPT_EXPECT } : {}),
|
|
335
465
|
};
|
|
336
466
|
}
|
|
337
467
|
/**
|
|
@@ -346,18 +476,21 @@ export function compileSequenceStep(args, res) {
|
|
|
346
476
|
*/
|
|
347
477
|
async function resolveRef(session, step) {
|
|
348
478
|
// Dispatched the way it ran live: at the document, with no ref. See compileAnchorArgs.
|
|
349
|
-
if (isDocumentPress(step))
|
|
479
|
+
if (isDocumentPress(step)) {
|
|
350
480
|
return { ref: '' };
|
|
481
|
+
}
|
|
351
482
|
const by = asString(step.by);
|
|
352
483
|
const value = asString(step.value);
|
|
353
484
|
if (by === QueryBy.TESTID && value !== undefined) {
|
|
354
485
|
const result = await session.command(ReticleCommand.QUERY, { by, value });
|
|
355
|
-
if (!result.ok)
|
|
486
|
+
if (!result.ok) {
|
|
356
487
|
throw new Error(result.error ?? 'query failed');
|
|
488
|
+
}
|
|
357
489
|
const refs = queryRefs(result);
|
|
358
490
|
const ref = refs[0];
|
|
359
|
-
if (ref === undefined)
|
|
491
|
+
if (ref === undefined) {
|
|
360
492
|
throw new Error(`testid '${value}' did not resolve in current page`);
|
|
493
|
+
}
|
|
361
494
|
return refs.length > 1 ? { ref, note: ambiguousTestidNote(value) } : { ref };
|
|
362
495
|
}
|
|
363
496
|
// Role + accessible NAME: the anchor that distinguishes one row's control from another's, which
|
|
@@ -366,13 +499,16 @@ async function resolveRef(session, step) {
|
|
|
366
499
|
const name = asString(step.name);
|
|
367
500
|
const query = { by, value, ...(name === undefined ? {} : { name }) };
|
|
368
501
|
const result = await session.command(ReticleCommand.QUERY, query);
|
|
369
|
-
if (!result.ok)
|
|
502
|
+
if (!result.ok) {
|
|
370
503
|
throw new Error(result.error ?? 'query failed');
|
|
371
|
-
|
|
504
|
+
}
|
|
505
|
+
const refs = name === undefined ? namelessRefs(result) : queryRefs(result);
|
|
372
506
|
const meant = refFor(step, refs);
|
|
373
507
|
const ref = meant ?? refs[0];
|
|
374
508
|
if (ref === undefined) {
|
|
375
|
-
throw new Error(
|
|
509
|
+
throw new Error(name === undefined
|
|
510
|
+
? `no ${value} with no accessible name resolved in current page`
|
|
511
|
+
: `${value} named '${String(name)}' did not resolve in current page`);
|
|
376
512
|
}
|
|
377
513
|
return meant === undefined ? { ref, note: ambiguousRoleNote(value, String(name)) } : { ref };
|
|
378
514
|
}
|
|
@@ -385,8 +521,9 @@ async function resolveRef(session, step) {
|
|
|
385
521
|
...(source === undefined ? {} : { source }),
|
|
386
522
|
};
|
|
387
523
|
const result = await session.command(ReticleCommand.QUERY, query);
|
|
388
|
-
if (!result.ok)
|
|
524
|
+
if (!result.ok) {
|
|
389
525
|
throw new Error(result.error ?? 'query failed');
|
|
526
|
+
}
|
|
390
527
|
const refs = queryRefs(result);
|
|
391
528
|
const ref = refs[0];
|
|
392
529
|
if (ref === undefined) {
|
|
@@ -468,8 +605,9 @@ via = []) {
|
|
|
468
605
|
...via,
|
|
469
606
|
]);
|
|
470
607
|
results.push(...nested);
|
|
471
|
-
if (nested.some((r) => !r.ok))
|
|
608
|
+
if (nested.some((r) => !r.ok)) {
|
|
472
609
|
break;
|
|
610
|
+
}
|
|
473
611
|
continue;
|
|
474
612
|
}
|
|
475
613
|
try {
|
|
@@ -480,8 +618,9 @@ via = []) {
|
|
|
480
618
|
for (const raw of subs) {
|
|
481
619
|
const sub = asRecord(raw);
|
|
482
620
|
const { ref, note } = await resolveRef(session, sub);
|
|
483
|
-
if (note !== undefined)
|
|
621
|
+
if (note !== undefined) {
|
|
484
622
|
notes.push(note);
|
|
623
|
+
}
|
|
485
624
|
liveSteps.push({
|
|
486
625
|
ref,
|
|
487
626
|
action: asString(sub['action']) ?? '',
|
|
@@ -502,8 +641,9 @@ via = []) {
|
|
|
502
641
|
session.finishAction();
|
|
503
642
|
}
|
|
504
643
|
results.push(buildResult(step.tool, r.ok, r.error, notes));
|
|
505
|
-
if (!r.ok)
|
|
644
|
+
if (!r.ok) {
|
|
506
645
|
break;
|
|
646
|
+
}
|
|
507
647
|
}
|
|
508
648
|
else {
|
|
509
649
|
const { ref, note } = await resolveRef(session, step.args);
|
|
@@ -520,8 +660,9 @@ via = []) {
|
|
|
520
660
|
session.finishAction();
|
|
521
661
|
}
|
|
522
662
|
results.push(buildResult(step.tool, r.ok, r.error, note !== undefined ? [note] : []));
|
|
523
|
-
if (!r.ok)
|
|
663
|
+
if (!r.ok) {
|
|
524
664
|
break;
|
|
665
|
+
}
|
|
525
666
|
}
|
|
526
667
|
}
|
|
527
668
|
catch (e) {
|
|
@@ -537,9 +678,11 @@ via = []) {
|
|
|
537
678
|
}
|
|
538
679
|
function buildResult(tool, ok, error, notes) {
|
|
539
680
|
const base = { tool, ok };
|
|
540
|
-
if (!ok)
|
|
681
|
+
if (!ok) {
|
|
541
682
|
base.error = error ?? 'command failed';
|
|
542
|
-
|
|
683
|
+
}
|
|
684
|
+
if (notes.length > 0) {
|
|
543
685
|
base.note = notes.join('; ');
|
|
686
|
+
}
|
|
544
687
|
return base;
|
|
545
688
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Steps that reach past the page the journey is on: one opens another page (`navigate`), one sends a
|
|
3
|
+
* request to the app (`request`). Neither acts on an element, and both depend on a caller that owns
|
|
4
|
+
* what the replay cannot reach by itself: the sessions, the origin, the cookies.
|
|
5
|
+
*/
|
|
6
|
+
import { type Drift, type FlowRequest, type FlowStep, type FlowStepResult } from '@reticlehq/core';
|
|
7
|
+
/**
|
|
8
|
+
* Opens the page a `navigate` step names and returns the session of the page that loaded, or why no
|
|
9
|
+
* page of the app answered. A full page load ends the session that asked for it, so only the caller
|
|
10
|
+
* that owns the sessions can do this.
|
|
11
|
+
*/
|
|
12
|
+
export type OpenPage<S> = (url: string) => Promise<{
|
|
13
|
+
session: S;
|
|
14
|
+
} | {
|
|
15
|
+
error: string;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Sends the request a `request` step names and returns the answer, or why nothing could be sent.
|
|
19
|
+
* Supplied by the caller that knows the app's origin and the page's cookies.
|
|
20
|
+
*/
|
|
21
|
+
export type SendRequest = (request: FlowRequest) => Promise<{
|
|
22
|
+
status: number;
|
|
23
|
+
body: string;
|
|
24
|
+
} | {
|
|
25
|
+
error: string;
|
|
26
|
+
}>;
|
|
27
|
+
/** Where the page's cookies come from: the driven browser's storage state. */
|
|
28
|
+
interface CookieSource {
|
|
29
|
+
storageState?(sessionUrl: string): Promise<unknown>;
|
|
30
|
+
}
|
|
31
|
+
/** The step's result before its `expect` is judged, and the session to go on with. */
|
|
32
|
+
export declare function openStepPage<S>(step: FlowStep, index: number, open: OpenPage<S> | undefined): Promise<{
|
|
33
|
+
result: FlowStepResult;
|
|
34
|
+
session?: S;
|
|
35
|
+
}>;
|
|
36
|
+
export declare function runRequestStep(step: FlowStep, index: number, send: SendRequest | undefined, judged: boolean,
|
|
37
|
+
/**
|
|
38
|
+
* The run's own yes to steps that change data, never the flow file's: flow files are shared, and a
|
|
39
|
+
* saved `DELETE` would otherwise run with the user's cookies on any app the flow is pointed at.
|
|
40
|
+
*/
|
|
41
|
+
confirmDangerous: boolean): Promise<FlowStepResult>;
|
|
42
|
+
/** True for a step that reaches past the page: `navigate` or `request`. */
|
|
43
|
+
export declare function isPageStep(step: FlowStep): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Run a `navigate` or `request` step. `judge` evaluates an `expect` on a page; it comes from the
|
|
46
|
+
* replay so this file does not import the replay back. `checked` is false for a setup step, whose
|
|
47
|
+
* consequence is not checked. A navigate step returns the session to go on with.
|
|
48
|
+
*/
|
|
49
|
+
export declare function runPageStep<S>(step: FlowStep, index: number, ctx: {
|
|
50
|
+
open?: OpenPage<S> | undefined;
|
|
51
|
+
send?: SendRequest | undefined;
|
|
52
|
+
checked: boolean;
|
|
53
|
+
confirmDangerous: boolean;
|
|
54
|
+
judge: (session: S, expect: NonNullable<FlowStep['expect']>) => Promise<Drift | undefined>;
|
|
55
|
+
route: (session: S) => string | undefined;
|
|
56
|
+
}): Promise<{
|
|
57
|
+
result: FlowStepResult;
|
|
58
|
+
session?: S;
|
|
59
|
+
}>;
|
|
60
|
+
/**
|
|
61
|
+
* The sender a `request` step uses: same origin as the page only, the page's cookies unless the step
|
|
62
|
+
* is anonymous, no redirects followed (a 302 is the answer to judge). `pageUrl` is read at send time,
|
|
63
|
+
* because a `navigate` step changes the page.
|
|
64
|
+
*/
|
|
65
|
+
export declare function requestSender(pageUrl: () => string | undefined, provider: CookieSource | undefined,
|
|
66
|
+
/** The `Cookie` header of the account a step names in `as`, or undefined when not supplied. */
|
|
67
|
+
accountCookie?: (name: string) => string | undefined): SendRequest;
|
|
68
|
+
export {};
|