@reticlehq/server 3.9.0 → 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/SKILL.md +13 -12
- 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 -187
- 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/cli-doctor.js +1 -1
- package/dist/command/cli/cli-flow-commands.js +2 -9
- package/dist/command/cli/cli-kill.js +1 -1
- 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 +17 -15
- package/dist/command/cli/cli-parse.js +44 -27
- 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 +58 -29
- package/dist/command/cli/cli-verify.d.ts +11 -2
- package/dist/command/cli/cli-verify.js +27 -8
- 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/doctor-daemon-line.js +6 -3
- package/dist/command/cli/doctor-repairs.js +1 -1
- 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/lifecycle/daemon-lifecycle.d.ts +1 -1
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +1 -1
- package/dist/command/cli/ports/port-holder.d.ts +9 -0
- package/dist/command/cli/ports/port-holder.js +27 -3
- package/dist/command/cli/status/status-lines.d.ts +1 -0
- package/dist/command/cli/status/status-lines.js +22 -0
- package/dist/command/cli/status-fields.d.ts +5 -1
- package/dist/command/cli/status-fields.js +7 -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 +46 -41
- 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 +12 -1
- package/dist/command/daemon/daemon.js +35 -4
- package/dist/command/daemon/lifetime/death-cause.js +21 -2
- package/dist/command/daemon/lifetime/heartbeat.js +7 -2
- package/dist/command/daemon/lifetime/startup-failure.d.ts +29 -0
- package/dist/command/daemon/lifetime/startup-failure.js +62 -0
- 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-runtime.js +6 -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 +6 -3
- package/dist/command/update/updater.js +6 -0
- package/dist/command/version/version-skew.js +1 -1
- 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/visual/visual-tools.js +66 -19
- package/dist/index.js +7 -4
- 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/runner-port.d.ts +2 -0
- package/dist/judgement/runs/runner-port.js +23 -5
- 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 +44 -0
- 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 +19 -3
- package/dist/language/flows/recording/tape/recordings.js +71 -5
- package/dist/language/flows/replay.d.ts +19 -5
- package/dist/language/flows/replay.js +99 -7
- 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/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/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/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 +28 -9
- 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 +22 -20
- package/dist/portal/input/real-input.js +41 -31
- package/dist/portal/input/viewport-tools.d.ts +8 -0
- package/dist/portal/input/viewport-tools.js +75 -18
- package/dist/portal/pool/browser-pool.d.ts +11 -29
- package/dist/portal/pool/browser-pool.js +35 -17
- package/dist/portal/pool/context-permissions.d.ts +17 -3
- package/dist/portal/pool/context-permissions.js +36 -5
- 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 +44 -17
- package/dist/portal/pool/lease-page-error.js +147 -5
- package/dist/portal/pool/page-error-journal.d.ts +7 -1
- package/dist/portal/pool/page-error-journal.js +27 -0
- package/dist/portal/pool/playwright-launcher.js +51 -8
- package/dist/portal/pool/pool-contract.d.ts +27 -1
- package/dist/portal/pool/pool-lease.d.ts +36 -1
- package/dist/portal/pool/zero-install.d.ts +8 -0
- package/dist/portal/pool/zero-install.js +23 -1
- package/dist/portal/session/dev-server/dev-command.d.ts +7 -6
- package/dist/portal/session/dev-server/dev-command.js +61 -15
- 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 +67 -25
- package/dist/portal/session/no-session-next-action.d.ts +2 -0
- package/dist/portal/session/no-session-next-action.js +12 -3
- package/dist/portal/session/no-session-watch.d.ts +6 -0
- package/dist/portal/session/no-session-watch.js +38 -3
- 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 +174 -63
- package/dist/start-wiring.d.ts +2 -1
- package/dist/start-wiring.js +2 -1
- package/dist/surface/mcp/mcp.js +3 -2
- 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 +1 -1
- 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/after-match.d.ts +4 -1
- package/dist/surface/tools/act/after-match.js +8 -1
- 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 +15 -1
- package/dist/surface/tools/act/resolve-target.js +24 -1
- package/dist/surface/tools/act/sequence-grade.d.ts +12 -0
- package/dist/surface/tools/act/sequence-grade.js +37 -26
- 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 +78 -50
- package/dist/surface/tools/act-tools.d.ts +1 -13
- package/dist/surface/tools/act-tools.js +74 -86
- 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 +16 -37
- package/dist/surface/tools/browser-tools.js +12 -6
- 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 +9 -2
- package/dist/surface/tools/error-recovery.d.ts +12 -1
- package/dist/surface/tools/error-recovery.js +91 -21
- package/dist/surface/tools/explore-tools.js +1 -1
- package/dist/surface/tools/invoke-tool.js +3 -2
- 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 +35 -1
- package/dist/surface/tools/lease-hint.js +42 -0
- package/dist/surface/tools/lease-readiness.d.ts +26 -0
- package/dist/surface/tools/lease-readiness.js +79 -0
- package/dist/surface/tools/lease-seed.d.ts +14 -1
- package/dist/surface/tools/lease-seed.js +35 -3
- package/dist/surface/tools/lease-tools.d.ts +3 -41
- package/dist/surface/tools/lease-tools.js +62 -110
- 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/session-ports.d.ts +14 -0
- package/dist/surface/tools/session-ports.js +53 -0
- package/dist/surface/tools/tool-kit.d.ts +6 -0
- package/dist/surface/tools/tool-kit.js +2 -3
- package/dist/surface/tools/tool-surface.js +0 -1
- package/dist/surface/tools/tools.js +28 -5
- 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 +1 -0
- package/dist/telemetry/tool-refused.d.ts +6 -3
- package/dist/telemetry/tool-refused.js +8 -3
- package/docs/actions.mdx +3 -3
- package/docs/agent-cheatsheet.md +1 -1
- 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 +1 -1
- package/docs/cli/grade.mdx +97 -0
- package/docs/cli/license.mdx +9 -7
- package/docs/cli/restart.mdx +7 -5
- package/docs/cli/rollback.mdx +5 -5
- 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 +33 -23
- package/docs/deploy-checks.md +1 -1
- package/docs/desktop.mdx +1 -1
- package/docs/enterprise.md +2 -2
- package/docs/environment.mdx +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 +1 -1
- package/docs/license-activation.mdx +3 -3
- package/docs/packages/tauri.mdx +1 -1
- package/docs/packages.mdx +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 +2 -2
- 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 +13 -13
- package/dist/features/exhaust/exhaust-run.d.ts +0 -33
- package/dist/features/exhaust/exhaust-run.js +0 -82
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { ReticleTool } from '@reticlehq/core';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { asString, ReticleTool } from '@reticlehq/core';
|
|
3
|
+
import { sessionIdShape } from '../../surface/tools/tool-kit.js';
|
|
4
|
+
import { resolveChangedFiles } from '../../command/cli/cli-flow-commands.js';
|
|
5
|
+
import { namedFlowsForSession } from './flow-store-for-session.js';
|
|
6
6
|
import { affectedSavedFlows } from './change/flow-sources.js';
|
|
7
7
|
import { RECORD_A_FLOW } from './suite/coverage.js';
|
|
8
|
+
/**
|
|
9
|
+
* Why the answer is empty, when that needs saying.
|
|
10
|
+
*
|
|
11
|
+
* Several situations produced the same empty answer: no files changed, no flows saved, and a git
|
|
12
|
+
* ref that resolved to nothing. Only the first means "nothing to re-verify". The others mean the
|
|
13
|
+
* question could not be answered, and re-running nothing on that basis is how a regression ships.
|
|
14
|
+
*/
|
|
15
|
+
function emptyAnswerReason(facts) {
|
|
16
|
+
const { changed, since, fileCount, flowCount, changedCount, unmatchedRoot } = facts;
|
|
17
|
+
// No folder declares this project, so nothing here is about a checkout (#1550).
|
|
18
|
+
if (unmatchedRoot !== undefined) {
|
|
19
|
+
return `no flows here: no folder on disk declares this project, so its evidence goes to ${unmatchedRoot}. Run \`reticle init\` in the app's folder, or lease the tab from there.`;
|
|
20
|
+
}
|
|
21
|
+
// A git failure OUTRANKS every other explanation: the others describe a question that was
|
|
22
|
+
// answered, and this one is a question that was not. Reporting "nothing changed" over a mistyped
|
|
23
|
+
// ref or a shallow clone is how a regression ships past the tool meant to catch it.
|
|
24
|
+
if (true === changed.failed) {
|
|
25
|
+
return `could not read the diff for \`${String(since)}\`, so NOTHING was compared and this result proves nothing: ${changed.reason ?? 'git failed'}`;
|
|
26
|
+
}
|
|
27
|
+
if (0 === flowCount) {
|
|
28
|
+
return `no saved flows exist yet, so nothing COULD be affected. ${RECORD_A_FLOW}`;
|
|
29
|
+
}
|
|
30
|
+
if (0 !== changedCount) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
if (since === undefined && 0 === fileCount) {
|
|
34
|
+
return 'no files were given and no `since` ref was passed, so nothing was compared — pass the files you edited, or a git ref';
|
|
35
|
+
}
|
|
36
|
+
return 'nothing changed against that input, so no saved flow needs re-verifying';
|
|
37
|
+
}
|
|
8
38
|
/**
|
|
9
39
|
* `reticle_affected` — which saved flows must re-verify for a set of changed files.
|
|
10
40
|
*
|
|
@@ -27,6 +57,7 @@ export const AFFECTED_TOOLS = [
|
|
|
27
57
|
description: 'Which saved flows must re-verify for a set of changed files. Pass the files you edited (and/or `since` for a git ref to diff against). Returns { changedFiles, affected, unknownProvenance } — `affected` is what to re-run, and `unknownProvenance` are flows included only because Reticle cannot tell which sources they cover, so they are re-verified by default rather than silently skipped.',
|
|
28
58
|
example: { files: ['src/App.tsx'] },
|
|
29
59
|
inputSchema: {
|
|
60
|
+
...sessionIdShape,
|
|
30
61
|
files: z
|
|
31
62
|
.array(z.string())
|
|
32
63
|
.optional()
|
|
@@ -46,34 +77,22 @@ export const AFFECTED_TOOLS = [
|
|
|
46
77
|
? args['files'].filter((f) => 'string' === typeof f)
|
|
47
78
|
: [];
|
|
48
79
|
const since = 'string' === typeof args['since'] ? args['since'] : undefined;
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
80
|
+
// The project of the tab being driven, not the folder the daemon started in (#1550). The flows
|
|
81
|
+
// come from the store `flows` replays from, so a flow named here can be replayed by that name
|
|
82
|
+
// (#1996). `git diff` runs in the project directory that holds that store.
|
|
83
|
+
const { flows, projectDir, unmatchedRoot } = await namedFlowsForSession(deps, asString(args['sessionId']));
|
|
84
|
+
// A bucket of evidence is not a tree, so a `since` has nothing to diff against.
|
|
85
|
+
const changed = await resolveChangedFiles(files, unmatchedRoot === undefined ? since : undefined, projectDir);
|
|
54
86
|
const changedFiles = changed.files;
|
|
55
|
-
// No `sessionId` on this tool's surface, and it does not need one: passing `undefined`
|
|
56
|
-
// resolves the single connected session, and falls back exactly as before when it cannot.
|
|
57
|
-
// Adding an argument here would be a surface change to fix an addressing bug.
|
|
58
|
-
const flows = await loadNamedFlows(deps.fs, sessionRoot(deps, undefined), sessionProjectId(deps, undefined));
|
|
59
87
|
const result = affectedSavedFlows(flows, changedFiles);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
changed.failed
|
|
69
|
-
? `could not read the diff for \`${String(since)}\`, so NOTHING was compared and this result proves nothing: ${changed.reason ?? 'git failed'}`
|
|
70
|
-
: 0 === flows.length
|
|
71
|
-
? `no saved flows exist yet, so nothing COULD be affected. ${RECORD_A_FLOW}`
|
|
72
|
-
: 0 === changedFiles.length
|
|
73
|
-
? since === undefined && 0 === files.length
|
|
74
|
-
? 'no files were given and no `since` ref was passed, so nothing was compared — pass the files you edited, or a git ref'
|
|
75
|
-
: 'nothing changed against that input, so no saved flow needs re-verifying'
|
|
76
|
-
: undefined;
|
|
88
|
+
const why = emptyAnswerReason({
|
|
89
|
+
changed,
|
|
90
|
+
since,
|
|
91
|
+
fileCount: files.length,
|
|
92
|
+
flowCount: flows.length,
|
|
93
|
+
changedCount: changedFiles.length,
|
|
94
|
+
unmatchedRoot,
|
|
95
|
+
});
|
|
77
96
|
return {
|
|
78
97
|
changedFiles,
|
|
79
98
|
...result,
|
|
@@ -17,7 +17,8 @@ export interface ChangedFiles {
|
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* Files changed since a git ref (`git diff --name-only <ref>`), so `reticle gate --since main` works
|
|
20
|
-
* from the real diff instead of hand-listed files.
|
|
20
|
+
* from the real diff instead of hand-listed files. Files under Reticle's own directory are left
|
|
21
|
+
* out: a replay writes them, and they are not a change to the app's code.
|
|
21
22
|
*
|
|
22
23
|
* Never throws, and never pretends. The CLI gate may still degrade to "no changes" and pass rather
|
|
23
24
|
* than crash CI — that reasoning was right and is unchanged — but it now has to opt into doing so by
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
2
|
import { promisify } from 'node:util';
|
|
3
|
+
import { ReticleDir } from '@reticlehq/core';
|
|
3
4
|
const run = promisify(execFile);
|
|
4
5
|
/** Parse `git diff --name-only` output into a clean file list. Pure; exported for testing. */
|
|
5
6
|
export function parseGitFiles(output) {
|
|
@@ -19,9 +20,22 @@ export function parseGitFiles(output) {
|
|
|
19
20
|
function refIsOptionLike(ref) {
|
|
20
21
|
return ref.startsWith('-');
|
|
21
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* True when a diff path sits under Reticle's own project directory.
|
|
25
|
+
*
|
|
26
|
+
* A replay writes intent, impact and episode files into that directory. Those writes are
|
|
27
|
+
* Reticle's output, not a change to the app's code. A flow with no source stamps reads any
|
|
28
|
+
* change as "affected", so counting them marked flows the gate had just proved as uncovered
|
|
29
|
+
* (#2050). The directory can sit below the repo root, so any path segment counts. `git diff`
|
|
30
|
+
* prints paths with `/` on every platform.
|
|
31
|
+
*/
|
|
32
|
+
function isReticleOwnPath(path) {
|
|
33
|
+
return path.split('/').includes(ReticleDir.ROOT);
|
|
34
|
+
}
|
|
22
35
|
/**
|
|
23
36
|
* Files changed since a git ref (`git diff --name-only <ref>`), so `reticle gate --since main` works
|
|
24
|
-
* from the real diff instead of hand-listed files.
|
|
37
|
+
* from the real diff instead of hand-listed files. Files under Reticle's own directory are left
|
|
38
|
+
* out: a replay writes them, and they are not a change to the app's code.
|
|
25
39
|
*
|
|
26
40
|
* Never throws, and never pretends. The CLI gate may still degrade to "no changes" and pass rather
|
|
27
41
|
* than crash CI — that reasoning was right and is unchanged — but it now has to opt into doing so by
|
|
@@ -38,7 +52,10 @@ export async function changedFilesSince(ref, cwd) {
|
|
|
38
52
|
}
|
|
39
53
|
try {
|
|
40
54
|
const { stdout } = await run('git', ['diff', '--name-only', ref], { cwd });
|
|
41
|
-
return {
|
|
55
|
+
return {
|
|
56
|
+
files: parseGitFiles(stdout).filter((file) => !isReticleOwnPath(file)),
|
|
57
|
+
failed: false,
|
|
58
|
+
};
|
|
42
59
|
}
|
|
43
60
|
catch (error) {
|
|
44
61
|
return {
|
|
@@ -41,7 +41,7 @@ export declare const SECRET_FIELD_ARG = "secretField";
|
|
|
41
41
|
* rules must not be able to drift. It used to sit in `replay.ts`, one import away from the sentence
|
|
42
42
|
* saying it had to stay together.
|
|
43
43
|
*/
|
|
44
|
-
export declare
|
|
44
|
+
export declare function secretEnvKey(field: string): string;
|
|
45
45
|
/** The schema of that argument, shared by every tool that replays a flow. */
|
|
46
46
|
export { CALL_SECRETS_ARG };
|
|
47
47
|
export declare const callSecretsArg: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
@@ -59,16 +59,4 @@ export interface UnsuppliedSecret {
|
|
|
59
59
|
field: string;
|
|
60
60
|
envKey: string;
|
|
61
61
|
}
|
|
62
|
-
/**
|
|
63
|
-
* Every credential this flow will replay as the literal placeholder.
|
|
64
|
-
*
|
|
65
|
-
* Checked BEFORE a step runs, because the alternative is what shipped: the placeholder is typed
|
|
66
|
-
* into the password box, sign-in fails, and the flow reports that an element further down the
|
|
67
|
-
* journey has gone missing -- a `drift` verdict naming a component nobody touched, with an
|
|
68
|
-
* invitation to update a flow that was correct.
|
|
69
|
-
*
|
|
70
|
-
* The emptiness rule matches `replayActionArgs` exactly: it substitutes only for a value of
|
|
71
|
-
* non-zero length, so an empty variable leaves the placeholder and must count as unsupplied here.
|
|
72
|
-
* Two different answers to "is this supplied" is how the gate would pass and the replay still fail.
|
|
73
|
-
*/
|
|
74
62
|
export declare function unsuppliedSecrets(flow: FlowFile, env: Record<string, string | undefined>): UnsuppliedSecret[];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
1
2
|
import { z } from 'zod';
|
|
2
3
|
import { AnchorKind } from '@reticlehq/core';
|
|
3
4
|
import { CALL_SECRETS_ARG, callSecrets } from '../../../surface/tools/tool-kit.js';
|
|
@@ -14,12 +15,15 @@ import { CALL_SECRETS_ARG, callSecrets } from '../../../surface/tools/tool-kit.j
|
|
|
14
15
|
* to find the env var because the runner passed a role or a label instead.
|
|
15
16
|
*/
|
|
16
17
|
export function anchorFieldName(anchor) {
|
|
17
|
-
if (AnchorKind.TESTID === anchor.kind)
|
|
18
|
+
if (AnchorKind.TESTID === anchor.kind) {
|
|
18
19
|
return anchor.value;
|
|
19
|
-
|
|
20
|
+
}
|
|
21
|
+
if (AnchorKind.ROLE === anchor.kind) {
|
|
20
22
|
return anchor.name;
|
|
21
|
-
|
|
23
|
+
}
|
|
24
|
+
if (AnchorKind.SIGNAL === anchor.kind) {
|
|
22
25
|
return anchor.name;
|
|
26
|
+
}
|
|
23
27
|
return undefined;
|
|
24
28
|
}
|
|
25
29
|
/**
|
|
@@ -39,6 +43,16 @@ export const SECRET_NAME_ARG = 'secret';
|
|
|
39
43
|
export const SECRET_FIELD_ARG = 'secretField';
|
|
40
44
|
/** The prefix every secret's variable carries. */
|
|
41
45
|
const SECRET_ENV_PREFIX = 'RETICLE_SECRET_';
|
|
46
|
+
/** Any character outside ASCII. */
|
|
47
|
+
const NON_ASCII = /[^\p{ASCII}]/u;
|
|
48
|
+
/** The word in the variable of a field whose name is not ASCII. */
|
|
49
|
+
const NON_ASCII_FIELD = 'FIELD';
|
|
50
|
+
const NON_ASCII_DIGEST_LENGTH = 8;
|
|
51
|
+
/**
|
|
52
|
+
* The variable name an ASCII field gets. Up to 3.9.0 a non-ASCII field got this name too, and a
|
|
53
|
+
* flow saved then still names it.
|
|
54
|
+
*/
|
|
55
|
+
const asciiSecretEnvKey = (field) => `${SECRET_ENV_PREFIX}${field.replace(/[^a-zA-Z0-9]+/g, '_').toUpperCase()}`;
|
|
42
56
|
/**
|
|
43
57
|
* The environment variable that supplies one redacted field.
|
|
44
58
|
*
|
|
@@ -51,7 +65,16 @@ const SECRET_ENV_PREFIX = 'RETICLE_SECRET_';
|
|
|
51
65
|
* rules must not be able to drift. It used to sit in `replay.ts`, one import away from the sentence
|
|
52
66
|
* saying it had to stay together.
|
|
53
67
|
*/
|
|
54
|
-
export
|
|
68
|
+
export function secretEnvKey(field) {
|
|
69
|
+
if (!NON_ASCII.test(field)) {
|
|
70
|
+
return asciiSecretEnvKey(field);
|
|
71
|
+
}
|
|
72
|
+
// A name in another script has no ASCII letters to keep: "Пароль" and "Гасло" both became
|
|
73
|
+
// `RETICLE_SECRET__`, so one field's value was typed into the other. A short hash of the name
|
|
74
|
+
// keeps each field's variable distinct and the same on every machine.
|
|
75
|
+
const digest = createHash('sha256').update(field.normalize('NFC').toLowerCase()).digest('hex');
|
|
76
|
+
return `${SECRET_ENV_PREFIX}${NON_ASCII_FIELD}_${digest.slice(0, NON_ASCII_DIGEST_LENGTH).toUpperCase()}`;
|
|
77
|
+
}
|
|
55
78
|
/** The schema of that argument, shared by every tool that replays a flow. */
|
|
56
79
|
export { CALL_SECRETS_ARG };
|
|
57
80
|
export const callSecretsArg = z
|
|
@@ -64,30 +87,35 @@ export const callSecretsArg = z
|
|
|
64
87
|
*/
|
|
65
88
|
export function secretValue(envKey, env) {
|
|
66
89
|
for (const [key, value] of Object.entries(callSecrets() ?? {})) {
|
|
67
|
-
if (envKey === (key.startsWith(SECRET_ENV_PREFIX) ? key : secretEnvKey(key)))
|
|
90
|
+
if (envKey === (key.startsWith(SECRET_ENV_PREFIX) ? key : secretEnvKey(key))) {
|
|
68
91
|
return value;
|
|
92
|
+
}
|
|
69
93
|
}
|
|
70
94
|
return env[envKey];
|
|
71
95
|
}
|
|
72
96
|
const SECRET_OCCURRENCE = /^(?:[2-9]|[1-9][0-9]+)$/;
|
|
73
97
|
/** The field's own saved variable name, or its original key for legacy and invalid metadata. */
|
|
74
98
|
export function secretKeyForFill(args, field) {
|
|
75
|
-
if (args?.['value'] !== REDACTED_FILL)
|
|
99
|
+
if (args?.['value'] !== REDACTED_FILL) {
|
|
76
100
|
return undefined;
|
|
101
|
+
}
|
|
77
102
|
const named = args[SECRET_NAME_ARG];
|
|
78
103
|
const base = secretEnvKey(field);
|
|
79
|
-
// A flow can supply this field's occurrence, never an unrelated environment variable.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
104
|
+
// A flow can supply this field's occurrence, never an unrelated environment variable. The name
|
|
105
|
+
// an earlier version gave a non-ASCII field is still this field's.
|
|
106
|
+
if ('string' !== typeof named) {
|
|
107
|
+
return base;
|
|
108
|
+
}
|
|
109
|
+
const own = (key) => named === key ||
|
|
110
|
+
(named.startsWith(`${key}_`) && SECRET_OCCURRENCE.test(named.slice(key.length + 1)));
|
|
111
|
+
return own(base) || own(asciiSecretEnvKey(field)) ? named : base;
|
|
85
112
|
}
|
|
86
113
|
function* secretSteps(steps) {
|
|
87
114
|
for (const step of steps) {
|
|
88
115
|
yield step;
|
|
89
|
-
if (step.steps !== undefined)
|
|
116
|
+
if (step.steps !== undefined) {
|
|
90
117
|
yield* secretSteps(step.steps);
|
|
118
|
+
}
|
|
91
119
|
}
|
|
92
120
|
}
|
|
93
121
|
/** Allocate recorded fills' names while preserving legacy placeholders and existing suffixes. */
|
|
@@ -96,14 +124,17 @@ export function withDistinctSecretKeys(flow) {
|
|
|
96
124
|
const used = new Set();
|
|
97
125
|
for (const step of secretSteps(flow.steps)) {
|
|
98
126
|
const field = anchorFieldName(step.anchor);
|
|
99
|
-
if (field === undefined)
|
|
127
|
+
if (field === undefined) {
|
|
100
128
|
continue;
|
|
129
|
+
}
|
|
101
130
|
const key = secretKeyForFill(step.args, field);
|
|
102
|
-
if (key === undefined)
|
|
131
|
+
if (key === undefined) {
|
|
103
132
|
continue;
|
|
133
|
+
}
|
|
104
134
|
reserved.add(key);
|
|
105
|
-
if (key !== secretEnvKey(field) || step.args?.[SECRET_NAME_ARG] === undefined)
|
|
135
|
+
if (key !== secretEnvKey(field) || step.args?.[SECRET_NAME_ARG] === undefined) {
|
|
106
136
|
used.add(key);
|
|
137
|
+
}
|
|
107
138
|
}
|
|
108
139
|
const assign = (step) => {
|
|
109
140
|
let out = step;
|
|
@@ -119,8 +150,9 @@ export function withDistinctSecretKeys(flow) {
|
|
|
119
150
|
occurrence += 1;
|
|
120
151
|
}
|
|
121
152
|
used.add(key);
|
|
122
|
-
if (key !== base)
|
|
153
|
+
if (key !== base) {
|
|
123
154
|
out = { ...step, args: { ...step.args, [SECRET_NAME_ARG]: key } };
|
|
155
|
+
}
|
|
124
156
|
}
|
|
125
157
|
return step.steps === undefined ? out : { ...out, steps: step.steps.map(assign) };
|
|
126
158
|
};
|
|
@@ -138,23 +170,47 @@ export function withDistinctSecretKeys(flow) {
|
|
|
138
170
|
* non-zero length, so an empty variable leaves the placeholder and must count as unsupplied here.
|
|
139
171
|
* Two different answers to "is this supplied" is how the gate would pass and the replay still fail.
|
|
140
172
|
*/
|
|
173
|
+
function* flattenAll(steps) {
|
|
174
|
+
for (const step of steps) {
|
|
175
|
+
yield step;
|
|
176
|
+
yield* flattenAll(step.steps ?? []);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
141
179
|
export function unsuppliedSecrets(flow, env) {
|
|
142
180
|
const out = [];
|
|
143
181
|
const seen = new Set();
|
|
144
182
|
for (const step of secretSteps(flow.steps ?? [])) {
|
|
145
183
|
const field = anchorFieldName(step.anchor);
|
|
146
|
-
if (field === undefined)
|
|
184
|
+
if (field === undefined) {
|
|
147
185
|
continue;
|
|
186
|
+
}
|
|
148
187
|
const envKey = secretKeyForFill(step.args, field);
|
|
149
|
-
if (envKey === undefined)
|
|
188
|
+
if (envKey === undefined) {
|
|
150
189
|
continue;
|
|
190
|
+
}
|
|
151
191
|
const supplied = secretValue(envKey, env);
|
|
152
|
-
if (supplied !== undefined && supplied.length > 0)
|
|
192
|
+
if (supplied !== undefined && supplied.length > 0) {
|
|
153
193
|
continue;
|
|
154
|
-
|
|
194
|
+
}
|
|
195
|
+
if (seen.has(envKey)) {
|
|
155
196
|
continue;
|
|
197
|
+
}
|
|
156
198
|
seen.add(envKey);
|
|
157
199
|
out.push({ field, envKey });
|
|
158
200
|
}
|
|
201
|
+
// A request step that acts as another account needs that account's session.
|
|
202
|
+
for (const step of flattenAll(flow.steps ?? [])) {
|
|
203
|
+
const account = step.request?.as;
|
|
204
|
+
if (account === undefined) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
const envKey = secretEnvKey(account);
|
|
208
|
+
const supplied = secretValue(envKey, env);
|
|
209
|
+
if ((supplied !== undefined && supplied.length > 0) || seen.has(envKey)) {
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
seen.add(envKey);
|
|
213
|
+
out.push({ field: account, envKey });
|
|
214
|
+
}
|
|
159
215
|
return out;
|
|
160
216
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnchorKind, type Drift, type FlowAnchor, type QueryEmptyHint } from '@reticlehq/core';
|
|
1
|
+
import { AnchorKind, type CommandResult, type Drift, type FlowAnchor, type QueryEmptyHint } from '@reticlehq/core';
|
|
2
2
|
import type { FlowReplaySession, Sleep } from './flow-replay-types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Finding a step's anchor again, and saying legibly why it could not be found.
|
|
@@ -33,6 +33,29 @@ export declare function nearestTestid(missing: string, present: string[]): strin
|
|
|
33
33
|
export declare function nearestIsAmbiguous(missing: string, present: string[]): boolean;
|
|
34
34
|
/** Build the legible-drift record for a testid anchor that resolved to zero live elements. */
|
|
35
35
|
export declare function testidDrift(value: string, hint: QueryEmptyHint | undefined): Drift;
|
|
36
|
+
/**
|
|
37
|
+
* How an anchor is ADDRESSED — the sentence that names it, and the label a result row carries.
|
|
38
|
+
*
|
|
39
|
+
* Two different strings, and neither can be derived from the other: `value` is a raw testid for one
|
|
40
|
+
* anchor kind and a human-readable label for the others, so one sentence cannot name both. Calling a
|
|
41
|
+
* role anchor `testid "button "View result""` sends the reader to edit a locator that does not exist
|
|
42
|
+
* on that step, which is the same misdirection the drift reason exists to remove.
|
|
43
|
+
*
|
|
44
|
+
* Derived from the anchor rather than passed in by the caller. The first version of the role fix took
|
|
45
|
+
* a `described` argument and wrote `ambiguousAnchorDrift(label, n, \`role anchor ${label}\`)` — the
|
|
46
|
+
* same string twice, so the `anchor` field and the sentence could drift apart with nothing to catch
|
|
47
|
+
* it, and the next anchor kind would have had to remember the convention on its own.
|
|
48
|
+
*/
|
|
49
|
+
/**
|
|
50
|
+
* How a role anchor reads in a message: `button "View result"`, or for a control with no accessible
|
|
51
|
+
* name, `button (no accessible name, #2 of 3)` — never `button "undefined"`.
|
|
52
|
+
*/
|
|
53
|
+
export declare function roleAnchorLabel(anchor: {
|
|
54
|
+
role: string;
|
|
55
|
+
name?: string | undefined;
|
|
56
|
+
nth?: number | undefined;
|
|
57
|
+
of?: number | undefined;
|
|
58
|
+
}): string;
|
|
36
59
|
/**
|
|
37
60
|
* What the stale-ref retry found when it ran the locator again.
|
|
38
61
|
*
|
|
@@ -106,10 +129,28 @@ export declare function queryOnce(session: FlowReplaySession, queryArgs: Record<
|
|
|
106
129
|
refs: string[];
|
|
107
130
|
hint?: QueryEmptyHint;
|
|
108
131
|
}>;
|
|
109
|
-
export declare function resolveQuery(session: FlowReplaySession, queryArgs: Record<string, unknown>, sleep: Sleep, now?: () => number
|
|
132
|
+
export declare function resolveQuery(session: FlowReplaySession, queryArgs: Record<string, unknown>, sleep: Sleep, now?: () => number, read?: (result: CommandResult) => {
|
|
133
|
+
refs: string[];
|
|
134
|
+
hint?: QueryEmptyHint;
|
|
135
|
+
}): Promise<{
|
|
110
136
|
refs: string[];
|
|
111
137
|
hint?: QueryEmptyHint;
|
|
112
138
|
}>;
|
|
139
|
+
/**
|
|
140
|
+
* Several queries for one control, pooled: each attempt runs every query and joins the refs, so
|
|
141
|
+
* the settle budget is spent once, not once for each query. A role anchor with `alsoRoles` uses it.
|
|
142
|
+
*/
|
|
143
|
+
export declare function resolveAnyQuery(session: FlowReplaySession, queries: readonly Record<string, unknown>[], sleep: Sleep, now?: () => number, read?: (result: CommandResult) => {
|
|
144
|
+
refs: string[];
|
|
145
|
+
hint?: QueryEmptyHint;
|
|
146
|
+
}): Promise<{
|
|
147
|
+
refs: string[];
|
|
148
|
+
hint?: QueryEmptyHint;
|
|
149
|
+
}>;
|
|
150
|
+
/** `resolveQuery`'s reader for a nameless role anchor: only the matches with no accessible name. */
|
|
151
|
+
export declare function readNamelessQuery(result: CommandResult): {
|
|
152
|
+
refs: string[];
|
|
153
|
+
};
|
|
113
154
|
/** Re-resolve a testid anchor. */
|
|
114
155
|
export declare function resolveTestid(session: FlowReplaySession, value: string, sleep: Sleep): Promise<{
|
|
115
156
|
refs: string[];
|
|
@@ -125,3 +166,20 @@ export declare function anchorLabel(anchor: FlowAnchor): string;
|
|
|
125
166
|
export declare function componentQueryArgs(anchor: Extract<FlowAnchor, {
|
|
126
167
|
kind: typeof AnchorKind.COMPONENT;
|
|
127
168
|
}>): Record<string, unknown>;
|
|
169
|
+
/** Query args for a NAMED role anchor — the handle that identifies an instance, not a JSX site. */
|
|
170
|
+
export declare function roleQueryArgs(anchor: Extract<FlowAnchor, {
|
|
171
|
+
kind: typeof AnchorKind.ROLE;
|
|
172
|
+
}>): Record<string, unknown>;
|
|
173
|
+
/**
|
|
174
|
+
* Resolve a role anchor. ONE function for the first look and the re-resolve after a stale ref: the
|
|
175
|
+
* re-resolve used to count every control of the role, so a nameless anchor's position came back
|
|
176
|
+
* ambiguous on a working page.
|
|
177
|
+
*
|
|
178
|
+
* A nameless anchor's position counts only the nameless controls of its role (an icon-only edit
|
|
179
|
+
* button is the 2nd nameless button of its row, not the 5th button), so it reads only those.
|
|
180
|
+
*/
|
|
181
|
+
export declare function resolveRoleAnchor(session: FlowReplaySession, anchor: Extract<FlowAnchor, {
|
|
182
|
+
kind: typeof AnchorKind.ROLE;
|
|
183
|
+
}>, sleep: Sleep): Promise<{
|
|
184
|
+
refs: string[];
|
|
185
|
+
}>;
|