@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
|
@@ -8,9 +8,12 @@ export function predicateToExpect(predicate) {
|
|
|
8
8
|
case PredicateKind.SIGNAL: {
|
|
9
9
|
if (predicate.name === undefined)
|
|
10
10
|
return undefined;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
const signal = { signal: predicate.name };
|
|
12
|
+
if (predicate.dataMatches !== undefined)
|
|
13
|
+
signal.signalData = predicate.dataMatches;
|
|
14
|
+
if (predicate.count !== undefined)
|
|
15
|
+
signal.signalCount = predicate.count;
|
|
16
|
+
return signal;
|
|
14
17
|
}
|
|
15
18
|
case PredicateKind.NET: {
|
|
16
19
|
const net = {};
|
|
@@ -75,29 +78,47 @@ export function predicateToExpect(predicate) {
|
|
|
75
78
|
}
|
|
76
79
|
}
|
|
77
80
|
/**
|
|
78
|
-
* The subset a REPLAY actually enforces
|
|
81
|
+
* The subset a REPLAY actually enforces.
|
|
82
|
+
*
|
|
83
|
+
* The rule has never changed: never write an assertion into a flow file that nothing evaluates. A
|
|
84
|
+
* flow reporting `grade: "asserted"` while its assertion is read by no one is a false green, in the
|
|
85
|
+
* feature whose entire purpose is preventing them.
|
|
79
86
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
87
|
+
* What changed is the SET. This kept only `element.testid` and `state`, because for a long time
|
|
88
|
+
* those were the only kinds replay checked — and the note here said lifting it "requires replay to
|
|
89
|
+
* evaluate them per step". Replay now does exactly that: `assertStepExpect` compiles every
|
|
90
|
+
* remaining kind through `successToPredicate` and waits on it. The condition was met and the filter
|
|
91
|
+
* was not updated, so the two drifted.
|
|
84
92
|
*
|
|
85
|
-
* That
|
|
86
|
-
*
|
|
87
|
-
*
|
|
93
|
+
* That drift had a cost, and it fell on the agent. `reticle_act_and_wait { until }` IS the agent
|
|
94
|
+
* saying what success means, and `net` is overwhelmingly what it says. Every one of those was
|
|
95
|
+
* discarded at capture, so an agent-recorded flow reached disk assertion-free BY CONSTRUCTION and
|
|
96
|
+
* `reticle_verify` then correctly called it `unverifiable` — the record → save → verify path
|
|
97
|
+
* completing all the way to a run that could never be a pass. Found by driving it.
|
|
88
98
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* machinery exists: successToPredicate + the predicate engine). Until then, recording them would
|
|
92
|
-
* trade a weak flow for a lying one.
|
|
99
|
+
* The list below is exactly what `successToPredicate` reads, plus the testid the step runner
|
|
100
|
+
* asserts directly against the DOM. Anything it cannot compile is still dropped.
|
|
93
101
|
*/
|
|
94
102
|
export function enforcedOnReplay(expect) {
|
|
95
103
|
if (expect === undefined)
|
|
96
104
|
return undefined;
|
|
97
105
|
const kept = {};
|
|
106
|
+
// The step runner asserts this one directly against the live DOM, before the predicate engine.
|
|
98
107
|
if (expect.element?.testid !== undefined)
|
|
99
108
|
kept.element = expect.element;
|
|
109
|
+
// Everything `successToPredicate` can compile. Replay evaluates EVERY kind of expect through it
|
|
110
|
+
// (see assertStepExpect); this list is what that function actually reads.
|
|
100
111
|
if (expect.state !== undefined)
|
|
101
112
|
kept.state = expect.state;
|
|
113
|
+
if (expect.signal !== undefined)
|
|
114
|
+
kept.signal = expect.signal;
|
|
115
|
+
if (expect.signalData !== undefined)
|
|
116
|
+
kept.signalData = expect.signalData;
|
|
117
|
+
if (expect.signalCount !== undefined)
|
|
118
|
+
kept.signalCount = expect.signalCount;
|
|
119
|
+
if (expect.net !== undefined)
|
|
120
|
+
kept.net = expect.net;
|
|
121
|
+
if (expect.console !== undefined)
|
|
122
|
+
kept.console = expect.console;
|
|
102
123
|
return 0 === Object.keys(kept).length ? undefined : kept;
|
|
103
124
|
}
|
|
@@ -13,12 +13,15 @@ export interface RecordedStep {
|
|
|
13
13
|
interface ActiveRecording {
|
|
14
14
|
cursor: number;
|
|
15
15
|
steps: RecordedStep[];
|
|
16
|
+
/** The route the journey began on. See CompiledProgram.startPath. */
|
|
17
|
+
startPath?: string;
|
|
16
18
|
}
|
|
17
19
|
/** A finished, replayable program compiled from a recording. */
|
|
18
20
|
export interface CompiledProgram {
|
|
19
21
|
name: string;
|
|
20
22
|
version: number;
|
|
21
23
|
steps: RecordedStep[];
|
|
24
|
+
startPath?: string;
|
|
22
25
|
}
|
|
23
26
|
/**
|
|
24
27
|
* Tracks in-flight recordings (name -> { buffer cursor at record_start, captured steps })
|
|
@@ -26,7 +29,7 @@ export interface CompiledProgram {
|
|
|
26
29
|
*/
|
|
27
30
|
export declare class RecordingStore {
|
|
28
31
|
#private;
|
|
29
|
-
start(name: string, cursor: number): void;
|
|
32
|
+
start(name: string, cursor: number, startPath?: string): void;
|
|
30
33
|
isRecording(name: string): boolean;
|
|
31
34
|
/**
|
|
32
35
|
* Number of steps captured so far in the named ACTIVE recording (0 if it
|
|
@@ -41,5 +44,14 @@ export declare class RecordingStore {
|
|
|
41
44
|
saveCompiled(program: CompiledProgram): void;
|
|
42
45
|
getCompiled(name: string): CompiledProgram | undefined;
|
|
43
46
|
active(): string[];
|
|
47
|
+
/**
|
|
48
|
+
* Names of recordings that have been STOPPED and compiled.
|
|
49
|
+
*
|
|
50
|
+
* The mirror of `active()`, and needed for the same defaulting: after `reticle_record stop` a
|
|
51
|
+
* recording is no longer active, so resolving "the obvious one" from `active()` finds nothing.
|
|
52
|
+
* Saving it then demanded the exact name back from the caller, which is a thing to remember for
|
|
53
|
+
* no reason when exactly one recording exists.
|
|
54
|
+
*/
|
|
55
|
+
compiled(): string[];
|
|
44
56
|
}
|
|
45
57
|
export {};
|
package/dist/flows/recordings.js
CHANGED
|
@@ -5,8 +5,12 @@
|
|
|
5
5
|
export class RecordingStore {
|
|
6
6
|
#active = new Map();
|
|
7
7
|
#compiled = new Map();
|
|
8
|
-
start(name, cursor) {
|
|
9
|
-
this.#active.set(name, {
|
|
8
|
+
start(name, cursor, startPath) {
|
|
9
|
+
this.#active.set(name, {
|
|
10
|
+
cursor,
|
|
11
|
+
steps: [],
|
|
12
|
+
...(startPath === undefined ? {} : { startPath }),
|
|
13
|
+
});
|
|
10
14
|
}
|
|
11
15
|
isRecording(name) {
|
|
12
16
|
return this.#active.has(name);
|
|
@@ -39,4 +43,15 @@ export class RecordingStore {
|
|
|
39
43
|
active() {
|
|
40
44
|
return [...this.#active.keys()];
|
|
41
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Names of recordings that have been STOPPED and compiled.
|
|
48
|
+
*
|
|
49
|
+
* The mirror of `active()`, and needed for the same defaulting: after `reticle_record stop` a
|
|
50
|
+
* recording is no longer active, so resolving "the obvious one" from `active()` finds nothing.
|
|
51
|
+
* Saving it then demanded the exact name back from the caller, which is a thing to remember for
|
|
52
|
+
* no reason when exactly one recording exists.
|
|
53
|
+
*/
|
|
54
|
+
compiled() {
|
|
55
|
+
return [...this.#compiled.keys()];
|
|
56
|
+
}
|
|
42
57
|
}
|
package/dist/flows/replay.d.ts
CHANGED
|
@@ -13,8 +13,28 @@ export declare function ambiguousTestidNote(value: string): string;
|
|
|
13
13
|
* resolution — can't drift between them.
|
|
14
14
|
*/
|
|
15
15
|
export declare function queryRefs(result: CommandResult): string[];
|
|
16
|
-
/**
|
|
17
|
-
|
|
16
|
+
/**
|
|
17
|
+
* The environment variable that supplies one redacted field.
|
|
18
|
+
*
|
|
19
|
+
* Named after the field so it is guessable from the flow alone: `auth-password` is read from
|
|
20
|
+
* `RETICLE_SECRET_AUTH_PASSWORD`. A scheme requiring a lookup table would mean the flow says a
|
|
21
|
+
* value is missing and cannot say what to set.
|
|
22
|
+
*/
|
|
23
|
+
export declare const secretEnvKey: (field: string) => string;
|
|
24
|
+
/**
|
|
25
|
+
* A destructive-action confirmation is one-shot and must never persist into a recording.
|
|
26
|
+
*
|
|
27
|
+
* This is also where a REDACTED fill is supplied back. Stripping credentials out of a git-checked
|
|
28
|
+
* flow is only half a fix: sign-in still has to replay, and a flow that drifts at step two forever
|
|
29
|
+
* because its own password was removed is a flow nobody keeps — along with everything behind the
|
|
30
|
+
* login it guards. The value comes from the environment, the one place a secret can live that is
|
|
31
|
+
* neither the customer's repository nor our database.
|
|
32
|
+
*
|
|
33
|
+
* Left as the PLACEHOLDER when nothing supplies it, rather than blanked. The replay then fails at
|
|
34
|
+
* the login form with `<redacted: supply at replay>` visible in the field, which names its own fix;
|
|
35
|
+
* an empty box fails identically and tells the reader nothing.
|
|
36
|
+
*/
|
|
37
|
+
export declare function replayActionArgs(value: unknown, confirmDangerous?: boolean, field?: string): Record<string, unknown>;
|
|
18
38
|
/**
|
|
19
39
|
* Capture an act into every in-flight recording, or do nothing when none is running.
|
|
20
40
|
*
|
package/dist/flows/replay.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { REDACTED_FILL } from './flows.js';
|
|
1
2
|
import { DANGEROUS_ACTION_CONFIRM_ARG, ReticleCommand, QueryBy, } from '@reticlehq/core';
|
|
2
3
|
import { ReticleTool } from '../tools/tool-names.js';
|
|
3
4
|
import { predicateToExpect, enforcedOnReplay } from './predicate-to-expect.js';
|
|
@@ -23,12 +24,37 @@ export function queryRefs(result) {
|
|
|
23
24
|
const elements = Array.isArray(payload['elements']) ? payload['elements'] : [];
|
|
24
25
|
return elements.map((e) => asString(asRecord(e)['ref']) ?? '').filter((r) => r.length > 0);
|
|
25
26
|
}
|
|
26
|
-
/**
|
|
27
|
-
|
|
27
|
+
/**
|
|
28
|
+
* The environment variable that supplies one redacted field.
|
|
29
|
+
*
|
|
30
|
+
* Named after the field so it is guessable from the flow alone: `auth-password` is read from
|
|
31
|
+
* `RETICLE_SECRET_AUTH_PASSWORD`. A scheme requiring a lookup table would mean the flow says a
|
|
32
|
+
* value is missing and cannot say what to set.
|
|
33
|
+
*/
|
|
34
|
+
export const secretEnvKey = (field) => `RETICLE_SECRET_${field.replace(/[^a-zA-Z0-9]+/g, '_').toUpperCase()}`;
|
|
35
|
+
/**
|
|
36
|
+
* A destructive-action confirmation is one-shot and must never persist into a recording.
|
|
37
|
+
*
|
|
38
|
+
* This is also where a REDACTED fill is supplied back. Stripping credentials out of a git-checked
|
|
39
|
+
* flow is only half a fix: sign-in still has to replay, and a flow that drifts at step two forever
|
|
40
|
+
* because its own password was removed is a flow nobody keeps — along with everything behind the
|
|
41
|
+
* login it guards. The value comes from the environment, the one place a secret can live that is
|
|
42
|
+
* neither the customer's repository nor our database.
|
|
43
|
+
*
|
|
44
|
+
* Left as the PLACEHOLDER when nothing supplies it, rather than blanked. The replay then fails at
|
|
45
|
+
* the login form with `<redacted: supply at replay>` visible in the field, which names its own fix;
|
|
46
|
+
* an empty box fails identically and tells the reader nothing.
|
|
47
|
+
*/
|
|
48
|
+
export function replayActionArgs(value, confirmDangerous = false, field) {
|
|
28
49
|
const args = { ...asRecord(value) };
|
|
29
50
|
delete args[DANGEROUS_ACTION_CONFIRM_ARG];
|
|
30
51
|
if (confirmDangerous)
|
|
31
52
|
args[DANGEROUS_ACTION_CONFIRM_ARG] = true;
|
|
53
|
+
if (REDACTED_FILL === args['value'] && field !== undefined) {
|
|
54
|
+
const supplied = process.env[secretEnvKey(field)];
|
|
55
|
+
if (supplied !== undefined && supplied.length > 0)
|
|
56
|
+
args['value'] = supplied;
|
|
57
|
+
}
|
|
32
58
|
return args;
|
|
33
59
|
}
|
|
34
60
|
/** The element's source location from an action result, when the framework stamped one. */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { VerifyMode } from '../cloud/cloud-config.js';
|
|
2
|
-
import { submitServerVerification } from '../cloud/cloud-sync.js';
|
|
2
|
+
import { CLOUD_VERIFY_TIMEOUT_MS, cloudFetch, submitServerVerification, } from '../cloud/cloud-sync.js';
|
|
3
|
+
import { log } from '../log.js';
|
|
3
4
|
const PASS = 'pass';
|
|
4
5
|
const UNVERIFIED = 'unverified';
|
|
5
6
|
const SOURCE = 'reticle-mcp';
|
|
@@ -31,7 +32,20 @@ export async function runServerVerify(deps, cloud, sessionId, flows) {
|
|
|
31
32
|
// The server hits the URL itself; with no URL (or a localhost one it can't reach) fall back to local.
|
|
32
33
|
if (previewUrl === undefined || 0 === previewUrl.length)
|
|
33
34
|
return null;
|
|
34
|
-
|
|
35
|
+
// The submit blocks while the hosted runner drives a real browser, so it gets the long budget — but a
|
|
36
|
+
// budget it must have: this is awaited inside the verify tool, and an unbounded wait here is an MCP
|
|
37
|
+
// call that never returns. A timeout is reported and then falls back to the local replay below.
|
|
38
|
+
const report = await submitServerVerification({ previewUrl, flows, source: SOURCE }, cloud.config, async (url, init) => {
|
|
39
|
+
try {
|
|
40
|
+
return await cloudFetch(url, init, CLOUD_VERIFY_TIMEOUT_MS);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
log('cloud-server-verify-failed', {
|
|
44
|
+
error: error instanceof Error ? error.message : String(error),
|
|
45
|
+
});
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
35
49
|
if (null === report)
|
|
36
50
|
return null;
|
|
37
51
|
// The hosted runner said it couldn't actually verify (e.g. it's not enabled yet). Never surface that as
|
|
@@ -5,6 +5,7 @@ import { attributedFailures } from './attributed-failure.js';
|
|
|
5
5
|
import { Verified } from '@reticlehq/core';
|
|
6
6
|
import { ReticleTool } from '../tools/tool-names.js';
|
|
7
7
|
import { asNumber, asRecord, asString } from '../tools/tools-helpers.js';
|
|
8
|
+
import { workerCountSchema } from '../tools/numeric-bounds.js';
|
|
8
9
|
import { loadNamedFlows, resolveChangedFiles } from '../cli/cli-flow-commands.js';
|
|
9
10
|
import { affectedSavedFlows } from './flow-sources.js';
|
|
10
11
|
import { FLOW_TOOLS } from './flow-tools.js';
|
|
@@ -25,8 +26,7 @@ export const VERIFY_CHANGE_TOOLS = [
|
|
|
25
26
|
.string()
|
|
26
27
|
.optional()
|
|
27
28
|
.describe('Git ref to diff against (e.g. "HEAD~1", "main"). Unioned with `files`.'),
|
|
28
|
-
parallel:
|
|
29
|
-
.number()
|
|
29
|
+
parallel: workerCountSchema
|
|
30
30
|
.optional()
|
|
31
31
|
.describe('Replay this many affected flows at once (needs the browser pool).'),
|
|
32
32
|
sessionId: z
|
|
@@ -197,7 +197,13 @@ async function inspectAfterReplay(deps, args, cursor) {
|
|
|
197
197
|
}
|
|
198
198
|
try {
|
|
199
199
|
const session = deps.sessions.resolve(asString(args['sessionId']));
|
|
200
|
-
const contradictions = findContradictions(session.eventsSince(cursor)
|
|
200
|
+
const contradictions = findContradictions(session.eventsSince(cursor), {
|
|
201
|
+
currentDocumentId: session.currentDocumentId,
|
|
202
|
+
currentEditEpoch: session.currentEditEpoch,
|
|
203
|
+
appOrigin: session.url,
|
|
204
|
+
// The replay is the action, and the cursor is where it started.
|
|
205
|
+
actionSince: cursor,
|
|
206
|
+
});
|
|
201
207
|
const snapshot = await session.command(ReticleCommand.SNAPSHOT, {
|
|
202
208
|
mode: SnapshotMode.INTERACTIVE,
|
|
203
209
|
});
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export { BlindSpotKind } from '@reticlehq/core';
|
|
8
8
|
import { BlindSpotKind, type ReticleEvent } from '@reticlehq/core';
|
|
9
|
-
interface BlindSpot {
|
|
9
|
+
export interface BlindSpot {
|
|
10
10
|
kind: BlindSpotKind;
|
|
11
11
|
count: number;
|
|
12
12
|
}
|
|
@@ -55,6 +55,15 @@ export declare function buildCoverageStatement(spots: readonly BlindSpot[]): Cov
|
|
|
55
55
|
* from what the SDK observed during the action, with no extra round-trip.
|
|
56
56
|
*/
|
|
57
57
|
export declare function blindSpotsFromEvents(events: readonly ReticleEvent[]): BlindSpot[];
|
|
58
|
+
/**
|
|
59
|
+
* Drop Electron-only coverage rows unless this session is actually an Electron renderer.
|
|
60
|
+
*
|
|
61
|
+
* The kinds live in the same vocabulary as "no store registered", so listing whatever is present
|
|
62
|
+
* reported a Vite + React tab as an un-instrumented Electron renderer. The session already knows
|
|
63
|
+
* the runtime (PAGE_HEALTH). Unknown runtime (older SDK) keeps the rows — dropping them would hide
|
|
64
|
+
* a real missing-preload warning.
|
|
65
|
+
*/
|
|
66
|
+
export declare function spotsForRuntime(spots: readonly BlindSpot[], runtime: string | undefined): BlindSpot[];
|
|
58
67
|
/**
|
|
59
68
|
* Blind spots from the session's remembered LEVEL state rather than from a window of events.
|
|
60
69
|
*
|
|
@@ -63,25 +72,35 @@ export declare function blindSpotsFromEvents(events: readonly ReticleEvent[]): B
|
|
|
63
72
|
* reports "full" for a page a third of which is unobservable — and the act tool's own description
|
|
64
73
|
* tells harnesses to gate on that block. Ask the session what is true now instead of inferring it
|
|
65
74
|
* from what happened to be said recently.
|
|
75
|
+
*
|
|
76
|
+
* `runtime` gates Electron-only kinds (see `spotsForRuntime`) so a web session cannot inherit them
|
|
77
|
+
* from the coverage vocabulary.
|
|
66
78
|
*/
|
|
67
|
-
export declare function blindSpotsFromState(state: Readonly<Record<string, number
|
|
79
|
+
export declare function blindSpotsFromState(state: Readonly<Record<string, number>>, runtime?: string): BlindSpot[];
|
|
68
80
|
/**
|
|
69
|
-
*
|
|
81
|
+
* The narrow slice of a predicate the absence-blind-spot check needs.
|
|
70
82
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
83
|
+
* Kept minimal to avoid pulling the full Predicate type (and its transitive deps) into the
|
|
84
|
+
* honesty module. Anything that quacks like this works.
|
|
85
|
+
*/
|
|
86
|
+
interface AbsencePredicate {
|
|
87
|
+
kind: string;
|
|
88
|
+
absent?: boolean;
|
|
89
|
+
query?: {
|
|
90
|
+
scope?: unknown;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* When an absence assertion targets a page with regions Reticle cannot observe, "the element is
|
|
95
|
+
* absent" means only "it is absent in what I CAN see". Returns a note when that distinction
|
|
96
|
+
* matters, undefined otherwise.
|
|
78
97
|
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
98
|
+
* Fires on three blind-spot kinds:
|
|
99
|
+
* - CROSS_ORIGIN_IFRAME (only when the predicate is scoped to a frame region)
|
|
100
|
+
* - VIRTUALIZED_UNMOUNTED — a row that was never rendered could hold the element
|
|
101
|
+
* - CLOSED_SHADOW_ROOT — a subtree Reticle cannot see into
|
|
83
102
|
*/
|
|
84
|
-
export declare function
|
|
103
|
+
export declare function absenceBlindSpotNote(predicate: AbsencePredicate, spots: readonly BlindSpot[]): string | undefined;
|
|
85
104
|
/** The impeaching note for a transport gap, or undefined when the window was intact. */
|
|
86
105
|
export declare function transportGapNote(events: readonly ReticleEvent[]): string | undefined;
|
|
87
106
|
/**
|
|
@@ -93,3 +112,20 @@ export declare function transportGapNote(events: readonly ReticleEvent[]): strin
|
|
|
93
112
|
* predicate would eventually disagree with the first about what "unwatched" means.
|
|
94
113
|
*/
|
|
95
114
|
export declare function isStateUnwatched(spots: readonly BlindSpot[]): boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Does a passing verdict on this predicate REST on the window being complete?
|
|
117
|
+
*
|
|
118
|
+
* Only an absence claim does. A positive assertion that passed found its evidence, and events aged
|
|
119
|
+
* out elsewhere in the buffer do not unmake it. An absence claim concluded "nothing is there" — and
|
|
120
|
+
* the thing the buffer dropped is precisely the disproof, so "absent" degrades to "absent in what I
|
|
121
|
+
* still hold".
|
|
122
|
+
*
|
|
123
|
+
* The distinction is not optional. Scarce-loss is recorded for AGE eviction too, so `lostSince(0)`
|
|
124
|
+
* is true on any session older than the 60s cutoff; impeaching every verdict over a caller-chosen
|
|
125
|
+
* window would make `unknown` the answer to everything, which this repo has already paid for once.
|
|
126
|
+
*/
|
|
127
|
+
export declare function restsOnCompleteWindow(predicate: {
|
|
128
|
+
kind: string;
|
|
129
|
+
absent?: boolean;
|
|
130
|
+
predicate?: unknown;
|
|
131
|
+
}): boolean;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// The kind enum lives in core (it crosses the wire in a BLIND_SPOT event); re-exported here so existing
|
|
8
8
|
// honesty-side imports keep working.
|
|
9
9
|
export { BlindSpotKind } from '@reticlehq/core';
|
|
10
|
-
import { BlindSpotKind, EventType, ReticleEnv, TRANSPORT_LIMITS, } from '@reticlehq/core';
|
|
10
|
+
import { AppRuntime, BlindSpotKind, EventType, PredicateKind, ReticleEnv, TRANSPORT_LIMITS, isDesktopBlindSpot, } from '@reticlehq/core';
|
|
11
11
|
/**
|
|
12
12
|
* Whether the observation window saw everything it was asked about.
|
|
13
13
|
*
|
|
@@ -107,6 +107,19 @@ export function blindSpotsFromEvents(events) {
|
|
|
107
107
|
}
|
|
108
108
|
return [...latest].map(([kind, count]) => ({ kind, count }));
|
|
109
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Drop Electron-only coverage rows unless this session is actually an Electron renderer.
|
|
112
|
+
*
|
|
113
|
+
* The kinds live in the same vocabulary as "no store registered", so listing whatever is present
|
|
114
|
+
* reported a Vite + React tab as an un-instrumented Electron renderer. The session already knows
|
|
115
|
+
* the runtime (PAGE_HEALTH). Unknown runtime (older SDK) keeps the rows — dropping them would hide
|
|
116
|
+
* a real missing-preload warning.
|
|
117
|
+
*/
|
|
118
|
+
export function spotsForRuntime(spots, runtime) {
|
|
119
|
+
if (runtime === undefined || AppRuntime.ELECTRON === runtime)
|
|
120
|
+
return [...spots];
|
|
121
|
+
return spots.filter((spot) => !isDesktopBlindSpot(spot.kind));
|
|
122
|
+
}
|
|
110
123
|
/**
|
|
111
124
|
* Blind spots from the session's remembered LEVEL state rather than from a window of events.
|
|
112
125
|
*
|
|
@@ -115,9 +128,16 @@ export function blindSpotsFromEvents(events) {
|
|
|
115
128
|
* reports "full" for a page a third of which is unobservable — and the act tool's own description
|
|
116
129
|
* tells harnesses to gate on that block. Ask the session what is true now instead of inferring it
|
|
117
130
|
* from what happened to be said recently.
|
|
131
|
+
*
|
|
132
|
+
* `runtime` gates Electron-only kinds (see `spotsForRuntime`) so a web session cannot inherit them
|
|
133
|
+
* from the coverage vocabulary.
|
|
118
134
|
*/
|
|
119
|
-
export function blindSpotsFromState(state) {
|
|
120
|
-
|
|
135
|
+
export function blindSpotsFromState(state, runtime) {
|
|
136
|
+
const spots = Object.entries(state).map(([kind, count]) => ({
|
|
137
|
+
kind: kind,
|
|
138
|
+
count,
|
|
139
|
+
}));
|
|
140
|
+
return spotsForRuntime(spots, runtime);
|
|
121
141
|
}
|
|
122
142
|
/**
|
|
123
143
|
* Events the BROWSER's own transport queue threw away inside this window, or 0.
|
|
@@ -135,7 +155,7 @@ export function blindSpotsFromState(state) {
|
|
|
135
155
|
* every real app, and a caveat that is always present is one nobody reads. TRANSPORT_OVERFLOW is the
|
|
136
156
|
* honest "arbitrary events are gone" marker — it cannot say which.
|
|
137
157
|
*/
|
|
138
|
-
|
|
158
|
+
function droppedByTransport(events) {
|
|
139
159
|
let dropped = 0;
|
|
140
160
|
for (const e of events) {
|
|
141
161
|
if (e.type !== EventType.TRANSPORT_OVERFLOW)
|
|
@@ -145,6 +165,29 @@ export function droppedByTransport(events) {
|
|
|
145
165
|
}
|
|
146
166
|
return dropped;
|
|
147
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* When an absence assertion targets a page with regions Reticle cannot observe, "the element is
|
|
170
|
+
* absent" means only "it is absent in what I CAN see". Returns a note when that distinction
|
|
171
|
+
* matters, undefined otherwise.
|
|
172
|
+
*
|
|
173
|
+
* Fires on three blind-spot kinds:
|
|
174
|
+
* - CROSS_ORIGIN_IFRAME (only when the predicate is scoped to a frame region)
|
|
175
|
+
* - VIRTUALIZED_UNMOUNTED — a row that was never rendered could hold the element
|
|
176
|
+
* - CLOSED_SHADOW_ROOT — a subtree Reticle cannot see into
|
|
177
|
+
*/
|
|
178
|
+
export function absenceBlindSpotNote(predicate, spots) {
|
|
179
|
+
if ('element' !== predicate.kind || true !== predicate.absent)
|
|
180
|
+
return undefined;
|
|
181
|
+
const relevant = spots.filter((spot) => spot.count > 0 &&
|
|
182
|
+
(spot.kind === BlindSpotKind.CROSS_ORIGIN_IFRAME
|
|
183
|
+
? undefined !== predicate.query?.scope
|
|
184
|
+
: spot.kind === BlindSpotKind.VIRTUALIZED_UNMOUNTED ||
|
|
185
|
+
spot.kind === BlindSpotKind.CLOSED_SHADOW_ROOT));
|
|
186
|
+
if (0 === relevant.length)
|
|
187
|
+
return undefined;
|
|
188
|
+
const statement = buildCoverageStatement(relevant);
|
|
189
|
+
return `the absence assertion targeted a region Reticle could not observe (${statement.note ?? 'partial coverage'}), so a passing DOM check cannot prove absence`;
|
|
190
|
+
}
|
|
148
191
|
/** The impeaching note for a transport gap, or undefined when the window was intact. */
|
|
149
192
|
export function transportGapNote(events) {
|
|
150
193
|
const dropped = droppedByTransport(events);
|
|
@@ -163,3 +206,20 @@ export function transportGapNote(events) {
|
|
|
163
206
|
export function isStateUnwatched(spots) {
|
|
164
207
|
return spots.some((spot) => spot.kind === BlindSpotKind.UNWATCHED_STATE && spot.count > 0);
|
|
165
208
|
}
|
|
209
|
+
/**
|
|
210
|
+
* Does a passing verdict on this predicate REST on the window being complete?
|
|
211
|
+
*
|
|
212
|
+
* Only an absence claim does. A positive assertion that passed found its evidence, and events aged
|
|
213
|
+
* out elsewhere in the buffer do not unmake it. An absence claim concluded "nothing is there" — and
|
|
214
|
+
* the thing the buffer dropped is precisely the disproof, so "absent" degrades to "absent in what I
|
|
215
|
+
* still hold".
|
|
216
|
+
*
|
|
217
|
+
* The distinction is not optional. Scarce-loss is recorded for AGE eviction too, so `lostSince(0)`
|
|
218
|
+
* is true on any session older than the 60s cutoff; impeaching every verdict over a caller-chosen
|
|
219
|
+
* window would make `unknown` the answer to everything, which this repo has already paid for once.
|
|
220
|
+
*/
|
|
221
|
+
export function restsOnCompleteWindow(predicate) {
|
|
222
|
+
if (PredicateKind.NOT === predicate.kind)
|
|
223
|
+
return true;
|
|
224
|
+
return true === predicate.absent;
|
|
225
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { type Intent, type JournalAction } from '@reticlehq/core';
|
|
2
|
+
/**
|
|
3
|
+
* Were `reticle_context` and `reticle_intent` used at all — and did using them change anything?
|
|
4
|
+
*
|
|
5
|
+
* Both shipped with the same pre-registered disproof: *if agents never call it, cut it*. Nothing
|
|
6
|
+
* recorded whether they were called, so the disproof could never be run, and a feature whose
|
|
7
|
+
* disproof cannot be run is one nobody can kill. This is the smallest thing that makes the question
|
|
8
|
+
* answerable, per session, locally — an instrument, not a scold. The numbers exist so a FEATURE can
|
|
9
|
+
* be removed, never so an agent can be blamed for how it drove.
|
|
10
|
+
*
|
|
11
|
+
* ## Fold first, record only what nothing records
|
|
12
|
+
*
|
|
13
|
+
* Three of the four questions are already answerable from what is on disk. The intent ledger says
|
|
14
|
+
* what was declared; the journal says what was driven and what verdicts were drawn. Those are folded
|
|
15
|
+
* here and never re-stored, for the reason `run-context.ts` gives at length: two ways to compute one
|
|
16
|
+
* number is worse than one way.
|
|
17
|
+
*
|
|
18
|
+
* The journal does NOT record read-only calls — it holds actions and verdicts only. So "was
|
|
19
|
+
* `reticle_context` called" has no ledger to fold, and that one thing is recorded, in memory, on the
|
|
20
|
+
* session, by `CaptureLedger`. It is the whole of the new state.
|
|
21
|
+
*
|
|
22
|
+
* ## Absent is not zero
|
|
23
|
+
*
|
|
24
|
+
* A session this daemon has recorded nothing for — journaling off, a session adopted after the fact
|
|
25
|
+
* — reports `observed: false` and states no counts at all. It has not established that the features
|
|
26
|
+
* went unused; it has established that it was not watching. This repo has shipped the other bug
|
|
27
|
+
* twice.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* The calls this instrument needs and the journal does not keep.
|
|
31
|
+
*
|
|
32
|
+
* Deliberately a short explicit list rather than "everything that is not an action". Under-inclusion
|
|
33
|
+
* is the safe direction: a read tool missing from here lowers the hit side and the miss side by the
|
|
34
|
+
* same call, so the comparison the disproof turns on stays fair. Over-inclusion is not — a lifecycle
|
|
35
|
+
* or disk-side tool landing in here would be counted as a "read" the agent made of the app, which it
|
|
36
|
+
* was not.
|
|
37
|
+
*/
|
|
38
|
+
export declare const CAPTURED_TOOLS: ReadonlySet<string>;
|
|
39
|
+
/** One recorded call: which tool, what it was about, and how far into the run it happened. */
|
|
40
|
+
export interface CapturedCall {
|
|
41
|
+
tool: string;
|
|
42
|
+
/** The ref or target the call named, when it named one. Absent for a whole-page read. */
|
|
43
|
+
subject?: string;
|
|
44
|
+
/**
|
|
45
|
+
* The session's dispatched-action count at the moment of the call — the same counter that mints
|
|
46
|
+
* journal action ids, so it lines up with `reticle_context`'s own `step` whenever the journal is on.
|
|
47
|
+
*/
|
|
48
|
+
afterActions: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The one thing that is stored rather than folded: the read-only calls the journal never sees.
|
|
52
|
+
*
|
|
53
|
+
* In memory and per session, the same shape as `GapLedger`. It is not durable on purpose — the
|
|
54
|
+
* question is about one run, and a second file on disk would be a second thing to reconcile with the
|
|
55
|
+
* journal.
|
|
56
|
+
*/
|
|
57
|
+
export declare class CaptureLedger {
|
|
58
|
+
#private;
|
|
59
|
+
/**
|
|
60
|
+
* One call, under the name of the tool that RAN — every tool, not just the read set above.
|
|
61
|
+
*
|
|
62
|
+
* Separate from `note` because it answers a different question and is bounded differently: this
|
|
63
|
+
* map cannot outgrow the tool table however long the session runs, so it needs no cap and never
|
|
64
|
+
* has to report a floor. See honesty/tool-hit-rate.ts for what it feeds.
|
|
65
|
+
*/
|
|
66
|
+
noteTool(tool: string): void;
|
|
67
|
+
/** How many times each tool was called this session, in first-call order. */
|
|
68
|
+
toolCalls(): ReadonlyMap<string, number>;
|
|
69
|
+
note(call: CapturedCall): void;
|
|
70
|
+
calls(): readonly CapturedCall[];
|
|
71
|
+
/** How many calls fell off the front. Non-zero means the counts below are a floor. */
|
|
72
|
+
get dropped(): number;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Record one captured call against the session that made it.
|
|
76
|
+
*
|
|
77
|
+
* Tolerates a session that carries no ledger, exactly as `noteSessionGaps` does and for the same
|
|
78
|
+
* reason: `Session` is satisfied structurally, and many specs — plus any consumer embedding this
|
|
79
|
+
* engine — build one as an object literal. Such a session is a real caller that simply keeps no
|
|
80
|
+
* ledger, and an instrument must never be the reason a tool call throws. Its calls are then absent
|
|
81
|
+
* rather than counted as zero, which is what `observed: false` exists to say.
|
|
82
|
+
*/
|
|
83
|
+
export declare function noteCapturedCall(session: {
|
|
84
|
+
capture?: CaptureLedger;
|
|
85
|
+
actionCount?: number;
|
|
86
|
+
}, call: Omit<CapturedCall, 'afterActions'>): void;
|
|
87
|
+
/**
|
|
88
|
+
* Count one call against the session that made it, whichever tool it was.
|
|
89
|
+
*
|
|
90
|
+
* Tolerant of a ledger-less session for exactly the reason `noteCapturedCall` is: its calls are then
|
|
91
|
+
* absent rather than counted as zero, which is what `observed: false` exists to say.
|
|
92
|
+
*/
|
|
93
|
+
export declare function noteToolDispatched(session: {
|
|
94
|
+
capture?: CaptureLedger;
|
|
95
|
+
}, tool: string): void;
|
|
96
|
+
/** What one session's use of the two features looks like. Everything but `observed` is omitted when nothing was recorded. */
|
|
97
|
+
export interface FeatureCapture {
|
|
98
|
+
/** False when this daemon recorded nothing for the session — "not watched", never "not used". */
|
|
99
|
+
observed: boolean;
|
|
100
|
+
/** The ledger dropped calls, so every count is a floor. Present only when true. */
|
|
101
|
+
truncated?: boolean;
|
|
102
|
+
context?: {
|
|
103
|
+
calls: number;
|
|
104
|
+
/** The dispatched-action count each call was made at, in order. */
|
|
105
|
+
atSteps: number[];
|
|
106
|
+
acted: number;
|
|
107
|
+
refetched: number;
|
|
108
|
+
readOther: number;
|
|
109
|
+
nothingAfter: number;
|
|
110
|
+
};
|
|
111
|
+
intents?: {
|
|
112
|
+
declared: number;
|
|
113
|
+
open: number;
|
|
114
|
+
};
|
|
115
|
+
missed?: {
|
|
116
|
+
verdictsWithNoIntentDeclared: number;
|
|
117
|
+
refetchedEstablished: number;
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Did calling `reticle_context` change what happened next?
|
|
122
|
+
*
|
|
123
|
+
* The mechanical proxy, stated so it can be argued with: look at the very next recorded call. If an
|
|
124
|
+
* action was dispatched before it — the action counter moved — the agent ACTED, and the context
|
|
125
|
+
* plausibly helped. If instead the next call is a read of a subject the context had just supplied,
|
|
126
|
+
* the agent re-fetched what it had been handed, and the context did not help.
|
|
127
|
+
*
|
|
128
|
+
* ## What this proxy CANNOT see
|
|
129
|
+
*
|
|
130
|
+
* - Whether the agent READ the response, reasoned over it, or wrote a better answer from it. There
|
|
131
|
+
* is no signal for that anywhere, and this must not be mistaken for one.
|
|
132
|
+
* - Anything that happens between two Reticle calls: source edits, calls to other MCP servers, a
|
|
133
|
+
* turn ending, a human interrupting. A long gap is invisible and reads as adjacency.
|
|
134
|
+
* - Reads that name no ref or target (a whole-page snapshot). They land in `readOther`, never in
|
|
135
|
+
* `refetched`, so a snapshot that duplicated the context is under-counted, not over-counted.
|
|
136
|
+
* - Causation. `acted` is proximity in a call sequence, nothing more. An agent that would have acted
|
|
137
|
+
* anyway is indistinguishable from one the context unblocked.
|
|
138
|
+
* - `reticle_context` called with no session connected — it answers there by design, and there is no
|
|
139
|
+
* per-session ledger to record it against, so those calls are missing entirely.
|
|
140
|
+
* - Two agents driving one session. Their calls interleave into one sequence and "next call" stops
|
|
141
|
+
* meaning "next thing that agent did".
|
|
142
|
+
*/
|
|
143
|
+
export declare function foldFeatureCapture(input: {
|
|
144
|
+
calls: readonly CapturedCall[];
|
|
145
|
+
dropped: number;
|
|
146
|
+
actions: readonly JournalAction[];
|
|
147
|
+
intents: readonly Intent[];
|
|
148
|
+
/** The session's dispatched-action count now, so a run that ended on an action is not read as idle. */
|
|
149
|
+
finalActions: number;
|
|
150
|
+
}): FeatureCapture;
|