@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
package/docs/predicates.mdx
CHANGED
|
@@ -316,7 +316,7 @@ This is the predicate that catches a UI-versus-store desync. A deploy that only
|
|
|
316
316
|
{ "kind": "animation", "name": "dialog-in", "completed": true }
|
|
317
317
|
```
|
|
318
318
|
|
|
319
|
-
`target` narrows it to one element. `completed: false` matches an animation that is still running.
|
|
319
|
+
`target` narrows it to one element by Reticle ref (`e12`) or CSS selector. `completed: false` matches an animation that is still running.
|
|
320
320
|
|
|
321
321
|
### settled
|
|
322
322
|
|
package/docs/quickstart.mdx
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: 'Quickstart: proof in five minutes'
|
|
3
3
|
sidebarTitle: Quickstart
|
|
4
|
-
description:
|
|
4
|
+
description: Check your app with one command, connect your coding agent, and get a real verdict with evidence in about five minutes.
|
|
5
5
|
icon: rocket
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
**
|
|
8
|
+
**Start with one command in your app's folder: `npx @reticlehq/server`.** It checks the running app with nothing installed and prints a verdict. Then `npx @reticlehq/server init`, once per project, connects your coding agent. The dashboard (`reticle connect`) is optional. No account is needed for steps 1 and 2.
|
|
9
9
|
|
|
10
10
|
By the end of this page your agent will click a button in your app and prove what happened: the request that fired, the state that changed, and the file to open if it didn't.
|
|
11
11
|
|
|
@@ -18,52 +18,47 @@ By the end of this page your agent will click a button in your app and prove wha
|
|
|
18
18
|
|
|
19
19
|
- Node 20.11 or newer
|
|
20
20
|
- A web app you can run locally, and its dev server
|
|
21
|
-
-
|
|
21
|
+
- For step 2, a coding agent that speaks MCP (Claude Code, Cursor, Codex, OpenCode, Windsurf, VS Code)
|
|
22
22
|
|
|
23
|
-
## Step 1.
|
|
23
|
+
## Step 1. Check your app, with nothing installed
|
|
24
24
|
|
|
25
|
-
In
|
|
25
|
+
In your app's folder:
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
curl -fsSL https://raw.githubusercontent.com/reticlehq/reticle/main/install/install.sh | sh
|
|
27
|
+
```bash
|
|
28
|
+
cd path/to/your-app
|
|
29
|
+
npx @reticlehq/server
|
|
31
30
|
```
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
irm https://raw.githubusercontent.com/reticlehq/reticle/main/install/install.ps1 | iex
|
|
35
|
-
```
|
|
32
|
+
It finds your app's dev server. If the app does not run, it starts the dev script, and it stops that server at the end. It opens the app in a Reticle browser and installs nothing in your app. It checks that the page loads, that there is no console error and no failed request, and that each same-origin link opens (8 at most). On a small app with two links, it printed:
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
```text
|
|
35
|
+
Starting your dev server: npm run dev
|
|
36
|
+
Reticle is checking http://localhost:58440/. It installs nothing in your app.
|
|
37
|
+
✓ The page loads.
|
|
38
|
+
✓ No console error.
|
|
39
|
+
✓ No failed request.
|
|
40
|
+
✓ 2 of 2 link(s) opened with no fault.
|
|
41
|
+
```
|
|
40
42
|
|
|
41
|
-
|
|
43
|
+
Then the verdict line, `verified: yes` with the URL it checked, and the next step, `npx @reticlehq/server init`. A fault gives `verified: no`, and one `✗` line for each fault, for example `✗ Failed request on /broken: GET http://localhost:58473/api/missing: HTTP 404`. The command exits 0 only on `yes`. When the app sends the page to a sign-in page, Reticle verifies up to there and says so.
|
|
42
44
|
|
|
43
45
|
<Note>
|
|
44
|
-
**
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
**Not in the app's folder?** It checks the one dev server that runs on this computer. When several
|
|
47
|
+
run, it names them and does not choose. In a folder that `init` already wired, the same command
|
|
48
|
+
starts the Reticle server (`reticle serve`) instead.
|
|
47
49
|
</Note>
|
|
48
50
|
|
|
49
|
-
|
|
51
|
+
## Step 2. Connect your coding agent
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
npm install -g @reticlehq/server
|
|
53
|
-
npx @reticlehq/server setup mcp
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Step 2. Wire this project
|
|
57
|
-
|
|
58
|
-
In your project directory, before opening your coding agent:
|
|
53
|
+
In the same folder, before you open your coding agent, run the command that step 1 printed:
|
|
59
54
|
|
|
60
55
|
```bash
|
|
61
56
|
RETICLE_INSTALL_SOURCE=docs_site npx @reticlehq/server init
|
|
62
57
|
```
|
|
63
58
|
|
|
64
|
-
This installs the dev-only SDK, wires your build config, starts the dev server
|
|
59
|
+
This installs the dev-only SDK, wires your build config, and registers Reticle with every coding agent it finds on this machine. Then it starts the dev server and checks that a browser session connected. Nothing from your project leaves your machine. If your dev server was already running, restart it once and hard-reload the tab: it read your build config before `init` edited it. Open your coding agent once this command finishes. If it was open while `init` ran, restart it once: a coding agent reads its MCP server list only when it starts. The `RETICLE_INSTALL_SOURCE` prefix is optional and only tells us which page you installed from. It is idempotent: run it twice and the second run reports what was already done rather than doing it again.
|
|
65
60
|
|
|
66
|
-
|
|
61
|
+
This step is once per project. **Skipping it is a common reason Reticle "does nothing":** the agent has no tools, or no app on the other end for them to see.
|
|
67
62
|
|
|
68
63
|
<Note>
|
|
69
64
|
**Skipped this step?** Ask your agent to verify something in the app. Its first `reticle_session`
|
|
@@ -73,21 +68,6 @@ Step 1 is once per machine. This step is once per project. **Skipping it is a co
|
|
|
73
68
|
second project while Reticle is already running for another one.
|
|
74
69
|
</Note>
|
|
75
70
|
|
|
76
|
-
Prefer to install the skill and let the agent run setup itself? On Claude Code the plugin registers the MCP server and the skill in one step:
|
|
77
|
-
|
|
78
|
-
```text
|
|
79
|
-
/plugin marketplace add reticlehq/reticle
|
|
80
|
-
/plugin install reticle@reticlehq
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
On Cursor, Codex, Copilot, Gemini and anything else the skills CLI supports:
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
npx skills add reticlehq/reticle --skill reticle
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
Then type `/reticle` and the agent runs the install from the skill.
|
|
90
|
-
|
|
91
71
|
Useful flags for the local-only `reticle init` path:
|
|
92
72
|
|
|
93
73
|
```
|
|
@@ -110,6 +90,44 @@ Start with `reticle init --dry-run` if you want to see the app changes before an
|
|
|
110
90
|
|
|
111
91
|
Prefer to wire it yourself? See [Manual install](/install-manual). It is about ten lines, and worth reading once even if you let the agent do it, because it explains what the agent actually changed.
|
|
112
92
|
|
|
93
|
+
### Other ways to connect your agent
|
|
94
|
+
|
|
95
|
+
**On Claude Code, the plugin** registers the MCP server and the skill in one step. Type `/reload-plugins` after the install and the tools load in the open session:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
/plugin marketplace add reticlehq/reticle
|
|
99
|
+
/plugin install reticle@reticlehq
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**On Cursor, Codex, Copilot, Gemini** and anything else the skills CLI supports, add the skill, then type `/reticle` and the agent runs the setup from the skill:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npx skills add reticlehq/reticle --skill reticle
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**The installer** puts `reticle` on your PATH once per machine and registers the MCP server with every coding agent it can reach: Claude Code, Cursor, Windsurf, VS Code, Zed, Gemini CLI, Copilot CLI, OpenCode, Antigravity, Warp, Kiro, Amazon Q, Cline, Roo Code, Amp, Continue and Factory Droid. It asks no questions and does not wire your app. Run it before you open your coding agent:
|
|
109
|
+
|
|
110
|
+
<CodeGroup>
|
|
111
|
+
|
|
112
|
+
```bash macOS / Linux
|
|
113
|
+
curl -fsSL https://raw.githubusercontent.com/reticlehq/reticle/main/install/install.sh | sh
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```powershell Windows
|
|
117
|
+
irm https://raw.githubusercontent.com/reticlehq/reticle/main/install/install.ps1 | iex
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
</CodeGroup>
|
|
121
|
+
|
|
122
|
+
Prefer not to pipe a script into a shell? The same result by hand:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
npm install -g @reticlehq/server
|
|
126
|
+
npx @reticlehq/server setup mcp
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Codex CLI keeps a TOML config. With the `codex` command installed, the installer registers Reticle through `codex mcp add`. Without it, the installer prints the lines to paste and the file to paste them into. Reticle then adds one line, `default_tools_approval_mode = "approve"`, under `[mcp_servers.reticle]` in `~/.codex/config.toml`. This line approves Reticle's own tools, so Codex does not ask before each call. Reticle changes no other line, and it keeps a mode that you set. To undo it, change that line to `default_tools_approval_mode = "prompt"`. Reticle does not change a mode that is already there.
|
|
130
|
+
|
|
113
131
|
## Step 3. Connect the dashboard (optional)
|
|
114
132
|
|
|
115
133
|
Skip this if you only want local verdicts. Everything above works without an account.
|
|
@@ -272,10 +290,11 @@ That third state is the one that matters. Most tools have two outcomes and quiet
|
|
|
272
290
|
|
|
273
291
|
<AccordionGroup>
|
|
274
292
|
<Accordion title="How long does it actually take to install Reticle?">
|
|
275
|
-
Two commands
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
293
|
+
Two commands in your app's folder. `npx @reticlehq/server` gives a first verdict with nothing
|
|
294
|
+
installed. Then `npx @reticlehq/server init` wires the project, registers Reticle with every
|
|
295
|
+
coding agent on the machine, starts your dev server and opens the app for you. Run them before
|
|
296
|
+
you open your agent, and it needs no restart. For most agents the MCP registration is global, so
|
|
297
|
+
a later project starts with the tools already there.
|
|
279
298
|
</Accordion>
|
|
280
299
|
|
|
281
300
|
<Accordion title="Do I need to write tests or learn a query syntax?">
|
package/docs/skill-setup.md
CHANGED
|
@@ -97,7 +97,7 @@ Enterprise features are unlocked by a signed key, verified locally with Ed25519
|
|
|
97
97
|
npx @reticlehq/server@latest init --license <key>
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
That writes `RETICLE_LICENSE_KEY` to the project's `.env` and adds `.env` to `.gitignore` if nothing there covers it. Do not do those two by hand: a key committed to git is a leaked credential, and it stays leaked after the file is removed. Confirm with `npx @reticlehq/server
|
|
100
|
+
That writes `RETICLE_LICENSE_KEY` to the project's `.env` and adds `.env` to `.gitignore` if nothing there covers it. Do not do those two by hand: a key committed to git is a leaked credential, and it stays leaked after the file is removed. Confirm with `npx @reticlehq/server status --json`. Its `license.status` is `active`, `eval`, `missing`, `invalid` or `expired`.
|
|
101
101
|
|
|
102
102
|
Never echo the key back in your reply, and never put it in a commit, a code comment, or a feedback report. The rest: `curl https://docs.reticle.sh/enterprise.md`.
|
|
103
103
|
|
package/docs/skill.md
CHANGED
|
@@ -3,7 +3,7 @@ name: reticle-docs
|
|
|
3
3
|
description: Install, instrument and verify this running web app from the inside (DOM, network, routing, console and framework state) instead of screenshots or guessing. Drives one real flow end to end and returns a verdict with the file:line to fix. Use when the user asks to set up or install Reticle, when a user-facing change needs proving before you call it done, when a test passes but the UI is broken, or when the user types /reticle.
|
|
4
4
|
license: Apache-2.0
|
|
5
5
|
metadata:
|
|
6
|
-
version: 3.
|
|
6
|
+
version: 3.10.0
|
|
7
7
|
homepage: https://docs.reticle.sh
|
|
8
8
|
repository: https://github.com/reticlehq/reticle
|
|
9
9
|
internal: true
|
|
@@ -13,30 +13,31 @@ metadata:
|
|
|
13
13
|
|
|
14
14
|
Reticle is the proof layer for AI coding agents. A dev-only SDK inside the user's running app gives you `reticle_*` MCP tools that read the DOM, network, routing, console and framework state. You act on the real app and get a verdict: `yes`, `no`, or `unknown` (could not tell), with evidence and the `file:line` to open. No screenshots: it drives the tab the user already has open.
|
|
15
15
|
|
|
16
|
-
**Your first goal: one real verdict in the user's app.** Do the
|
|
16
|
+
**Your first goal: one real verdict in the user's app.** Do the steps in order. Do not stop to explain Reticle first.
|
|
17
17
|
|
|
18
|
-
## 1.
|
|
18
|
+
## 1. Check the app, with nothing installed
|
|
19
19
|
|
|
20
|
-
**`reticle_*` tools visible?**
|
|
20
|
+
**`reticle_*` tools visible?** Call `reticle_session { action: "list" }`. It changes no file. On a wired project, go to step 3. On a project that is not wired, its `next_step` names the zero-install lease and asks the consent question for `init`.
|
|
21
21
|
|
|
22
|
-
**
|
|
22
|
+
**No tools, or an app with no `.reticle.json`?** Run this in the app's folder. It changes no file:
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
|
|
26
|
-
irm https://raw.githubusercontent.com/reticlehq/reticle/main/install/install.ps1 | iex # Windows
|
|
25
|
+
npx @reticlehq/server@latest
|
|
27
26
|
```
|
|
28
27
|
|
|
29
|
-
It
|
|
28
|
+
It starts the dev server if the app does not run, opens the app in a Reticle browser and checks it: the page loads, no console error, no failed request, and each same-origin link opens. It prints `verified: yes` or `verified: no` with each fault. Show the user that verdict, then offer `init`.
|
|
30
29
|
|
|
31
30
|
## 2. Wire this app (once per project)
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
`init` changes files, so run it only when the user agrees. A request to set up Reticle is that agreement. Run it in the app's folder:
|
|
34
33
|
|
|
35
34
|
```bash
|
|
36
35
|
RETICLE_INSTALL_SOURCE=skill_file npx @reticlehq/server@latest init
|
|
37
36
|
```
|
|
38
37
|
|
|
39
|
-
A dev server that was running when `init` ran must be restarted once. If `init` cannot finish alone, read SETUP below.
|
|
38
|
+
It registers Reticle with every coding agent it finds. A dev server that was running when `init` ran must be restarted once. If `init` cannot finish alone, read SETUP below.
|
|
39
|
+
|
|
40
|
+
**Still no `reticle_*` tools?** A client loads MCP servers only at start, so a prompt cannot add them. `npx @reticlehq/server init --relaunch` prints the command that resumes this conversation with the tools. Else ask the user to restart the agent. Do not register the server yourself and work around your client not having reloaded.
|
|
40
41
|
|
|
41
42
|
## 3. Prove one flow
|
|
42
43
|
|
|
@@ -87,7 +88,7 @@ The advertised surface is deliberately small (`default` 10, `all` 30). `RETICLE_
|
|
|
87
88
|
| `reticle_verify` | replay, coverage, Harness | `action`: `change` `flows` `affected` `coverage` `crawl` `explore` `mutate` `heal` |
|
|
88
89
|
| `reticle_tools` / `reticle_run` | everything else (below) | `names`; `tool`, `args` |
|
|
89
90
|
|
|
90
|
-
Actions: `click` `dblclick` `hover` `focus` `blur` `fill` `type` `clear` `select` `check` `uncheck` `submit` `press` `upload` `scrollIntoView` `scroll` `drag` `tap` `zoom`. `args`: `{ value }` for fill/select, `{ text: "Enter" }` for press, `{ toRef }` for drag, `{ path }` for upload, `{ native: true }` for a trusted click. A control whose label reads as destructive is refused until you pass `args.confirmDangerous: true`, and only do that when the user asked for it.
|
|
91
|
+
Actions: `click` `dblclick` `hover` `focus` `blur` `fill` `type` `clear` `select` `check` `uncheck` `submit` `press` `upload` `scrollIntoView` `scroll` `drag` `tap` `zoom` `insertText`. `args`: `{ value }` for fill/select, `{ text: "Enter" }` for press, `{ toRef }` for drag, `{ path }` for upload, `{ native: true }` for a trusted click. `insertText` takes `{ text }` and types into a contenteditable/Tiptap/ProseMirror editor, where `fill` and `type` are refused. A control whose label reads as destructive is refused until you pass `args.confirmDangerous: true`, and only do that when the user asked for it.
|
|
91
92
|
|
|
92
93
|
Beyond the advertised set, one hop each:
|
|
93
94
|
|
|
@@ -105,7 +106,7 @@ Every `until`, `predicate` and `expect` is `{ kind, ...fields }`; unknown fields
|
|
|
105
106
|
|
|
106
107
|
| kind | fields |
|
|
107
108
|
| --- | --- |
|
|
108
|
-
| `element` | `query: { testid \| role+name \| text \| label \| placeholder \| alt \| component, scope? }`, `state?`: `visible` `hidden` `enabled` `disabled` `checked` `expanded` `pressed` `focused` `present` `inViewport`, `absent?` |
|
|
109
|
+
| `element` | `query: { testid \| role+name \| text \| label \| placeholder \| alt \| component, scope? }`, `state?`: `visible` `hidden` `enabled` `disabled` `checked` `expanded` `pressed` `focused` `present` `inViewport` `receivesPointer`, `absent?` |
|
|
109
110
|
| `text` | `contains`, `scope?`, `visible?`, `absent?`, `ignoreCase?`, `satisfies?` |
|
|
110
111
|
| `net` | `method`, `urlContains`, `status`, `ok`, `count` (exact; omit = ≥1; 0 = never), `bodyContains`, `bodyMatches`, `requestBodyMatches`, `repeatable` |
|
|
111
112
|
| `route` | `pathname` or `contains` |
|
|
@@ -115,7 +116,7 @@ Every `until`, `predicate` and `expect` is `{ kind, ...fields }`; unknown fields
|
|
|
115
116
|
| `settled` / `animation` / `compare` | `quietMs`, `channel?` / `name`, `completed` / `left`, `right`, `as` |
|
|
116
117
|
| `allOf` / `anyOf` / `not` | `predicates: [...]` / `predicates: [...]` / `predicate` |
|
|
117
118
|
|
|
118
|
-
`satisfies` asserts a property when the exact value varies: `nonEmpty`, `oneOf`, `withinTolerance`, `matchesPattern`, `type`, `changed`, `unchanged`, `increased`, `decreased`. Composites hold only predicates: `absent` belongs inside a child, and an `element` takes a `query`, never a `ref`. A bare `route` or `state` is already true before the action and proves nothing; pair it with what the action causes.
|
|
119
|
+
`satisfies` asserts a property when the exact value varies: `nonEmpty`, `oneOf`, `withinTolerance`, `matchesPattern`, `type`, `changed`, `unchanged`, `increased`, `decreased`. Composites hold only predicates: `absent` belongs inside a child, and an `element` takes a `query`, never a `ref`. A bare `route` or `state` is already true before the action and proves nothing; pair it with what the action causes. `absent` means not in the DOM; to say a thing is not shown, add `visible: true`. Assert what the requirement names, not a label you saw: another correct build can name it differently.
|
|
119
120
|
|
|
120
121
|
## Feedback is first-class
|
|
121
122
|
|
package/docs/telemetry.md
CHANGED
|
@@ -43,7 +43,7 @@ Twenty-five kinds of events, each a single small JSON object. This is the whole
|
|
|
43
43
|
| `onboarding_step` | One step of getting set up begins, finishes, fails, is skipped, or is walked away from | Which phase (`install`, `onboard`, `first_run`), which step, what became of it, how long it took, and the framework. The step name comes from a closed list we define -- it can only ever be one of the names in `core/src/onboarding.ts`, so nothing you typed or any path on your disk can arrive in it. `unattended` says whether anybody was asked anything. A step that failed can carry why setup stopped, also from a closed list (`no_node`, `node_too_old`, `no_web_app`, `dev_server_failed`, `chromium_unavailable`, and so on) |
|
|
44
44
|
| `init_completed` | `reticle init` finishes | Whether it worked, a classified reason when it did not, and which published install route you came through, DECLARED by that route via `RETICLE_INSTALL_SOURCE` and never inferred, and `unknown` when nothing declared one |
|
|
45
45
|
| `bug_found` | Reticle finds a defect in the app under test | The **kind** of defect (`signal-contradicted`, `console-error`, …) and how it was found, never what it was found in |
|
|
46
|
-
| `tool_refused` | A tool cannot do what an agent asked | Which tool, why (one of six buckets: no session, no match, unsupported, bad arguments, not ready, other), and whether the same call was retried. **Never the message**, because a refusal interpolates whatever you asked for, so only the tool name and the bucket are sent. Capped at 50 per daemon run |
|
|
46
|
+
| `tool_refused` | A tool cannot do what an agent asked | Which tool, why (one of six buckets: no session, no match, unsupported, bad arguments, not ready, other), the cause inside the bucket as a name from a closed list (such as `chromium_missing` or `throttled`), and whether the same call was retried. **Never the message**, because a refusal interpolates whatever you asked for, so only the tool name and the bucket are sent. Capped at 50 per daemon run |
|
|
47
47
|
| `feedback_submitted` | **Only** when you or your agent explicitly send feedback | The report; see [Feedback](#feedback). The AGENT's call does not wait for the network: the receipt says `accepted` (validated, redacted, queued), never `sent`, and a delivery that then fails is reported back on the agent's next tool result. `reticle feedback` typed by a human still waits, because a person at a terminal is owed the real answer |
|
|
48
48
|
| `hud_viewed` | You open a page of the in-page HUD (Agent Log, Flows, Notes, Harness, Impact, Settings) or its account menu | Which page, from a closed list, and how many tabs had a HUD (a bucket: `1`, `2-3`, and so on). The same page opened again within 30 seconds counts once for the whole daemon run, also after a reload. The Agent Log that the HUD opens by itself when a page loads is not a view |
|
|
49
49
|
| `hud_signin_prompted` | The HUD shows you a sign-in or "link this project" prompt | Which prompt (`rail`, `harness` or `header`), once per prompt for each daemon run |
|
|
@@ -62,7 +62,7 @@ It also carries a snapshot of the **machine's** state (our own process's memory,
|
|
|
62
62
|
|
|
63
63
|
### Why a verdict came out that way
|
|
64
64
|
|
|
65
|
-
`verification_completed` carries the **clause** that decided the verdict, from a fixed list we define: `proved`, `contradicted`, `assertion_failed`, `already_true`, `hidden_match`, `unclean_capture`, `vacuous_grade`, `nothing_declared`, `outcome_pending`, `outcome_unread`, `unsettled`, `evidence_incomplete`, `absence_blind_spot`, `observation_lost`, `window_closed_early`, `inconclusive`, `version_skew`, `capability-absent`.
|
|
65
|
+
`verification_completed` carries the **clause** that decided the verdict, from a fixed list we define: `proved`, `contradicted`, `assertion_failed`, `already_true`, `hidden_match`, `unclean_capture`, `vacuous_grade`, `nothing_declared`, `outcome_pending`, `outcome_unread`, `unsettled`, `evidence_incomplete`, `absence_blind_spot`, `observation_lost`, `window_closed_early`, `dialog_declined`, `inconclusive`, `version_skew`, `capability-absent`.
|
|
66
66
|
|
|
67
67
|
It exists because `verified: "unknown"` covered seven different situations belonging to three different owners (your app, your agent, and Reticle's own blind spots), and they arrived as one value. It is a **name from our own vocabulary**, never a description of your app: `contradicted` says two channels disagreed, not which ones, about what, or on which page.
|
|
68
68
|
|
package/docs/tools/navigate.mdx
CHANGED
|
@@ -77,7 +77,7 @@ with [`reticle_session`](/tools/sessions), and only then look at the page. If no
|
|
|
77
77
|
| --- | --- |
|
|
78
78
|
| `url` | Where to go. Relative paths work |
|
|
79
79
|
| `reload` | Reload in place instead of navigating |
|
|
80
|
-
| `hard` | With `reload`, bypass the cache |
|
|
80
|
+
| `hard` | With `reload`, bypass the cache. On a leased tab the browser reloads with its cache ignored (`hardReload: "cache_ignored"`). On a tab Reticle does not drive, only the document is fetched again, and scripts and modules can come from the cache (`hardReload: "document_only"`) |
|
|
81
81
|
| `timeout_ms` | How long to wait for the page to come back before `confirmed: false`. Default 5000; 0 looks once |
|
|
82
82
|
|
|
83
83
|
## Client-side routing is different
|
package/docs/tools/verify.mdx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: reticle_verify
|
|
3
|
-
description: Prove what is and is not working, by action. Replay saved flows for a change or for the whole suite, list coverage, crawl, explore, mutate or
|
|
3
|
+
description: Prove what is and is not working, by action. Replay saved flows for a change or for the whole suite, list coverage, crawl, explore, mutate, heal, or compare two builds.
|
|
4
4
|
icon: shield-check
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -20,9 +20,12 @@ icon: shield-check
|
|
|
20
20
|
| `explore` | The Harness, Reticle's model-driven explorer, drives the journey you name in `persona` and saves what it drove as flows. Runs on the Reticle platform: run `reticle connect` first. A new account gets free credits to try it. **Destructive** | no |
|
|
21
21
|
| `mutate` | Grades a saved flow: breaks the endpoint it depends on and replays it. A flow that stays green is a click sequence, not a test | no |
|
|
22
22
|
| `heal` | Rebinds a flow whose locator was renamed. Re-asserts the saved consequence first and refuses if it stops firing. `apply: true` writes the fix | no |
|
|
23
|
+
| `compare` | Drives two running builds (`reference`, `candidate`, optional `base`) the same way and lists each difference in what users see and in the requests and console errors the app made. Nothing is installed in the app. Answers the JSON of [`reticle compare --json`](/cli/compare), with `verified` `yes` (same), `no` (different) or `unknown` (the run proves nothing). Within `wait` seconds it gives the result, or `{ status: "running", runId }` to poll with `runId`. **Destructive:** it presses every button it finds | yes |
|
|
23
24
|
|
|
24
25
|
Only `verified: "yes"` is a pass. `unknown` means Reticle could not tell, and `no-fault` means nothing was declared to prove.
|
|
25
26
|
|
|
27
|
+
For `action: "flows"` and `action: "change"`, `parallel` opens one isolated lease per replayed flow. These leases inherit the source lease's certificate setting. Set `ignoreHTTPSErrors: true` to accept a self-signed or local-CA certificate when the source is not a lease. An explicit `false` keeps certificate checks on.
|
|
28
|
+
|
|
26
29
|
Replay before you drive: a covered journey re-verifies for a few hundred tokens, where driving it again costs tens of thousands.
|
|
27
30
|
|
|
28
31
|
From a terminal, `reticle verify <url>` replays the saved flows and exits `0` on pass. See [`reticle verify`](/cli/verify).
|
package/docs/troubleshooting.mdx
CHANGED
|
@@ -263,7 +263,7 @@ Some clients read their MCP tool list once, at startup, and never again. Cursor
|
|
|
263
263
|
## Restarting things
|
|
264
264
|
|
|
265
265
|
```bash
|
|
266
|
-
npx @reticlehq/server restart # clean stop, then start and wait until it listens
|
|
266
|
+
npx @reticlehq/server serve --restart # clean stop, then start and wait until it listens
|
|
267
267
|
npx @reticlehq/server status # confirm it is back
|
|
268
268
|
```
|
|
269
269
|
|
package/docs/usage.md
CHANGED
|
@@ -129,7 +129,7 @@ Deep detail on one element, including the signals a snapshot/a11y tree omits, so
|
|
|
129
129
|
Perform one action / several in order.
|
|
130
130
|
|
|
131
131
|
- **`reticle_act` args:** `ref`, `action`, `args?`, `refuseWhenThrottled?`, `sessionId?`. → `{ since, dispatched, settled, settleReason, result, session, warning? }` where `result = { ok, ref, action, dispatched, settled, settleReason, effect }`. The `session` block `{ lastSeenMs, throttled, focused }` reports tab health on every act; when `throttled` is true a `warning` string is also attached. Pass `refuseWhenThrottled: true` to hard-fail instead of warning (opt-in; default is warn-only so background testing never breaks).
|
|
132
|
-
- **`reticle_act { steps: [...] }` args:** `steps: [{ ref | target, action, args?, expect? }]`. `expect` takes the same predicate as `reticle_act_and_wait` `until`. A step with `expect` proves its consequence. The call stops at the first `expect` that fails and returns `verified` and `because`. Each step takes `ref` (from a snapshot/query) or `target` (`{ testid }` / `{ label }` / `{ role, name }` / `{ text }`). That is the same locator `reticle_act` accepts. → `{ since, dispatched, result }` where `result = { ok, count, effects: [...], steps: [...] }` (one `effect` per step; each step carries its own `dispatched`/`settled`/`settleReason`).
|
|
132
|
+
- **`reticle_act { steps: [...] }` args:** `steps: [{ ref | target, action, args?, expect? }]`. `expect` takes the same predicate as `reticle_act_and_wait` `until`. A step with `expect` proves its consequence. The call stops at the first `expect` that fails and returns `verified` and `because`. When a step could not be judged, the plan is `verified: "unknown"` (`verifiedReason: "inconclusive"`), and `because` names that step and what was missing: `step 2 (click) could not be judged: the assertion could not be evaluated: …`. `stopped_at` is the index of the same step, counted from 0. Each step takes `ref` (from a snapshot/query) or `target` (`{ testid }` / `{ label }` / `{ role, name }` / `{ text }`). That is the same locator `reticle_act` accepts. → `{ since, dispatched, result }` where `result = { ok, count, effects: [...], steps: [...] }` (one `effect` per step; each step carries its own `dispatched`/`settled`/`settleReason`).
|
|
133
133
|
- See [§5](#5-actions-full-list) for the action list.
|
|
134
134
|
|
|
135
135
|
**Dispatch vs settle.** (Settle means the page has stopped changing for now.) The action is two phases: the **dispatch** (the synchronous click/fill, which is what can fail) and the **settle** (waiting one animation frame so React's commit lands before we return). The settle is **bounded** (~200ms): in a throttled/background tab `requestAnimationFrame` never fires, so Reticle falls back to a timer and resolves anyway. A settle timeout is therefore **never an error**: `reticle_act` resolves with `settled:false, settleReason:"timeout"` and the dispatch (the click) has still landed. Only a real dispatch failure (stale ref, wrong element type) throws.
|
|
@@ -148,9 +148,9 @@ Perform one action / several in order.
|
|
|
148
148
|
| `targetMatched` | the ref still resolved to a connected element |
|
|
149
149
|
| `visible` | element was visible at the start of the action |
|
|
150
150
|
| `enabled` | element was not disabled / aria-disabled at the start |
|
|
151
|
-
| `defaultPrevented` | a handler called `preventDefault()` on the primary cancelable event. Only meaningful for `click`/`dblclick`/`hover`/`fill`/`type`/`clear`/`press`/`upload`/`drag`; always `false` for non-cancelable events (`focus`/`blur`/`select`/`check`/`uncheck`/`submit`/`scrollIntoView`) |
|
|
151
|
+
| `defaultPrevented` | a handler called `preventDefault()` on the primary cancelable event. Only meaningful for `click`/`dblclick`/`hover`/`fill`/`type`/`insertText`/`clear`/`press`/`upload`/`drag`; always `false` for non-cancelable events (`focus`/`blur`/`select`/`check`/`uncheck`/`submit`/`scrollIntoView`). For `insertText`, `true` with `valueChanged: true` means an editor that owns its input took the text: that is success, not a refusal |
|
|
152
152
|
| `focusMoved` | `"<prevRef>-><newRef>"` if `document.activeElement` changed, else `null` (body counts as `null`) |
|
|
153
|
-
| `valueChanged` | `fill`/`type`/`clear`
|
|
153
|
+
| `valueChanged` | `fill`/`type`/`clear`, and `insertText`: the field value (or the editor's text) before !== after; otherwise `false` |
|
|
154
154
|
| `domMutatedWithin` | count of MutationObserver records seen in the window |
|
|
155
155
|
| `occluded` | `click`/`dblclick` only: the click point hit-tested to a _foreign_ element (an overlay is on top). Synthetic dispatch still delivered the event, but **a real user could not click it**, so treat the target as visually blocked. `false` when not click-like or not hit-testable |
|
|
156
156
|
| `occludedBy` | the ref of the element actually on top at the click point when `occluded`, else `null` |
|
|
@@ -283,13 +283,13 @@ Show the agent's intent on the page, and control time (toasts/debounces/auto-dis
|
|
|
283
283
|
|
|
284
284
|
Regression detection. See [§8](#8-regression-baselines--diff).
|
|
285
285
|
|
|
286
|
-
### `reticle_run { tool: "reticle_record", args: { action: "start"
|
|
286
|
+
### `reticle_run { tool: "reticle_record", args: { action: "start" | "stop" | "replay" } }`
|
|
287
287
|
|
|
288
288
|
Capture a flow's reaction report and compile it into a replayable program. See [§9](#9-recording-a-flow). `reticle_run { tool: "reticle_record", args: { action: "stop" } }` also returns a `cost:{ events, bytes }` hint alongside the reaction report so you can gauge the recording's size.
|
|
289
289
|
|
|
290
|
-
###
|
|
290
|
+
### Autonomous exploration
|
|
291
291
|
|
|
292
|
-
List interactive elements
|
|
292
|
+
List the interactive elements with `reticle_snapshot { mode: "interactive" }` and read console errors with `reticle_console`. See [§10](#10-autonomous-exploration).
|
|
293
293
|
|
|
294
294
|
### Flows, recorder & self-healing (`.reticle/`)
|
|
295
295
|
|
|
@@ -356,7 +356,9 @@ A **predicate** declares what should be true. `reticle_assert` / `reticle_assert
|
|
|
356
356
|
// An element exists / is in a state
|
|
357
357
|
{ "kind": "element", "query": { "role": "dialog", "name": "Confirm" }, "state": "visible" }
|
|
358
358
|
// query supports: role, name, text, label, placeholder, testid, alt, scope
|
|
359
|
-
// state: visible | hidden | enabled | disabled | checked | expanded | pressed | focused | present | inViewport
|
|
359
|
+
// state: visible | hidden | enabled | disabled | checked | expanded | pressed | focused | present | inViewport | receivesPointer
|
|
360
|
+
// receivesPointer asserts that a tap at the element's centre reaches it: visible, in the viewport, and no app element on top
|
|
361
|
+
// (a fixed header over a close button leaves it `visible` and untappable). Reticle's own UI never counts as a cover.
|
|
360
362
|
// inViewport asserts the element is in the viewport NOW (not just in the DOM), so a scrollIntoView is gradeable
|
|
361
363
|
// add "absent": true to assert it is NOT there (regression / removal)
|
|
362
364
|
|
|
@@ -419,11 +421,12 @@ A `state` assertion is graded as a **consequence** (a wrong element or stale ren
|
|
|
419
421
|
| `focus` / `blur` | n/a | |
|
|
420
422
|
| `fill` | `{ value }` | sets value via React-safe native setter + `input`/`change` |
|
|
421
423
|
| `type` | `{ text }` | appends to current value |
|
|
424
|
+
| `insertText` | `{ text }` | inserts plain text into a contenteditable/Tiptap/ProseMirror editor through the browser editing pipeline: it announces `beforeinput` first, then lets the browser insert, so the editor's own model updates. `fill` and `type` refuse these surfaces. It refuses an EditContext editor (Monaco, CodeMirror 6), where a scripted update fires no `textupdate` for the model, and it refuses when the native command exists and fails, rather than writing the DOM while the editor's model stays stale |
|
|
422
425
|
| `clear` | n/a | empties an input |
|
|
423
426
|
| `select` | `{ value }` | `<select>` option |
|
|
424
427
|
| `check` / `uncheck` | n/a | checkbox/radio |
|
|
425
428
|
| `submit` | n/a | submits the element's `<form>` |
|
|
426
|
-
| `press` | `{ text, modifiers?, holdMs?, keys?, code? }` | keydown/up (default `Enter`). `text` is the key name (`Escape`, `Tab`); `key` is an accepted alias; `modifiers`: an array of `Meta` / `Control` / `Shift` / `Alt` for Cmd+K-style shortcuts. With a `ref` the key is dispatched AT that element; with NO ref it is a document key (Escape, Tab, a shortcut) and goes through the real keyboard, so it can actually move focus. `holdMs` keeps the key DOWN for that long (hold-to-confirm, hold-to-reveal). `keys` holds several keys together, pressed in order and released in reverse, and `code` names the physical key: both stay on the in-page dispatcher, which is the only path that can express them |
|
|
429
|
+
| `press` | `{ text, modifiers?, holdMs?, keys?, code?, document? }` | keydown/up (default `Enter`). `document: true` makes any key a document key, so it needs no `ref`. `text` is the key name (`Escape`, `Tab`); `key` is an accepted alias; `modifiers`: an array of `Meta` / `Control` / `Shift` / `Alt` for Cmd+K-style shortcuts. With a `ref` the key is dispatched AT that element; with NO ref it is a document key (Escape, Tab, an arrow key, a shortcut) and goes through the real keyboard, so it can actually move focus. `holdMs` keeps the key DOWN for that long (hold-to-confirm, hold-to-reveal). `keys` holds several keys together, pressed in order and released in reverse, and `code` names the physical key: both stay on the in-page dispatcher, which is the only path that can express them |
|
|
427
430
|
| `scrollIntoView` | n/a | |
|
|
428
431
|
| `scroll` | `{ dy?, dx?, fraction? }` | Scrolls the nearest scrollable container (or the page, with no `ref`) by `dy`/`dx` pixels, either direction. `fraction` (0 to 1) jumps to that point of the height. No args steps down most of a screen |
|
|
429
432
|
| `tap` | `{ holdMs? }` | A touch tap: pointer and touch events, then `click`. `holdMs` makes it a long press |
|
|
@@ -441,7 +444,7 @@ A `state` assertion is graded as a **consequence** (a wrong element or stale ren
|
|
|
441
444
|
- **`interactive`** (~100 tokens): only actionable elements (buttons, inputs, tabs…). "What can I click?" Non-interactive content (e.g. 1,000 list rows) is skipped.
|
|
442
445
|
- **`full`**: the whole semantic tree. Use only when you truly need everything.
|
|
443
446
|
|
|
444
|
-
**`scope`** narrows any snapshot or query to a subtree, either a CSS selector (`scope: "[data-testid=item-list]"`) or a ref. This is the main lever for keeping payloads small and queries unambiguous on big pages.
|
|
447
|
+
**`scope`** narrows any snapshot or query to a subtree, either a CSS selector (`scope: "[data-testid=item-list]"`) or a ref. This is the main lever for keeping payloads small and queries unambiguous on big pages. In a query or a check, a CSS selector that matches several elements searches all of them, and the result reports how many it matched in `scopeMatches`. A ref names one element.
|
|
445
448
|
|
|
446
449
|
---
|
|
447
450
|
|
|
@@ -666,7 +669,7 @@ reticle_run({ tool: "reticle_record", args: { action: "stop", recordingName: "ch
|
|
|
666
669
|
`reticle_run { tool: "reticle_record", args: { action: "stop" } }` returns a compiled, replayable `program`: the agent's `reticle_act` / `reticle_act { steps: [...] }` invocations captured during the span, with each ref normalized to its element's `data-testid` where resolvable. Re-run it later:
|
|
667
670
|
|
|
668
671
|
```jsonc
|
|
669
|
-
reticle_run({ tool: "
|
|
672
|
+
reticle_run({ tool: "reticle_record", args: { action: "replay", recordingName: "checkout" } })
|
|
670
673
|
// re-resolves each step by testid and re-runs the actions in order
|
|
671
674
|
// → { recordingName, ok, steps: [{ tool, ok, error?, note? }] } // stops at the first failure
|
|
672
675
|
```
|
|
@@ -680,8 +683,8 @@ reticle_run({ tool: "reticle_replay", args: { recordingName: "checkout" } })
|
|
|
680
683
|
Have the agent crawl and stress a screen without a script:
|
|
681
684
|
|
|
682
685
|
```jsonc
|
|
683
|
-
|
|
684
|
-
|
|
686
|
+
reticle_snapshot({ mode: "interactive", scope: "main" }) // the controls, with refs
|
|
687
|
+
reticle_console({}) // the console errors so far
|
|
685
688
|
```
|
|
686
689
|
|
|
687
690
|
The agent then acts on each ref, observes the reaction, and reports anomalies (failed requests, console errors, dead controls). Good for "click everything on this page and tell me what breaks."
|
|
@@ -1043,9 +1046,9 @@ registerCapabilities({ testids: [...], signals: [...], stores: [...], flows: [..
|
|
|
1043
1046
|
reticle_run({ tool: "reticle_capabilities", args: {} }) // → { testids, signals, stores, flows }
|
|
1044
1047
|
```
|
|
1045
1048
|
|
|
1046
|
-
### `
|
|
1049
|
+
### `reticle_record { action: "replay" }`: recordings become re-runnable programs
|
|
1047
1050
|
|
|
1048
|
-
`reticle_run { tool: "reticle_record", args: { action: "start" } }` → drive the flow → `reticle_run { tool: "reticle_record", args: { action: "stop" } }` returns a **compiled program** (steps bound to testids/signals, not volatile refs). `reticle_run({ tool: "
|
|
1051
|
+
`reticle_run { tool: "reticle_record", args: { action: "start" } }` → drive the flow → `reticle_run { tool: "reticle_record", args: { action: "stop" } }` returns a **compiled program** (steps bound to testids/signals, not volatile refs). `reticle_run({ tool: "reticle_record", args: { action: "replay", recordingName } })` re-executes it, so your flow becomes a deterministic regression run, not a checklist.
|
|
1049
1052
|
|
|
1050
1053
|
---
|
|
1051
1054
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reticlehq/server",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0",
|
|
4
4
|
"mcpName": "io.github.reticlehq/reticle",
|
|
5
5
|
"description": "Reticle CLI, bridge and MCP server: a coding agent drives your running web app from the inside and gets a verdict with evidence, for change verification, access control, accessibility, performance and SEO checks.",
|
|
6
6
|
"type": "module",
|
|
@@ -20,23 +20,23 @@
|
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
24
|
-
"ws": "^8.
|
|
23
|
+
"@modelcontextprotocol/sdk": "^1.32.2",
|
|
24
|
+
"ws": "^8.22.1",
|
|
25
25
|
"zod": "^4.6.6",
|
|
26
|
-
"@reticlehq/browser": "3.
|
|
27
|
-
"@reticlehq/
|
|
28
|
-
"@reticlehq/
|
|
29
|
-
"
|
|
30
|
-
"
|
|
26
|
+
"@reticlehq/browser": "3.10.0",
|
|
27
|
+
"@reticlehq/init": "3.10.0",
|
|
28
|
+
"@reticlehq/core": "3.10.0",
|
|
29
|
+
"@reticlehq/engine": "3.10.0",
|
|
30
|
+
"open-verification": "1.1.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/pngjs": "^6.0.5",
|
|
34
|
-
"@types/ws": "^8.
|
|
34
|
+
"@types/ws": "^8.18.2",
|
|
35
35
|
"yaml": "^2.9.1"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
38
|
"pixelmatch": "^8.0.0",
|
|
39
|
-
"playwright": "^1.
|
|
39
|
+
"playwright": "^1.64.1",
|
|
40
40
|
"pngjs": "^7.0.0"
|
|
41
41
|
},
|
|
42
42
|
"license": "Apache-2.0",
|
|
@@ -65,10 +65,10 @@
|
|
|
65
65
|
"cli"
|
|
66
66
|
],
|
|
67
67
|
"reticle": {
|
|
68
|
-
"changelog": "3.
|
|
68
|
+
"changelog": "3.10.0 checks every change against what worked before. reticle compare and verify --against list what users would see change between two builds, and reticle grade grades a finished run from the app's stored data. Several false verdicts are fixed, most of them text checks that answered no for text that was on the page. An agent in a Claude Code worktree now reaches its own tab. Update the CLI and the SDK in your app.",
|
|
69
69
|
"breakingChanges": [
|
|
70
|
-
"
|
|
71
|
-
"The
|
|
70
|
+
"The commands kill, login, link, project, whoami, push, regression, share, issues and memory are removed. Each prints the command that replaces it and exits 1. See MIGRATION.md.",
|
|
71
|
+
"The MCP tools reticle_explore and reticle_replay left the tool surface. Use reticle_look { action: \"page\", mode: \"interactive\" } and reticle_record { action: \"replay\" }."
|
|
72
72
|
]
|
|
73
73
|
},
|
|
74
74
|
"publishConfig": {
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `reticle_crawl { exhaustive: true }` — explore every reachable state, drive every write's failure
|
|
3
|
-
* path, take the code coverage, fold all of it into the ledger, and say what is left.
|
|
4
|
-
*
|
|
5
|
-
* It answers in crawl's own shape, so every caller that reads a crawl keeps working, and adds one
|
|
6
|
-
* `exhaustive` block with what only this mode knows.
|
|
7
|
-
*/
|
|
8
|
-
import type { FileSystemPort } from '../../memory/project/fs/fs-port.js';
|
|
9
|
-
import { type RawScriptCoverage } from './code-coverage.js';
|
|
10
|
-
import { type PortSession } from './session-port.js';
|
|
11
|
-
/** Default action budget: generous, because every edge replays its path from a fresh load. */
|
|
12
|
-
export declare const EXHAUST_DEFAULT_ACTIONS = 400;
|
|
13
|
-
export declare function runExhaustive(input: {
|
|
14
|
-
sessions: {
|
|
15
|
-
get(id: string): PortSession | undefined;
|
|
16
|
-
};
|
|
17
|
-
session: PortSession;
|
|
18
|
-
startUrl: string;
|
|
19
|
-
maxActions: number;
|
|
20
|
-
settleMs: number;
|
|
21
|
-
/** What to type into a field, given the page it is on — a secret is only for its own origin. */
|
|
22
|
-
fillValue: (label: string, pageUrl: string) => string;
|
|
23
|
-
now: () => number;
|
|
24
|
-
sleep: (ms: number) => Promise<void>;
|
|
25
|
-
setMocks?: (sessionUrl: string, rules: {
|
|
26
|
-
urlContains: string;
|
|
27
|
-
method?: string;
|
|
28
|
-
abort?: boolean;
|
|
29
|
-
}[]) => Promise<boolean>;
|
|
30
|
-
takeCode?: (sessionUrl: string) => Promise<readonly RawScriptCoverage[] | undefined>;
|
|
31
|
-
fs: FileSystemPort;
|
|
32
|
-
reticleRoot: string;
|
|
33
|
-
}): Promise<Record<string, unknown>>;
|