@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,5 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { coverageRegressed, observabilityOf } from '../honesty/observability.js';
|
|
3
|
+
import { foldFeatureCapture } from '../honesty/feature-capture.js';
|
|
4
|
+
import { foldToolHitRate } from '../honesty/tool-hit-rate.js';
|
|
5
|
+
import { allSessionIntents } from '../intent/open-intents.js';
|
|
3
6
|
import { ReticleCommand, SnapshotMode } from '@reticlehq/core';
|
|
4
7
|
import { ReticleTool } from './tool-names.js';
|
|
5
8
|
import { asString } from './tools-helpers.js';
|
|
@@ -49,73 +52,124 @@ export function parseControls(tree) {
|
|
|
49
52
|
}
|
|
50
53
|
return controls;
|
|
51
54
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Build the coverage tool over the dispatchable tool table.
|
|
57
|
+
*
|
|
58
|
+
* The table arrives as a thunk rather than an import: `tools.ts` assembles it FROM this module, so
|
|
59
|
+
* importing it back would close a cycle whose failure mode is a load-order-dependent crash rather
|
|
60
|
+
* than an error anyone sees while writing it. The thunk is called inside the handler, long after the
|
|
61
|
+
* table exists. It carries the merged names — the ones `reticle_run` will actually accept — because
|
|
62
|
+
* a tool that merged into a parent is not something an agent can call or a maintainer can cut.
|
|
63
|
+
*/
|
|
64
|
+
export function buildCoverageTools(toolNames) {
|
|
65
|
+
return [
|
|
66
|
+
{
|
|
67
|
+
name: ReticleTool.COVERAGE,
|
|
68
|
+
description: 'Which interactive controls you have driven this session, and which you have NOT. Returns { total, exercised, untouched:[{ref,label}], alsoDroveGone? } over the controls currently on the page. Use it to decide whether verification is finished: an untouched list that still holds the controls your change affects means you are not done. This is about what you did not TOUCH — distinct from the `coverage` field on an action result, which reports what the layer could not SEE.',
|
|
69
|
+
example: {},
|
|
70
|
+
inputSchema: { ...sessionIdShape },
|
|
71
|
+
outputSchema: {
|
|
72
|
+
total: z.number(),
|
|
73
|
+
exercised: z.number(),
|
|
74
|
+
untouched: z.array(z.object({ ref: z.string(), label: z.string() })),
|
|
75
|
+
alsoDroveGone: z
|
|
76
|
+
.number()
|
|
77
|
+
.optional()
|
|
78
|
+
.describe('Controls you drove that are no longer on the page — usually because the action SUCCEEDED and removed them (archive/delete/submit/navigate). Counted separately so `exercised: 0` never appears immediately after real work.'),
|
|
79
|
+
instrumentationGaps: z
|
|
80
|
+
.array(z.unknown())
|
|
81
|
+
.optional()
|
|
82
|
+
.describe('What this app still cannot tell Reticle, as of your most recent verdict — each entry is { kind, missing, cost, fix, source?, ref? }. These are not controls you skipped; they are checks this app CANNOT answer until it is instrumented, so driving the untouched list will not close them. Apply each `fix` and re-verify: the gap disappears from this list when the app can answer, and every later verdict on this app gets stronger. OMITTED when nothing is missing.'),
|
|
83
|
+
unproven: z
|
|
84
|
+
.boolean()
|
|
85
|
+
.optional()
|
|
86
|
+
.describe('True when verification is NOT finished for a reason driving more controls cannot fix — instrumentationGaps is non-empty. Present only when true, so its absence is not a claim.'),
|
|
87
|
+
observability: z
|
|
88
|
+
.object({ driven: z.number(), observable: z.number(), percent: z.number().optional() })
|
|
89
|
+
.optional()
|
|
90
|
+
.describe('Of the controls you DROVE, how many Reticle could fully observe. `untouched` above is work left for you; this is work left in the APP, and driving more controls does not move it. `percent` is OMITTED when nothing was driven, because 0/0 is not 100%.'),
|
|
91
|
+
featureUse: z
|
|
92
|
+
.object({
|
|
93
|
+
observed: z.boolean(),
|
|
94
|
+
truncated: z.boolean().optional(),
|
|
95
|
+
context: z.unknown().optional(),
|
|
96
|
+
intents: z.unknown().optional(),
|
|
97
|
+
missed: z.unknown().optional(),
|
|
98
|
+
})
|
|
99
|
+
.optional()
|
|
100
|
+
.describe('Whether this session used `reticle_context` and `reticle_intent` at all, and what it cost when it did not: `context` counts the calls and what followed each one, `intents` the ledger, `missed` the verdicts drawn against an empty ledger and the reads that re-fetched a fact already established. `observed:false` means nothing was recorded for this session — NOT that nothing was used. An instrument for deciding whether those two features earn their place; nothing here is a fault of yours.'),
|
|
101
|
+
toolHitRate: z
|
|
102
|
+
.object({
|
|
103
|
+
observed: z.boolean(),
|
|
104
|
+
cells: z.unknown().optional(),
|
|
105
|
+
called: z.unknown().optional(),
|
|
106
|
+
neverCalled: z.unknown().optional(),
|
|
107
|
+
})
|
|
108
|
+
.optional()
|
|
109
|
+
.describe('Which Reticle tools THIS session called, and how reachable each one was: `called` lists every tool with its call count, `neverCalled` the rest of the table, and both carry a `tier` — `default` (advertised to every agent), `extended` (advertised only on the full surface) or `run-only` (reachable solely by naming it to reticle_run). `cells` counts each tier on both sides. `observed:false` means nothing was recorded for this session, NOT that nothing was called. THREE LIMITS, all load-bearing: this is ONE session, so it is evidence about this run and is not a hit rate — a hit rate is a distribution over many sessions. A never-called tool is not a useless tool; one used once a month in an emergency looks identical here to one nobody has ever called, so frequency alone cannot decide a cut. And the counts describe how this run went, never how it should have gone — nothing here is a fault of yours.'),
|
|
110
|
+
observabilityRegressed: z
|
|
111
|
+
.object({ was: z.number(), now: z.number() })
|
|
112
|
+
.optional()
|
|
113
|
+
.describe('This project has previously reached a HIGHER observability than this run did. Usually means an assertion or an instrumented path was removed — the cheapest way to stop a gap firing is to stop asserting the thing that revealed it. Present only when a drop is real and the run was large enough to compare.'),
|
|
114
|
+
},
|
|
115
|
+
handler: async (deps, args) => {
|
|
116
|
+
const sessionId = asString(args['sessionId']);
|
|
117
|
+
const session = deps.sessions.resolve(sessionId);
|
|
118
|
+
// INTERACTIVE mode is already the "controls only" view, so the denominator is the page's own
|
|
119
|
+
// notion of what can be driven rather than a second, drifting definition maintained here.
|
|
120
|
+
const result = await commandOrThrow(deps, sessionId, ReticleCommand.SNAPSHOT, {
|
|
121
|
+
mode: SnapshotMode.INTERACTIVE,
|
|
122
|
+
});
|
|
123
|
+
const tree = asString(result['tree']) ?? '';
|
|
124
|
+
// Matched by ref AND by label — see coverage-identity. A ref dies with the next re-render, so
|
|
125
|
+
// on a framework that replaces nodes this reported `exercised: 0` however much work was done.
|
|
126
|
+
// `droveGone` keeps the other honesty: archive/delete/submit remove their own control, so a
|
|
127
|
+
// drive that WORKED must not read as no coverage at all.
|
|
128
|
+
const { exercised, droveGone, untouched } = exercisedCount(parseControls(tree), session.actedRefs(), session.actedLabels());
|
|
129
|
+
// The other half of "am I done?". `untouched` answers what you did not DRIVE; this answers
|
|
130
|
+
// what this app cannot ANSWER, which no amount of further driving will change. Reporting the
|
|
131
|
+
// first without the second is how an agent finishes a pass believing it verified something the
|
|
132
|
+
// app was never able to confirm.
|
|
133
|
+
const gaps = session.gaps?.open() ?? [];
|
|
134
|
+
// Folded here rather than given a tool of its own: this is already the "am I done, and what is
|
|
135
|
+
// this verdict worth" read, and a number nobody has a reason to ask for separately is one
|
|
136
|
+
// nobody ever sees. It is a fold over the journal and the intent ledger plus the one thing
|
|
137
|
+
// neither records — see honesty/feature-capture.ts.
|
|
138
|
+
const featureUse = foldFeatureCapture({
|
|
139
|
+
calls: session.capture.calls(),
|
|
140
|
+
dropped: session.capture.dropped,
|
|
141
|
+
actions: await session.readJournalActions(),
|
|
142
|
+
intents: await allSessionIntents(deps, sessionId),
|
|
143
|
+
finalActions: session.actionCount,
|
|
144
|
+
});
|
|
145
|
+
// Same fold, same reason, one level out: which of the whole tool table this session reached
|
|
146
|
+
// for, crossed with how reachable each name was. See honesty/tool-hit-rate.ts for what it can
|
|
147
|
+
// and cannot establish — the limits matter more than usual, because this is the number a
|
|
148
|
+
// decision to DELETE tools would be made on.
|
|
149
|
+
const toolHitRate = foldToolHitRate({
|
|
150
|
+
calls: session.capture?.toolCalls(),
|
|
151
|
+
allTools: toolNames(),
|
|
152
|
+
});
|
|
153
|
+
// The number, and the floor under it, together. A coverage figure that can only ever be
|
|
154
|
+
// reported and never contradicted is one an agent learns to satisfy rather than to earn.
|
|
155
|
+
const observability = observabilityOf(session.actedRefs(), gaps);
|
|
156
|
+
const best = await deps.project.bestObservability();
|
|
157
|
+
const regressed = coverageRegressed(best, observability);
|
|
158
|
+
if (observability.percent !== undefined) {
|
|
159
|
+
await deps.project.raiseObservability(observability.percent);
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
total: parseControls(tree).length,
|
|
163
|
+
exercised,
|
|
164
|
+
untouched,
|
|
165
|
+
...(droveGone > 0 ? { alsoDroveGone: droveGone } : {}),
|
|
166
|
+
...(gaps.length > 0 ? { instrumentationGaps: gaps, unproven: true } : {}),
|
|
167
|
+
observability,
|
|
168
|
+
...(regressed === undefined ? {} : { observabilityRegressed: regressed }),
|
|
169
|
+
featureUse,
|
|
170
|
+
toolHitRate,
|
|
171
|
+
};
|
|
172
|
+
},
|
|
119
173
|
},
|
|
120
|
-
|
|
121
|
-
|
|
174
|
+
];
|
|
175
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { runTool } from './invoke-tool.js';
|
|
3
3
|
import { buildErrorPayload } from './error-recovery.js';
|
|
4
|
-
import { mergedNameRedirect, mergedNameMessage } from './merged-name-redirect.js';
|
|
4
|
+
import { mergedNameRedirect, mergedNameMessage, retiredToolNames } from './merged-name-redirect.js';
|
|
5
|
+
import { takeVersionSkewOnto } from '../version/version-nudge.js';
|
|
5
6
|
import { ReticleTool } from './tool-names.js';
|
|
6
|
-
import {
|
|
7
|
+
import { ADVERTISE_ALL_ENV } from './tool-surface.js';
|
|
7
8
|
import { getSessionMetrics } from '../telemetry/session-metrics.js';
|
|
9
|
+
import { isPredicateParam, predicateGrammar } from '../events/predicate-eval.js';
|
|
8
10
|
/**
|
|
9
11
|
* On-demand tool loading for MCP — the answer to the per-turn tool-definition tax.
|
|
10
12
|
*
|
|
@@ -47,6 +49,8 @@ function paramInfo(shape) {
|
|
|
47
49
|
function unknownParamsError(toolName, unknown) {
|
|
48
50
|
return `unknown ${1 === unknown.length ? 'parameter' : 'parameters'} for ${toolName}: ${unknown.join(', ')} — NOT applied, so any result would be an answer to a different question`;
|
|
49
51
|
}
|
|
52
|
+
/** What to write instead — the one parameter reticle_tools declares, and the no-argument form. */
|
|
53
|
+
const TOOLS_ARG_HINT = 'name the tools you want in `names`: reticle_tools { names: ["reticle_act_and_wait"] } — or call it with no arguments for the full catalog';
|
|
50
54
|
/** The keys not declared by `shape`, in call order. */
|
|
51
55
|
function unknownKeys(args, shape) {
|
|
52
56
|
const declared = new Set(Object.keys(shape));
|
|
@@ -70,19 +74,32 @@ export function buildDynamicTools(allTools, profile) {
|
|
|
70
74
|
// advertises the whole registry any more, so BOTH meta-tools are on every surface and
|
|
71
75
|
// reticle_run is always the way to the tail. The old wording would now send an agent
|
|
72
76
|
// away from the only tool that can reach half the registry.
|
|
73
|
-
note: `The surface is read once at daemon startup:
|
|
77
|
+
note: `The surface is read once at daemon startup: set ${ADVERTISE_ALL_ENV}=1 and restart the daemon, or it has no effect. No surface advertises every tool: the advertised count is capped because editors budget tools across all connected MCP servers. Every tool listed here is callable through reticle_run { tool, args } whether or not it is advertised.`,
|
|
74
78
|
},
|
|
75
79
|
};
|
|
80
|
+
const toolsShape = {
|
|
81
|
+
names: z
|
|
82
|
+
.array(z.string())
|
|
83
|
+
.optional()
|
|
84
|
+
.describe('Tool names to load full params for. Omit to list all tools with summaries.'),
|
|
85
|
+
};
|
|
76
86
|
const reticleTools = {
|
|
77
87
|
name: ReticleTool.TOOLS,
|
|
78
88
|
description: 'Discover Reticle tools on demand. Call with no arguments to list every tool (name + one-line summary); call with names:["reticle_network", …] to load full descriptions and parameters for specific tools. Then invoke them with reticle_run. This avoids paying for every tool definition on every turn. To make a verification REUSABLE (record once, replay free forever), the flow workflow lives here: reticle_record{action:"start"} → act → reticle_flow_save → reticle_verify{action:"flows"} (and reticle_flow_heal on drift). Load those names when you want to save or re-run a flow.',
|
|
79
|
-
inputSchema:
|
|
80
|
-
names: z
|
|
81
|
-
.array(z.string())
|
|
82
|
-
.optional()
|
|
83
|
-
.describe('Tool names to load full params for. Omit to list all tools with summaries.'),
|
|
84
|
-
},
|
|
89
|
+
inputSchema: toolsShape,
|
|
85
90
|
handler: (_deps, args) => {
|
|
91
|
+
// The discovery tool declared one parameter and checked none, so a call that misnamed it had
|
|
92
|
+
// the key dropped and came back with the WHOLE catalogue — a well-formed answer to a question
|
|
93
|
+
// nobody asked, and one the caller cannot tell from the answer it wanted. Same check and same
|
|
94
|
+
// wording as reticle_run's, because two spellings of one refusal is how one of them rots.
|
|
95
|
+
const stray = unknownKeys(args, toolsShape);
|
|
96
|
+
if (stray.length > 0) {
|
|
97
|
+
return Promise.resolve({
|
|
98
|
+
error: unknownParamsError(ReticleTool.TOOLS, stray),
|
|
99
|
+
params: paramInfo(toolsShape),
|
|
100
|
+
hint: TOOLS_ARG_HINT,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
86
103
|
const names = Array.isArray(args['names'])
|
|
87
104
|
? args['names'].filter((n) => 'string' === typeof n)
|
|
88
105
|
: undefined;
|
|
@@ -94,20 +111,43 @@ export function buildDynamicTools(allTools, profile) {
|
|
|
94
111
|
name: t.name,
|
|
95
112
|
summary: firstSentence(t.description),
|
|
96
113
|
}));
|
|
114
|
+
// Names that USED to be tools, against the call that replaces each. Instructions written
|
|
115
|
+
// against an earlier release are a permanent fact of the product — `reticle_crawl` is still
|
|
116
|
+
// named by guidance in the wild — and without this the catalogue is silent about them: the
|
|
117
|
+
// old name is simply absent, which reads as "no such capability" rather than "renamed".
|
|
118
|
+
// Reaching the new name then costs an error string, or never happens.
|
|
119
|
+
const retired = retiredToolNames();
|
|
97
120
|
return Promise.resolve({
|
|
98
121
|
total: catalog.length,
|
|
99
122
|
tools: catalog,
|
|
123
|
+
retired,
|
|
100
124
|
...profileBlock,
|
|
101
|
-
next: `All ${catalog.length} tools above are callable, advertised or not. Load full params with reticle_tools { names:[…] }, then call reticle_run { tool, args }.`,
|
|
125
|
+
next: `All ${catalog.length} tools above are callable, advertised or not. Load full params with reticle_tools { names:[…] }, then call reticle_run { tool, args }. \`retired\` maps names that are no longer tools to the call that replaced each.`,
|
|
102
126
|
});
|
|
103
127
|
}
|
|
128
|
+
// The grammar rides ONLY on a `names:[…]` reply that asked for a tool taking a predicate, so
|
|
129
|
+
// no turn pays for it in the catalog or in the advertised schema. The lean tool surface says
|
|
130
|
+
// "call reticle_tools for the full field grammar of a kind"; this is where that lands.
|
|
131
|
+
const carriesPredicate = names.some((n) => Object.values(byName.get(n)?.inputSchema ?? {}).some((schema) => isPredicateParam(schema)));
|
|
104
132
|
return Promise.resolve({
|
|
105
133
|
tools: names.map((n) => {
|
|
106
134
|
const t = byName.get(n);
|
|
107
|
-
|
|
135
|
+
if (t !== undefined)
|
|
136
|
+
return { name: n, description: t.description, params: paramInfo(t.inputSchema) };
|
|
137
|
+
// `reticle_run` has answered a merged name with its replacement for a while; the tool
|
|
138
|
+
// asked to DISCOVER tools still said "unknown tool", which is the wrong answer in the one
|
|
139
|
+
// place an agent goes to resolve a name it is unsure of. Same redirect, same derivation.
|
|
140
|
+
const moved = mergedNameRedirect(n);
|
|
141
|
+
return moved === undefined
|
|
108
142
|
? { name: n, error: 'unknown tool' }
|
|
109
|
-
: {
|
|
143
|
+
: {
|
|
144
|
+
name: n,
|
|
145
|
+
error: mergedNameMessage(n, moved),
|
|
146
|
+
tool: moved.tool,
|
|
147
|
+
...(moved.action === undefined ? {} : { action: moved.action }),
|
|
148
|
+
};
|
|
110
149
|
}),
|
|
150
|
+
...(carriesPredicate ? { predicateGrammar: predicateGrammar() } : {}),
|
|
111
151
|
});
|
|
112
152
|
},
|
|
113
153
|
};
|
|
@@ -201,7 +241,7 @@ export function buildDynamicTools(allTools, profile) {
|
|
|
201
241
|
// is reached through here: a stale ref, a paused session, a missing pairing token all came
|
|
202
242
|
// back as the agent's arguments being wrong, which is advice that spends the retry.
|
|
203
243
|
const message = error instanceof Error ? error.message : String(error);
|
|
204
|
-
return { ...buildErrorPayload(message), tool: name };
|
|
244
|
+
return { ...takeVersionSkewOnto(buildErrorPayload(message)), tool: name };
|
|
205
245
|
}
|
|
206
246
|
},
|
|
207
247
|
};
|
|
@@ -18,13 +18,38 @@ export declare const RECOVERY: {
|
|
|
18
18
|
readonly MISSING_BASELINE: string;
|
|
19
19
|
readonly MISSING_RECORDING: string;
|
|
20
20
|
readonly STALE_REF: string;
|
|
21
|
+
readonly STALE_REF_AFTER_EDIT: string;
|
|
21
22
|
readonly INVALID_NAME: string;
|
|
23
|
+
/**
|
|
24
|
+
* The call was well-formed and the SELECTOR missed. Nothing about the arguments was wrong, so the
|
|
25
|
+
* BAD_ARGUMENTS answer ("re-read that tool's parameters") sends the reader to the one place that
|
|
26
|
+
* holds no answer — measured live on a `target: { testid }` that simply was not on the page yet.
|
|
27
|
+
*
|
|
28
|
+
* The error text already names the two moves that work, so this adds the fact the text cannot
|
|
29
|
+
* carry: which of them to reach for, and that nothing was acted on.
|
|
30
|
+
*/
|
|
31
|
+
readonly TARGET_MISSED: string;
|
|
22
32
|
readonly NO_SUCH_OPTION: string;
|
|
23
33
|
readonly BAD_ARGUMENTS: string;
|
|
24
34
|
readonly WRONG_TARGET: string;
|
|
25
35
|
readonly NOT_EDITABLE: string;
|
|
36
|
+
/**
|
|
37
|
+
* Written as the ARGUMENT OBJECT the caller has to send, not as a dotted path.
|
|
38
|
+
*
|
|
39
|
+
* Measured on a benchmark run that spent its entire budget here: the refusal said "retry with
|
|
40
|
+
* args.confirmDangerous=true", and the agent went looking for a parameter by that name, could not
|
|
41
|
+
* find one at the top level of the schema, and re-read the tool list rather than retrying. The
|
|
42
|
+
* flag IS documented — inside the `args` object's own description — so a dotted path pointing at
|
|
43
|
+
* something that is not a top-level parameter is the whole distance between a one-line retry and
|
|
44
|
+
* a lost budget.
|
|
45
|
+
*
|
|
46
|
+
* The classifier is also wider than "destructive": it matches `deploy` and `publish`, so an
|
|
47
|
+
* ordinary "New deploy" button trips it. Naming a real trigger word here keeps that from reading
|
|
48
|
+
* as a malfunction on an app where nothing is being deleted.
|
|
49
|
+
*/
|
|
26
50
|
readonly CONFIRM_DANGEROUS: string;
|
|
27
51
|
readonly UNSUPPORTED_SURFACE: string;
|
|
52
|
+
readonly HOVER_NEEDS_POINTER: string;
|
|
28
53
|
readonly TOKEN_REQUIRED: string;
|
|
29
54
|
readonly SCOPE_MISMATCH: string;
|
|
30
55
|
readonly SESSION_GONE: string;
|
|
@@ -50,20 +75,6 @@ export declare function recoveryFor(message: string): string | undefined;
|
|
|
50
75
|
* this table rather than about anybody's app.
|
|
51
76
|
*/
|
|
52
77
|
export declare function refusalReasonFor(rawMessage: string): RefusalReason;
|
|
53
|
-
/**
|
|
54
|
-
* A serialized zod issue array, rendered as a sentence. Anything else is returned untouched.
|
|
55
|
-
*
|
|
56
|
-
* This is the one boundary every agent-visible tool failure crosses, which is why the rewrite lives
|
|
57
|
-
* here rather than in each tool. `parsePredicate` solved this for the three predicate tools by never
|
|
58
|
-
* producing the array; it cannot help anywhere else, because the MCP SDK validates a tool's schema
|
|
59
|
-
* BEFORE our handler runs. So `reticle_session` with no action — the commonest mistake there is —
|
|
60
|
-
* never reaches the friendly "unknown action … expected: [tune, yield, …]" its handler already
|
|
61
|
-
* builds, and the agent gets the raw array instead. Driven live against the shipped daemon.
|
|
62
|
-
*
|
|
63
|
-
* Conservative by construction: it only rewrites a JSON ARRAY whose every element carries both
|
|
64
|
-
* `code` and `message`. A tool that legitimately returns JSON is left alone.
|
|
65
|
-
*/
|
|
66
|
-
export declare function zodArrayAsSentence(message: string): string;
|
|
67
78
|
/**
|
|
68
79
|
* The ask attached to errors we do NOT recognize. An unrecognized error is, by definition, the case
|
|
69
80
|
* where Reticle failed in a way nobody anticipated — the single highest-value moment to hear from the
|
|
@@ -66,7 +66,9 @@ export const RECOVERY = {
|
|
|
66
66
|
'target the one you mean.',
|
|
67
67
|
UNKNOWN_SESSION: 'That sessionId is not connected. Call reticle_sessions for the current ids and retry with a valid one.',
|
|
68
68
|
THROTTLED: 'The target tab is backgrounded/throttled, so actions may silently no-op. Ask the human to bring ' +
|
|
69
|
-
'the tab to the front, or
|
|
69
|
+
'the tab to the front, or acquire a guaranteed scriptable context yourself with ' +
|
|
70
|
+
'`reticle_run { tool: "reticle_lease", action: "acquire", url }` (a human can equivalently run ' +
|
|
71
|
+
'`reticle drive <url>`).',
|
|
70
72
|
MISSING_BASELINE: 'That baseline does not exist yet. Call reticle_baseline { action: "list" } to see saved names, or ' +
|
|
71
73
|
'reticle_baseline { action: "save", name } to capture one before diffing against it.',
|
|
72
74
|
MISSING_RECORDING:
|
|
@@ -79,11 +81,28 @@ export const RECOVERY = {
|
|
|
79
81
|
'before it. Reticle refuses here rather than clicking whatever now occupies that slot. Call ' +
|
|
80
82
|
'reticle_query again for a fresh ref and retry the action — and prefer reticle_act_and_wait ' +
|
|
81
83
|
'{ until } when an action changes the page, so the next ref is taken after it settles.',
|
|
84
|
+
STALE_REF_AFTER_EDIT: 'That ref went stale because YOUR OWN EDIT landed: the dev server hot-updated the module named ' +
|
|
85
|
+
'in the message above and the framework re-rendered, so the node the ref pointed at was ' +
|
|
86
|
+
'replaced. Nothing is wrong with the app and nothing is wrong with Reticle — this is the ' +
|
|
87
|
+
'build-and-verify loop working. Call reticle_query for a fresh ref and drive again, and treat ' +
|
|
88
|
+
'anything you observed before the update as describing the previous version of the code.',
|
|
82
89
|
INVALID_NAME: 'That name is not a usable one. A flow, baseline or recording name must be a single safe path ' +
|
|
83
90
|
'segment — letters, digits, dash and underscore only, starting with a letter or digit, at most ' +
|
|
84
91
|
'64 characters. No slashes, no "..", no leading dot: the name becomes a filename under ' +
|
|
85
92
|
'.reticle/, so anything that could escape that directory is refused. Retry with a slug like ' +
|
|
86
93
|
'"checkout-happy-path". This is an invalid call, not a Reticle defect: there is nothing to report.',
|
|
94
|
+
/**
|
|
95
|
+
* The call was well-formed and the SELECTOR missed. Nothing about the arguments was wrong, so the
|
|
96
|
+
* BAD_ARGUMENTS answer ("re-read that tool's parameters") sends the reader to the one place that
|
|
97
|
+
* holds no answer — measured live on a `target: { testid }` that simply was not on the page yet.
|
|
98
|
+
*
|
|
99
|
+
* The error text already names the two moves that work, so this adds the fact the text cannot
|
|
100
|
+
* carry: which of them to reach for, and that nothing was acted on.
|
|
101
|
+
*/
|
|
102
|
+
TARGET_MISSED: 'The call was valid — the selector matched nothing on the page RIGHT NOW, and nothing was ' +
|
|
103
|
+
'acted on. Take a reticle_snapshot to see what is actually there (a view may still be ' +
|
|
104
|
+
'rendering, or the control may be named differently), then retry with what it shows. This is ' +
|
|
105
|
+
'a miss, not a Reticle defect: there is nothing to report.',
|
|
87
106
|
NO_SUCH_OPTION: 'That <select> has no option with the value you asked for, and the message above lists the ones ' +
|
|
88
107
|
'it does have. Reticle refuses rather than assigning it: an unmatched value deselects everything, ' +
|
|
89
108
|
'and the change event that follows has been observed persisting an empty setting into the app. ' +
|
|
@@ -102,13 +121,34 @@ export const RECOVERY = {
|
|
|
102
121
|
'telling you something: drive whatever ENABLES the field (open the editor, satisfy the ' +
|
|
103
122
|
'precondition) and act again. If the field should have been editable, that is a bug in the app, ' +
|
|
104
123
|
'not in Reticle.',
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Written as the ARGUMENT OBJECT the caller has to send, not as a dotted path.
|
|
126
|
+
*
|
|
127
|
+
* Measured on a benchmark run that spent its entire budget here: the refusal said "retry with
|
|
128
|
+
* args.confirmDangerous=true", and the agent went looking for a parameter by that name, could not
|
|
129
|
+
* find one at the top level of the schema, and re-read the tool list rather than retrying. The
|
|
130
|
+
* flag IS documented — inside the `args` object's own description — so a dotted path pointing at
|
|
131
|
+
* something that is not a top-level parameter is the whole distance between a one-line retry and
|
|
132
|
+
* a lost budget.
|
|
133
|
+
*
|
|
134
|
+
* The classifier is also wider than "destructive": it matches `deploy` and `publish`, so an
|
|
135
|
+
* ordinary "New deploy" button trips it. Naming a real trigger word here keeps that from reading
|
|
136
|
+
* as a malfunction on an app where nothing is being deleted.
|
|
137
|
+
*/
|
|
138
|
+
CONFIRM_DANGEROUS: 'Reticle blocked a control whose label reads as consequential (delete, remove, revoke, deploy, ' +
|
|
139
|
+
'publish, pay…) on purpose. If you mean it, send the SAME call again with ' +
|
|
140
|
+
'`args: { confirmDangerous: true }` — it goes inside the `args` object, not beside it. This is ' +
|
|
141
|
+
'a deliberate refusal, not a defect: there is nothing to report.',
|
|
108
142
|
UNSUPPORTED_SURFACE: 'That surface is not supported yet, and Reticle refuses rather than pretending — a rich-text ' +
|
|
109
143
|
'editor keeps its own document model, so writing to the DOM would look right and submit the old ' +
|
|
110
144
|
'content. Drive the same outcome another way (a plain input, a command, a keyboard action) or ' +
|
|
111
145
|
'assert on the result instead of typing it. Known gap, already reported: no need to file it.',
|
|
146
|
+
HOVER_NEEDS_POINTER: 'Hover needs a real pointer: a synthetic mouseover does not apply CSS :hover, and Reticle ' +
|
|
147
|
+
'refuses rather than reporting the styles as applied. Acquire a tab with ' +
|
|
148
|
+
'reticle_run { tool: "reticle_lease", action: "acquire", url } — reticle_lease is not ' +
|
|
149
|
+
'advertised under the default profile, so it is reached through reticle_run, not called ' +
|
|
150
|
+
'directly — or ask the human to drive with `reticle drive` / RETICLE_CDP_URL. This is a ' +
|
|
151
|
+
'deliberate refusal, not a defect: there is nothing to report.',
|
|
112
152
|
TOKEN_REQUIRED: 'The bridge binds beyond localhost and requires a pairing token. Set the same token in the SDK ' +
|
|
113
153
|
'init (@reticlehq/core) and the Reticle server config, then reconnect.',
|
|
114
154
|
SCOPE_MISMATCH: 'A tab IS connected — it just belongs to a different project than the daemon is scoped to, so ' +
|
|
@@ -163,9 +203,12 @@ const REASON_OF = {
|
|
|
163
203
|
MISSING_BASELINE: RefusalReason.NO_MATCH,
|
|
164
204
|
MISSING_RECORDING: RefusalReason.NO_MATCH,
|
|
165
205
|
STALE_REF: RefusalReason.NO_MATCH,
|
|
206
|
+
STALE_REF_AFTER_EDIT: RefusalReason.NO_MATCH,
|
|
166
207
|
NO_SUCH_OPTION: RefusalReason.NO_MATCH,
|
|
208
|
+
TARGET_MISSED: RefusalReason.NO_MATCH,
|
|
167
209
|
FLOW_STEP_MISSING: RefusalReason.NO_MATCH,
|
|
168
210
|
UNSUPPORTED_SURFACE: RefusalReason.UNSUPPORTED,
|
|
211
|
+
HOVER_NEEDS_POINTER: RefusalReason.UNSUPPORTED,
|
|
169
212
|
NOT_EDITABLE: RefusalReason.UNSUPPORTED,
|
|
170
213
|
CONFIRM_DANGEROUS: RefusalReason.UNSUPPORTED,
|
|
171
214
|
WRONG_TARGET: RefusalReason.UNSUPPORTED,
|
|
@@ -200,6 +243,9 @@ const RULES = [
|
|
|
200
243
|
},
|
|
201
244
|
// The commonest post-action condition there is. Unmatched, it fell through to FEEDBACK_ASK and
|
|
202
245
|
// told the agent a successful click's aftermath might be a bug in Reticle.
|
|
246
|
+
// Before the general rule: the edit-aware refusal contains the general one's substring too, and
|
|
247
|
+
// the first hit wins. "Your edit landed" is a next step; "the ref is stale" is a dead end.
|
|
248
|
+
{ match: /the code changed underneath it/i, hint: RECOVERY.STALE_REF_AFTER_EDIT },
|
|
203
249
|
{ match: /no longer resolves to an element/i, hint: RECOVERY.STALE_REF },
|
|
204
250
|
{ match: /no <option> with value/i, hint: RECOVERY.NO_SUCH_OPTION },
|
|
205
251
|
// Every guard in the browser's executeAction. These are Reticle-authored refusals of an invalid
|
|
@@ -208,6 +254,7 @@ const RULES = [
|
|
|
208
254
|
// broken. Order matters: contenteditable and disabled/readonly are `cannot <verb> …` messages too,
|
|
209
255
|
// so they must be tested before the general wrong-target rule.
|
|
210
256
|
{ match: /contenteditable/i, hint: RECOVERY.UNSUPPORTED_SURFACE },
|
|
257
|
+
{ match: /cannot hover without a real pointer/i, hint: RECOVERY.HOVER_NEEDS_POINTER },
|
|
211
258
|
{ match: /cannot \w+ a (disabled|readonly) </i, hint: RECOVERY.NOT_EDITABLE },
|
|
212
259
|
// Three spellings ship — "action", "native action", "WebMCP tool" — and the rule matched one, so
|
|
213
260
|
// two thirds of the same deliberate refusal still read as a possible defect.
|
|
@@ -224,15 +271,37 @@ const RULES = [
|
|
|
224
271
|
match: /no form to submit|upload target must be|is not an HTMLElement/i,
|
|
225
272
|
hint: RECOVERY.WRONG_TARGET,
|
|
226
273
|
},
|
|
274
|
+
// BEFORE the catch-all, which would otherwise claim this one.
|
|
275
|
+
//
|
|
276
|
+
// "target matched no element ... take a reticle_snapshot" names a `reticle_*` tool in its own
|
|
277
|
+
// advice, so the catch-all below matched it and answered "That call did not match the tool's
|
|
278
|
+
// schema". The call matched the schema perfectly; the element was not on the page. Sending an
|
|
279
|
+
// agent to re-read arguments that were already correct costs it a turn, and this is the commonest
|
|
280
|
+
// refusal there is.
|
|
281
|
+
{ match: /target matched no element/i, hint: RECOVERY.TARGET_MISSED },
|
|
227
282
|
// Authored by Reticle, about the caller's arguments: the message already names the valid answers.
|
|
228
283
|
{ match: /^unknown action '/i, hint: RECOVERY.BAD_ARGUMENTS },
|
|
229
284
|
{ match: /^unsupported query strategy '/i, hint: RECOVERY.BAD_ARGUMENTS },
|
|
230
285
|
{ match: /^\w+ requires a string `\w+`/i, hint: RECOVERY.BAD_ARGUMENTS },
|
|
231
|
-
// A message naming a `reticle_*` tool is one WE authored about our own
|
|
232
|
-
// an unanticipated failure. Left unmatched it collected the feedback
|
|
233
|
-
// file reports about their own bad arguments. Kept LAST so a specific
|
|
286
|
+
// A message naming a `reticle_*` tool or an `args.*` parameter is one WE authored about our own
|
|
287
|
+
// API — an invalid call, not an unanticipated failure. Left unmatched it collected the feedback
|
|
288
|
+
// ask, which pushed agents to file reports about their own bad arguments. Kept LAST so a specific
|
|
289
|
+
// rule above always wins.
|
|
290
|
+
//
|
|
291
|
+
// Keyed on the tool/parameter NAME rather than on a sentence shape. The previous form wanted
|
|
292
|
+
// `reticle_x { ... }` with braces AND requires/must/expected, which is one phrasing out of many;
|
|
293
|
+
// measured live, a drag refusal reading "pass a ref from reticle_snapshot or reticle_query as
|
|
294
|
+
// args.toRef" fell straight through and told the agent its own malformed call might be a Reticle
|
|
295
|
+
// defect worth a root-cause report. That is the FOURTH patch to this same default, after the
|
|
296
|
+
// executeAction guards, the destructive-action block, and two of the three spellings of
|
|
297
|
+
// "potentially destructive ... blocked" — each one added a phrasing instead of changing the key.
|
|
298
|
+
//
|
|
299
|
+
// A path is deliberately excluded: `@reticlehq/server/dist/...` in a stack trace is a crash we did
|
|
300
|
+
// NOT anticipate, and silencing the feedback ask there would lose the reports worth having. Hence
|
|
301
|
+
// a word boundary before `reticle_` and a required space-or-punctuation after the name, so a tool
|
|
302
|
+
// named in prose matches and a module path does not.
|
|
234
303
|
{
|
|
235
|
-
match: /reticle_[a-z_]
|
|
304
|
+
match: /(?:^|[\s'"`(])reticle_[a-z_]+(?![\w/.-])|(?:^|[\s'"`(])args\.[a-z][\w]*/i,
|
|
236
305
|
hint: RECOVERY.BAD_ARGUMENTS,
|
|
237
306
|
},
|
|
238
307
|
];
|
|
@@ -321,7 +390,7 @@ function issueClause(issue) {
|
|
|
321
390
|
* Conservative by construction: it only rewrites a JSON ARRAY whose every element carries both
|
|
322
391
|
* `code` and `message`. A tool that legitimately returns JSON is left alone.
|
|
323
392
|
*/
|
|
324
|
-
|
|
393
|
+
function zodArrayAsSentence(message) {
|
|
325
394
|
const text = message.trim();
|
|
326
395
|
if (!text.startsWith('['))
|
|
327
396
|
return message;
|
|
@@ -24,7 +24,7 @@ export declare const FEEDBACK_PROMPT: {
|
|
|
24
24
|
* calls, assert ZERO, verification_completed 2. Agents were verifying the entire time and the metric
|
|
25
25
|
* could not see it. The contract test now checks the SHAPE instead.
|
|
26
26
|
*/
|
|
27
|
-
export declare const
|
|
27
|
+
export declare const VERDICT_TOOLS: ReadonlySet<string>;
|
|
28
28
|
/**
|
|
29
29
|
* The human prompt, when one is due. Resettable for tests.
|
|
30
30
|
*
|
|
@@ -173,7 +173,7 @@ export const FEEDBACK_PROMPT = {
|
|
|
173
173
|
* calls, assert ZERO, verification_completed 2. Agents were verifying the entire time and the metric
|
|
174
174
|
* could not see it. The contract test now checks the SHAPE instead.
|
|
175
175
|
*/
|
|
176
|
-
export const
|
|
176
|
+
export const VERDICT_TOOLS = new Set([
|
|
177
177
|
ReticleTool.ACT_AND_WAIT,
|
|
178
178
|
ReticleTool.ASSERT,
|
|
179
179
|
// Merged: `flow_verify` and `verify_change` are actions on this tool now. Naming the merged tool
|
|
@@ -206,7 +206,7 @@ let verificationsSincePrompt = 0;
|
|
|
206
206
|
* collect is worse than not asking: it spends their attention on a message with nowhere to go.
|
|
207
207
|
*/
|
|
208
208
|
export function takeFeedbackPrompt(toolName) {
|
|
209
|
-
if (!
|
|
209
|
+
if (!VERDICT_TOOLS.has(toolName))
|
|
210
210
|
return undefined;
|
|
211
211
|
if (feedbackDisabled() || !getTelemetry().enabled)
|
|
212
212
|
return undefined;
|