@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
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: reticle grade
|
|
3
|
+
description: Grade a finished run of an app from snapshots of its stored data, and check its final answer.
|
|
4
|
+
icon: clipboard-check
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`reticle grade` answers one question: did a run leave the app the way the correct steps leave it, and give the correct answer? A run is any sequence of steps on an app you can reset: an agent, a script or a person. The command needs no daemon, no browser and nothing installed in the app. It reads the app's stored data through the [state sources](/cli/compare#state-sources) that `reticle compare --state` uses.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx @reticlehq/server grade snapshot --state <file> --out <file> [--url <url>]
|
|
11
|
+
npx @reticlehq/server grade judge --reference <file> --again <file> --candidate <file> [--expect <file>] [--answer <text>] [--json]
|
|
12
|
+
npx @reticlehq/server grade tables --list <command> --rows <template> [--container <name>] [--skip <prefix,...>] --out <file>
|
|
13
|
+
npx @reticlehq/server grade suggest --state <file> --reference <file> --again <file> --out <file>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## How to grade a run
|
|
17
|
+
|
|
18
|
+
1. Reset the app. Do the correct steps. Run `grade snapshot --out reference.json`.
|
|
19
|
+
2. Reset the app. Do the correct steps again. Run `grade snapshot --out again.json`.
|
|
20
|
+
3. Reset the app. Do the run to grade. Run `grade snapshot --out candidate.json`.
|
|
21
|
+
4. Run `grade judge --reference reference.json --again again.json --candidate candidate.json`.
|
|
22
|
+
|
|
23
|
+
Steps 1 and 2 are done one time for each task. Keep the two files, and grade every run of the task against them.
|
|
24
|
+
|
|
25
|
+
`judge` compares the lines of the three snapshots. A line that differs between the two correct runs (a clock, a random id) is noise and is ignored. Any other line that differs between the reference and the candidate is a difference, and the grade fails. So the grade fails when the run changed the wrong record, changed a record the task did not name, or did not change the record at all. A source that could not be read makes the grade unverified, never a pass.
|
|
26
|
+
|
|
27
|
+
A row that the two correct runs wrote with different values in some cells (a time of the run, written into `updated_at`) has noise in those cells only. A candidate row that differs from the reference row only in those cells is not a difference. A change to another cell of that row, or to the same cell of another row, is a difference.
|
|
28
|
+
|
|
29
|
+
Many apps save a record by deleting its child rows and writing them again, with new ids. A run that saves a record two times then has the same data under other ids. `judge` matches these rows: a removed row and an added row of one source are the same record when every cell after the first (the id) is equal, after each id it already matched is replaced by its new id. So a row that links to a written-again row matches too. A match needs an old id that the candidate no longer has, and a new id that the reference did not have, so a changed value in a first column that is not an id is still a difference. `--json` gives the count as `state.renumbered`. This applies to text rows (a `command` source, or a file of plain lines) whose cells are separated by tabs.
|
|
30
|
+
|
|
31
|
+
| Exit code | Verdict | Meaning |
|
|
32
|
+
| --------- | ------------ | ------------------------------------------------------------------ |
|
|
33
|
+
| 0 | `PASS` | The stored data matches, and the answer is correct |
|
|
34
|
+
| 1 | `FAIL` | A line differs, or the answer is wrong |
|
|
35
|
+
| 2 | `UNVERIFIED` | A source or a snapshot could not be read. The grade proves nothing |
|
|
36
|
+
|
|
37
|
+
`--json` prints one JSON object: `verdict`, `state.removed` and `state.added` (every line that differs), `state.ignored`, `answer` and `unread`. The text output shows the first 10 lines on each side and says how many it left out.
|
|
38
|
+
|
|
39
|
+
## Snapshot
|
|
40
|
+
|
|
41
|
+
`grade snapshot --state <file> --out <file>` reads each declared source and writes its rows as `state <label> <row>` lines, sorted. A snapshot keeps every row: unlike `compare`, it has no 1000-row cap, so a changed row always names its record. A read that fails gives a `state read failed: <label>: <reason>` line, and the command exits 2.
|
|
42
|
+
|
|
43
|
+
`--url <url>` adds the page the run ended on, as a `url` line. Use it for a task whose goal is to open a page. The fragment and a final slash are removed, and the query values are sorted.
|
|
44
|
+
|
|
45
|
+
## Check the answer
|
|
46
|
+
|
|
47
|
+
A task that asks a question has a final answer. A fixed answer string goes stale when the data changes. Declare a source whose rows are the correct answer instead, and `judge` reads it when it grades:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"answer": {
|
|
52
|
+
"source": {
|
|
53
|
+
"kind": "command",
|
|
54
|
+
"label": "answer",
|
|
55
|
+
"container": "shop-db",
|
|
56
|
+
"command": "mysql -N shop -e \"select count(*) from sales_order where customer_email = 'jane@example.com'\""
|
|
57
|
+
},
|
|
58
|
+
"match": "number",
|
|
59
|
+
"none": ["N/A"]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Give the file with `--expect`, and the run's answer with `--answer`. Text is folded before it is compared: Unicode normal form, lower case, spacing, quotes and a final full stop.
|
|
65
|
+
|
|
66
|
+
| `match` | The answer passes when |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| `exact` (default) | It is the one value in the rows. With more than one row, it is checked as `set` |
|
|
69
|
+
| `number` | It is one number and nothing else, equal to the first value within 0.005. `$`, `%` and digit-group commas are removed. `3 orders` and `3 or 4` fail |
|
|
70
|
+
| `set` | It is a list (split on commas, semicolons and new lines, or also on "and") with each value one time and nothing more, in any order |
|
|
71
|
+
| `includes` | It contains each value. An answer that names every choice also passes, so use it only where the run cannot list all choices |
|
|
72
|
+
|
|
73
|
+
A source with no rows means that the task cannot be done. Then the answer must be one of the `none` words. The default is `N/A`. A row with more than one column is one value, with the columns joined by a space.
|
|
74
|
+
|
|
75
|
+
## Write the declaration
|
|
76
|
+
|
|
77
|
+
The declaration must list every table that a run can change, or a change to that table is not seen. Do not write it by hand. Generate it, then remove the tables that change on every run:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# 1. One source for each table.
|
|
81
|
+
npx @reticlehq/server grade tables --container shop-db --skip queue_,cron_ --list "mysql -N shop -e 'show tables'" --rows "mysql -N shop -e 'select * from {table}'" --out wide.json
|
|
82
|
+
|
|
83
|
+
# 2. Two snapshots of the correct steps, from a reset app each time.
|
|
84
|
+
npx @reticlehq/server grade snapshot --state wide.json --out reference.json
|
|
85
|
+
npx @reticlehq/server grade snapshot --state wide.json --out again.json
|
|
86
|
+
|
|
87
|
+
# 3. Keep the tables that read the same on both runs.
|
|
88
|
+
npx @reticlehq/server grade suggest --state wide.json --reference reference.json --again again.json --out state.json
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`tables` takes the first column of each line of the `--list` output as a table name. It skips a name with a character other than A-Z, 0-9, `_` or `$`, and says so. `{table}` in `--rows` is the table name.
|
|
92
|
+
|
|
93
|
+
`--skip <prefix,...>` leaves out each table whose name starts with one of the prefixes. Separate the prefixes with commas. Use it for tables that hold no task data and that the app changes at its own time: a message queue that a background worker empties, a cron schedule, a session store. Two correct runs do not always show these tables as noise, because the worker can finish before both snapshots and not before a third. For Magento, `--skip queue_,cron_,session`.
|
|
94
|
+
|
|
95
|
+
Some apps write an empty row that means the same as no row. Magento saves a product form with a `NULL` row for each empty attribute, so a run that saves the form one more time than the reference adds rows with no value. Add an `ignore` pattern that matches all of such a row to the source in `state.json`. A pattern that removes all of a row removes the row. For the Magento attribute tables (`catalog_product_entity_int`, `_decimal`, `_varchar`, `_text`, `_datetime`), use `"ignore": ["^\\d+\\t\\d+\\t\\d+\\t\\d+\\tNULL$"]`.
|
|
96
|
+
|
|
97
|
+
`suggest` keeps a source that reads the same on both runs, also a source the correct steps did not change: a change to it by a run is a change to a record the task did not name. A source that differs between the two runs only by a date and time is kept, with the time removed. Every other source that differs (a session table, a log) is dropped, because each run adds its own new rows to it, and every run would fail. Each dropped source is printed with the first row that differs. A change to a dropped table is not seen.
|
package/docs/cli/license.mdx
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
3
|
-
description: Show the enterprise license status resolved from the environment, offline.
|
|
2
|
+
title: License status
|
|
3
|
+
description: Show the enterprise license status resolved from the environment, offline, with reticle status.
|
|
4
4
|
icon: key
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
`reticle
|
|
7
|
+
[`reticle status`](/cli/status) reports whether an enterprise license is active. It resolves the license entirely from the environment. Nothing leaves the machine.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npx @reticlehq/server
|
|
10
|
+
npx @reticlehq/server status --json
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
The block that `status` prints has a `license` row only when a key is set. `--json` always carries the `license` object.
|
|
14
|
+
|
|
15
|
+
`reticle license` is the old name. It still works for one release, prints one line naming `status`, and prints the `reticle_license` line below.
|
|
14
16
|
|
|
15
17
|
## What it prints
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
The `license` object of `status --json`. `reticle license` printed the same fields as one `reticle_license` JSON line on stderr. On a checkout with no issuer key configured:
|
|
18
20
|
|
|
19
21
|
```json
|
|
20
22
|
{
|
|
@@ -43,7 +45,7 @@ Always `0`.
|
|
|
43
45
|
## Worked example
|
|
44
46
|
|
|
45
47
|
```bash
|
|
46
|
-
npx @reticlehq/server
|
|
48
|
+
npx @reticlehq/server status --json | jq -r .license.status
|
|
47
49
|
```
|
|
48
50
|
|
|
49
51
|
<Card title="Enterprise" icon="building" href="/enterprise">
|
package/docs/cli/restart.mdx
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: reticle restart
|
|
2
|
+
title: reticle serve --restart
|
|
3
3
|
description: Free the bridge port and put a daemon back on it, reporting each half separately.
|
|
4
4
|
icon: rotate
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
`reticle restart` is [`reticle stop --force`](/cli/stop#freeing-the-port-force) followed by a daemon start that waits for a real bind.
|
|
7
|
+
`reticle serve --restart` is [`reticle stop --force`](/cli/stop#freeing-the-port-force) followed by a daemon start that waits for a real bind.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npx @reticlehq/server restart [--port N] [--force]
|
|
10
|
+
npx @reticlehq/server serve --restart [--port N] [--force]
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
`reticle restart` is the old name. It still works for one release and prints one line naming `serve --restart`.
|
|
14
|
+
|
|
13
15
|
## Flags
|
|
14
16
|
|
|
15
17
|
| Flag | Type | Default | What it does |
|
|
@@ -31,7 +33,7 @@ Real capture, restarting over a running daemon (exit `0`), with the long `note`
|
|
|
31
33
|
Real capture, when the port is held by something that is not ours (exit `1`). Both `reason` strings are trimmed at the ellipsis:
|
|
32
34
|
|
|
33
35
|
```
|
|
34
|
-
{"t":"2026-08-15T18:43:57.317Z","event":"reticle_kill_refused","port":4498,"reason":"pid 78795 (\"Python\") is listening, and it is not a Reticle daemon ... it never answered /status and it is not the pid Reticle recorded. Killing it would be killing someone else's process. If that is what you meant, `reticle restart --force` stops it and starts Reticle there (`stop --force` never does); or start Reticle on another port.","holder":"Python"}
|
|
36
|
+
{"t":"2026-08-15T18:43:57.317Z","event":"reticle_kill_refused","port":4498,"reason":"pid 78795 (\"Python\") is listening, and it is not a Reticle daemon ... it never answered /status and it is not the pid Reticle recorded. Killing it would be killing someone else's process. If that is what you meant, `reticle serve --restart --force` stops it and starts Reticle there (`stop --force` never does); or start Reticle on another port.","holder":"Python"}
|
|
35
37
|
{"t":"2026-08-15T18:43:57.318Z","event":"reticle_restart_aborted","port":4498,"reason":"the port was not freed, so nothing was started ... the old holder is still there"}
|
|
36
38
|
```
|
|
37
39
|
|
|
@@ -51,7 +53,7 @@ Real capture, when the port is held by something that is not ours (exit `1`). Bo
|
|
|
51
53
|
## Worked example
|
|
52
54
|
|
|
53
55
|
```bash
|
|
54
|
-
npx @reticlehq/server restart
|
|
56
|
+
npx @reticlehq/server serve --restart # after an upgrade, so the new version is the one serving
|
|
55
57
|
npx @reticlehq/server status
|
|
56
58
|
```
|
|
57
59
|
|
package/docs/cli/rollback.mdx
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: reticle rollback
|
|
2
|
+
title: reticle update --rollback
|
|
3
3
|
description: Reinstall the previously installed Reticle server version, then exit so your agent restarts it.
|
|
4
4
|
icon: arrow-rotate-left
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
`reticle rollback` is the undo for [`reticle update`](/cli/update). It reinstalls the version `update` replaced (recorded in the update manifest), then exits so the next start runs it.
|
|
7
|
+
`reticle update --rollback` is the undo for [`reticle update`](/cli/update). It reinstalls the version `update` replaced (recorded in the update manifest), then exits so the next start runs it.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npx @reticlehq/server rollback
|
|
10
|
+
npx @reticlehq/server update --rollback
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
`reticle rollback` is the old name. It still works for one release and prints one line naming `update --rollback`.
|
|
14
14
|
|
|
15
15
|
## What it prints
|
|
16
16
|
|
|
@@ -36,6 +36,6 @@ On the global install the installer puts on your PATH (under `npx` there is noth
|
|
|
36
36
|
```text
|
|
37
37
|
reticle update
|
|
38
38
|
# the new build misbehaves:
|
|
39
|
-
reticle rollback
|
|
39
|
+
reticle update --rollback
|
|
40
40
|
reticle version
|
|
41
41
|
```
|
package/docs/cli/stop.mdx
CHANGED
|
@@ -10,7 +10,7 @@ icon: circle-stop
|
|
|
10
10
|
npx @reticlehq/server stop [--port N] [--quiet] [--force]
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
`reticle kill`
|
|
13
|
+
`reticle kill` was removed. It prints that `stop --force` replaces it and exits `1`.
|
|
14
14
|
|
|
15
15
|
## Flags
|
|
16
16
|
|
|
@@ -94,7 +94,7 @@ Killed:
|
|
|
94
94
|
Refused, because the listener is not ours. This one was captured with `python3 -m http.server 4498` holding the port:
|
|
95
95
|
|
|
96
96
|
```
|
|
97
|
-
{"t":"2026-08-15T18:43:57.128Z","event":"reticle_kill_refused","port":4498,"reason":"pid 78795 (\"Python\") is listening, and it is not a Reticle daemon ... it never answered /status and it is not the pid Reticle recorded. Killing it would be killing someone else's process. If that is what you meant, `reticle restart --force` stops it and starts Reticle there (`stop --force` never does); or start Reticle on another port.","holder":"Python"}
|
|
97
|
+
{"t":"2026-08-15T18:43:57.128Z","event":"reticle_kill_refused","port":4498,"reason":"pid 78795 (\"Python\") is listening, and it is not a Reticle daemon ... it never answered /status and it is not the pid Reticle recorded. Killing it would be killing someone else's process. If that is what you meant, `reticle serve --restart --force` stops it and starts Reticle there (`stop --force` never does); or start Reticle on another port.","holder":"Python"}
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
Nothing to free:
|
|
@@ -118,6 +118,6 @@ With `--force`, exit `0` means the port is free and `1` means it is still held:
|
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
120
|
npx @reticlehq/server stop --port 4400 --quiet && npx @reticlehq/server serve --port 4400
|
|
121
|
-
npx @reticlehq/server restart --port 4400 # the same thing, honest about each half
|
|
121
|
+
npx @reticlehq/server serve --restart --port 4400 # the same thing, honest about each half
|
|
122
122
|
npx @reticlehq/server stop --force # the port is held and the pid file says nothing
|
|
123
123
|
```
|
package/docs/cli/update.mdx
CHANGED
|
@@ -61,6 +61,6 @@ npx @reticlehq/server update
|
|
|
61
61
|
<Warning>
|
|
62
62
|
A daemon that is already running keeps its own version. When no tab and no other agent is attached
|
|
63
63
|
to it, your agent's new MCP server stops it and starts the new version. When a tab or another
|
|
64
|
-
agent is attached, the old daemon keeps running. Run [`reticle restart`](/cli/restart) to
|
|
65
|
-
the new version now.
|
|
64
|
+
agent is attached, the old daemon keeps running. Run [`reticle serve --restart`](/cli/restart) to
|
|
65
|
+
start the new version now.
|
|
66
66
|
</Warning>
|
package/docs/cli/verify.mdx
CHANGED
|
@@ -20,12 +20,13 @@ It uses the same runner and the same verdict as the MCP and HTTP paths, so a pla
|
|
|
20
20
|
| `--headed` | boolean | `false` (headless) | Show the browser |
|
|
21
21
|
| `--timeout N` | number, ms | `15000` | How long to wait for a browser session to dial back. With `--expect`, how long the predicate may take to come true instead, default `4000` |
|
|
22
22
|
| `--storage-state <file>` | string | unset | A Playwright storage state file. This is how you verify flows behind a login without scripting the login every time |
|
|
23
|
-
| `--results-json <file>` | string | unset | Also write one verdict per journey to this file: `{ verdict, results: [{ journey, verdict, reason?, runId
|
|
23
|
+
| `--results-json <file>` | string | unset | Also write one verdict per journey to this file: `{ schemaVersion, verdict, results: [{ journey, verdict, reason?, runId?, steps }], score }`, each verdict `yes`, `no` or `unknown`. `schemaVersion` is 2 (a file without it has only `verdict` and `results`). `steps` is `{ passed, failed, unknown }` for the journey, and `score` is the total with `value` = passed / total. A step counts only when every earlier step of its journey passed; a step never reached is `unknown` and stays in the total. With `--sweep`, verdicts after a failed step are reported apart as `steps.swept` and never raise the score. A skipped journey is `unknown`, and the run is `yes` only when every journey is. `runId` names the run the journey came from, and is set only when that run reached the platform. Written when verify boots its own browser and a run finishes; a refusal before that writes nothing. The [GitHub Action](https://github.com/reticlehq/reticle/tree/main/action) posts this file |
|
|
24
24
|
| `--port N` | number | `RETICLE_PORT`, else the project's port, else `4400` | The bridge port the app dials |
|
|
25
25
|
| `--session-id <id>` | string | unset | Use a tab that is already connected |
|
|
26
26
|
| `--select <label>` | string, repeatable | unset | Verify only flows carrying this label |
|
|
27
27
|
| `--expect '<json predicate>'` / `--expect-file <path>` | string | unset | One verdict on one predicate, no saved flows needed. Asks the daemon that owns the port and never starts one; with no daemon it refuses. Waits up to `--timeout` for the predicate, the way `reticle_assert { action: "wait" }` does, so a request still in flight after the page loads is waited for. Exits `0` only on `verified: "yes"`. Cannot be combined with `--storage-state` |
|
|
28
28
|
| `--explore` / `--persona "<who does what>"` | boolean / string | off | No saved flows yet? The Harness drives the app and records them. `--persona` implies `--explore`. Needs a linked project (`reticle connect`, or `RETICLE_API_KEY` in CI). It runs at any instrumentation score |
|
|
29
|
+
| `--against <reference-url>` | string | unset | Compare the URL with a reference build, for example a pull request preview with production. See [Compare two builds](#compare-two-builds). Cannot be combined with `--expect`, `--expect-file`, `--explore` or `--persona` |
|
|
29
30
|
| `--confirm-dangerous` | boolean | off | Let this run press the controls the replay guard holds as destructive, such as a "Place order" or "Delete" button in a saved flow. Without it such a step is refused, so a checkout flow cannot pass. It covers this run only and is never saved into a flow. |
|
|
30
31
|
|
|
31
32
|
On Windows PowerShell, write the predicate to a file and pass `--expect-file` so the JSON never goes through shell quoting:
|
|
@@ -35,6 +36,27 @@ On Windows PowerShell, write the predicate to a file and pass `--expect-file` so
|
|
|
35
36
|
npx @reticlehq/server verify http://localhost:3000 --expect-file expect.json
|
|
36
37
|
```
|
|
37
38
|
|
|
39
|
+
## Compare two builds
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx @reticlehq/server verify https://pr-42.preview.example.com --against https://example.com
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`--against` answers one question: did the change alter what users see? It drives both running builds with the same actions and reports each difference in what a person can read and use.
|
|
46
|
+
|
|
47
|
+
- **The actions.** Each saved flow in `.reticle/flows/` (with `--select`, only the flows with those labels) is replayed one step at a time, and the page is read after every step. Then the explorer of `reticle_verify { action: "crawl", exhaustive: true }` walks the reference breadth first. It fills each empty text field with its own value (`text 1`, `text 2`), clicks each control, and waits a short time after each action. Both builds then get the same list of actions.
|
|
48
|
+
- **What is compared.** The accessibility tree, reduced to what a person sees: names, text, values, and the checked, selected, disabled, expanded and pressed states, in page order. Case and spacing are folded. Refs, focus, layout, test ids, source locations and component names are removed.
|
|
49
|
+
- **Noise.** The reference is driven two times, each time in a new browser. A line that differs between those two runs (a clock, a random id) is ignored. A step that the reference did on only one of its runs is not compared.
|
|
50
|
+
- **A step the candidate cannot do.** When the reference did a step and the candidate could not (the control is gone, or a flow anchor does not resolve), that is a difference.
|
|
51
|
+
|
|
52
|
+
The command uses the daemon on `--port`, and starts one when there is none. Each run is a leased browser tab, so the apps do not need `reticle init`. Each replayed flow step is written as a run, the same as any replay.
|
|
53
|
+
|
|
54
|
+
The explorer clicks every control it finds. The action guard refuses a control it holds as destructive, and `--confirm-dangerous` removes that guard. Point `--against` at a build whose data you can change, not at a production database.
|
|
55
|
+
|
|
56
|
+
Each difference prints the actions that first reached it, then `-` for the lines only the reference shows and `+` for the lines only the candidate shows. Differences with the same lines are printed one time, with the number of steps they were seen at. Exit `0` only when steps were compared and nothing differs. A run that compared no step exits `1`, because it proved nothing.
|
|
57
|
+
|
|
58
|
+
`--results-json <file>` writes `{ schemaVersion: 1, reference, candidate, identical, differences: [{ id, kind, actions, removed, added, seen }], journeys, compared, unstable, ignored, explored }`. `kind` is `changed` or `unreached`. `id` is a hash of the difference's lines, so the same difference has the same id on every run. `ignored` counts the lines skipped as noise, and `unstable` counts the steps not compared.
|
|
59
|
+
|
|
38
60
|
## What it prints
|
|
39
61
|
|
|
40
62
|
The rendered run report on stdout. On failure it names the cause on stderr instead, and there are two refusals worth knowing:
|
package/docs/cli.mdx
CHANGED
|
@@ -41,18 +41,20 @@ npx @reticlehq/server <command>
|
|
|
41
41
|
| Command | What it does | Page |
|
|
42
42
|
| --- | --- | --- |
|
|
43
43
|
| `reticle verify <url>` | One-shot: drive the URL, verify saved flows or one predicate, exit 0 on pass | [verify](/cli/verify) |
|
|
44
|
+
| `reticle compare <reference-url> <candidate-url> [--base <url>] [--state <file>] [--json] [--report <file>]` | Drive two running builds the same way and list each difference in what users see; exit 0 same, 1 different, 2 invalid | [compare](/cli/compare) |
|
|
45
|
+
| `reticle grade <snapshot\|judge\|tables\|suggest> [flags]` | Grade a finished run of an app from snapshots of its stored data, and check its final answer; exit 0 pass, 1 fail, 2 unverified | [grade](/cli/grade) |
|
|
44
46
|
| `reticle gate [--since <ref>] [--accept-coverage] [--hook]` | Exit non-zero unless passing artifacts cover the affected flows | [gate](/cli/gate) |
|
|
47
|
+
| `reticle gate --list [--since <ref>]` | Which saved flows must re-verify for the changed files | [affected](/cli/affected) |
|
|
45
48
|
|
|
46
49
|
### Reticle on this machine
|
|
47
50
|
|
|
48
51
|
| Command | What it does | Page |
|
|
49
52
|
| --- | --- | --- |
|
|
50
|
-
| `reticle status [--json]` | Is the daemon up, which pages connected, who is signed in, is this repo linked | [status](/cli/status) |
|
|
53
|
+
| `reticle status [--json]` | Is the daemon up, which pages connected, who is signed in, is this repo linked, which license is active | [status](/cli/status) |
|
|
51
54
|
| `reticle doctor` | Find what is wrong with the setup (Chromium, daemon, port, agent link), and what is missing from coverage | [doctor](/cli/doctor) |
|
|
52
55
|
| `reticle open [url]` | Show the app: reuse the connected tab, else open one | [open](/cli/open) |
|
|
53
56
|
| `reticle stop [--force]` | Stop the daemon we started; `--force` frees the port by its listener, never the agent's MCP proxy | [stop](/cli/stop) |
|
|
54
|
-
| `reticle
|
|
55
|
-
| `reticle update` | Install the latest server version and restart | [update](/cli/update) |
|
|
57
|
+
| `reticle update [--rollback]` | Install the latest server version and restart; `--rollback` restores the previous one | [update](/cli/update) |
|
|
56
58
|
|
|
57
59
|
### Account
|
|
58
60
|
|
|
@@ -75,14 +77,11 @@ npx @reticlehq/server <command>
|
|
|
75
77
|
| `reticle config` | Choose what syncs: runs, memory, flows; where verification runs | [cloud](/cli/cloud#reticle-config) |
|
|
76
78
|
| `reticle hook [status\|install\|uninstall]` | The prompt hook: is each prompt captured here, add it, or remove exactly what was added | [prompt capture](/prompt-capture#reticle-hook) |
|
|
77
79
|
| `reticle setup mcp` | Register the MCP server with your coding agents (the installer's registration half) | [setup](/cli/setup) |
|
|
78
|
-
| `reticle serve` | Start the daemon and wait for it to bind | [serve](/cli/serve) |
|
|
80
|
+
| `reticle serve [--restart]` | Start the daemon and wait for it to bind; `--restart` frees the port first | [serve](/cli/serve) |
|
|
79
81
|
| `reticle mcp` | The MCP stdio proxy your agent runs; starts the daemon if needed | [mcp](/cli/mcp) |
|
|
80
82
|
| `reticle drive <url>` | Foreground mode, for debugging | [drive](/cli/drive) |
|
|
81
|
-
| `reticle affected [--since <ref>]` | Which saved flows must re-verify for the changed files | [affected](/cli/affected) |
|
|
82
83
|
| `reticle context --compact [--session <id>]` | Resume after a compaction: what was proved, failed and is still owed | none |
|
|
83
84
|
| `reticle report [--session <id>] [--hook]` | What the latest session claimed, and what held | [report](/cli/report) |
|
|
84
|
-
| `reticle rollback` | Restore the previous server version and restart | [rollback](/cli/rollback) |
|
|
85
|
-
| `reticle license` | Enterprise license status: active, eval or missing | [license](/cli/license) |
|
|
86
85
|
| `reticle version` | Print the version | [version](/cli/version) |
|
|
87
86
|
| `reticle help [all\|<command>]` | Usage: the short list, every command, or one command | [help](/cli/help) |
|
|
88
87
|
|
|
@@ -90,16 +89,27 @@ npx @reticlehq/server <command>
|
|
|
90
89
|
|
|
91
90
|
The old names below still work for one release and print one line naming the new one.
|
|
92
91
|
|
|
93
|
-
| Old
|
|
92
|
+
| Old | Now |
|
|
93
|
+
| ------------------ | --------------------------- |
|
|
94
|
+
| `reticle affected` | `reticle gate --list` |
|
|
95
|
+
| `reticle license` | `reticle status` |
|
|
96
|
+
| `reticle rollback` | `reticle update --rollback` |
|
|
97
|
+
| `reticle restart` | `reticle serve --restart` |
|
|
98
|
+
|
|
99
|
+
These names were removed. Each prints what to use instead and exits `1`.
|
|
100
|
+
|
|
101
|
+
| Removed | Use |
|
|
94
102
|
| --- | --- |
|
|
95
103
|
| `reticle kill` | `reticle stop --force` |
|
|
96
|
-
| `reticle login`, `reticle link` | `reticle connect`.
|
|
104
|
+
| `reticle login`, `reticle link` | `reticle connect`. Sign-in is only in the browser, with Google or GitHub. Without a browser, set `RETICLE_API_KEY` |
|
|
97
105
|
| `reticle project` | `reticle connect --project <name\|id>` |
|
|
98
106
|
| `reticle whoami` | `reticle status` |
|
|
99
107
|
| `reticle push` | `reticle sync` |
|
|
100
108
|
| `reticle regression`, `share`, `issues`, `memory` | `reticle runs regression`, `runs share`, `runs issues`, `runs memory` |
|
|
101
|
-
|
|
102
|
-
|
|
109
|
+
| `reticle watch` | `reticle gate --list` or `reticle gate` |
|
|
110
|
+
| `reticle tutorial` | `reticle init` or `reticle try <url>` |
|
|
111
|
+
| `reticle identify` | `reticle feedback` |
|
|
112
|
+
| `reticle hunt`, `reticle capsules` | nothing. Saved capsules stay in `.reticle/capsules` |
|
|
103
113
|
|
|
104
114
|
## Setup and diagnosis
|
|
105
115
|
|
|
@@ -192,7 +202,7 @@ policy https://github.com/reticlehq/reticle/blob/main/docs/telemetry.md
|
|
|
192
202
|
| `reticle serve` | Start the daemon and wait for it to bind. `--drive <url>`, `--headless`, `--headed`, `--http`, `--http-port N`, `--http-token T` |
|
|
193
203
|
| `reticle stop` | Stop the daemon we started, by its recorded pid. `--quiet` |
|
|
194
204
|
| `reticle stop --force` | Free the port by asking who is **listening** on it |
|
|
195
|
-
| `reticle restart` | Free the port, then start a daemon and wait for a real bind. `--force` |
|
|
205
|
+
| `reticle serve --restart` | Free the port, then start a daemon and wait for a real bind. `--force` |
|
|
196
206
|
| `reticle open [url]` | Show the app. Reuse the connected tab, or open one |
|
|
197
207
|
| `reticle drive <url>` | Foreground mode, for debugging |
|
|
198
208
|
| `reticle mcp` | The MCP stdio proxy. Auto-starts the daemon if needed. This is what your agent runs |
|
|
@@ -203,7 +213,7 @@ A bare `reticle` with no arguments is not help. In a project that `init` wired,
|
|
|
203
213
|
When the Reticle SDK installed in the project is a different **major** version from the CLI you ran,
|
|
204
214
|
the CLI hands the same command to `npx @reticlehq/server@<that version>`, so an unpinned
|
|
205
215
|
`npx @reticlehq/server` never pairs a daemon with an SDK it cannot talk to. `init`, `update`,
|
|
206
|
-
`rollback`, `setup install`, `version` and `help` always run as typed, and so does a command whose
|
|
216
|
+
`update --rollback`, `setup install`, `version` and `help` always run as typed, and so does a command whose
|
|
207
217
|
version you pinned yourself (`npx @reticlehq/server@<version> …`). Set `RETICLE_NO_VERSION_MATCH=1` to
|
|
208
218
|
turn it off. Because `--help` runs as typed too, it describes the CLI you ran. When the command it
|
|
209
219
|
describes would run at the project's version instead, the help opens with a line naming that version.
|
|
@@ -238,12 +248,12 @@ Options:
|
|
|
238
248
|
- `--results-json <file>`: also write one verdict per journey as JSON, for CI.
|
|
239
249
|
- `--confirm-dangerous`: let this run press what the replay guard holds as destructive.
|
|
240
250
|
|
|
241
|
-
### `reticle
|
|
251
|
+
### `reticle gate --list`
|
|
242
252
|
|
|
243
|
-
Which saved flows must re-verify for a set of changed files.
|
|
253
|
+
Which saved flows must re-verify for a set of changed files. It checks nothing.
|
|
244
254
|
|
|
245
255
|
```bash
|
|
246
|
-
npx @reticlehq/server
|
|
256
|
+
npx @reticlehq/server gate --list --since HEAD~1
|
|
247
257
|
```
|
|
248
258
|
|
|
249
259
|
```json
|
|
@@ -290,13 +300,13 @@ Measured exit code: **`1`**, with the flow lists trimmed above. That run genuine
|
|
|
290
300
|
|
|
291
301
|
## Maintenance
|
|
292
302
|
|
|
293
|
-
| Command
|
|
294
|
-
|
|
|
295
|
-
| `reticle update`
|
|
296
|
-
| `reticle rollback` | Restore the previous version and restart
|
|
297
|
-
| `reticle
|
|
298
|
-
| `reticle version`
|
|
299
|
-
| `reticle help`
|
|
303
|
+
| Command | What it does |
|
|
304
|
+
| --------------------------- | ------------------------------------------------------------ |
|
|
305
|
+
| `reticle update` | Install the latest server version and restart |
|
|
306
|
+
| `reticle update --rollback` | Restore the previous version and restart |
|
|
307
|
+
| `reticle status --json` | Carries `license`: active, eval, missing, expired or invalid |
|
|
308
|
+
| `reticle version` | Print the version |
|
|
309
|
+
| `reticle help` | The short list; `help all` for every command |
|
|
300
310
|
|
|
301
311
|
<Tip>
|
|
302
312
|
`rollback` exists because an auto-updating dev tool that cannot go back is a dev tool that can
|
package/docs/deploy-checks.md
CHANGED
|
@@ -70,7 +70,7 @@ jobs:
|
|
|
70
70
|
runs-on: ubuntu-latest
|
|
71
71
|
steps:
|
|
72
72
|
- uses: actions/checkout@v4
|
|
73
|
-
- uses: reticlehq/reticle/action@v3.
|
|
73
|
+
- uses: reticlehq/reticle/action@v3.10.0
|
|
74
74
|
with:
|
|
75
75
|
api-key: ${{ secrets.RETICLE_API_KEY }}
|
|
76
76
|
# Only for a Vercel preview behind Deployment Protection.
|
package/docs/desktop.mdx
CHANGED
package/docs/enterprise.md
CHANGED
|
@@ -22,7 +22,7 @@ No feature in the open packages needs a key. A key identifies your organisation
|
|
|
22
22
|
export RETICLE_LICENSE_KEY="<your key>"
|
|
23
23
|
# the release already bakes the issuer public key (RETICLE_LICENSE_PUBLIC_KEY)
|
|
24
24
|
```
|
|
25
|
-
3. **Verify.** `reticle
|
|
25
|
+
3. **Verify.** `reticle status --json` carries a `license` object whose `status` and `detail` say where you stand:
|
|
26
26
|
|
|
27
27
|
```
|
|
28
28
|
active licensed to Acme Corp (enterprise), expires 2027-06-20T00:00:00.000Z
|
|
@@ -36,7 +36,7 @@ No feature in the open packages needs a key. A key identifies your organisation
|
|
|
36
36
|
|
|
37
37
|
4. **Renew.** Keys carry an expiry, shown as `expiresAt`; once it passes, the status is `expired`.
|
|
38
38
|
|
|
39
|
-
> Procuring a license: contact **[hey@reticle.sh](mailto:hey@reticle.sh)**. Keys are issued offline and signed with Ed25519; the activation
|
|
39
|
+
> Procuring a license: contact **[hey@reticle.sh](mailto:hey@reticle.sh)**. Keys are issued offline and signed with Ed25519; the activation check (`reticle status`) verifies them locally with no network call.
|
|
40
40
|
|
|
41
41
|
## Roadmap
|
|
42
42
|
|
package/docs/environment.mdx
CHANGED
|
@@ -53,7 +53,7 @@ Reticle works with none of these set. Each one changes a single behaviour, and m
|
|
|
53
53
|
| Variable | Read by | What it does |
|
|
54
54
|
| --- | --- | --- |
|
|
55
55
|
| `RETICLE_SKIP_GATE` | `reticle gate --hook` | Lets an agent's stop hook proceed past a failing gate. The skip is printed and recorded, never silent. It does not affect `reticle gate` without `--hook`, which is what CI runs. |
|
|
56
|
-
| `RETICLE_NO_CI_HINT` | `reticle gate`, `reticle verify
|
|
56
|
+
| `RETICLE_NO_CI_HINT` | `reticle gate`, `reticle verify` | `1` stops the one line these commands write to stderr at the end of a run in a CI runner or a container. The line names the pull request check and `https://reticle.sh/ci`. It never prints in an interactive terminal or for `gate --hook`, and it makes no network call. |
|
|
57
57
|
| `RETICLE_VERIFY_TOKEN` | `reticle serve --http` | The bearer token the optional HTTP verify endpoint requires. |
|
|
58
58
|
| `RETICLE_SECRET_<FIELD>` | replay, verify, crawl | The value typed into a password or secret field at replay. A recorded flow never stores it. See [what is recorded](/what-is-recorded). |
|
|
59
59
|
|
package/docs/flows.md
CHANGED
|
@@ -80,7 +80,7 @@ reticle_run({ tool: "reticle_flow_save", args: { flowName: "create-task" } })
|
|
|
80
80
|
}
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
Each step binds to a **semantic anchor**, never a `eXX` ref: a `testid`/`signal` when available, else an auto-derived `component` anchor (component name + source `file:line`) for an element with no testid, so the flow stays stable with zero hand-added testids. A press of a document key (Escape, Tab, a shortcut) with no target is aimed at no element, so it is saved with a `{ "kind": "role", "role": "document" }` anchor and replayed at the document, as it ran. Only when none of those resolve is a step kept `degraded: true` (a last-resort "add a testid here" marker) rather than silently dropped.
|
|
83
|
+
Each step binds to a **semantic anchor**, never a `eXX` ref: a `testid`/`signal` when available, else an auto-derived `component` anchor (component name + source `file:line`) for an element with no testid, so the flow stays stable with zero hand-added testids. A press of a document key (Escape, Tab, an arrow key, a shortcut) with no target is aimed at no element, so it is saved with a `{ "kind": "role", "role": "document" }` anchor and replayed at the document, as it ran. Only when none of those resolve is a step kept `degraded: true` (a last-resort "add a testid here" marker) rather than silently dropped.
|
|
84
84
|
|
|
85
85
|
## Run a flow
|
|
86
86
|
|
|
@@ -110,6 +110,16 @@ Every session's driving is saved as a flow at teardown when it declared a conseq
|
|
|
110
110
|
- declare `requires` (the start page) and `ensures` (the end page) as route claims, so `canFollow` can tell which flows chain. Replay treats a required start page as met by navigating there;
|
|
111
111
|
- carry `author: { agent, person }`: the MCP client that drove it and the email of whoever signed in with `reticle connect` on that machine. Either is left out when it is not known.
|
|
112
112
|
|
|
113
|
+
### A route in `requires`
|
|
114
|
+
|
|
115
|
+
A route claim in `requires` says which page the flow needs. Replay puts the tab there before step 1, so a suite does not run the flow on the page that the previous flow left open. It goes to `startPath` when that is on the route, else to the route itself.
|
|
116
|
+
|
|
117
|
+
A route can name an entity id with a `:name` segment, for example `{ "kind": "route", "pathname": "/cases/:id/notes" }`. When the tab is already on a page that matches, replay keeps that page and its id. When the tab is on another page of the same record (`/cases/c-42/files`), replay opens the route with that id (`/cases/c-42/notes`). It opens the recorded address only when the tab has no id to give. The recorded id can be a record that was deleted since.
|
|
118
|
+
|
|
119
|
+
Replay checks every route claim in `requires`, its `contains` too, on the page it arrives at. When the tab is already on the route, replay reloads it, the same reset a `startPath` gets. State that the previous flow left in memory is lost. A flow that needs that state declares it with a claim that is not a route.
|
|
120
|
+
|
|
121
|
+
When replay cannot put the tab on the route (the page refuses, the app redirects to another page, or a pattern has no recorded address to open), the flow is `unverifiable` with a reason that names the route. No step runs.
|
|
122
|
+
|
|
113
123
|
## Delete a flow
|
|
114
124
|
|
|
115
125
|
```jsonc
|
package/docs/frameworks.mdx
CHANGED
|
@@ -5,7 +5,7 @@ description: Which frameworks Reticle supports, which are wired but unverified,
|
|
|
5
5
|
icon: layer-group
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
**React + Vite, Next.js, Remix and Astro
|
|
8
|
+
**Reticle works on React, Next.js, Remix, Astro, Vue, SvelteKit and Angular. React + Vite, Next.js, Remix and Astro each have an example app in CI: React + Vite and Next.js are driven to a verdict by the e2e battery, and the Remix and Astro examples are booted and must register a session. Vue, SvelteKit and Angular are supported with the framework-neutral sensor; their install is gated (scaffolded from scratch whenever the install path changes, and a real session is required), and no CI gate drives them to a verdict yet. The `file:line` source pointer works on React and Svelte, not on Vue or Angular. Nuxt, React Router framework mode and Create React App have their install gated the same way. TanStack Start, Preact and plain HTML are wired by `init` and documented but not gated at all, so treat them as plausible rather than proven.** The exact wiring for each is below.
|
|
9
9
|
|
|
10
10
|
Reticle is a verification layer that embeds a dev-only SDK in your running web app so an AI coding agent can prove a change works. Its core is framework-neutral: DOM, network, console, routing, animations and source mapping work anywhere JavaScript runs.
|
|
11
11
|
|
|
@@ -15,7 +15,7 @@ What varies is two things: how `connect()` gets into your app, and whether you g
|
|
|
15
15
|
|
|
16
16
|
## Where each framework stands
|
|
17
17
|
|
|
18
|
-
We separate "
|
|
18
|
+
We separate "supported" from "what CI proves". Four frameworks have an example app and a CI gate. Vue, SvelteKit and Angular are supported and install gated. The rest are wired and documented, and nothing in CI proves they still work.
|
|
19
19
|
|
|
20
20
|
Two columns say different things and it is worth keeping them apart. **CI gate** `yes` means an example app runs in CI: React + Vite and Next.js are driven to a verdict, Remix and Astro are booted and must register a session. **install only** means the install gate scaffolds that stack from scratch, runs `init`, boots it and waits for a session, so the setup is proven and the drive is not. Vue is there because a release once nearly shipped an installer that left a Vue app connecting 0% of the time, and the gate that exists for exactly that had only React scaffolds.
|
|
21
21
|
|
|
@@ -27,14 +27,14 @@ Two columns say different things and it is worth keeping them apart. **CI gate**
|
|
|
27
27
|
| **Next.js** | yes | yes | yes | yes | Supported |
|
|
28
28
|
| **Remix** | yes | yes | yes | yes | Supported |
|
|
29
29
|
| **Astro** | yes | yes | yes | yes | Supported |
|
|
30
|
-
| **SvelteKit** | yes | no | install only |
|
|
30
|
+
| **SvelteKit** | yes | no | install only | yes | Supported |
|
|
31
31
|
| **TanStack Start** | yes | no | no | unproven | Wired, unverified |
|
|
32
32
|
| **Nuxt** | yes | no | install only | no | Install gated, drive unverified |
|
|
33
33
|
| **React Router (framework mode)** | yes | no | install only | yes | Install gated, drive unverified |
|
|
34
34
|
| **Create React App** | yes | no | install only | unproven | Install gated, drive unverified |
|
|
35
|
-
| **Angular 17+** | yes | no | install only | no |
|
|
35
|
+
| **Angular 17+** | yes | no | install only | no | Supported (no `file:line`) |
|
|
36
36
|
| **Plain HTML** | yes | no | no | no | Wired, unverified |
|
|
37
|
-
| **Vue (non-Nuxt)** | as Vite | no | install only | no |
|
|
37
|
+
| **Vue (non-Nuxt)** | as Vite | no | install only | no | Supported (no `file:line`) |
|
|
38
38
|
| **Preact** | as Vite | no | no | transform-tested; drive unproven | Sensor, React adapter via `preact/compat` |
|
|
39
39
|
| **Server-rendered (Django, Flask, FastAPI, Streamlit, Rails)** | yes | no | no | no | Wired, unverified |
|
|
40
40
|
|
|
@@ -392,10 +392,10 @@ Solid appears in dependency detection but has no wiring, no adapter and no gate.
|
|
|
392
392
|
</Accordion>
|
|
393
393
|
|
|
394
394
|
<Accordion title="Does Reticle work with Vue?">
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
395
|
+
Yes. Install `@reticlehq/browser` rather than the React kit, and you get DOM, network, console,
|
|
396
|
+
routing, actions, verdicts and Pinia state. The one thing you do not get is a `source` field:
|
|
397
|
+
source stamping covers JSX and Svelte components, and a Vue single-file component is neither. The
|
|
398
|
+
install path is gated in CI; no example app is driven to a verdict there yet.
|
|
399
399
|
</Accordion>
|
|
400
400
|
|
|
401
401
|
<Accordion title="Which framework should I pick if I want the strongest verdicts?">
|
package/docs/getting-started.md
CHANGED
|
@@ -287,7 +287,7 @@ if (process.env.NODE_ENV !== 'production') {
|
|
|
287
287
|
|
|
288
288
|
Change the `./reticle.local.js` path so that it points to the project root from your entry module. Do not commit `reticle.local.js`: the token is for this machine only. A teammate runs `reticle init` to get their own.
|
|
289
289
|
|
|
290
|
-
Plain HTML with no build step: run `npx @reticlehq/server init` in the folder that holds `index.html`. It adds a dev-only snippet that connects only on localhost
|
|
290
|
+
Plain HTML with no build step: run `npx @reticlehq/server init` in the folder that holds `index.html`. Init does not change `index.html`. It serves the folder with Reticle's static server, which adds a dev-only connect snippet to the page that it serves. With `--url` or `--files-only`, nothing of Reticle's serves the page, so init writes the snippet into `index.html`. That snippet connects only on localhost. Init puts this machine's pairing token in a gitignored `reticle.local.js` beside the page, so the token never lands in anything you publish. A hand-written script tag without that token is refused by the bridge.
|
|
291
291
|
|
|
292
292
|
> **Want to watch the agent work?** Add `present: true` to `reticle.connect()` for a glowing border, a synthetic cursor that flies to targets, click/hover effects, and a narration HUD. See [usage §16](usage.md#16-presenter-mode-narration-&-fake-clock-watch-+-control).
|
|
293
293
|
|
package/docs/install-manual.mdx
CHANGED
|
@@ -67,10 +67,10 @@ Put the key in the MCP server's own `env` block instead, then restart the editor
|
|
|
67
67
|
## Confirm it worked
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
|
-
npx @reticlehq/server
|
|
70
|
+
npx @reticlehq/server status --json
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
You do not need `NODE_ENV` set, a project, a dev server, or a running app.
|
|
73
|
+
Read `license.status` in the output. You do not need `NODE_ENV` set, a project, a dev server, or a running app. The license check reads the key and nothing else.
|
|
74
74
|
|
|
75
75
|
| `status` | What it means | What to do |
|
|
76
76
|
| --- | --- | --- |
|
|
@@ -142,4 +142,4 @@ export RETICLE_TELEMETRY=0
|
|
|
142
142
|
|
|
143
143
|
[hey@reticle.sh](mailto:hey@reticle.sh) for activation problems, renewals and re-issues.
|
|
144
144
|
|
|
145
|
-
Include the output of `npx @reticlehq/server
|
|
145
|
+
Include the output of `npx @reticlehq/server status --json`. It carries your license id and no secrets, and it usually tells us the answer immediately.
|
package/docs/packages/tauri.mdx
CHANGED
|
@@ -16,7 +16,7 @@ Tauri IPC observation needs nothing on the Rust side. An `invoke('load_todos')`
|
|
|
16
16
|
|
|
17
17
|
```toml
|
|
18
18
|
[dependencies]
|
|
19
|
-
reticle-tauri = "3.
|
|
19
|
+
reticle-tauri = "3.10"
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
Its own dependencies are `tauri = "2.12"` (the Windows backend must use the same `webview2-com` and `windows` versions Tauri does, so it follows Tauri's minor version) plus the per-platform capture backends: `objc2` and friends on macOS, `webview2-com` and `windows` on Windows, `webkit2gtk` and `cairo-rs` on Linux and the BSDs.
|
package/docs/packages.mdx
CHANGED
|
@@ -253,7 +253,7 @@ A lint rule makes the signal layer self-enforcing, which is the only way a conve
|
|
|
253
253
|
|
|
254
254
|
```toml
|
|
255
255
|
[dependencies]
|
|
256
|
-
reticle-tauri = "3.
|
|
256
|
+
reticle-tauri = "3.10"
|
|
257
257
|
```
|
|
258
258
|
|
|
259
259
|
<Card title="Desktop setup in full" icon="display" href="/desktop">
|