@reticlehq/server 2.13.0 → 2.14.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 +8 -18
- package/bin/reticle.js +3 -0
- package/dist/bridge/auth-failure-reason.js +12 -1
- package/dist/bridge/bridge-security.d.ts +8 -0
- package/dist/bridge/bridge-security.js +6 -1
- package/dist/bridge/bridge.d.ts +3 -0
- package/dist/bridge/bridge.js +23 -1
- package/dist/bridge/bridge.test-harness.d.ts +10 -1
- package/dist/bridge/bridge.test-harness.js +7 -1
- package/dist/bridge/pairing-token.d.ts +17 -0
- package/dist/bridge/pairing-token.js +26 -0
- package/dist/bridge/token-auth.d.ts +7 -0
- package/dist/bridge/token-auth.js +7 -1
- package/dist/capsule/capsule-store.d.ts +4 -4
- package/dist/capsule/capsule.d.ts +1 -1
- package/dist/capsule/capsule.js +3 -3
- package/dist/capsule/causal-summary.d.ts +21 -1
- package/dist/capsule/causal-summary.js +8 -6
- package/dist/capsule/divergence.d.ts +1 -1
- package/dist/capsule/divergence.js +26 -10
- package/dist/chromium-launch-options.d.ts +2 -1
- package/dist/cli/adhoc-verdict.d.ts +58 -0
- package/dist/cli/adhoc-verdict.js +115 -0
- package/dist/cli/chromium-hint.d.ts +18 -4
- package/dist/cli/chromium-hint.js +54 -6
- package/dist/cli/cli-doctor.js +1 -2
- package/dist/cli/cli-flow-commands.d.ts +16 -2
- package/dist/cli/cli-flow-commands.js +28 -9
- package/dist/cli/cli-parse-feedback.js +1 -1
- package/dist/cli/cli-parse.d.ts +2 -1
- package/dist/cli/cli-parse.js +38 -0
- package/dist/cli/cli-port.d.ts +5 -13
- package/dist/cli/cli-port.js +5 -38
- package/dist/cli/cli-update-commands.js +4 -4
- package/dist/cli/cli-verify.d.ts +24 -7
- package/dist/cli/cli-verify.js +87 -13
- package/dist/cli/cloud-keystore.d.ts +2 -1
- package/dist/cli/cloud-login.d.ts +2 -1
- package/dist/cli/cloud-session.d.ts +2 -1
- package/dist/cli/cloud-session.js +1 -1
- package/dist/cli/daemon-start-options.d.ts +2 -1
- package/dist/cli/device-flow.d.ts +2 -2
- package/dist/cli/doctor-daemon-line.d.ts +2 -1
- package/dist/cli/doctor-project-line.d.ts +2 -1
- package/dist/cli/doctor-rows.d.ts +2 -1
- package/dist/cli/drive-attach.d.ts +4 -3
- package/dist/cli/gate-hook-message.d.ts +2 -1
- package/dist/cli/status-next-action.js +10 -11
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +21 -9
- package/dist/cloud/account-state.d.ts +20 -0
- package/dist/cloud/account-state.js +65 -0
- package/dist/cloud/cloud-sync.d.ts +46 -3
- package/dist/cloud/cloud-sync.js +116 -0
- package/dist/cloud/sync-cycle.d.ts +5 -4
- package/dist/cloud/sync-cycle.js +1 -1
- package/dist/cloud/sync-daemon.d.ts +3 -19
- package/dist/cloud/sync-daemon.js +2 -2
- package/dist/crawl/crawl-tools.js +1 -1
- package/dist/crawl/crawl.d.ts +5 -5
- package/dist/crawl/crawl.js +138 -4
- package/dist/daemon/daemon-resilience.d.ts +3 -2
- package/dist/daemon/daemon-resilience.js +43 -4
- package/dist/daemon/daemon-resolve.d.ts +0 -9
- package/dist/daemon/daemon-resolve.js +2 -2
- package/dist/daemon/dev-servers.d.ts +1 -1
- package/dist/daemon/dev-servers.js +1 -1
- package/dist/daemon/loopback-alias.d.ts +2 -1
- package/dist/daemon/startup-failure.d.ts +11 -0
- package/dist/daemon/startup-failure.js +46 -0
- package/dist/events/contradictions.d.ts +10 -16
- package/dist/events/contradictions.js +149 -17
- package/dist/events/declared.d.ts +13 -1
- package/dist/events/declared.js +59 -3
- package/dist/events/echo-mismatch.js +75 -6
- package/dist/events/lineage.d.ts +52 -0
- package/dist/events/lineage.js +122 -0
- package/dist/events/net-evidence.d.ts +21 -0
- package/dist/events/net-evidence.js +81 -0
- package/dist/events/predicate-console.d.ts +13 -0
- package/dist/events/predicate-console.js +138 -0
- package/dist/events/predicate-element.d.ts +13 -0
- package/dist/events/predicate-element.js +214 -0
- package/dist/events/predicate-eval.d.ts +15 -3
- package/dist/events/predicate-eval.js +128 -110
- package/dist/events/predicate-parse.js +34 -1
- package/dist/events/predicate-request-body.d.ts +50 -0
- package/dist/events/predicate-request-body.js +120 -0
- package/dist/events/predicate-route.d.ts +21 -1
- package/dist/events/predicate-route.js +149 -21
- package/dist/events/predicate-schema.d.ts +8 -1
- package/dist/events/predicate-schema.js +34 -0
- package/dist/events/predicate.d.ts +2 -0
- package/dist/events/predicate.js +52 -159
- package/dist/events/split-text-miss.d.ts +6 -4
- package/dist/events/split-text-miss.js +12 -5
- package/dist/flows/affected-tools.js +22 -9
- package/dist/flows/annotate.d.ts +2 -1
- package/dist/flows/annotate.js +19 -1
- package/dist/flows/coverage.d.ts +2 -2
- package/dist/flows/flake.d.ts +3 -3
- package/dist/flows/flow-expect-grammar.d.ts +33 -0
- package/dist/flows/flow-expect-grammar.js +155 -0
- package/dist/flows/flow-replay-run.d.ts +1 -1
- package/dist/flows/flow-replay-run.js +28 -15
- package/dist/flows/flow-replay.d.ts +10 -0
- package/dist/flows/flow-replay.js +57 -22
- package/dist/flows/flow-secret-field.d.ts +14 -0
- package/dist/flows/flow-secret-field.js +22 -0
- package/dist/flows/flow-step-runners.d.ts +1 -0
- package/dist/flows/flow-step-runners.js +91 -34
- package/dist/flows/flow-success.js +22 -0
- package/dist/flows/flow-tools.js +27 -8
- package/dist/flows/flow-upload-resolve.d.ts +23 -0
- package/dist/flows/flow-upload-resolve.js +46 -0
- package/dist/flows/flows.d.ts +15 -0
- package/dist/flows/flows.js +17 -14
- package/dist/flows/git-changed.d.ts +23 -4
- package/dist/flows/git-changed.js +32 -6
- package/dist/flows/heal-run.js +2 -2
- package/dist/flows/predicate-to-expect.d.ts +3 -2
- package/dist/flows/predicate-to-expect.js +11 -5
- package/dist/flows/recording-backtrack.d.ts +24 -0
- package/dist/flows/recording-backtrack.js +73 -0
- package/dist/flows/recordings.d.ts +6 -0
- package/dist/flows/replay-halt.d.ts +26 -0
- package/dist/flows/replay-halt.js +30 -0
- package/dist/flows/replay.d.ts +0 -8
- package/dist/flows/replay.js +15 -3
- package/dist/flows/suite-flakes.d.ts +2 -1
- package/dist/flows/verify-change-tools.js +16 -4
- package/dist/honesty/already-true.d.ts +14 -0
- package/dist/honesty/already-true.js +47 -4
- package/dist/honesty/blind-spots.d.ts +3 -1
- package/dist/honesty/blind-spots.js +24 -1
- package/dist/honesty/body-capture-remedy.d.ts +42 -0
- package/dist/honesty/body-capture-remedy.js +95 -0
- package/dist/honesty/feature-capture.d.ts +3 -2
- package/dist/honesty/feature-capture.js +1 -1
- package/dist/honesty/gap-ledger.d.ts +1 -1
- package/dist/honesty/gap-ledger.js +1 -1
- package/dist/honesty/instrumentation-gaps.d.ts +8 -1
- package/dist/honesty/instrumentation-gaps.js +12 -2
- package/dist/honesty/observability.d.ts +4 -3
- package/dist/honesty/tool-hit-rate.d.ts +3 -2
- package/dist/honesty/uncaptured-bodies.d.ts +3 -1
- package/dist/honesty/uncaptured-bodies.js +6 -2
- package/dist/honesty/unsettled.d.ts +9 -0
- package/dist/honesty/unsettled.js +45 -0
- package/dist/honesty/verified.d.ts +32 -1
- package/dist/honesty/verified.js +37 -10
- package/dist/impact/impact-store.d.ts +5 -14
- package/dist/impact/impact-store.js +49 -6
- package/dist/index.js +1 -1
- package/dist/input/network-detail.d.ts +26 -1
- package/dist/input/network-detail.js +44 -12
- package/dist/input/network-mock-tools.js +24 -17
- package/dist/input/real-input.js +1 -1
- package/dist/input/viewport-tools.js +25 -13
- package/dist/intent/inline-intent.d.ts +0 -10
- package/dist/intent/inline-intent.js +1 -1
- package/dist/intent/intent-shard-store.d.ts +3 -2
- package/dist/intent/intent-shard-store.js +1 -1
- package/dist/intent/intent-shard.d.ts +14 -14
- package/dist/intent/intent-shard.js +4 -4
- package/dist/intent/intent-store.d.ts +1 -1
- package/dist/intent/intent-store.js +1 -1
- package/dist/intent/intent-subject.d.ts +2 -1
- package/dist/intent/open-intents.d.ts +3 -2
- package/dist/license/license.d.ts +4 -4
- package/dist/license/license.js +1 -1
- package/dist/mcp/attach-memory.d.ts +2 -1
- package/dist/mcp/client-identity.d.ts +2 -1
- package/dist/mcp/mcp-outage.d.ts +1 -1
- package/dist/mcp/mcp-outage.js +1 -1
- package/dist/mcp/mcp-proxy.d.ts +3 -1
- package/dist/mcp/mcp-proxy.js +32 -7
- package/dist/mcp/mcp.js +3 -1
- package/dist/mcp/proxy-handshake.d.ts +2 -1
- package/dist/mcp/proxy-idle-exit.d.ts +45 -0
- package/dist/mcp/proxy-idle-exit.js +94 -0
- package/dist/mcp/server-instructions.d.ts +2 -1
- package/dist/memory/project-memory.d.ts +2 -3
- package/dist/memory/project-memory.js +1 -1
- package/dist/oracles/propose-consequences.js +5 -5
- package/dist/oracles/self-instrument.d.ts +2 -2
- package/dist/oracles/self-instrument.js +1 -1
- package/dist/platform.d.ts +3 -5
- package/dist/platform.js +3 -5
- package/dist/pool/browser-pool.d.ts +92 -0
- package/dist/pool/browser-pool.js +119 -5
- package/dist/pool/playwright-launcher.js +29 -2
- package/dist/pool/storage-seed.d.ts +23 -0
- package/dist/pool/storage-seed.js +198 -0
- package/dist/project/artifact-root.d.ts +2 -1
- package/dist/project/memory-fs.d.ts +2 -1
- package/dist/project/reticle-dir.js +1 -1
- package/dist/project/session-root.d.ts +8 -0
- package/dist/project/session-root.js +9 -2
- package/dist/runs/reticle-runner.d.ts +14 -1
- package/dist/runs/reticle-runner.js +39 -2
- package/dist/session/attachment-history.d.ts +2 -1
- package/dist/session/fake-session.d.ts +37 -0
- package/dist/session/fake-session.js +81 -0
- package/dist/session/lease-visibility.d.ts +2 -1
- package/dist/session/live-control-tools.js +6 -0
- package/dist/session/no-session-diagnosis.d.ts +17 -1
- package/dist/session/no-session-diagnosis.js +32 -6
- package/dist/session/no-session-next-action.d.ts +14 -0
- package/dist/session/no-session-next-action.js +18 -0
- package/dist/session/no-session-watch.js +46 -3
- package/dist/session/registered-projects.d.ts +54 -0
- package/dist/session/registered-projects.js +73 -0
- package/dist/session/review-store.d.ts +2 -1
- package/dist/session/session-health.d.ts +62 -1
- package/dist/session/session-health.js +82 -2
- package/dist/session/session-manager.d.ts +11 -1
- package/dist/session/session-manager.js +18 -3
- package/dist/session/session-replaced.d.ts +24 -0
- package/dist/session/session-replaced.js +29 -0
- package/dist/session/session-successor.js +20 -4
- package/dist/session/session.d.ts +13 -5
- package/dist/session/session.js +31 -23
- package/dist/setup/agent-configs.d.ts +3 -2
- package/dist/setup/agent-writer.d.ts +3 -2
- package/dist/setup/approval-migration.d.ts +2 -1
- package/dist/setup/approval-migration.js +1 -1
- package/dist/setup/auto-approve.d.ts +11 -19
- package/dist/setup/auto-approve.js +15 -12
- package/dist/{init → setup}/confirm.js +1 -1
- package/dist/setup/desktop-shape.d.ts +3 -2
- package/dist/setup/dev-server-wait.d.ts +8 -0
- package/dist/setup/dev-server-wait.js +3 -1
- package/dist/setup/drive-agent.d.ts +2 -3
- package/dist/setup/drive-agent.js +1 -1
- package/dist/setup/drive-plan.d.ts +3 -2
- package/dist/setup/ensure-daemon.d.ts +2 -1
- package/dist/setup/existing-app.d.ts +12 -0
- package/dist/setup/existing-app.js +13 -0
- package/dist/setup/init-host.d.ts +11 -0
- package/dist/setup/init-host.js +26 -0
- package/dist/setup/init-runtime.d.ts +4 -10
- package/dist/setup/init-runtime.js +23 -16
- package/dist/setup/license-key.d.ts +2 -1
- package/dist/setup/listeners.d.ts +2 -1
- package/dist/setup/loopback-probe-urls.d.ts +18 -0
- package/dist/setup/loopback-probe-urls.js +52 -0
- package/dist/setup/node-effects.d.ts +3 -0
- package/dist/setup/node-effects.js +26 -11
- package/dist/setup/page-probe.d.ts +5 -0
- package/dist/setup/relaunch.d.ts +2 -1
- package/dist/setup/run-setup.d.ts +5 -1
- package/dist/setup/run-setup.js +155 -48
- package/dist/setup/setup-command.d.ts +3 -2
- package/dist/setup/setup-command.js +8 -0
- package/dist/setup/setup-options.d.ts +5 -3
- package/dist/setup/setup-options.js +3 -2
- package/dist/setup/wait-progress.d.ts +28 -0
- package/dist/setup/wait-progress.js +43 -0
- package/dist/telemetry/app-instrumented.d.ts +2 -1
- package/dist/telemetry/app-instrumented.js +1 -1
- package/dist/telemetry/automation-hint.d.ts +1 -1
- package/dist/telemetry/automation-hint.js +1 -1
- package/dist/telemetry/cli-telemetry.js +1 -1
- package/dist/telemetry/connect-failure.d.ts +1 -1
- package/dist/telemetry/connect-failure.js +1 -1
- package/dist/telemetry/crash-cause.d.ts +3 -2
- package/dist/telemetry/crash-cause.js +1 -1
- package/dist/telemetry/daemon-telemetry.d.ts +3 -2
- package/dist/telemetry/daemon-telemetry.js +1 -1
- package/dist/telemetry/error-class.d.ts +3 -2
- package/dist/telemetry/error-class.js +1 -1
- package/dist/telemetry/feedback-cli.js +1 -1
- package/dist/telemetry/feedback-context.d.ts +3 -2
- package/dist/telemetry/feedback-context.js +5 -4
- package/dist/telemetry/feedback-local.d.ts +3 -2
- package/dist/telemetry/feedback.d.ts +4 -3
- package/dist/telemetry/feedback.js +1 -1
- package/dist/telemetry/git-facts.d.ts +2 -2
- package/dist/telemetry/git-facts.js +1 -1
- package/dist/telemetry/identify.d.ts +1 -1
- package/dist/telemetry/identify.js +1 -1
- package/dist/telemetry/init-telemetry.d.ts +2 -14
- package/dist/telemetry/init-telemetry.js +4 -13
- package/dist/telemetry/install-source.d.ts +7 -13
- package/dist/telemetry/install-source.js +7 -29
- package/dist/telemetry/license-activation.d.ts +3 -2
- package/dist/telemetry/license-activation.js +1 -1
- package/dist/telemetry/machine-snapshot.d.ts +1 -1
- package/dist/telemetry/mcp-connection.js +1 -1
- package/dist/telemetry/project-profile.d.ts +0 -14
- package/dist/telemetry/project-profile.js +1 -1
- package/dist/telemetry/proxy-telemetry.js +1 -1
- package/dist/telemetry/session-metrics.d.ts +1 -1
- package/dist/telemetry/session-metrics.js +1 -1
- package/dist/telemetry/telemetry.d.ts +1 -17
- package/dist/telemetry/telemetry.js +4 -4
- package/dist/telemetry/tool-refused.d.ts +1 -1
- package/dist/telemetry/tool-refused.js +1 -1
- package/dist/tools/act-observation.d.ts +3 -2
- package/dist/tools/act-preflight.js +8 -3
- package/dist/tools/act-target.d.ts +4 -0
- package/dist/tools/act-target.js +14 -5
- package/dist/tools/act-tools.d.ts +0 -2
- package/dist/tools/act-tools.js +45 -15
- package/dist/tools/assert-source.d.ts +30 -0
- package/dist/tools/assert-source.js +21 -0
- package/dist/tools/assert-verdict.d.ts +1 -1
- package/dist/tools/assert-verdict.js +14 -4
- package/dist/tools/browser-tools.js +28 -8
- package/dist/tools/complete-snapshot.d.ts +3 -2
- package/dist/tools/dynamic-tools.js +8 -0
- package/dist/tools/error-recovery.d.ts +10 -0
- package/dist/tools/error-recovery.js +23 -0
- package/dist/tools/feedback-tools.js +1 -1
- package/dist/tools/invoke-tool.js +2 -0
- package/dist/tools/lease-tools.d.ts +48 -20
- package/dist/tools/lease-tools.js +311 -76
- package/dist/tools/lineage-tools.d.ts +14 -0
- package/dist/tools/lineage-tools.js +64 -0
- package/dist/tools/merge-tools.js +1 -3
- package/dist/tools/navigate-arrival.d.ts +45 -1
- package/dist/tools/navigate-arrival.js +39 -6
- package/dist/tools/navigate-result.d.ts +8 -1
- package/dist/tools/navigate-result.js +14 -4
- package/dist/tools/numeric-bounds.d.ts +0 -11
- package/dist/tools/numeric-bounds.js +4 -4
- package/dist/tools/observe-tools.js +22 -26
- package/dist/tools/observed-nothing.d.ts +9 -0
- package/dist/tools/observed-nothing.js +2 -1
- package/dist/tools/read-tools.js +12 -17
- package/dist/tools/real-input-attempt.d.ts +14 -6
- package/dist/tools/real-input-attempt.js +75 -18
- package/dist/tools/reconcile-tools.js +2 -1
- package/dist/tools/reload-result.d.ts +6 -1
- package/dist/tools/reload-result.js +7 -2
- package/dist/tools/resolve-target.d.ts +7 -1
- package/dist/tools/resolve-target.js +72 -9
- package/dist/tools/settle-in-flight.d.ts +1 -1
- package/dist/tools/settle-in-flight.js +9 -2
- package/dist/tools/snapshot-delta.d.ts +24 -1
- package/dist/tools/snapshot-delta.js +66 -7
- package/dist/tools/tool-names.d.ts +1 -0
- package/dist/tools/tool-names.js +1 -0
- package/dist/tools/tool-surface.js +20 -2
- package/dist/tools/tools.js +120 -11
- package/dist/tools/verify-next-baton.d.ts +2 -1
- package/dist/update/sdk-sync.d.ts +1 -1
- package/dist/update/sdk-sync.js +1 -1
- package/dist/update/updater.js +1 -1
- package/dist/version/sdk-fix.d.ts +2 -1
- package/dist/version/version-skew.d.ts +0 -8
- package/dist/version/version-skew.js +1 -1
- package/docs/README.md +8 -6
- package/docs/actions.mdx +1 -1
- package/docs/agent-cheatsheet.md +4 -2
- package/docs/architecture.md +1 -1
- package/docs/cli/mcp.mdx +3 -1
- package/docs/cli/watch.mdx +1 -1
- package/docs/cli.mdx +1 -1
- package/docs/desktop.mdx +1 -1
- package/docs/docs.json +8 -3
- package/docs/faq.mdx +9 -0
- package/docs/first-drive.md +136 -0
- package/docs/frameworks.mdx +29 -7
- package/docs/gate-plan.md +2 -2
- package/docs/gates.md +19 -11
- package/docs/getting-started.md +7 -1
- package/docs/http-transport.md +164 -0
- package/docs/index.mdx +5 -3
- package/docs/install-manual.mdx +1 -1
- package/docs/packages/tauri.mdx +1 -1
- package/docs/packages.mdx +15 -3
- package/docs/platform-integration.md +1 -1
- package/docs/predicates.mdx +2 -0
- package/docs/system-map.md +2 -2
- package/docs/telemetry-contract.md +4 -4
- package/docs/telemetry-events.mdx +1 -1
- package/docs/telemetry.md +3 -3
- package/docs/tools-navigate.mdx +14 -6
- package/docs/usage.md +4 -4
- package/package.json +7 -4
- package/dist/init/agent-rules.d.ts +0 -116
- package/dist/init/agent-rules.js +0 -279
- package/dist/init/app-choice.d.ts +0 -20
- package/dist/init/app-choice.js +0 -25
- package/dist/init/astro-host.d.ts +0 -21
- package/dist/init/astro-host.js +0 -27
- package/dist/init/astro-patch.d.ts +0 -33
- package/dist/init/astro-patch.js +0 -300
- package/dist/init/capabilities.d.ts +0 -40
- package/dist/init/capabilities.js +0 -150
- package/dist/init/closing-hint.d.ts +0 -36
- package/dist/init/closing-hint.js +0 -120
- package/dist/init/connect-steps.d.ts +0 -2
- package/dist/init/connect-steps.js +0 -50
- package/dist/init/cra.d.ts +0 -79
- package/dist/init/cra.js +0 -178
- package/dist/init/csp-check.d.ts +0 -38
- package/dist/init/csp-check.js +0 -107
- package/dist/init/csp-doctor.d.ts +0 -32
- package/dist/init/csp-doctor.js +0 -54
- package/dist/init/desktop-doctor.d.ts +0 -41
- package/dist/init/desktop-doctor.js +0 -198
- package/dist/init/detect.d.ts +0 -96
- package/dist/init/detect.js +0 -209
- package/dist/init/dev-script.d.ts +0 -50
- package/dist/init/dev-script.js +0 -66
- package/dist/init/format-generated.d.ts +0 -18
- package/dist/init/format-generated.js +0 -39
- package/dist/init/install-hint.d.ts +0 -9
- package/dist/init/install-hint.js +0 -29
- package/dist/init/mcp-clients.d.ts +0 -89
- package/dist/init/mcp-clients.js +0 -299
- package/dist/init/mcp-registered.d.ts +0 -12
- package/dist/init/mcp-registered.js +0 -14
- package/dist/init/mcp.d.ts +0 -89
- package/dist/init/mcp.js +0 -129
- package/dist/init/next-patch.d.ts +0 -39
- package/dist/init/next-patch.js +0 -196
- package/dist/init/node-io.d.ts +0 -7
- package/dist/init/node-io.js +0 -117
- package/dist/init/non-js-project.d.ts +0 -27
- package/dist/init/non-js-project.js +0 -84
- package/dist/init/patch-kind.d.ts +0 -20
- package/dist/init/patch-kind.js +0 -10
- package/dist/init/plan-framework.d.ts +0 -64
- package/dist/init/plan-framework.js +0 -565
- package/dist/init/plan.d.ts +0 -242
- package/dist/init/plan.js +0 -703
- package/dist/init/preflight.d.ts +0 -28
- package/dist/init/preflight.js +0 -38
- package/dist/init/project-id.d.ts +0 -12
- package/dist/init/project-id.js +0 -25
- package/dist/init/refresh-rules.d.ts +0 -39
- package/dist/init/refresh-rules.js +0 -51
- package/dist/init/run.d.ts +0 -117
- package/dist/init/run.js +0 -806
- package/dist/init/slash-command.d.ts +0 -27
- package/dist/init/slash-command.js +0 -132
- package/dist/init/snippets.d.ts +0 -134
- package/dist/init/snippets.js +0 -572
- package/dist/init/vite-config.d.ts +0 -18
- package/dist/init/vite-config.js +0 -114
- package/dist/init/windows-quote.d.ts +0 -38
- package/dist/init/windows-quote.js +0 -70
- package/dist/init/workspace-apps.d.ts +0 -30
- package/dist/init/workspace-apps.js +0 -178
- package/dist/project/remember-project.d.ts +0 -24
- package/dist/project/remember-project.js +0 -40
- /package/dist/{init → setup}/confirm.d.ts +0 -0
package/dist/tools/act-tools.js
CHANGED
|
@@ -10,6 +10,7 @@ import { leanActResult, mutatedWithin } from './act-view.js';
|
|
|
10
10
|
import { ReticleTool } from './tool-names.js';
|
|
11
11
|
import { buildReactionReport, summarizeReaction } from '../events/reaction.js';
|
|
12
12
|
import { parsePredicate } from '../events/predicate-parse.js';
|
|
13
|
+
import { bodyClauseRefusal } from '../honesty/body-capture-remedy.js';
|
|
13
14
|
import { causalSummary } from '../capsule/causal-summary.js';
|
|
14
15
|
import { findContradictions } from '../events/contradictions.js';
|
|
15
16
|
import { gapsForAction } from '../honesty/instrumentation-gaps.js';
|
|
@@ -24,8 +25,8 @@ import { waitForReaction } from './react-grace.js';
|
|
|
24
25
|
import { decideVerified } from '../honesty/verified.js';
|
|
25
26
|
import { honestyForVerdict } from '../honesty/honesty.js';
|
|
26
27
|
import { declaredExpectations, declaresBodyIndependentChannel } from '../events/declared.js';
|
|
27
|
-
import { readsDomState } from '../honesty/already-true.js';
|
|
28
|
-
import { describeWaitTarget } from '../honesty/unsettled.js';
|
|
28
|
+
import { readsDomState, alreadyTrueHiddenMatch as alreadyTrueHiddenMatchOf, } from '../honesty/already-true.js';
|
|
29
|
+
import { describeWaitTarget, namedNetIsInFlight } from '../honesty/unsettled.js';
|
|
29
30
|
import { saveFailedAssertCapsule } from './act-capsule.js';
|
|
30
31
|
import { buildDivergenceCapsule } from '../capsule/capsule.js';
|
|
31
32
|
import { predicateToExpectedLinks } from '../capsule/predicate-to-links.js';
|
|
@@ -97,8 +98,7 @@ export async function actCommand(deps, session, actArgs, timeoutMs) {
|
|
|
97
98
|
* one layer earlier, before any session is resolved or any work is done.
|
|
98
99
|
*/
|
|
99
100
|
const ACTION_TYPE_VALUES = Object.values(ActionType);
|
|
100
|
-
const
|
|
101
|
-
export const actionTypeEnum = z.enum(ACTION_TYPE_VALUES);
|
|
101
|
+
const actionTypeEnum = z.enum(ACTION_TYPE_VALUES);
|
|
102
102
|
export const ACT_TOOLS = [
|
|
103
103
|
{
|
|
104
104
|
name: ReticleTool.ACT,
|
|
@@ -108,12 +108,12 @@ export const ACT_TOOLS = [
|
|
|
108
108
|
ref: z
|
|
109
109
|
.string()
|
|
110
110
|
.optional()
|
|
111
|
-
.describe(`Element ref (e.g. 'e42') from reticle_snapshot/reticle_query — stable until the element leaves the DOM, so no re-snapshot between actions. Give this OR \`target
|
|
111
|
+
.describe(`Element ref (e.g. 'e42') from reticle_snapshot/reticle_query — stable until the element leaves the DOM, so no re-snapshot between actions. Give this OR \`target\`. A press of Escape, Tab, or a modifier shortcut (Cmd+K) is a document key and needs neither.`),
|
|
112
112
|
target: z
|
|
113
113
|
.record(z.unknown())
|
|
114
114
|
.optional()
|
|
115
115
|
.describe('Find the element and act on it in ONE call, instead of a reticle_query round trip first: { testid } | { text } | { role, name } | { label }. Refuses if it matches more than one, rather than guessing.'),
|
|
116
|
-
action: actionTypeEnum.describe(
|
|
116
|
+
action: actionTypeEnum.describe('Action to perform.'),
|
|
117
117
|
args: z
|
|
118
118
|
.record(z.unknown())
|
|
119
119
|
.optional()
|
|
@@ -248,12 +248,12 @@ export const ACT_TOOLS = [
|
|
|
248
248
|
ref: z
|
|
249
249
|
.string()
|
|
250
250
|
.optional()
|
|
251
|
-
.describe(`Element ref (e.g. 'e42') from reticle_snapshot/reticle_query — stable until the element leaves the DOM, so no re-snapshot between actions. Give this OR \`target
|
|
251
|
+
.describe(`Element ref (e.g. 'e42') from reticle_snapshot/reticle_query — stable until the element leaves the DOM, so no re-snapshot between actions. Give this OR \`target\`. A press of Escape, Tab, or a modifier shortcut (Cmd+K) is a document key and needs neither.`),
|
|
252
252
|
target: z
|
|
253
253
|
.record(z.unknown())
|
|
254
254
|
.optional()
|
|
255
255
|
.describe('Find the element and act on it in ONE call, instead of a reticle_query round trip first: { testid } | { text } | { role, name } | { label }. Refuses if it matches more than one, rather than guessing.'),
|
|
256
|
-
action: actionTypeEnum.describe(
|
|
256
|
+
action: actionTypeEnum.describe('Action to perform.'),
|
|
257
257
|
args: z
|
|
258
258
|
.record(z.unknown())
|
|
259
259
|
.optional()
|
|
@@ -369,6 +369,11 @@ export const ACT_TOOLS = [
|
|
|
369
369
|
const until = withUntil['until'] !== undefined
|
|
370
370
|
? parsePredicate(withUntil['until'])
|
|
371
371
|
: { kind: PredicateKind.SETTLED };
|
|
372
|
+
// BEFORE the action. A body clause this session cannot answer would fail whatever the app
|
|
373
|
+
// did, and on a drive that mutates state the action is not always repeatable. See #801(C).
|
|
374
|
+
const bodyRefusal = bodyClauseRefusal(until, session);
|
|
375
|
+
if (bodyRefusal !== undefined)
|
|
376
|
+
throw new Error(bodyRefusal);
|
|
372
377
|
const timeout = asNumber(args['timeout_ms']) ?? DEFAULT_ASSERT_TIMEOUT_MS;
|
|
373
378
|
// An intent declared here lands in the ledger BEFORE the verdict is drawn, which is what makes
|
|
374
379
|
// the undeclared-change gap silent on THIS verdict rather than the next one: it reads the
|
|
@@ -396,8 +401,15 @@ export const ACT_TOOLS = [
|
|
|
396
401
|
// state — event-based ones are floored at this act's cursor and cannot be satisfied by the
|
|
397
402
|
// past, so they need no pre-check and pay nothing. One extra query, on the path where a green
|
|
398
403
|
// is otherwise unfalsifiable. See honesty/already-true.
|
|
399
|
-
const
|
|
400
|
-
?
|
|
404
|
+
const alreadyTruePrecheck = until !== undefined && readsDomState(until)
|
|
405
|
+
? await evaluatePredicate(session, until, since, false)
|
|
406
|
+
: undefined;
|
|
407
|
+
const alreadyTrue = alreadyTruePrecheck?.pass ?? false;
|
|
408
|
+
// #889: the pre-check evidence is already in hand — cheap to also ask whether that match was
|
|
409
|
+
// against something hidden, so the already_true message can name it instead of leaving the
|
|
410
|
+
// agent to re-derive "was this actually showing?" from nothing.
|
|
411
|
+
const alreadyTrueHiddenMatch = alreadyTrue && until !== undefined
|
|
412
|
+
? alreadyTrueHiddenMatchOf(until, alreadyTruePrecheck?.evidence)
|
|
401
413
|
: false;
|
|
402
414
|
try {
|
|
403
415
|
// actCommand is the single interception point for upload+path rewrite.
|
|
@@ -488,7 +500,12 @@ export const ACT_TOOLS = [
|
|
|
488
500
|
// On RED only, attach the Tier-2 divergence capsule (first-divergence + blast radius). Red-only,
|
|
489
501
|
// so the common green path — what the loop optimizes — is unchanged; on red, diagnosis is the point.
|
|
490
502
|
const links = predicateToExpectedLinks(until);
|
|
491
|
-
|
|
503
|
+
// Read before the capsule, which needs it: a window the buffer trimmed cannot state an
|
|
504
|
+
// absolute about what did NOT happen. See CausalSummary.truncated.
|
|
505
|
+
const bufferLost = session.lostSince(since);
|
|
506
|
+
const capsule = verdict.pass
|
|
507
|
+
? undefined
|
|
508
|
+
: buildDivergenceCapsule(links, windowEvents, bufferLost);
|
|
492
509
|
// Grade from what the verdict PROVED, not what it declared. A green anyOf holds on one branch, so
|
|
493
510
|
// grading off `links` (every branch) would let a presence-only OR report grade `signal` — a false
|
|
494
511
|
// green in the gate itself. `provenExpectedLinks` narrows a green to the branch that actually held;
|
|
@@ -515,7 +532,6 @@ export const ACT_TOOLS = [
|
|
|
515
532
|
// whose own words were "over a clean capture".
|
|
516
533
|
const gapNote = transportGapNote(windowEvents);
|
|
517
534
|
const impeachingNotes = [impeaching.note, gapNote].filter((n) => n !== undefined);
|
|
518
|
-
const bufferLost = session.lostSince(since);
|
|
519
535
|
// Which loss, as an enum, beside the prose that describes it. Classified here because this is
|
|
520
536
|
// the only place that knows the three apart: our buffer, our transport, and the page's own
|
|
521
537
|
// boundaries. See `CaptureLoss`.
|
|
@@ -594,8 +610,12 @@ export const ACT_TOOLS = [
|
|
|
594
610
|
// this is the only one that has to be interpreted, and now it interprets itself.
|
|
595
611
|
const outcomePending = hasAcceptedWrite(windowEvents);
|
|
596
612
|
const outcomeUnread = unreadWriteLabels(windowEvents);
|
|
613
|
+
const stillInFlight = inFlightRequestLabels(windowEvents);
|
|
597
614
|
const decision = decideVerified({
|
|
598
615
|
pass: verdict.pass,
|
|
616
|
+
// So the unread-body remedy can check it applies to THIS page. Threaded rather than
|
|
617
|
+
// looked up inside decideVerified, which is pure and has no session.
|
|
618
|
+
...(session.sdkVersion === undefined ? {} : { sdkVersion: session.sdkVersion }),
|
|
599
619
|
// The caller NAMED the consequence rather than defaulting to "wait for idle". A
|
|
600
620
|
// declaration made before the action is what this tool sells, and idle-settlement was
|
|
601
621
|
// overriding it — see `declaredConsequence`. An explicit `{ kind: "settled" }` is not a
|
|
@@ -605,12 +625,15 @@ export const ACT_TOOLS = [
|
|
|
605
625
|
// Omit when false: a net-only `until` must still hit `outcome_unread`.
|
|
606
626
|
...(declaresBodyIndependentChannel(until) ? { independentOfBody: true } : {}),
|
|
607
627
|
...(alreadyTrue ? { alreadyTrue } : {}),
|
|
628
|
+
...(alreadyTrueHiddenMatch ? { alreadyTrueHiddenMatch } : {}),
|
|
608
629
|
// An assertion nobody could evaluate must not be reported as one the app failed.
|
|
609
630
|
...(verdict.inconclusive === undefined ? {} : { inconclusive: verdict.inconclusive }),
|
|
610
631
|
// Nor must one nobody could OBSERVE. This is the act path, so it is the one that produced
|
|
611
632
|
// the measured false red: a reload mid-wait, graded assertion_failed at the clicked
|
|
612
633
|
// component's own file and line.
|
|
613
|
-
...(true === verdict.observationLost
|
|
634
|
+
...(true === verdict.observationLost
|
|
635
|
+
? { observationLost: true, lastUrl: session.url }
|
|
636
|
+
: {}),
|
|
614
637
|
...(absenceBlindSpot === undefined ? {} : { absenceBlindSpot }),
|
|
615
638
|
honesty,
|
|
616
639
|
contradictions,
|
|
@@ -624,14 +647,18 @@ export const ACT_TOOLS = [
|
|
|
624
647
|
// window is already in hand.
|
|
625
648
|
unsettled: {
|
|
626
649
|
waitedFor: describeWaitTarget(until),
|
|
627
|
-
stillInFlight
|
|
650
|
+
stillInFlight,
|
|
628
651
|
// The retry loop that leaves nothing outstanding — see repeatedRequestLabels.
|
|
629
652
|
repeated: repeatedRequestLabels(windowEvents),
|
|
630
653
|
},
|
|
654
|
+
...(namedNetIsInFlight(until, stillInFlight) ? { namedRequestInFlight: true } : {}),
|
|
631
655
|
});
|
|
632
656
|
// Computed once: the verdict block reports it, and the instrumentation gaps are a second
|
|
633
657
|
// reading of the same evidence rather than a new observation.
|
|
634
|
-
const actionSummary = causalSummary(windowEvents, {
|
|
658
|
+
const actionSummary = causalSummary(windowEvents, {
|
|
659
|
+
stateUnwatched,
|
|
660
|
+
truncated: bufferLost,
|
|
661
|
+
});
|
|
635
662
|
// Asked of every verdict drawn after an observed edit, not once per edit — see
|
|
636
663
|
// isChangeUndeclared for why repeating it is disclosure rather than nagging.
|
|
637
664
|
// Read ONCE and used twice: `changeUndeclared` asks whether the ledger is empty, and the
|
|
@@ -649,6 +676,9 @@ export const ACT_TOOLS = [
|
|
|
649
676
|
stateUnwatched,
|
|
650
677
|
// What the app DECLARED, so an under-instrumented one is told without having to be asked.
|
|
651
678
|
hasCapabilities: session.hasCapabilities,
|
|
679
|
+
// Whether the build TURNED the source stamp off, so a red with no file:line prescribes the
|
|
680
|
+
// right fix. `false` from the page is the only value that means anything; absent is unknown.
|
|
681
|
+
...(false === session.sourceMapping ? { sourceMappingDisabled: true } : {}),
|
|
652
682
|
// What the run still owes. A green that leaves this above zero is not the same as done.
|
|
653
683
|
// MINUS the one this verdict is about to discharge.
|
|
654
684
|
//
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Predicate } from '../events/predicate-schema.js';
|
|
2
|
+
import type { Session } from '../session/session.js';
|
|
2
3
|
/**
|
|
3
4
|
* The `file:line` an ASSERTION is entitled to report — its own evidence, or nothing.
|
|
4
5
|
*
|
|
@@ -19,4 +20,33 @@ export declare function assertSource(facts: {
|
|
|
19
20
|
evidence: unknown;
|
|
20
21
|
pass: boolean;
|
|
21
22
|
lastActSource: string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Set when the verdict could not be EVALUATED rather than evaluated and found false.
|
|
25
|
+
*
|
|
26
|
+
* A file:line reads as a precise, well-attributed finding about that file. Attaching one to a
|
|
27
|
+
* reading that proved nothing sends the investigation into correct code: reported against a
|
|
28
|
+
* wedged Next.js dev server, where a route verdict named `components/.../header.tsx:53` and the
|
|
29
|
+
* reporter nearly filed "the header Sign Up link is broken" — the server was answering nothing at
|
|
30
|
+
* all, on every route.
|
|
31
|
+
*
|
|
32
|
+
* Gated here rather than in the route oracle, because every producer of an inconclusive verdict
|
|
33
|
+
* has the same problem: a throttled tab, a superseded window, an unreadable locator. One guard
|
|
34
|
+
* where all of them route through.
|
|
35
|
+
*/
|
|
36
|
+
inconclusive?: string | undefined;
|
|
22
37
|
}): string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* The file:line an assertion may report — see `assertSource`.
|
|
40
|
+
*
|
|
41
|
+
* Neither `reticle_assert` nor `reticle_wait_for` drives anything, so the last act's source is about
|
|
42
|
+
* some earlier action and not about this verdict. The pointer comes from the assertion's own matched
|
|
43
|
+
* evidence; the last driven control is borrowed only for a RED whose predicate has no DOM clause at
|
|
44
|
+
* all, which is the failure that genuinely has no element to point at.
|
|
45
|
+
*/
|
|
46
|
+
export declare function assertionSource(session: Session, predicate: Predicate, verdict: {
|
|
47
|
+
pass: boolean;
|
|
48
|
+
evidence?: unknown;
|
|
49
|
+
inconclusive?: string;
|
|
50
|
+
}): {
|
|
51
|
+
source?: string;
|
|
52
|
+
};
|
|
@@ -49,5 +49,26 @@ export function assertSource(facts) {
|
|
|
49
49
|
return own;
|
|
50
50
|
if (facts.pass || declaresDom(facts.predicate))
|
|
51
51
|
return undefined;
|
|
52
|
+
// Nothing was proven and nobody could have proven it — so there is nothing to point at.
|
|
53
|
+
if (facts.inconclusive !== undefined)
|
|
54
|
+
return undefined;
|
|
52
55
|
return facts.lastActSource;
|
|
53
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* The file:line an assertion may report — see `assertSource`.
|
|
59
|
+
*
|
|
60
|
+
* Neither `reticle_assert` nor `reticle_wait_for` drives anything, so the last act's source is about
|
|
61
|
+
* some earlier action and not about this verdict. The pointer comes from the assertion's own matched
|
|
62
|
+
* evidence; the last driven control is borrowed only for a RED whose predicate has no DOM clause at
|
|
63
|
+
* all, which is the failure that genuinely has no element to point at.
|
|
64
|
+
*/
|
|
65
|
+
export function assertionSource(session, predicate, verdict) {
|
|
66
|
+
const source = assertSource({
|
|
67
|
+
predicate,
|
|
68
|
+
evidence: verdict.evidence,
|
|
69
|
+
pass: verdict.pass,
|
|
70
|
+
lastActSource: session.lastAct.source(),
|
|
71
|
+
...(verdict.inconclusive === undefined ? {} : { inconclusive: verdict.inconclusive }),
|
|
72
|
+
});
|
|
73
|
+
return source === undefined ? {} : { source };
|
|
74
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { InstrumentationGap, JournalVerdictEffect } from '@reticlehq/core';
|
|
1
|
+
import type { InstrumentationGap, JournalVerdictEffect } from '@reticlehq/core/artifacts';
|
|
2
2
|
import type { Predicate } from '../events/predicate.js';
|
|
3
3
|
import type { Session } from '../session/session.js';
|
|
4
4
|
import { type Contradiction } from '../events/contradictions.js';
|
|
@@ -10,7 +10,7 @@ import { buildHonestyBlock } from '../honesty/honesty.js';
|
|
|
10
10
|
import { hasAcceptedWrite } from '../honesty/accepted-write.js';
|
|
11
11
|
import { unreadWriteLabels } from '../honesty/unread-outcome.js';
|
|
12
12
|
import { decideVerified } from '../honesty/verified.js';
|
|
13
|
-
import { describeWaitTarget } from '../honesty/unsettled.js';
|
|
13
|
+
import { describeWaitTarget, namedNetIsInFlight } from '../honesty/unsettled.js';
|
|
14
14
|
import { inFlightRequestLabels, repeatedRequestLabels } from './settle-in-flight.js';
|
|
15
15
|
import { gradeOfPredicate } from './assert-grade.js';
|
|
16
16
|
import { assertSource } from './assert-source.js';
|
|
@@ -85,6 +85,7 @@ changeUndeclared) {
|
|
|
85
85
|
currentEditEpoch: session.currentEditEpoch,
|
|
86
86
|
appOrigin: session.url,
|
|
87
87
|
expectedFailures: declared.netFailures,
|
|
88
|
+
namedNetUrls: declared.netUrls,
|
|
88
89
|
renderProved: pass && declared.rendersContent,
|
|
89
90
|
...(actCursor !== undefined && actCursor >= since ? { actionSince: actCursor } : {}),
|
|
90
91
|
});
|
|
@@ -98,16 +99,22 @@ changeUndeclared) {
|
|
|
98
99
|
const impeachingNotes = [impeaching.note, gap].filter((n) => n !== undefined);
|
|
99
100
|
const outcomePending = hasAcceptedWrite(windowEvents);
|
|
100
101
|
const outcomeUnread = unreadWriteLabels(windowEvents);
|
|
102
|
+
const stillInFlight = inFlightRequestLabels(windowEvents);
|
|
103
|
+
const effectiveInconclusive = inconclusive ?? (!pass ? session.preconditionFailure?.() : undefined);
|
|
101
104
|
const decision = decideVerified({
|
|
102
105
|
pass,
|
|
106
|
+
// So the unread-body remedy can check it applies to THIS page. Threaded rather than
|
|
107
|
+
// looked up inside decideVerified, which is pure and has no session.
|
|
108
|
+
...(session.sdkVersion === undefined ? {} : { sdkVersion: session.sdkVersion }),
|
|
103
109
|
// Same rule as the act path: the caller named a consequence, so a settlement-only finding must
|
|
104
110
|
// not override it. A fix that lived on one half of the verdict surface would leave the other
|
|
105
111
|
// half broken, and this is the tool agents call most.
|
|
106
112
|
declaredConsequence: predicate.kind !== PredicateKind.SETTLED,
|
|
107
113
|
...(declaresBodyIndependentChannel(predicate) ? { independentOfBody: true } : {}),
|
|
108
|
-
...(
|
|
109
|
-
...(true === observationLost ? { observationLost: true } : {}),
|
|
114
|
+
...(effectiveInconclusive === undefined ? {} : { inconclusive: effectiveInconclusive }),
|
|
115
|
+
...(true === observationLost ? { observationLost: true, lastUrl: session.url } : {}),
|
|
110
116
|
...(absenceBlindSpot === undefined ? {} : { absenceBlindSpot }),
|
|
117
|
+
...(namedNetIsInFlight(predicate, stillInFlight) ? { namedRequestInFlight: true } : {}),
|
|
111
118
|
honesty: buildHonestyBlock({
|
|
112
119
|
grade: gradeOfPredicate(predicate),
|
|
113
120
|
attribution: 'window',
|
|
@@ -143,7 +150,7 @@ changeUndeclared) {
|
|
|
143
150
|
// contradiction, and "the window closed before the app finished" is no more actionable here.
|
|
144
151
|
unsettled: {
|
|
145
152
|
waitedFor: describeWaitTarget(predicate),
|
|
146
|
-
stillInFlight
|
|
153
|
+
stillInFlight,
|
|
147
154
|
repeated: repeatedRequestLabels(windowEvents),
|
|
148
155
|
},
|
|
149
156
|
});
|
|
@@ -158,6 +165,9 @@ changeUndeclared) {
|
|
|
158
165
|
stateUnwatched: isStateUnwatched(spots),
|
|
159
166
|
// What the app DECLARED, so an under-instrumented one is told without having to be asked.
|
|
160
167
|
hasCapabilities: session.hasCapabilities,
|
|
168
|
+
// Whether the build TURNED the source stamp off, so a red with no file:line prescribes the
|
|
169
|
+
// right fix. `false` from the page is the only value that means anything; absent is unknown.
|
|
170
|
+
...(false === session.sourceMapping ? { sourceMappingDisabled: true } : {}),
|
|
161
171
|
domMutated: false,
|
|
162
172
|
signalsFired: 0,
|
|
163
173
|
routeChanged: false,
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { carryReticleIdentity } from './lease-tools.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { navigateResult } from './navigate-result.js';
|
|
4
|
-
import { awaitArrival } from './navigate-arrival.js';
|
|
4
|
+
import { awaitArrival, idsAtTarget, ARRIVAL_TIMEOUT_MS } from './navigate-arrival.js';
|
|
5
5
|
import { reloadResult } from './reload-result.js';
|
|
6
6
|
import { waitForReconnect, RELOAD_RECONNECT_TIMEOUT_MS } from '../session/session-reconnect.js';
|
|
7
7
|
import { ReticleCommand } from '@reticlehq/core';
|
|
8
8
|
import { ReticleTool } from './tool-names.js';
|
|
9
|
-
import { asString } from './tools-helpers.js';
|
|
9
|
+
import { asNumber, asString } from './tools-helpers.js';
|
|
10
10
|
import { sessionIdShape, commandOrThrow } from './tool-kit.js';
|
|
11
|
+
import { timeoutMsSchema } from './numeric-bounds.js';
|
|
11
12
|
export const BROWSER_TOOLS = [
|
|
12
13
|
{
|
|
13
14
|
name: ReticleTool.NAVIGATE,
|
|
14
15
|
example: { url: '/settings' },
|
|
15
|
-
description: 'Navigate the connected browser tab to a URL, or reload it in place with { reload: true } (add { hard: true } to bypass the cache). `ok` means the navigation was DISPATCHED — the SDK is torn down by the navigation, so the page itself cannot report on it. The daemon then waits
|
|
16
|
+
description: 'Navigate the connected browser tab to a URL, or reload it in place with { reload: true } (add { hard: true } to bypass the cache). `ok` means the navigation was DISPATCHED — the SDK is torn down by the navigation, so the page itself cannot report on it. The daemon then waits up to `timeout_ms` (default 5000) for the SDK to reconnect: `confirmed:true` with a new `sessionId` means the page arrived and you can act immediately. `confirmed:false` means it did not arrive within that window (reported as `waitedMs`) — the page may be slow, uninstrumented, or not there. A slow SPA can take 30-60s to reattach: raise `timeout_ms` rather than polling reticle_sessions.',
|
|
16
17
|
inputSchema: {
|
|
17
18
|
url: z.string().optional().describe('The URL to navigate to. Omit when using reload.'),
|
|
18
19
|
reload: z
|
|
@@ -23,6 +24,9 @@ export const BROWSER_TOOLS = [
|
|
|
23
24
|
.boolean()
|
|
24
25
|
.optional()
|
|
25
26
|
.describe('With reload:true, bypass the browser cache (Cmd+Shift+R). Default: false.'),
|
|
27
|
+
timeout_ms: timeoutMsSchema
|
|
28
|
+
.optional()
|
|
29
|
+
.describe('How long to wait for the page to come back (the SDK reconnecting at the new URL, or under the same id on a reload) before answering confirmed:false. Default 5000. 0 looks once without waiting. An SPA reattaching under HMR has been measured at 30-60s — say so here instead of polling reticle_sessions.'),
|
|
26
30
|
...sessionIdShape,
|
|
27
31
|
},
|
|
28
32
|
outputSchema: {
|
|
@@ -34,11 +38,19 @@ export const BROWSER_TOOLS = [
|
|
|
34
38
|
confirmed: z.boolean().optional(),
|
|
35
39
|
/** The session the SDK reconnected as, when arrival was confirmed — it is a NEW id. */
|
|
36
40
|
sessionId: z.string().optional(),
|
|
41
|
+
/**
|
|
42
|
+
* On confirmed:false — the budget (ms) that expired without the page coming back. Says which
|
|
43
|
+
* of "Reticle stopped waiting" and "the page never came back" you are looking at.
|
|
44
|
+
*/
|
|
45
|
+
waitedMs: z.number().optional(),
|
|
37
46
|
note: z.string().optional(),
|
|
38
47
|
},
|
|
39
48
|
handler: async (deps, args) => {
|
|
40
49
|
// reload:true is the absorbed reticle_refresh — same command, one fewer advertised tool.
|
|
41
50
|
if (true === args['reload']) {
|
|
51
|
+
// The reload branch has its own default, sized for a cold dev-server rebuild; the caller's
|
|
52
|
+
// budget overrides it for the same reason it overrides the arrival wait below.
|
|
53
|
+
const timeoutMs = asNumber(args['timeout_ms']) ?? RELOAD_RECONNECT_TIMEOUT_MS;
|
|
42
54
|
const before = deps.sessions.resolve(asString(args['sessionId']));
|
|
43
55
|
// The verdict floor moves HERE, before the page goes away. A reload destroys the document,
|
|
44
56
|
// so every request that failed under the old one belongs to a page that no longer exists —
|
|
@@ -56,14 +68,14 @@ export const BROWSER_TOOLS = [
|
|
|
56
68
|
const back = await waitForReconnect({
|
|
57
69
|
current: () => deps.sessions.get(before.id),
|
|
58
70
|
previous: before,
|
|
59
|
-
timeoutMs
|
|
71
|
+
timeoutMs,
|
|
60
72
|
now: deps.now,
|
|
61
73
|
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
62
74
|
});
|
|
63
75
|
// Not a bare `{ ok: true }`. The URL branch below already discloses that `ok` means
|
|
64
76
|
// DISPATCHED — the reload branch had identical semantics and said nothing, on the path most
|
|
65
77
|
// likely to need it. See reload-result.
|
|
66
|
-
return reloadResult(back);
|
|
78
|
+
return reloadResult(back, timeoutMs);
|
|
67
79
|
}
|
|
68
80
|
const requested = asString(args['url']);
|
|
69
81
|
if (requested === undefined || 0 === requested.length)
|
|
@@ -74,6 +86,10 @@ export const BROWSER_TOOLS = [
|
|
|
74
86
|
// A leased tab is addressed by a URL param, so navigating away from it used to strand the
|
|
75
87
|
// lease — see carryReticleIdentity. A tab that claims no identity is untouched.
|
|
76
88
|
const url = carryReticleIdentity(session.url, requested);
|
|
89
|
+
// Sampled BEFORE dispatch, because that is the only moment it can be known. A session already
|
|
90
|
+
// sitting on the target is not evidence that THIS navigation arrived — and the arrival scan,
|
|
91
|
+
// which reads whatever is at the target afterwards, cannot tell the two apart on its own.
|
|
92
|
+
const priorIds = idsAtTarget(deps.sessions, url);
|
|
77
93
|
session.beginAction(ReticleTool.NAVIGATE, { url });
|
|
78
94
|
// Same floor as the reload path above, for the same reason: going to a new URL replaces the
|
|
79
95
|
// document just as thoroughly. `beginAction` attributes events to this action; it does not move
|
|
@@ -83,9 +99,13 @@ export const BROWSER_TOOLS = [
|
|
|
83
99
|
const result = (await commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.NAVIGATE, { url }));
|
|
84
100
|
// `ok` is the browser accepting the instruction, not the page arriving — see navigate-result.
|
|
85
101
|
// The daemon is the only party that CAN see arrival (the SDK reconnects to it), so it looks,
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
102
|
+
// for as long as the caller said to, instead of telling the agent to go poll
|
|
103
|
+
// reticle_sessions itself. A refusal skips the wait: there is nothing to wait FOR.
|
|
104
|
+
const timeoutMs = asNumber(args['timeout_ms']) ?? ARRIVAL_TIMEOUT_MS;
|
|
105
|
+
const arrival = true === result.ok
|
|
106
|
+
? await awaitArrival(deps.sessions, url, { navigatedId: session.id, priorIds }, timeoutMs)
|
|
107
|
+
: null;
|
|
108
|
+
return navigateResult(result, arrival, timeoutMs);
|
|
89
109
|
}
|
|
90
110
|
finally {
|
|
91
111
|
session.finishAction();
|
|
@@ -35,8 +35,8 @@ export declare const MAX_COMPLETION_READS = 12;
|
|
|
35
35
|
*/
|
|
36
36
|
export declare const MAX_COMPLETION_DEPTH = 4;
|
|
37
37
|
/** Reads one snapshot — whole page when `scope` is undefined, that branch when it is not. */
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
type SnapshotReader = (scope: string | undefined) => Promise<unknown>;
|
|
39
|
+
interface CompletedRead {
|
|
40
40
|
/** The union of every subtree that was read. Never a lie about what it contains — only about how much. */
|
|
41
41
|
tree: string;
|
|
42
42
|
/** True only when every branch the page cut was read back. A negative conclusion needs this. */
|
|
@@ -46,3 +46,4 @@ export interface CompletedRead {
|
|
|
46
46
|
incompleteBecause?: string;
|
|
47
47
|
}
|
|
48
48
|
export declare function readCompleteTree(read: SnapshotReader): Promise<CompletedRead>;
|
|
49
|
+
export {};
|
|
@@ -245,5 +245,13 @@ export function buildDynamicTools(allTools, profile) {
|
|
|
245
245
|
}
|
|
246
246
|
},
|
|
247
247
|
};
|
|
248
|
+
// The server instructions say, verbatim, "reticle_tools lists it, reticle_run calls it" — naming
|
|
249
|
+
// these two meta-tools as reachable through EACH OTHER, same as everything else on the surface.
|
|
250
|
+
// `byName` was built from `allTools` before either was constructed, so it never held them:
|
|
251
|
+
// `reticle_run { tool: "reticle_tools" }` — the exact discovery path the instructions document —
|
|
252
|
+
// answered "unknown tool 'reticle_tools'" (#876). Registered here, after both exist, so the
|
|
253
|
+
// dispatch this closure reads from (`byName.get`, evaluated lazily on each call) can find them.
|
|
254
|
+
byName.set(ReticleTool.TOOLS, reticleTools);
|
|
255
|
+
byName.set(ReticleTool.RUN, reticleRun);
|
|
248
256
|
return [reticleTools, reticleRun];
|
|
249
257
|
}
|
|
@@ -29,6 +29,16 @@ export declare const RECOVERY: {
|
|
|
29
29
|
* carry: which of them to reach for, and that nothing was acted on.
|
|
30
30
|
*/
|
|
31
31
|
readonly TARGET_MISSED: string;
|
|
32
|
+
/**
|
|
33
|
+
* The selector was underspecified, which is the caller's to fix and the same class as a miss.
|
|
34
|
+
*
|
|
35
|
+
* It reached the feedback ask for a punctuation reason: the text ends "pass an explicit `ref` from
|
|
36
|
+
* reticle_query.", and the catch-all excludes a `reticle_*` name followed by `.` so a module path
|
|
37
|
+
* in a stack trace stays an unanticipated crash. A tool named at the END of a sentence is
|
|
38
|
+
* indistinguishable from one under that rule, so the whole message fell through and told the
|
|
39
|
+
* caller their own ambiguous query might be a defect worth a root-cause report.
|
|
40
|
+
*/
|
|
41
|
+
readonly AMBIGUOUS_TARGET: string;
|
|
32
42
|
readonly NO_SUCH_OPTION: string;
|
|
33
43
|
readonly BAD_ARGUMENTS: string;
|
|
34
44
|
readonly WRONG_TARGET: string;
|
|
@@ -103,6 +103,20 @@ export const RECOVERY = {
|
|
|
103
103
|
'acted on. Take a reticle_snapshot to see what is actually there (a view may still be ' +
|
|
104
104
|
'rendering, or the control may be named differently), then retry with what it shows. This is ' +
|
|
105
105
|
'a miss, not a Reticle defect: there is nothing to report.',
|
|
106
|
+
/**
|
|
107
|
+
* The selector was underspecified, which is the caller's to fix and the same class as a miss.
|
|
108
|
+
*
|
|
109
|
+
* It reached the feedback ask for a punctuation reason: the text ends "pass an explicit `ref` from
|
|
110
|
+
* reticle_query.", and the catch-all excludes a `reticle_*` name followed by `.` so a module path
|
|
111
|
+
* in a stack trace stays an unanticipated crash. A tool named at the END of a sentence is
|
|
112
|
+
* indistinguishable from one under that rule, so the whole message fell through and told the
|
|
113
|
+
* caller their own ambiguous query might be a defect worth a root-cause report.
|
|
114
|
+
*/
|
|
115
|
+
AMBIGUOUS_TARGET: 'The call was valid and the selector matched SEVERAL elements, so nothing was acted on. Acting ' +
|
|
116
|
+
'on one of them would report a verdict about an element you did not choose, which is the false ' +
|
|
117
|
+
'green Reticle refuses to produce. The message above names each match: narrow the query with a ' +
|
|
118
|
+
'role, name, testid or scope, or pass an explicit `ref` from reticle_query. This is an ' +
|
|
119
|
+
'underspecified selector, not a Reticle defect: there is nothing to report.',
|
|
106
120
|
NO_SUCH_OPTION: 'That <select> has no option with the value you asked for, and the message above lists the ones ' +
|
|
107
121
|
'it does have. Reticle refuses rather than assigning it: an unmatched value deselects everything, ' +
|
|
108
122
|
'and the change event that follows has been observed persisting an empty setting into the app. ' +
|
|
@@ -206,6 +220,9 @@ const REASON_OF = {
|
|
|
206
220
|
STALE_REF_AFTER_EDIT: RefusalReason.NO_MATCH,
|
|
207
221
|
NO_SUCH_OPTION: RefusalReason.NO_MATCH,
|
|
208
222
|
TARGET_MISSED: RefusalReason.NO_MATCH,
|
|
223
|
+
// Target resolution failed to name one element. NO_MATCH rather than BAD_ARGS: the arguments were
|
|
224
|
+
// well-formed and the query simply did not identify a single node, same as a miss.
|
|
225
|
+
AMBIGUOUS_TARGET: RefusalReason.NO_MATCH,
|
|
209
226
|
FLOW_STEP_MISSING: RefusalReason.NO_MATCH,
|
|
210
227
|
UNSUPPORTED_SURFACE: RefusalReason.UNSUPPORTED,
|
|
211
228
|
HOVER_NEEDS_POINTER: RefusalReason.UNSUPPORTED,
|
|
@@ -279,6 +296,12 @@ const RULES = [
|
|
|
279
296
|
// agent to re-read arguments that were already correct costs it a turn, and this is the commonest
|
|
280
297
|
// refusal there is.
|
|
281
298
|
{ match: /target matched no element/i, hint: RECOVERY.TARGET_MISSED },
|
|
299
|
+
// Also BEFORE the catch-all, and for the same reason the line above is: the caller's query is the
|
|
300
|
+
// thing to fix, so the answer must not be "re-read the tool's parameters" or a bug-report nudge.
|
|
301
|
+
{
|
|
302
|
+
match: /target matched \d+ elements and an action must not guess/i,
|
|
303
|
+
hint: RECOVERY.AMBIGUOUS_TARGET,
|
|
304
|
+
},
|
|
282
305
|
// Authored by Reticle, about the caller's arguments: the message already names the valid answers.
|
|
283
306
|
{ match: /^unknown action '/i, hint: RECOVERY.BAD_ARGUMENTS },
|
|
284
307
|
{ match: /^unsupported query strategy '/i, hint: RECOVERY.BAD_ARGUMENTS },
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* tokens on that and not on politeness.
|
|
13
13
|
*/
|
|
14
14
|
import { z } from 'zod';
|
|
15
|
-
import { FeedbackKind, FeedbackSource, FEEDBACK_RATING_MAX, FEEDBACK_RATING_MIN, } from '@reticlehq/core';
|
|
15
|
+
import { FeedbackKind, FeedbackSource, FEEDBACK_RATING_MAX, FEEDBACK_RATING_MIN, } from '@reticlehq/core/telemetry';
|
|
16
16
|
import { ReticleTool } from './tool-names.js';
|
|
17
17
|
import { asNumber, asString } from './tools-helpers.js';
|
|
18
18
|
import { submitFeedback, feedbackDisabled } from '../telemetry/feedback.js';
|
|
@@ -69,6 +69,8 @@ const REF_MINTING_TOOLS = new Set([
|
|
|
69
69
|
ReticleTool.VERIFY,
|
|
70
70
|
]);
|
|
71
71
|
export const SESSION_BOUND_TOOLS = new Set([
|
|
72
|
+
// Resolves a session and reads its event window (`session.eventsSince`), exactly as OBSERVE and
|
|
73
|
+
// NETWORK do. Without this it runs with no session and answers from nothing.
|
|
72
74
|
ReticleTool.SNAPSHOT,
|
|
73
75
|
ReticleTool.QUERY,
|
|
74
76
|
ReticleTool.INSPECT,
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Attach-only: the pool drives a browser against an already-running dev server — it never starts one.
|
|
11
11
|
*/
|
|
12
|
+
import { type SeedStorage } from '@reticlehq/core';
|
|
12
13
|
import type { ToolDef } from './tool-kit.js';
|
|
13
14
|
/** The origin of a URL, or undefined when it does not parse. */
|
|
14
15
|
export declare function originOf(url: string): string | undefined;
|
|
@@ -17,12 +18,28 @@ export declare function originOf(url: string): string | undefined;
|
|
|
17
18
|
* adopts them on connect. Pure; falls back to plain concatenation if the URL can't be parsed.
|
|
18
19
|
*/
|
|
19
20
|
export declare function appendReticleParams(url: string, session: string, projectId?: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Scrub known secret shapes and raw seedStorage values (cookies, localStorage, sessionStorage)
|
|
23
|
+
* from an error string before it reaches daemon logs, metrics, or MCP error responses.
|
|
24
|
+
*/
|
|
25
|
+
export declare function scrubSeedFromError(text: string, seed?: unknown): string;
|
|
20
26
|
/**
|
|
21
27
|
* Turn a raw navigation failure (Playwright's `page.goto: net::ERR_… at <url>\nCall log:…`, often
|
|
22
28
|
* with ANSI codes) into a short, clean reason — so the agent/user sees "is the app running?" instead
|
|
23
29
|
* of an internals-leaking wall of text.
|
|
24
30
|
*/
|
|
25
|
-
export declare function cleanNavError(err: unknown): string;
|
|
31
|
+
export declare function cleanNavError(err: unknown, seed?: SeedStorage): string;
|
|
32
|
+
/**
|
|
33
|
+
* Determine if a required seedStorage application precondition failed.
|
|
34
|
+
*
|
|
35
|
+
* Checks strong signals:
|
|
36
|
+
* 1. HTTP 401/403 status on the initial navigation.
|
|
37
|
+
* 2. Cross-origin redirect when localStorage or sessionStorage was requested (skipped by origin-scoping).
|
|
38
|
+
* 3. Clear redirect to an authentication/login endpoint when the requested URL was not a login page.
|
|
39
|
+
*
|
|
40
|
+
* Normal app redirects (e.g. / → /dashboard) are valid and return undefined.
|
|
41
|
+
*/
|
|
42
|
+
export declare function evaluateSeedPrecondition(requestedUrl: string, actualUrl: string | undefined, seed: SeedStorage, navStatus?: number): string | undefined;
|
|
26
43
|
/**
|
|
27
44
|
* The session a lease's tab actually registered as, or undefined while nothing has.
|
|
28
45
|
*
|
|
@@ -57,6 +74,31 @@ export declare function resolveLeasedSessionId(sessions: {
|
|
|
57
74
|
* a human's own URL.
|
|
58
75
|
*/
|
|
59
76
|
export declare function carryReticleIdentity(fromUrl: string | undefined, toUrl: string): string;
|
|
77
|
+
/** The narrow slice of a session the probe needs. Anything that quacks like this works. */
|
|
78
|
+
interface ProbeableSession {
|
|
79
|
+
command?: (name: string, args: Record<string, unknown>, timeoutMs: number) => Promise<unknown>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Does this tab still answer?
|
|
83
|
+
*
|
|
84
|
+
* `ready: true` used to mean "a row is in the sessions map", which is how a lease came back ready
|
|
85
|
+
* and was then rejected by `snapshot`, `state` and `console`. Presence is not liveness: the map
|
|
86
|
+
* still holds a tab that is attached, streaming events, and answering nothing (#692).
|
|
87
|
+
*
|
|
88
|
+
* ANY reply counts, including one that reports the command failed. The question is whether the SDK
|
|
89
|
+
* answers at all, not what it says — so an SDK too old to know the command replies
|
|
90
|
+
* `unknown command '…'`, and that is proof. Only the absence of a reply is evidence of absence:
|
|
91
|
+
* `PendingCommands.track` REJECTS on timeout and on a dropped socket, and resolves on every real
|
|
92
|
+
* answer, so the two cases are already separated for us.
|
|
93
|
+
*
|
|
94
|
+
* `CAPABILITIES` is the probe because it takes no arguments and returns a small fixed list. No new
|
|
95
|
+
* wire command is introduced: this rides an existing round trip.
|
|
96
|
+
*
|
|
97
|
+
* Fails OPEN. A registry entry with no `command` is a shape this code did not put there, and
|
|
98
|
+
* turning a lease that works into a refusal over a probe that could not run would be a worse
|
|
99
|
+
* failure than the one being fixed.
|
|
100
|
+
*/
|
|
101
|
+
export declare function probeLeaseAlive(session: ProbeableSession | undefined, timeoutMs?: number): Promise<boolean>;
|
|
60
102
|
/**
|
|
61
103
|
* Poll until the leased tab's SDK has actually registered on the bridge, so the sessionId we return
|
|
62
104
|
* is immediately usable (the page navigates first, then connects a moment later — without this wait
|
|
@@ -71,9 +113,11 @@ export declare function carryReticleIdentity(fromUrl: string | undefined, toUrl:
|
|
|
71
113
|
export declare function acquireLeasedSession(pool: {
|
|
72
114
|
acquire: (url: string, opts: {
|
|
73
115
|
sessionId: string;
|
|
116
|
+
seedStorage?: SeedStorage;
|
|
74
117
|
}) => Promise<{
|
|
75
118
|
sessionId: string;
|
|
76
119
|
release: () => Promise<void>;
|
|
120
|
+
navStatus?: number;
|
|
77
121
|
}>;
|
|
78
122
|
/**
|
|
79
123
|
* The address this lease's page said it could not reach. Optional so a test double need not
|
|
@@ -88,28 +132,12 @@ export declare function acquireLeasedSession(pool: {
|
|
|
88
132
|
id: string;
|
|
89
133
|
url?: string;
|
|
90
134
|
}[];
|
|
91
|
-
}, url: string, projectId?: string): Promise<{
|
|
135
|
+
}, url: string, projectId?: string, seedStorage?: SeedStorage): Promise<{
|
|
92
136
|
sessionId: string;
|
|
93
137
|
release: () => Promise<void>;
|
|
94
138
|
}>;
|
|
95
139
|
export declare function waitForLeasedSession(isConnected: () => boolean, sleeper?: (ms: number) => Promise<void>, attempts?: number, pollMs?: number): Promise<boolean>;
|
|
96
|
-
|
|
97
|
-
* Named on its own because `reticle drive <url>` runs it too.
|
|
98
|
-
*
|
|
99
|
-
* When a daemon already owns the bridge port, `drive` asks that daemon for a browser instead of
|
|
100
|
-
* competing for the port (see cli/drive-attach.ts), and the browser it should get is exactly the one
|
|
101
|
-
* an agent gets: same pool, same isolation, same reporting. Sharing the ToolDef rather than the
|
|
102
|
-
* handler keeps that literal — the drive route dispatches through `runTool`, so it is counted like
|
|
103
|
-
* any other call instead of being a second, invisible dispatch path.
|
|
104
|
-
*/
|
|
140
|
+
export declare function hasOriginLock(origin: string): boolean;
|
|
105
141
|
export declare const LEASE_ACQUIRE_TOOL: ToolDef;
|
|
106
|
-
/**
|
|
107
|
-
* What to say when a lease was taken while a real tab was already open.
|
|
108
|
-
*
|
|
109
|
-
* Not a refusal. Leases are the highest-value path for autonomous work and an agent that genuinely
|
|
110
|
-
* needs isolation must still get one — but a human watching their own tab cannot see a lease, so
|
|
111
|
-
* when both exist the visible one is the better default and the agent should hear that here, where
|
|
112
|
-
* it is choosing, rather than discover it when somebody asks why nothing is happening.
|
|
113
|
-
*/
|
|
114
|
-
export declare const PREFER_EXISTING_NOTE = "a non-leased tab for this app was already connected \u2014 that is the one a human can see, and this lease is not. Unless you need an isolated context (a second identity, a clean profile, parallel flows), release this lease and drive that sessionId instead.";
|
|
115
142
|
export declare const LEASE_TOOLS: ToolDef[];
|
|
143
|
+
export {};
|