@reticlehq/server 2.11.0 → 2.13.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 +93 -111
- package/dist/bridge/auth-failure-reason.d.ts +6 -2
- package/dist/bridge/auth-failure-reason.js +15 -8
- package/dist/bridge/bridge.d.ts +18 -14
- package/dist/bridge/bridge.js +248 -165
- package/dist/bridge/bridge.test-harness.d.ts +2 -0
- package/dist/bridge/bridge.test-harness.js +8 -1
- package/dist/bridge/pairing-token.d.ts +5 -0
- package/dist/bridge/pairing-token.js +28 -0
- package/dist/bridge/protocol-skew.d.ts +37 -0
- package/dist/bridge/protocol-skew.js +45 -0
- package/dist/capsule/capsule-store.d.ts +8 -7
- package/dist/capsule/capsule-store.js +1 -1
- package/dist/capsule/causal-summary.d.ts +2 -2
- package/dist/capsule/causal-summary.js +7 -2
- package/dist/chromium-launch-options.d.ts +28 -0
- package/dist/chromium-launch-options.js +29 -0
- package/dist/cli/cli-doctor.js +39 -1
- package/dist/cli/cli-flow-commands.d.ts +3 -1
- package/dist/cli/cli-flow-commands.js +34 -4
- package/dist/cli/cli-kill.d.ts +2 -1
- package/dist/cli/cli-launch.d.ts +11 -1
- package/dist/cli/cli-launch.js +59 -10
- package/dist/cli/cli-parse.d.ts +17 -1
- package/dist/cli/cli-parse.js +238 -12
- package/dist/cli/cli-update-commands.js +20 -1
- package/dist/cli/cli-verify.d.ts +2 -1
- package/dist/cli/cli-verify.js +5 -4
- package/dist/cli/cloud-cli.js +428 -253
- package/dist/cli/cloud-keystore.d.ts +37 -0
- package/dist/cli/cloud-keystore.js +97 -0
- package/dist/cli/cloud-kit.d.ts +37 -0
- package/dist/cli/cloud-kit.js +121 -0
- package/dist/cli/cloud-login.d.ts +17 -0
- package/dist/cli/cloud-login.js +183 -0
- package/dist/cli/cloud-session.d.ts +48 -0
- package/dist/cli/cloud-session.js +53 -0
- package/dist/cli/config-discovery.d.ts +2 -1
- package/dist/cli/config-discovery.js +1 -0
- package/dist/cli/daemon-start-options.d.ts +32 -0
- package/dist/cli/daemon-start-options.js +38 -0
- package/dist/cli/device-flow.d.ts +76 -0
- package/dist/cli/device-flow.js +56 -0
- package/dist/cli/doctor-rows.d.ts +12 -1
- package/dist/cli/doctor-rows.js +12 -1
- package/dist/cli/drive-attach.d.ts +13 -0
- package/dist/cli/drive-attach.js +18 -0
- package/dist/cli/drive-command.js +7 -3
- package/dist/cli/gate-exit.d.ts +21 -0
- package/dist/cli/gate-exit.js +21 -0
- package/dist/cli/gate-hook-message.d.ts +33 -0
- package/dist/cli/gate-hook-message.js +46 -0
- package/dist/cli/mcp-command.d.ts +25 -0
- package/dist/cli/mcp-command.js +174 -0
- package/dist/cli/project-name.d.ts +30 -0
- package/dist/cli/project-name.js +44 -0
- package/dist/cli/sibling-ports.d.ts +37 -0
- package/dist/cli/sibling-ports.js +56 -0
- package/dist/cli/status-next-action.d.ts +14 -0
- package/dist/cli/status-next-action.js +4 -4
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +167 -186
- package/dist/cloud/cloud-config.d.ts +24 -2
- package/dist/cloud/cloud-config.js +64 -5
- package/dist/cloud/cloud-sync.d.ts +16 -5
- package/dist/cloud/cloud-sync.js +64 -1
- package/dist/cloud/sync-cycle.d.ts +110 -0
- package/dist/cloud/sync-cycle.js +270 -0
- package/dist/cloud/sync-daemon.d.ts +69 -0
- package/dist/cloud/sync-daemon.js +260 -0
- package/dist/cloud/sync-disk.d.ts +9 -0
- package/dist/cloud/sync-disk.js +191 -0
- package/dist/cloud/sync-hash.d.ts +2 -0
- package/dist/cloud/sync-hash.js +35 -0
- package/dist/crawl/crawl-tools.js +5 -3
- package/dist/crawl/crawl.d.ts +12 -13
- package/dist/crawl/crawl.js +25 -3
- package/dist/daemon/daemon-resolve.d.ts +122 -0
- package/dist/daemon/daemon-resolve.js +187 -0
- package/dist/daemon/dev-servers.d.ts +15 -0
- package/dist/daemon/dev-servers.js +68 -0
- package/dist/daemon/free-port.d.ts +29 -0
- package/dist/daemon/free-port.js +55 -0
- package/dist/daemon/heartbeat.d.ts +0 -4
- package/dist/daemon/heartbeat.js +2 -2
- package/dist/daemon/wake-decision.d.ts +32 -0
- package/dist/daemon/wake-decision.js +38 -0
- package/dist/dev/stale-issue-guard.d.ts +0 -2
- package/dist/dev/stale-issue-guard.js +1 -1
- package/dist/domain/domain-tools.js +2 -2
- package/dist/events/contradictions.d.ts +59 -0
- package/dist/events/contradictions.js +253 -27
- package/dist/events/declared.d.ts +17 -0
- package/dist/events/declared.js +43 -1
- package/dist/events/echo-mismatch.js +65 -1
- package/dist/events/event-filters.d.ts +8 -0
- package/dist/events/event-filters.js +19 -2
- package/dist/events/observed-in-window.d.ts +12 -0
- package/dist/events/observed-in-window.js +17 -0
- package/dist/events/predicate-asks.d.ts +13 -0
- package/dist/events/predicate-asks.js +22 -0
- package/dist/events/predicate-eval.js +117 -27
- package/dist/events/predicate-parse.d.ts +0 -6
- package/dist/events/predicate-parse.js +43 -3
- package/dist/events/predicate-precheck.d.ts +8 -0
- package/dist/events/predicate-precheck.js +41 -0
- package/dist/events/predicate-route.d.ts +14 -0
- package/dist/events/predicate-route.js +36 -8
- package/dist/events/predicate-schema.d.ts +44 -0
- package/dist/events/predicate-schema.js +126 -23
- package/dist/events/predicate.d.ts +20 -0
- package/dist/events/predicate.js +77 -6
- package/dist/events/split-text-miss.d.ts +30 -0
- package/dist/events/split-text-miss.js +44 -0
- package/dist/flows/coverage.d.ts +0 -8
- package/dist/flows/coverage.js +1 -1
- package/dist/flows/decision.d.ts +5 -1
- package/dist/flows/decision.js +33 -7
- package/dist/flows/flake.d.ts +6 -8
- package/dist/flows/flake.js +1 -1
- package/dist/flows/flow-intent.d.ts +52 -0
- package/dist/flows/flow-intent.js +123 -0
- package/dist/flows/flow-memory-consult.d.ts +55 -0
- package/dist/flows/flow-memory-consult.js +38 -0
- package/dist/flows/flow-replay-run.d.ts +18 -7
- package/dist/flows/flow-replay-run.js +263 -23
- package/dist/flows/flow-replay.js +11 -2
- package/dist/flows/flow-step-runners.d.ts +8 -0
- package/dist/flows/flow-step-runners.js +8 -2
- package/dist/flows/flow-store-for-session.d.ts +31 -0
- package/dist/flows/flow-store-for-session.js +33 -0
- package/dist/flows/flow-success.js +15 -3
- package/dist/flows/flow-tools.js +87 -33
- package/dist/flows/flows.d.ts +14 -1
- package/dist/flows/flows.js +502 -24
- package/dist/flows/heal-run.js +5 -2
- package/dist/flows/predicate-to-expect.d.ts +17 -12
- package/dist/flows/predicate-to-expect.js +36 -15
- package/dist/flows/recordings.d.ts +13 -1
- package/dist/flows/recordings.js +17 -2
- package/dist/flows/replay.d.ts +22 -2
- package/dist/flows/replay.js +28 -2
- package/dist/flows/server-verify.js +16 -2
- package/dist/flows/verify-change-tools.js +9 -3
- package/dist/honesty/blind-spots.d.ts +51 -15
- package/dist/honesty/blind-spots.js +64 -4
- package/dist/honesty/feature-capture.d.ts +150 -0
- package/dist/honesty/feature-capture.js +233 -0
- package/dist/honesty/honesty.d.ts +24 -0
- package/dist/honesty/honesty.js +25 -1
- package/dist/honesty/instrumentation-gaps.d.ts +39 -6
- package/dist/honesty/instrumentation-gaps.js +88 -5
- package/dist/honesty/tool-hit-rate.d.ts +86 -0
- package/dist/honesty/tool-hit-rate.js +90 -0
- package/dist/honesty/undeclared-change.d.ts +51 -0
- package/dist/honesty/undeclared-change.js +56 -0
- package/dist/honesty/verified.d.ts +16 -0
- package/dist/honesty/verified.js +84 -5
- package/dist/http-server.d.ts +0 -1
- package/dist/http-server.js +13 -1
- package/dist/hunt/hunt-report.d.ts +0 -2
- package/dist/hunt/hunt-report.js +1 -1
- package/dist/impact/impact-recorder.d.ts +31 -8
- package/dist/impact/impact-recorder.js +104 -21
- package/dist/impact/impact-store.d.ts +13 -4
- package/dist/impact/impact-store.js +44 -3
- package/dist/index.d.ts +4 -1
- package/dist/index.js +113 -7
- package/dist/init/agent-rules.d.ts +30 -6
- package/dist/init/agent-rules.js +54 -13
- package/dist/init/astro-patch.d.ts +16 -0
- package/dist/init/astro-patch.js +28 -0
- package/dist/init/capabilities.d.ts +4 -3
- package/dist/init/capabilities.js +23 -3
- package/dist/init/closing-hint.d.ts +36 -0
- package/dist/init/closing-hint.js +120 -0
- package/dist/init/confirm.d.ts +27 -28
- package/dist/init/confirm.js +51 -11
- package/dist/init/cra.d.ts +34 -5
- package/dist/init/cra.js +96 -25
- package/dist/init/csp-check.js +17 -2
- package/dist/init/csp-doctor.d.ts +8 -1
- package/dist/init/csp-doctor.js +8 -3
- package/dist/init/dev-script.d.ts +50 -0
- package/dist/init/dev-script.js +66 -0
- package/dist/init/format-generated.d.ts +18 -0
- package/dist/init/format-generated.js +39 -0
- package/dist/init/install-hint.d.ts +9 -0
- package/dist/init/install-hint.js +29 -0
- package/dist/init/mcp-clients.d.ts +7 -0
- package/dist/init/mcp-clients.js +7 -0
- package/dist/init/mcp.d.ts +17 -6
- package/dist/init/mcp.js +27 -11
- package/dist/init/node-io.js +11 -1
- package/dist/init/plan-framework.d.ts +0 -5
- package/dist/init/plan-framework.js +147 -37
- package/dist/init/plan.d.ts +30 -37
- package/dist/init/plan.js +50 -60
- package/dist/init/preflight.d.ts +28 -0
- package/dist/init/preflight.js +38 -0
- package/dist/init/refresh-rules.d.ts +39 -0
- package/dist/init/refresh-rules.js +51 -0
- package/dist/init/run.d.ts +32 -35
- package/dist/init/run.js +151 -202
- package/dist/init/slash-command.d.ts +1 -1
- package/dist/init/snippets.js +90 -31
- package/dist/init/vite-config.d.ts +1 -1
- package/dist/init/vite-config.js +39 -25
- package/dist/init/workspace-apps.d.ts +17 -10
- package/dist/init/workspace-apps.js +110 -0
- package/dist/input/network-mock-tools.js +3 -6
- package/dist/input/real-input.d.ts +2 -0
- package/dist/input/real-input.js +28 -7
- package/dist/input/scroll-find.d.ts +7 -4
- package/dist/input/scroll-find.js +63 -25
- package/dist/input/scroll-tools.js +4 -6
- package/dist/input/viewport-tools.js +5 -4
- package/dist/intent/inline-intent.d.ts +37 -0
- package/dist/intent/inline-intent.js +193 -0
- package/dist/intent/intent-shard-store.d.ts +72 -0
- package/dist/intent/intent-shard-store.js +203 -0
- package/dist/intent/intent-shard.d.ts +411 -0
- package/dist/intent/intent-shard.js +176 -0
- package/dist/intent/intent-store.d.ts +49 -0
- package/dist/intent/intent-store.js +133 -0
- package/dist/intent/intent-subject.d.ts +45 -0
- package/dist/intent/intent-subject.js +177 -0
- package/dist/intent/intent-tools.d.ts +2 -0
- package/dist/intent/intent-tools.js +143 -0
- package/dist/intent/open-intents.d.ts +42 -0
- package/dist/intent/open-intents.js +40 -0
- package/dist/journal/envelope.d.ts +26 -26
- package/dist/journal/journal-recorder.d.ts +23 -0
- package/dist/journal/journal-recorder.js +35 -0
- package/dist/license/license-env.d.ts +29 -0
- package/dist/license/license-env.js +148 -0
- package/dist/loopback-agent.d.ts +31 -0
- package/dist/loopback-agent.js +57 -0
- package/dist/mcp/attach-memory.d.ts +83 -0
- package/dist/mcp/attach-memory.js +185 -0
- package/dist/mcp/client-identity.d.ts +31 -0
- package/dist/mcp/client-identity.js +51 -0
- package/dist/mcp/mcp-post-transport.d.ts +26 -0
- package/dist/mcp/mcp-post-transport.js +109 -0
- package/dist/mcp/mcp-proxy.d.ts +2 -8
- package/dist/mcp/mcp-proxy.js +64 -62
- package/dist/mcp/mcp.d.ts +2 -0
- package/dist/mcp/mcp.js +52 -24
- package/dist/mcp/proxy-backoff.d.ts +11 -0
- package/dist/mcp/proxy-backoff.js +13 -0
- package/dist/mcp/proxy-daemon-probe.d.ts +1 -0
- package/dist/mcp/proxy-daemon-probe.js +7 -1
- package/dist/mcp/proxy-handshake.d.ts +23 -0
- package/dist/mcp/proxy-handshake.js +31 -0
- package/dist/mcp/server-instructions.js +45 -3
- package/dist/mcp/tool-catalog-cache.d.ts +16 -0
- package/dist/mcp/tool-catalog-cache.js +22 -0
- package/dist/memory/memory-tools.d.ts +2 -0
- package/dist/memory/memory-tools.js +82 -0
- package/dist/memory/project-memory.d.ts +34 -0
- package/dist/memory/project-memory.js +96 -0
- package/dist/oracles/flow-instrument-gaps.d.ts +4 -4
- package/dist/oracles/flow-instrument-gaps.js +4 -5
- package/dist/oracles/propose-consequences.js +12 -3
- package/dist/oracles/self-instrument.d.ts +9 -9
- package/dist/oracles/self-instrument.js +19 -13
- package/dist/pool/browser-pool.d.ts +75 -5
- package/dist/pool/browser-pool.js +144 -5
- package/dist/pool/playwright-launcher.js +12 -1
- package/dist/project/fs-port.d.ts +3 -0
- package/dist/project/fs-port.js +3 -2
- package/dist/project/memory-fs.js +6 -1
- package/dist/project/project-tools.js +6 -35
- package/dist/project/reticle-dir.d.ts +17 -2
- package/dist/project/reticle-dir.js +22 -4
- package/dist/runs/context-tools.d.ts +2 -0
- package/dist/runs/context-tools.js +89 -0
- package/dist/runs/run-context.d.ts +40 -0
- package/dist/runs/run-context.js +158 -0
- package/dist/runs/run-diff.d.ts +2 -1
- package/dist/runs/run-store.d.ts +10 -0
- package/dist/runs/run-store.js +10 -0
- package/dist/runs/verification-sync.d.ts +0 -11
- package/dist/runs/verification-sync.js +24 -3
- package/dist/runs/verify-server.d.ts +8 -1
- package/dist/runs/verify-server.js +14 -2
- package/dist/session/command-timeout.d.ts +5 -2
- package/dist/session/command-timeout.js +5 -4
- package/dist/session/dev-server-probe.d.ts +0 -8
- package/dist/session/dev-server-probe.js +1 -1
- package/dist/session/last-act.d.ts +7 -1
- package/dist/session/last-act.js +2 -2
- package/dist/session/lease-visibility.d.ts +67 -0
- package/dist/session/lease-visibility.js +76 -0
- package/dist/session/live-control-tools.js +1 -42
- package/dist/session/no-session-diagnosis.d.ts +33 -0
- package/dist/session/no-session-diagnosis.js +82 -24
- package/dist/session/no-session-next-action.d.ts +12 -0
- package/dist/session/no-session-next-action.js +77 -6
- package/dist/session/no-session-watch.d.ts +18 -6
- package/dist/session/no-session-watch.js +125 -75
- package/dist/session/output-budget.js +4 -1
- package/dist/session/pending-commands.d.ts +11 -1
- package/dist/session/pending-commands.js +12 -2
- package/dist/session/resolve-within.d.ts +34 -0
- package/dist/session/resolve-within.js +53 -0
- package/dist/session/session-health.d.ts +9 -0
- package/dist/session/session-health.js +23 -0
- package/dist/session/session-info.d.ts +18 -0
- package/dist/session/session-info.js +11 -0
- package/dist/session/session-manager.d.ts +14 -0
- package/dist/session/session-manager.js +111 -4
- package/dist/session/session-mirror.d.ts +16 -0
- package/dist/session/session-mirror.js +22 -0
- package/dist/session/session-recommendation.d.ts +19 -5
- package/dist/session/session-recommendation.js +25 -9
- package/dist/session/session-successor.d.ts +37 -0
- package/dist/session/session-successor.js +113 -0
- package/dist/session/session-tools.js +2 -2
- package/dist/session/session.d.ts +53 -3
- package/dist/session/session.js +162 -9
- package/dist/session/wall-clock.d.ts +12 -0
- package/dist/session/wall-clock.js +14 -0
- package/dist/setup/agent-configs.d.ts +96 -0
- package/dist/setup/agent-configs.js +333 -0
- package/dist/setup/agent-io.d.ts +9 -0
- package/dist/setup/agent-io.js +16 -0
- package/dist/setup/agent-writer.d.ts +51 -0
- package/dist/setup/agent-writer.js +115 -0
- package/dist/setup/approval-migration.d.ts +47 -0
- package/dist/setup/approval-migration.js +68 -0
- package/dist/setup/auto-approve.d.ts +85 -0
- package/dist/setup/auto-approve.js +150 -0
- package/dist/setup/bridge-port.d.ts +15 -0
- package/dist/setup/bridge-port.js +24 -0
- package/dist/setup/desktop-shape.d.ts +57 -0
- package/dist/setup/desktop-shape.js +63 -0
- package/dist/setup/dev-server-wait.d.ts +60 -0
- package/dist/setup/dev-server-wait.js +65 -0
- package/dist/setup/drive-agent.d.ts +71 -0
- package/dist/setup/drive-agent.js +171 -0
- package/dist/setup/drive-plan.d.ts +68 -0
- package/dist/setup/drive-plan.js +130 -0
- package/dist/setup/ensure-daemon.d.ts +29 -0
- package/dist/setup/ensure-daemon.js +58 -0
- package/dist/setup/init-runtime.d.ts +47 -0
- package/dist/setup/init-runtime.js +160 -0
- package/dist/setup/interrupt.d.ts +25 -0
- package/dist/setup/interrupt.js +40 -0
- package/dist/setup/license-key.d.ts +39 -0
- package/dist/setup/license-key.js +72 -0
- package/dist/setup/listeners.d.ts +37 -0
- package/dist/setup/listeners.js +85 -0
- package/dist/setup/node-effects.d.ts +60 -0
- package/dist/setup/node-effects.js +210 -0
- package/dist/setup/page-probe.d.ts +39 -0
- package/dist/setup/page-probe.js +49 -0
- package/dist/setup/relaunch.d.ts +36 -0
- package/dist/setup/relaunch.js +57 -0
- package/dist/setup/remaining-steps.d.ts +19 -0
- package/dist/setup/remaining-steps.js +31 -0
- package/dist/setup/run-setup.d.ts +99 -0
- package/dist/setup/run-setup.js +187 -0
- package/dist/setup/session-pick.d.ts +47 -0
- package/dist/setup/session-pick.js +51 -0
- package/dist/setup/setup-command.d.ts +45 -0
- package/dist/setup/setup-command.js +199 -0
- package/dist/setup/setup-options.d.ts +74 -0
- package/dist/setup/setup-options.js +67 -0
- package/dist/setup/transcripts.d.ts +16 -0
- package/dist/setup/transcripts.js +43 -0
- package/dist/status-payload.d.ts +14 -1
- package/dist/status-payload.js +23 -1
- package/dist/telemetry/automation-hint.d.ts +2 -1
- package/dist/telemetry/daemon-telemetry.d.ts +8 -1
- package/dist/telemetry/daemon-telemetry.js +52 -5
- package/dist/telemetry/error-class.js +1 -1
- package/dist/telemetry/feedback-context.d.ts +9 -1
- package/dist/telemetry/feedback-context.js +60 -29
- package/dist/telemetry/feedback-local.d.ts +15 -0
- package/dist/telemetry/feedback-local.js +56 -0
- package/dist/telemetry/feedback-outbox.d.ts +2 -1
- package/dist/telemetry/feedback.d.ts +11 -0
- package/dist/telemetry/feedback.js +19 -6
- package/dist/telemetry/init-telemetry.d.ts +2 -0
- package/dist/telemetry/init-telemetry.js +2 -0
- package/dist/telemetry/install-source.d.ts +14 -0
- package/dist/telemetry/install-source.js +30 -0
- package/dist/telemetry/license-activation.d.ts +7 -1
- package/dist/telemetry/license-activation.js +9 -5
- package/dist/telemetry/mcp-connection.js +7 -0
- package/dist/telemetry/project-profile.d.ts +12 -9
- package/dist/telemetry/project-profile.js +12 -7
- package/dist/telemetry/proxy-telemetry.d.ts +3 -0
- package/dist/telemetry/proxy-telemetry.js +21 -0
- package/dist/telemetry/run-telemetry.d.ts +0 -2
- package/dist/telemetry/run-telemetry.js +1 -1
- package/dist/telemetry/session-metrics.d.ts +12 -0
- package/dist/telemetry/session-metrics.js +35 -1
- package/dist/telemetry/telemetry.js +17 -2
- package/dist/telemetry/tool-refused.d.ts +3 -1
- package/dist/telemetry/tool-refused.js +34 -2
- package/dist/telemetry/verification-of.js +2 -2
- package/dist/tools/act-capsule.d.ts +10 -0
- package/dist/tools/act-capsule.js +8 -2
- package/dist/tools/act-danger.d.ts +2 -1
- package/dist/tools/act-danger.js +11 -3
- package/dist/tools/act-observation.d.ts +41 -0
- package/dist/tools/act-observation.js +36 -0
- package/dist/tools/act-preflight.d.ts +20 -0
- package/dist/tools/act-preflight.js +98 -0
- package/dist/tools/act-sequence-retry.d.ts +45 -0
- package/dist/tools/act-sequence-retry.js +58 -0
- package/dist/tools/act-sequence-tool.d.ts +13 -0
- package/dist/tools/act-sequence-tool.js +135 -0
- package/dist/tools/act-target.d.ts +14 -0
- package/dist/tools/act-target.js +47 -0
- package/dist/tools/act-tools.d.ts +21 -1
- package/dist/tools/act-tools.js +196 -204
- package/dist/tools/assert-source.d.ts +22 -0
- package/dist/tools/assert-source.js +53 -0
- package/dist/tools/assert-verdict.d.ts +20 -3
- package/dist/tools/assert-verdict.js +58 -20
- package/dist/tools/browser-tools.js +6 -22
- package/dist/tools/complete-snapshot.d.ts +48 -0
- package/dist/tools/complete-snapshot.js +75 -0
- package/dist/tools/coverage-tools.d.ts +10 -1
- package/dist/tools/coverage-tools.js +123 -69
- package/dist/tools/dynamic-tools.js +53 -13
- package/dist/tools/error-recovery.d.ts +25 -14
- package/dist/tools/error-recovery.js +78 -9
- package/dist/tools/feedback-tools.d.ts +1 -1
- package/dist/tools/feedback-tools.js +2 -2
- package/dist/tools/invoke-tool.js +121 -11
- package/dist/tools/lease-hint.d.ts +10 -0
- package/dist/tools/lease-hint.js +53 -4
- package/dist/tools/lease-tools.d.ts +35 -5
- package/dist/tools/lease-tools.js +191 -13
- package/dist/tools/merged-name-redirect.d.ts +13 -0
- package/dist/tools/merged-name-redirect.js +22 -0
- package/dist/tools/navigate-arrival.d.ts +0 -2
- package/dist/tools/navigate-arrival.js +1 -1
- package/dist/tools/numeric-bounds.d.ts +100 -0
- package/dist/tools/numeric-bounds.js +125 -0
- package/dist/tools/observe-tools.js +109 -65
- package/dist/tools/read-tools.js +31 -8
- package/dist/tools/real-input-attempt.d.ts +32 -0
- package/dist/tools/real-input-attempt.js +212 -2
- package/dist/tools/reconcile-tools.js +22 -8
- package/dist/tools/resolve-target.d.ts +0 -7
- package/dist/tools/sdk-marker-probe.d.ts +29 -0
- package/dist/tools/sdk-marker-probe.js +57 -0
- package/dist/tools/snapshot-delta.d.ts +1 -1
- package/dist/tools/tool-kit.d.ts +24 -0
- package/dist/tools/tool-kit.js +21 -0
- package/dist/tools/tool-names.d.ts +5 -0
- package/dist/tools/tool-names.js +5 -0
- package/dist/tools/tool-surface.d.ts +85 -6
- package/dist/tools/tool-surface.js +122 -2
- package/dist/tools/tools-helpers.d.ts +19 -0
- package/dist/tools/tools-helpers.js +46 -0
- package/dist/tools/tools.d.ts +2 -0
- package/dist/tools/tools.js +78 -12
- package/dist/tools/unadvertised-help.js +4 -4
- package/dist/tools/verify-next-baton.d.ts +53 -0
- package/dist/tools/verify-next-baton.js +52 -0
- package/dist/update/reticle-deps.d.ts +9 -0
- package/dist/update/reticle-deps.js +27 -0
- package/dist/update/sdk-sync.d.ts +1 -2
- package/dist/update/sdk-sync.js +1 -21
- package/dist/update/update-nudge.d.ts +25 -10
- package/dist/update/update-nudge.js +32 -3
- package/dist/update/updater.d.ts +1 -1
- package/dist/version/peer-announce.js +4 -2
- package/dist/version/sdk-fix.d.ts +47 -0
- package/dist/version/sdk-fix.js +127 -0
- package/dist/version/version-nudge.d.ts +14 -0
- package/dist/version/version-nudge.js +21 -0
- package/dist/version/version-skew.d.ts +38 -3
- package/dist/version/version-skew.js +83 -7
- package/dist/visual/visual-store.d.ts +6 -6
- package/dist/visual/visual-store.js +18 -16
- package/dist/visual/visual-tools.js +57 -12
- package/docs/README.md +2 -1
- package/docs/cli/cloud.mdx +1 -1
- package/docs/cli/doctor.mdx +2 -0
- package/docs/cli/serve.mdx +4 -2
- package/docs/cli/verify.mdx +4 -5
- package/docs/cli.mdx +7 -3
- package/docs/desktop.mdx +1 -1
- package/docs/docs.json +2 -2
- package/docs/gates.md +1 -1
- package/docs/getting-started.md +19 -3
- package/docs/index.mdx +9 -6
- package/docs/install-agentic.mdx +38 -12
- package/docs/install-manual.mdx +1 -1
- package/docs/packages/browser.mdx +2 -2
- package/docs/packages/server.mdx +1 -1
- package/docs/packages.mdx +8 -6
- package/docs/platform-integration.md +17 -0
- package/docs/predicates.mdx +8 -0
- package/docs/reticle-manual.md +106 -0
- package/docs/skill-file.mdx +3 -3
- package/docs/telemetry-contract.md +108 -4
- package/docs/tools-act-sequence.mdx +16 -0
- package/docs/tools-tools-and-run.mdx +2 -4
- package/docs/troubleshooting.mdx +9 -0
- package/docs/usage.md +4 -3
- package/package.json +4 -3
- package/dist/init/cursor.d.ts +0 -24
- package/dist/init/cursor.js +0 -80
- package/dist/session/session-readiness.d.ts +0 -34
- package/dist/session/session-readiness.js +0 -36
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { ReticleCommand, RETICLE_CAPTURE_FILE_PREFIX, VISUAL_NO_PROVIDER_RECOMMENDATION, VisualReason, } from '@reticlehq/core';
|
|
2
|
+
import { AppRuntime, ReticleCommand, RETICLE_CAPTURE_FILE_PREFIX, VISUAL_NO_PROVIDER_RECOMMENDATION, VisualReason, } from '@reticlehq/core';
|
|
3
3
|
import { ReticleTool } from '../tools/tool-names.js';
|
|
4
4
|
import { sessionIdShape } from '../tools/tool-kit.js';
|
|
5
|
+
import { ratioSchema } from '../tools/numeric-bounds.js';
|
|
5
6
|
import { asNumber, asRecord, asString } from '../tools/tools-helpers.js';
|
|
6
7
|
import { diffPng } from './visual-diff.js';
|
|
7
8
|
import { VisualStore } from './visual-store.js';
|
|
@@ -148,19 +149,51 @@ function isCompletePng(bytes) {
|
|
|
148
149
|
* `full-page-unsupported` — a viewport image returned as though it were the whole scroll height is a
|
|
149
150
|
* baseline that says nothing about the content below the fold, and a later diff would call it green.
|
|
150
151
|
*/
|
|
152
|
+
/**
|
|
153
|
+
* Which runtime this session is, for scoping a visual artifact.
|
|
154
|
+
*
|
|
155
|
+
* Undefined when the session cannot be resolved or its SDK never reported one — and undefined means
|
|
156
|
+
* the flat legacy path, so a baseline captured before any of this keeps matching.
|
|
157
|
+
*/
|
|
158
|
+
function runtimeOf(deps, sessionId) {
|
|
159
|
+
try {
|
|
160
|
+
return deps.sessions.resolve(sessionId).runtime;
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
151
166
|
async function capture(deps, sessionId, args) {
|
|
152
167
|
const provider = screenshotProvider(deps);
|
|
153
168
|
if (provider !== undefined) {
|
|
154
169
|
const session = deps.sessions.resolve(sessionId);
|
|
155
170
|
const png = await provider.screenshot(session.url, await buildOpts(deps, sessionId, args));
|
|
171
|
+
// A driven browser renders the session's URL in a BROWSER — so the pixels are web even when the
|
|
172
|
+
// session named is a desktop window. Scoping those under the desktop runtime would corrupt that
|
|
173
|
+
// runtime's baseline with a picture of a different renderer.
|
|
156
174
|
if (png !== undefined)
|
|
157
|
-
return { png };
|
|
175
|
+
return { png, runtime: AppRuntime.WEB };
|
|
158
176
|
}
|
|
177
|
+
// The window's own backing store, via the Electron/Tauri adapter — the only route whose pixels
|
|
178
|
+
// really are the desktop app.
|
|
159
179
|
const desktop = await desktopCapture(deps, sessionId, true === args['fullPage']);
|
|
160
180
|
if (desktop.png !== undefined)
|
|
161
|
-
return { png: desktop.png };
|
|
181
|
+
return { png: desktop.png, runtime: runtimeOf(deps, sessionId) };
|
|
162
182
|
if (desktop.reason !== undefined)
|
|
163
183
|
return { reason: desktop.reason };
|
|
184
|
+
/*
|
|
185
|
+
* A LEASED page is a real browser page, so the pixels were always there — the visual tools simply
|
|
186
|
+
* had no route to them. Without this, `reticle_screenshot` answered "no provider" for every context
|
|
187
|
+
* an agent can actually acquire, which made visual regression impossible on exactly the isolated
|
|
188
|
+
* contexts the pool exists to hand out. Tried last: a CDP provider, when there is one, is driving
|
|
189
|
+
* the page the caller means, and a lease is the fallback rather than a competitor.
|
|
190
|
+
*/
|
|
191
|
+
const leased = sessionId === undefined
|
|
192
|
+
? undefined
|
|
193
|
+
: await deps.pool?.screenshotLease(sessionId, { fullPage: true === args['fullPage'] });
|
|
194
|
+
// A leased page is a real browser page, whatever the session is.
|
|
195
|
+
if (leased !== undefined)
|
|
196
|
+
return { png: leased, runtime: AppRuntime.WEB };
|
|
164
197
|
return {
|
|
165
198
|
reason: provider === undefined ? VisualReason.NO_PROVIDER : VisualReason.CAPTURE_FAILED,
|
|
166
199
|
};
|
|
@@ -215,13 +248,16 @@ export const VISUAL_TOOLS = [
|
|
|
215
248
|
},
|
|
216
249
|
handler: async (deps, args) => {
|
|
217
250
|
const sessionId = asString(args['sessionId']);
|
|
218
|
-
const { png, reason } = await capture(deps, sessionId, args);
|
|
251
|
+
const { png, reason, runtime } = await capture(deps, sessionId, args);
|
|
219
252
|
if (png === undefined) {
|
|
220
253
|
return reason === VisualReason.NO_PROVIDER ? noProvider : { ok: false, reason };
|
|
221
254
|
}
|
|
222
255
|
const name = asString(args['name']) ?? 'default';
|
|
223
256
|
const store = new VisualStore(deps.fs, deps.reticleRoot);
|
|
224
|
-
|
|
257
|
+
// Scoped to the runtime that produced it: an Electron window, a Tauri webview and a browser
|
|
258
|
+
// tab do not render the same url the same way, and one shared baseline makes every
|
|
259
|
+
// cross-runtime diff wrong. See visualDir.
|
|
260
|
+
const path = await store.saveBaseline(name, png, runtime);
|
|
225
261
|
return { ok: true, saved: true, name, path, bytes: png.length };
|
|
226
262
|
},
|
|
227
263
|
},
|
|
@@ -237,8 +273,10 @@ export const VISUAL_TOOLS = [
|
|
|
237
273
|
ref: z.string().optional(),
|
|
238
274
|
clip: rectShape.optional(),
|
|
239
275
|
masks: z.array(rectShape).optional(),
|
|
240
|
-
maxRatio:
|
|
241
|
-
threshold:
|
|
276
|
+
maxRatio: ratioSchema.optional(),
|
|
277
|
+
threshold: ratioSchema
|
|
278
|
+
.optional()
|
|
279
|
+
.describe('Pixel difference threshold (0–1). Default: 0.01.'),
|
|
242
280
|
...sessionIdShape,
|
|
243
281
|
},
|
|
244
282
|
outputSchema: {
|
|
@@ -255,14 +293,21 @@ export const VISUAL_TOOLS = [
|
|
|
255
293
|
handler: async (deps, args) => {
|
|
256
294
|
const baseline = asString(args['baseline']) ?? '';
|
|
257
295
|
const store = new VisualStore(deps.fs, deps.reticleRoot);
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
296
|
+
// Capture FIRST, then fetch the baseline for the runtime that produced these pixels. Reading it
|
|
297
|
+
// by the session's runtime looked equivalent and is not: the route decides the renderer, so a
|
|
298
|
+
// desktop session captured through a driven browser must be compared against the WEB baseline,
|
|
299
|
+
// not the desktop one. Comparing across renderers is a confident wrong diff in one direction
|
|
300
|
+
// and a silently overwritten baseline in the other.
|
|
261
301
|
const sessionId = asString(args['sessionId']);
|
|
262
|
-
const { png: current, reason } = await capture(deps, sessionId, args);
|
|
302
|
+
const { png: current, reason, runtime } = await capture(deps, sessionId, args);
|
|
263
303
|
if (current === undefined) {
|
|
264
304
|
return reason === VisualReason.NO_PROVIDER ? noProvider : { ok: false, reason };
|
|
265
305
|
}
|
|
306
|
+
// A baseline from another runtime is not missing by accident — it is a different rendering, and
|
|
307
|
+
// "no baseline for this one" is the honest answer.
|
|
308
|
+
const baselineBytes = await store.readBaseline(baseline, runtime);
|
|
309
|
+
if (baselineBytes === undefined)
|
|
310
|
+
return { ok: false, reason: VisualReason.BASELINE_MISSING };
|
|
266
311
|
const masks = rectsFrom(args['masks']);
|
|
267
312
|
const threshold = asNumber(args['threshold']);
|
|
268
313
|
const maxRatio = asNumber(args['maxRatio']);
|
|
@@ -276,7 +321,7 @@ export const VISUAL_TOOLS = [
|
|
|
276
321
|
if (diffBytes === undefined) {
|
|
277
322
|
return { ok: false, ...verdict, reason: VisualReason.DIMENSION_MISMATCH };
|
|
278
323
|
}
|
|
279
|
-
const diffPath = await store.saveDiff(baseline, diffBytes);
|
|
324
|
+
const diffPath = await store.saveDiff(baseline, diffBytes, runtime);
|
|
280
325
|
return { ok: true, ...verdict, diffPath };
|
|
281
326
|
},
|
|
282
327
|
},
|
package/docs/README.md
CHANGED
|
@@ -26,7 +26,7 @@ Everything here is published to [docs.reticle.sh](https://docs.reticle.sh) by `d
|
|
|
26
26
|
| [faq.mdx](faq.mdx) | production, frameworks, comparisons, and the honest limits |
|
|
27
27
|
| [tools-overview.mdx](tools-overview.mdx) | the 18 advertised tools, the 30 in the cold tail, and why |
|
|
28
28
|
| [tools-snapshot.mdx](tools-snapshot.mdx) | `reticle_snapshot`: three modes, from full tree to a 25-token route check |
|
|
29
|
-
| [tools-query.mdx](tools-query.mdx) | `reticle_query` finds elements by
|
|
29
|
+
| [tools-query.mdx](tools-query.mdx) | `reticle_query` finds elements by their reported roles, names and labels |
|
|
30
30
|
| [tools-inspect.mdx](tools-inspect.mdx) | `reticle_inspect`: one element, down to source and design tokens |
|
|
31
31
|
| [tools-navigate.mdx](tools-navigate.mdx) | `reticle_navigate`, and why `ok` does not mean the page arrived |
|
|
32
32
|
| [tools-act.mdx](tools-act.mdx) | `reticle_act` acts, proves nothing, and says so |
|
|
@@ -46,6 +46,7 @@ Everything here is published to [docs.reticle.sh](https://docs.reticle.sh) by `d
|
|
|
46
46
|
| [best-practices.mdx](best-practices.mdx) | the habits that make a verdict worth trusting |
|
|
47
47
|
| [skill-file.mdx](skill-file.mdx) | the paste-one-URL skill that teaches an agent Reticle |
|
|
48
48
|
| [agent-cheatsheet.md](agent-cheatsheet.md) | the condensed version an agent keeps in context |
|
|
49
|
+
| [reticle-manual.md](reticle-manual.md) | GENERATED: what each tool actually returned when it was called, per argument shape |
|
|
49
50
|
| [for-agents.md](for-agents.md) | how to fetch these docs as Markdown or `llms.txt` |
|
|
50
51
|
| [architecture.md](architecture.md) | how it works, and why it is built this way |
|
|
51
52
|
| [platform-integration.md](platform-integration.md) | Vite, Next, Remix, Astro, plain HTML |
|
package/docs/cli/cloud.mdx
CHANGED
|
@@ -20,7 +20,7 @@ These are thin clients over the `/v1` API. The moat is the server, not the verbs
|
|
|
20
20
|
| `~/.reticle/credentials.json` | Project-scoped API keys from `reticle link`, keyed by `projectId` | Yes |
|
|
21
21
|
| `<repo>/.reticle/cloud.json` | `{ projectId, projectName, url, sync, verify }`. The non-secret binding | No, commit it |
|
|
22
22
|
|
|
23
|
-
Auth for any command is `RETICLE_CLOUD_KEY` from the environment (the agent path) if set, otherwise the login token. `RETICLE_CLOUD_URL` overrides the endpoint; the default is `http://localhost:8890`.
|
|
23
|
+
Auth for any command is `RETICLE_CLOUD_KEY` from the environment (the agent path) if set, otherwise the login token. `RETICLE_CLOUD_URL` overrides the endpoint; the default is `http://localhost:8890`. When a command falls back to that default without `RETICLE_CLOUD_URL` (or a saved session URL), it prints a one-line notice on stderr; stdout stays pure JSON for agents.
|
|
24
24
|
|
|
25
25
|
## The commands
|
|
26
26
|
|
package/docs/cli/doctor.mdx
CHANGED
|
@@ -51,8 +51,10 @@ When nothing has connected, the `sessions` line fails and the daemon's own diagn
|
|
|
51
51
|
| `chromium` | Whether the exact Chromium revision the bundled Playwright wants is on disk. The most common silent failure |
|
|
52
52
|
| `daemon` | Whether the port holds a Reticle daemon, a foreign process (named where possible), or nothing. Adds a `version` line when the daemon's version or contract fingerprint disagrees with the CLI's |
|
|
53
53
|
| `sessions` | Whether any page has actually connected. Zero is a FAILING check rather than a neutral note, because it is the state the setup most often stalls in: wired correctly, daemon up, nothing dialled in. When it is zero the daemon's own no-session diagnosis prints below the checklist |
|
|
54
|
+
| `agent link` | Whether an MCP client has listed Reticle's tools on this port **and actually called one**. Every other row here checks a component; this one checks the hop between your agent and the daemon. It is possible for the SDK to be injected, a session to be live, and your client to show every tool enabled, while no request has ever crossed from the agent. That state passes every other check and is the one people lose hours to |
|
|
54
55
|
| `bridge port` | The port your app must dial, spelled out because mixing it up with the dev server port is the most common setup failure |
|
|
55
56
|
| `port check` | Only when your project's configured port disagrees with the one the daemon is on. Prints the mismatch rather than leaving you to spot it across two lines |
|
|
57
|
+
| `sibling` | Only when a well-known Reticle port other than this daemon's has a listener. An observation, not a diagnosis: that listener may or may not be related |
|
|
56
58
|
| `daemon log` | Where the structured daemon log lives |
|
|
57
59
|
| `tracing` | How to turn that log into a per-stage trace |
|
|
58
60
|
| `desktop` | Only on a desktop project. Every Electron and Tauri misconfiguration here fails silently, so it is diagnosed explicitly |
|
package/docs/cli/serve.mdx
CHANGED
|
@@ -21,8 +21,10 @@ Most people never type this. Your agent runs [`reticle mcp`](/cli/mcp), which st
|
|
|
21
21
|
| `--headless` | boolean | `true` for `serve` | Hide the browser |
|
|
22
22
|
| `--headed` | boolean | `false` | Show it. `serve` owns the pooled browser behind leases, which is batch work, so it hides by default |
|
|
23
23
|
| `--http` | boolean | `false` | Also expose the HTTP verify endpoint |
|
|
24
|
-
| `--http-port N` | number | unset | Port for that endpoint |
|
|
25
|
-
| `--http-token T` | string | unset | Bearer token the endpoint requires |
|
|
24
|
+
| `--http-port N` | number | unset (`7331`) | Port for that endpoint. Requires `--http`. |
|
|
25
|
+
| `--http-token T` | string | unset | Bearer token the endpoint requires. Requires `--http`. |
|
|
26
|
+
|
|
27
|
+
The HTTP flags are honoured or refused, never silently dropped: against an already-running daemon that does not serve the requested verify port, `serve --http` exits 1 and names both ports. A running daemon keeps the flags it was started with, so `reticle stop`, then serve again. A verify port that cannot be bound fails the daemon start with a `reticle_daemon_start_failed` line naming that port.
|
|
26
28
|
|
|
27
29
|
## What it prints
|
|
28
30
|
|
package/docs/cli/verify.mdx
CHANGED
|
@@ -50,11 +50,10 @@ Call log:
|
|
|
50
50
|
|
|
51
51
|
<Warning>
|
|
52
52
|
`verify` binds the bridge port itself and has **no `--port` flag**: passing one is rejected as
|
|
53
|
-
`unknown argument '--port'`. If a daemon is already on the port, `verify`
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
port is normally free.
|
|
53
|
+
`unknown argument '--port'`. If a daemon is already on the port, `verify` does not start a second
|
|
54
|
+
one: it prints three ways out (ask the running daemon via `reticle_run`, stop it, or move with
|
|
55
|
+
`RETICLE_PORT`) rather than a raw listen error. This bites most often on a developer machine,
|
|
56
|
+
where an agent has usually left a daemon running; in CI the port is normally free.
|
|
58
57
|
</Warning>
|
|
59
58
|
|
|
60
59
|
## Exit codes
|
package/docs/cli.mdx
CHANGED
|
@@ -4,7 +4,7 @@ description: Every reticle command. What it does, what it prints, and what it ex
|
|
|
4
4
|
icon: terminal
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
The `reticle` CLI
|
|
7
|
+
The `reticle` CLI installs Reticle into a project and proves the install works (`init`), runs and diagnoses the daemon your app connects to (`serve`, `status`, `doctor`, `kill`, `restart`), and gates a build on verification in CI (`verify`, `affected`, `gate`). This page is the index; each command has its own page with real captured output and measured exit codes.
|
|
8
8
|
|
|
9
9
|
The CLI is mostly for you, not your agent. Your agent talks MCP; you use these to set things up, work out why nothing connected, and wire verification into CI.
|
|
10
10
|
|
|
@@ -32,12 +32,16 @@ npx @reticlehq/server <command>
|
|
|
32
32
|
|
|
33
33
|
### `reticle init`
|
|
34
34
|
|
|
35
|
-
Wires Reticle into the project in the current directory.
|
|
35
|
+
Wires Reticle into the project in the current directory, then boots the app, proves a session connected and drives one flow to a verdict. It exits non-zero if no verdict was produced, and prints what is left to do.
|
|
36
36
|
|
|
37
37
|
```
|
|
38
|
-
reticle init [--
|
|
38
|
+
reticle init [--flow "<what to drive>"] [--env KEY=VALUE]... [--app <dir>] [--license <key>]
|
|
39
|
+
[--json] [--files-only] [--no-open] [--no-drive] [--dry-run]
|
|
40
|
+
[--port N] [--no-mcp] [--no-install] [--timeout S] [--drive-model M]
|
|
39
41
|
```
|
|
40
42
|
|
|
43
|
+
`--flow`, `--env` and `--app` are the answers the command cannot work out for itself: which journey proves what you care about, what the app needs to reach a usable state, and which app in a monorepo. `--files-only` is what `init` did before it learned to boot the app: it still registers the MCP server and pre-approves Reticle's tools, so it doubles as the upgrade path for an existing install.
|
|
44
|
+
|
|
41
45
|
<Card title="Full walkthrough with real output" icon="wand-magic-sparkles" href="/install-agentic">
|
|
42
46
|
What it writes, and how to read its four status marks.
|
|
43
47
|
</Card>
|
package/docs/desktop.mdx
CHANGED
package/docs/docs.json
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"navigation": {
|
|
33
33
|
"versions": [
|
|
34
34
|
{
|
|
35
|
-
"version": "2.
|
|
35
|
+
"version": "2.13.0",
|
|
36
36
|
"default": true,
|
|
37
37
|
"tabs": [
|
|
38
38
|
{
|
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
},
|
|
154
154
|
{
|
|
155
155
|
"group": "Long form",
|
|
156
|
-
"pages": ["agent-cheatsheet", "usage", "faq"]
|
|
156
|
+
"pages": ["agent-cheatsheet", "reticle-manual", "usage", "faq"]
|
|
157
157
|
}
|
|
158
158
|
]
|
|
159
159
|
},
|
package/docs/gates.md
CHANGED
|
@@ -69,7 +69,7 @@ Each gate exists because the ones above it are blind to something. That blindnes
|
|
|
69
69
|
| **Integration** | `pnpm test:integration` | real headless Chromium: browser pool, crash isolation, framework adapters, `withReticle` | the MCP surface, the daemon | `e2e` |
|
|
70
70
|
| **Web e2e battery** | `pnpm test:e2e` | 32 specs against 3 booted servers and a real browser (the tool surface, the daemon lifecycle, transport faults, telemetry, trace shape), plus the soak | desktop runtimes; the install | `e2e` |
|
|
71
71
|
| **Desktop battery** | `pnpm test:e2e:desktop` | a real Electron main process and a **packaged** Tauri binary, driven headless | web-only paths | `desktop-e2e` |
|
|
72
|
-
| **Install gate** | `pnpm gate:install` | scaffolds 3 pristine apps, publishes this checkout to a local Verdaccio, lets `init` install itself, boots each app in a real browser, polls for a session | install _complexity_; see [`fixtures.md`](./fixtures.md) | `install-gate` |
|
|
72
|
+
| **Install gate** | `pnpm gate:install` | scaffolds 3 pristine apps, publishes this checkout to a local Verdaccio, lets `init` install itself, boots each app in a real browser, polls for a session that advertised capabilities | install _complexity_; see [`fixtures.md`](./fixtures.md) | `install-gate` |
|
|
73
73
|
| **Matrix records** | `pnpm matrix:validate` | every submitted client-compat record is well-formed | whether the client actually works | `matrix-records` |
|
|
74
74
|
| **Windows** | (CI only) | that the code runs at all on the majority platform | e2e; Windows is unit-only | `windows` |
|
|
75
75
|
| **Rust** | `cargo fmt/clippy/check` | `packages/tauri` compiles and lints on Linux, macOS, and cross-checks Windows | everything JS | `rust`, `rust-macos` |
|
package/docs/getting-started.md
CHANGED
|
@@ -4,7 +4,7 @@ description: 'Zero to your agent verifying your real app, step by step, with wor
|
|
|
4
4
|
icon: rocket
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
**To get started with Reticle: run `npx @reticlehq/server init` in your project root,
|
|
7
|
+
**To get started with Reticle: run `npx @reticlehq/server init --flow "<the journey worth proving>"` in your project root.** That one command wires your project, starts your dev server, opens the app, waits for it to connect, and drives that flow to a verdict. You do not restart anything and you do not drive it yourself. 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 instead of guessing. It needs Node 20 or newer, an app you run locally, and an agent that speaks MCP.
|
|
8
8
|
|
|
9
9
|
> **Looking for the fast path?** [Quickstart](/quickstart) gets you to a real verdict in five minutes, and every response on it was captured live. [Agentic install](/install-agentic) and [Manual install](/install-manual) cover setup in detail, per agent and per framework.
|
|
10
10
|
>
|
|
@@ -76,7 +76,19 @@ It detects your framework, package manager, and React version, then:
|
|
|
76
76
|
|
|
77
77
|
The bridge + MCP server is a single process that serves all your projects, so it's registered at **user scope**, not in a per-project `.mcp.json`. Only the SDK (the `reticle()` plugin / connect call) is added per project.
|
|
78
78
|
|
|
79
|
-
Re-running is safe
|
|
79
|
+
Re-running is safe: already-registered and already-patched steps are skipped, and on a wired project it goes straight to proving the app still works. Preview without writing via `npx @reticlehq/server init --dry-run`.
|
|
80
|
+
|
|
81
|
+
`init` does not stop at writing files. It starts your dev server (restarting one whose bundle predates the config edit), opens the app, waits for a session to connect from inside it, and drives one flow to a verdict, which it saves so later checks are a single call with no model involved. It exits non-zero if no verdict was produced and prints what is left to do.
|
|
82
|
+
|
|
83
|
+
Three flags carry what the command cannot work out for itself:
|
|
84
|
+
|
|
85
|
+
| Flag | What only you know |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| `--flow "<what>"` | Which journey proves the thing you care about. It can list the buttons on your page; it cannot know that checkout matters and the theme toggle does not. |
|
|
88
|
+
| `--env KEY=VALUE` | What your app needs to reach a usable state: the key from `.env.example`, the mock backend, the variable that skips an auth wall. Repeatable. |
|
|
89
|
+
| `--app <dir>` | Which app in a monorepo. It finds the servable ones; only you know which you are working in. |
|
|
90
|
+
|
|
91
|
+
The rest are dials: `--license <key>` (writes it to `.env` and keeps `.env` out of git), `--json` (one object for an agent to read), `--files-only` (write, register, pre-approve, and stop, which is what `init` did before it learned to boot the app, and what an existing install re-runs to pick up new wiring), `--no-open`, `--no-drive`, `--dry-run`, `--port N`, `--no-mcp`, `--no-install`.
|
|
80
92
|
|
|
81
93
|
Then restart your dev server and skip to [Step 4](#step-4-run-it-and-verify-the-connection). The manual steps below explain what `init` sets up, if you prefer to wire it yourself.
|
|
82
94
|
|
|
@@ -310,6 +322,8 @@ export default defineConfig({
|
|
|
310
322
|
|
|
311
323
|
## Step 4: Run it and verify the connection
|
|
312
324
|
|
|
325
|
+
> `reticle init` does this for you: it starts the dev server, opens the app and waits for the session. Read on only if you are wiring by hand, or if it told you it could not.
|
|
326
|
+
|
|
313
327
|
1. Start your app's dev server as usual (`npm run dev`).
|
|
314
328
|
2. Open it in the browser (the SDK connects when the page loads).
|
|
315
329
|
3. In your agent, ask it to confirm the connection:
|
|
@@ -328,6 +342,8 @@ If the list is empty, see [Troubleshooting](#troubleshooting).
|
|
|
328
342
|
|
|
329
343
|
## Step 5: Your first verification
|
|
330
344
|
|
|
345
|
+
> `reticle init --flow "<what>"` drives this for you and saves the flow. This section is what it does, for when you want to do it yourself.
|
|
346
|
+
|
|
331
347
|
Now just talk to your agent in plain language. For example:
|
|
332
348
|
|
|
333
349
|
> "Add a 'Refresh' button to the header that re-fetches the dashboard data, then use Reticle to verify clicking it fires `GET /api/dashboard` and shows no console errors."
|
|
@@ -490,7 +506,7 @@ pnpm add @reticlehq/next
|
|
|
490
506
|
|
|
491
507
|
### What exactly does `reticle init` change in my project?
|
|
492
508
|
|
|
493
|
-
Four
|
|
509
|
+
Four files, and none of them are mysterious: a `.reticle.json` project config, your build config (the `reticle()` Vite plugin, or `withReticle` in `next.config`), a dev-only capabilities file at `src/reticle-dev.ts` (or `app/reticle-dev.tsx` on Next.js), and your agent's rule files. It then starts your dev server, opens the app and drives one flow, none of which changes your source: the dev server is left running for you afterwards, and the only file the drive may edit is the capabilities file, and only when your app registers none. It also registers the MCP server globally, which is a once-per-machine step rather than a per-project one. Run `npx @reticlehq/server init --dry-run` first to see the exact plan before anything is written.
|
|
494
510
|
|
|
495
511
|
### Do I have to re-register the MCP server for every project?
|
|
496
512
|
|
package/docs/index.mdx
CHANGED
|
@@ -14,7 +14,7 @@ It answers the only question that matters: did the change actually work? On Reac
|
|
|
14
14
|
|
|
15
15
|
## Install it: paste this into your coding agent
|
|
16
16
|
|
|
17
|
-
You do not install Reticle by hand. Copy the block below into Claude Code, Cursor, Copilot, Codex, Windsurf, OpenCode, or any MCP agent, and let
|
|
17
|
+
You do not install Reticle by hand, and neither does your agent: it runs one command that does the whole thing. Copy the block below into Claude Code, Cursor, Copilot, Codex, Windsurf, OpenCode, or any MCP agent, and let it wire its own workspace. It ends with the only definition of "installed" that counts: one real flow driven, one real verdict returned.
|
|
18
18
|
|
|
19
19
|
```text
|
|
20
20
|
Reticle is the proof layer for AI coding agents. It runs a dev-only SDK inside my
|
|
@@ -30,12 +30,15 @@ silent 500.
|
|
|
30
30
|
|
|
31
31
|
Install it now:
|
|
32
32
|
|
|
33
|
-
RETICLE_INSTALL_SOURCE=docs_site npx @reticlehq/server@latest init
|
|
33
|
+
RETICLE_INSTALL_SOURCE=docs_site npx @reticlehq/server@latest init \
|
|
34
|
+
--flow "<pick the journey that matters in my app and name it here>"
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
That one command wires the project, starts the dev server, opens the app, waits
|
|
37
|
+
for it to connect and drives that flow to a verdict. Do not walk it by hand: read
|
|
38
|
+
what it prints, do anything it says is outstanding, and re-run it, which is safe.
|
|
39
|
+
It exits non-zero until a verdict exists, and that, not a config file, is what
|
|
40
|
+
"installed" means. Only if it could not run at all, follow
|
|
41
|
+
https://docs.reticle.sh/install-manual.md.
|
|
39
42
|
|
|
40
43
|
Afterwards, use it whenever you change any user-facing behaviour.
|
|
41
44
|
```
|
package/docs/install-agentic.mdx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: 'Agentic install: let the agent do it'
|
|
3
3
|
sidebarTitle: Agentic install
|
|
4
|
-
description:
|
|
4
|
+
description: One command wires Reticle into your project, boots the app, proves a session connected and drives one flow to a verdict. What it changes, what you pass it, and how to read what it returns.
|
|
5
5
|
icon: wand-magic-sparkles
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -195,21 +195,47 @@ reticle init [--dry-run] [--port N] [--no-mcp] [--no-install] [--app <dir>]
|
|
|
195
195
|
only make sense once the tools are reachable.
|
|
196
196
|
```
|
|
197
197
|
|
|
198
|
-
|
|
199
|
-
| -------------- | -------------------------------------------------------------------------- |
|
|
200
|
-
| `--dry-run` | Always, the first time. |
|
|
201
|
-
| `--app <dir>` | Monorepos. Without it, `init` finds several apps and asks which you meant. |
|
|
202
|
-
| `--no-mcp` | Your MCP config is managed elsewhere (dotfiles, a team template). |
|
|
203
|
-
| `--no-install` | You want to add the dependencies yourself, at your own versions. |
|
|
204
|
-
| `--port N` | Something else already owns the default port. |
|
|
198
|
+
Three of these are answers only the caller has. `init` reads your repository; it cannot read your request, and these live only there.
|
|
205
199
|
|
|
206
|
-
|
|
200
|
+
| Flag | When you want it |
|
|
201
|
+
| --- | --- |
|
|
202
|
+
| `--flow "<what>"` | **Name the journey worth proving.** `init` can list the buttons on a page; it cannot know that checkout matters and the theme toggle does not. Naming it is the difference between a drive that finishes and one that spends its budget looking for something to do. |
|
|
203
|
+
| `--env KEY=VALUE` | What the app needs to reach a usable state: the key from `.env.example`, the mock backend, the variable that skips an auth wall. Repeatable, and a value may contain spaces and equals signs. Without it a real app sits on a login screen and there is no flow to drive. |
|
|
204
|
+
| `--app <dir>` | Monorepos. `init` can find the apps that are servable; only your request says which one you are working in. |
|
|
205
|
+
| `--license <key>` | Writes `RETICLE_LICENSE_KEY` to `.env` and keeps `.env` out of git. Do not do those two by hand. |
|
|
206
|
+
| `--json` | One object on stdout: what was wired, what connected, the verdict, and an `agentTodo` array. For agents. |
|
|
207
|
+
| `--files-only` | Write the files, register the MCP server with every agent on the machine, pre-approve Reticle's tools, and stop: no dev server, no drive. What `init` did before it learned to boot the app, and the upgrade path for a machine that installed Reticle on an earlier version. |
|
|
208
|
+
| `--no-open` | Do not open a browser: CI, a container, an SSH session, or a tab you already have. |
|
|
209
|
+
| `--no-drive` | Stop once a session connects and leave the verdict to you. The only honest way to skip it. |
|
|
210
|
+
| `--dry-run` | See the plan before anything is written. |
|
|
211
|
+
| `--no-mcp` | Your MCP config is managed elsewhere (dotfiles, a team template). |
|
|
212
|
+
| `--no-install` | You want to add the dependencies yourself, at your own versions. |
|
|
213
|
+
| `--port N` | Something else already owns the bridge port. Not the dev server's port. |
|
|
207
214
|
|
|
208
|
-
|
|
215
|
+
## Already installed? Mostly automatic
|
|
209
216
|
|
|
210
|
-
|
|
217
|
+
The first time `reticle mcp` starts on a new version it applies the pre-approval rules for the agents it finds, once, and records that it did. You get that by upgrading. There is nothing to type.
|
|
211
218
|
|
|
212
|
-
|
|
219
|
+
One case is deliberately left out. Creating Cursor's `permissions.json` when you do not already have one supersedes whatever you approved inside Cursor itself, so a version bump doing it silently would make your OTHER MCP servers start prompting again, with nothing to connect that to us. Reticle defers it and waits to be asked:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
npx @reticlehq/server@latest init --files-only
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
That writes the files, registers the MCP server with every agent it finds, pre-approves Reticle's tools so the per-call Accept dialog stops, and stops there: no dev server, no browser, no drive. Every step is idempotent, so a repo that is already wired reports "already" and changes nothing.
|
|
226
|
+
|
|
227
|
+
Two things to know afterwards:
|
|
228
|
+
|
|
229
|
+
- **A GUI client reads its config at startup.** Cursor, Antigravity, Claude Desktop and VS Code need a window reload before the new rules take effect. The CLIs pick them up on their next run.
|
|
230
|
+
- **The pre-approval is scoped to `reticle` alone**, never a blanket rule for every MCP server, and never a global auto-run switch. If a client's approval file did not exist before, `init` says so in a line, because in Cursor's case that file supersedes what you had approved inside the app.
|
|
231
|
+
|
|
232
|
+
Drop `--files-only` to get the full run: boot the app, drive a flow, return a verdict.
|
|
233
|
+
|
|
234
|
+
## The two restarts you no longer have to think about
|
|
235
|
+
|
|
236
|
+
**Your dev server: `init` handles it.** A dev server that was already running read your build config before `init` edited it, so it keeps serving the old bundle and nothing connects. `init` restarts it and waits for the port to answer, rather than telling you to.
|
|
237
|
+
|
|
238
|
+
**Your agent: not on the critical path any more.** Your agent read its MCP server list at startup, before Reticle existed, and no slash command re-reads it. `/mcp` manages servers already loaded, so it cannot pick up a new one. That used to mean stopping the install to restart. It does not now: the flow is driven by a child agent process started after registration, which reads the list `init` just wrote. Your own session picks the tools up whenever you next start it, and nothing is waiting on that. This is a once-per-machine annoyance in any case, because Reticle registers globally.
|
|
213
239
|
|
|
214
240
|
## Confirm it worked
|
|
215
241
|
|
package/docs/install-manual.mdx
CHANGED
|
@@ -6,13 +6,13 @@ icon: window
|
|
|
6
6
|
|
|
7
7
|
`@reticlehq/browser` is the Reticle SDK that runs inside your page. It installs the observers, builds semantic snapshots, executes actions, and talks to the bridge. Install it directly only if you are **not** on React or want to call `connect()` yourself, because [`@reticlehq/react`](/packages/react) already re-exports all of it.
|
|
8
8
|
|
|
9
|
-
**Apache 2.0. Depends on `@reticlehq/core
|
|
9
|
+
**Apache 2.0. Depends on `@reticlehq/core`.**
|
|
10
10
|
|
|
11
11
|
## Why it exists
|
|
12
12
|
|
|
13
13
|
This is what makes Reticle different from a browser-automation tool. Because it runs _inside_ the app rather than driving it from outside, it can see a state mutation and a fired signal, not just a rendered pixel. It never imports a Node API; that boundary is enforced by the dependency graph.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
[`reticle_query`](/tools-query) speaks role, label and testid instead of CSS selectors through its own local accessibility engine: one engine computes both what elements are called and what they match by, so a reported identity always round-trips.
|
|
16
16
|
|
|
17
17
|
## When you need it directly
|
|
18
18
|
|
package/docs/packages/server.mdx
CHANGED
|
@@ -64,7 +64,7 @@ await server.close();
|
|
|
64
64
|
| `reticleRoot` | `string` | `cwd()/.reticle` |
|
|
65
65
|
| `pairingTokenDir` | `string` | `~/.reticle` |
|
|
66
66
|
| `now` | `() => number` | `Date.now` |
|
|
67
|
-
| `toolProfile` | `string` |
|
|
67
|
+
| `toolProfile` | `string` | retired names (`core`/`full`/…) still map. Live switch is `RETICLE_ADVERTISE_ALL_TOOLS=1`. Default is the lean surface |
|
|
68
68
|
| `httpVerify` | `boolean` | `false` |
|
|
69
69
|
| `httpVerifyPort` | `number` | `RETICLE_VERIFY_DEFAULT_PORT` (`7331`) |
|
|
70
70
|
| `httpVerifyToken` | `string` | `RETICLE_VERIFY_TOKEN` |
|
package/docs/packages.mdx
CHANGED
|
@@ -8,9 +8,11 @@ icon: cubes
|
|
|
8
8
|
Reticle is eleven packages, and most people install two. This page exists so you can tell which two, and so that the ones you skip stop looking mysterious.
|
|
9
9
|
|
|
10
10
|
<Note>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
Everything ships together at one version: whatever `npm view @reticlehq/core version` says, every
|
|
12
|
+
other `@reticlehq/*` package says too, and so does the `reticle-tauri` crate on crates.io.
|
|
13
|
+
|
|
14
|
+
It was versioned independently until 2.12.0, and that turned out to mean _stuck_: the crate sat at `0.1.0` from the day it was written, the publish job skipped it every release because that version already existed, and no Rust-side fix reached anybody. Lockstep costs one line in the bump script and cannot fail that way.
|
|
15
|
+
|
|
14
16
|
</Note>
|
|
15
17
|
|
|
16
18
|
## Which ones do I need?
|
|
@@ -70,7 +72,7 @@ Those rules are why the browser SDK cannot accidentally pull in a filesystem cal
|
|
|
70
72
|
|
|
71
73
|
**Why it exists:** this is the part that makes Reticle different from a browser-automation tool. Because it runs _inside_ the app rather than driving it from outside, it can see a state mutation and a fired signal, not just a rendered pixel.
|
|
72
74
|
|
|
73
|
-
**Depends on:** `@reticlehq/core
|
|
75
|
+
**Depends on:** `@reticlehq/core`. [`reticle_query`](/tools-query) speaks role, label and testid rather than CSS selectors through its own local accessibility engine, so what a snapshot reports is exactly what a query matches.
|
|
74
76
|
|
|
75
77
|
**Install it directly when** you are not on React, or you want `connect()` under your own control:
|
|
76
78
|
|
|
@@ -199,13 +201,13 @@ A lint rule makes the signal layer self-enforcing, which is the only way a conve
|
|
|
199
201
|
|
|
200
202
|
## reticle-tauri
|
|
201
203
|
|
|
202
|
-
**The Rust crate**, on crates.io. Versioned
|
|
204
|
+
**The Rust crate**, on crates.io. Versioned in lockstep with the npm packages, so `2.11` here and `2.11` there mean the same release.
|
|
203
205
|
|
|
204
206
|
**Why it exists:** Tauri IPC observation needs nothing on the Rust side; an `invoke('load_todos')` already reaches Reticle as `ipc://load_todos`. You only need this crate for screenshots and headless mode.
|
|
205
207
|
|
|
206
208
|
```toml
|
|
207
209
|
[dependencies]
|
|
208
|
-
reticle-tauri = "
|
|
210
|
+
reticle-tauri = "2.13"
|
|
209
211
|
```
|
|
210
212
|
|
|
211
213
|
<Warning>
|
|
@@ -93,6 +93,23 @@ Live, clickable demo of each: `apps/vibe-builder-demo/` (set `BUG_MODE=…`). Pr
|
|
|
93
93
|
|
|
94
94
|
---
|
|
95
95
|
|
|
96
|
+
## The minimal attach contract (for a harness or MCP host)
|
|
97
|
+
|
|
98
|
+
Reticle is a stdio MCP server. A host that wires it correctly does four things, and each one is a step Reticle can see:
|
|
99
|
+
|
|
100
|
+
1. **Spawn it.** `npx @reticlehq/server mcp`, over stdio, one process per host. That process is the proxy: it starts the local daemon on demand, reconnects on its own when the stream drops, and answers from cache while a daemon comes back.
|
|
101
|
+
2. **Complete `initialize`.** Reticle answers the handshake itself when the daemon is slow, so a host that waits for a reply gets one either way.
|
|
102
|
+
3. **Send `tools/list`, and send it again on `notifications/tools/list_changed`.** This is the step hosts skip. Registering a server is not the same as enumerating it: a host can register Reticle and never ask for the tool list until the client is restarted, and the model then has no Reticle tools at all while the install looks healthy from every other angle. Reticle declares `tools.listChanged` so a host that honours the notification recovers without a restart.
|
|
103
|
+
4. **Call the tools.** `tools/call`, with the tool name and its arguments.
|
|
104
|
+
|
|
105
|
+
`reticle status` reports how far a host has got. `mcpClient: "never-attached"` means no client has started the server on this port. `mcpClient: "never-enumerated"` means one started it and never asked for the tool list, which is the state a client restart fixes. `mcpClient: "enumerated"` means the client side is done, and anything still missing is the app rather than the host. The record is per port rather than per client, and it begins the first time a client starts a Reticle version that keeps it, so `status` says both of those out loud instead of naming a client it cannot see.
|
|
106
|
+
|
|
107
|
+
### Hosts that cap the number of tools
|
|
108
|
+
|
|
109
|
+
Some editors cap the total tool count across every MCP server, which is why Reticle advertises a small surface instead of everything it can do. Nothing is out of reach: `reticle_tools { names: [...] }` lists the tools and returns the full argument grammar for the ones you name, and `reticle_run { tool, args }` invokes any of them, advertised or not. A host that is short on tool slots pays for the advertised handful and still reaches the whole surface through that pair. See [`reticle_tools` and `reticle_run`](/tools-tools-and-run).
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
96
113
|
## Exact steps per platform
|
|
97
114
|
|
|
98
115
|
The shape is identical (in-app SDK in the template → verify in the sandbox → act on the verdict); the specifics differ by where each platform runs the preview.
|
package/docs/predicates.mdx
CHANGED
|
@@ -115,6 +115,14 @@ A passing route verdict quotes the transition itself:
|
|
|
115
115
|
|
|
116
116
|
The app emitted a named signal via `reticle.signal()`. `dataMatches` is shallow JSON matching, and `*` means "present, any value".
|
|
117
117
|
|
|
118
|
+
`count` works here exactly as it does on `net`:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{ "kind": "signal", "name": "order:placed", "count": 1 }
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Exactly once.** A handler wired twice fires the signal twice and leaves the store in the right shape either way, so every state-only check stays green. `count: 0` is a claim of its own (the signal never fired) and is not the same as leaving `count` out, which asserts presence.
|
|
125
|
+
|
|
118
126
|
Nothing outranks this. A `200` proves the server was reachable; a rendered row proves React ran. A signal is the application itself saying the thing succeeded. See [instrumentation](/instrumentation) for how to emit them.
|
|
119
127
|
|
|
120
128
|
### state
|