@reticlehq/server 2.4.0 → 2.5.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 +702 -0
- package/dist/bridge/auth-failure-reason.d.ts +19 -0
- package/dist/bridge/auth-failure-reason.js +29 -0
- package/dist/{bridge-security.d.ts → bridge/bridge-security.d.ts} +1 -1
- package/dist/{bridge-security.js → bridge/bridge-security.js} +1 -1
- package/dist/{bridge.d.ts → bridge/bridge.d.ts} +1 -1
- package/dist/{bridge.js → bridge/bridge.js} +63 -13
- package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +1 -11
- package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +9 -9
- package/dist/{pairing-token.js → bridge/pairing-token.js} +1 -1
- package/dist/capsule/capsule-store.d.ts +8 -3
- package/dist/capsule/capsule-store.js +7 -2
- package/dist/capsule/capsule.js +3 -3
- package/dist/capsule/causal-summary.d.ts +8 -0
- package/dist/capsule/causal-summary.js +22 -12
- package/dist/capsule/divergence.d.ts +9 -4
- package/dist/capsule/divergence.js +8 -8
- package/dist/capsule/predicate-to-links.js +11 -8
- package/dist/{cli-doctor.js → cli/cli-doctor.js} +9 -2
- package/dist/{cli-flow-commands.d.ts → cli/cli-flow-commands.d.ts} +2 -2
- package/dist/{cli-flow-commands.js → cli/cli-flow-commands.js} +15 -15
- package/dist/{cli-launch.d.ts → cli/cli-launch.d.ts} +32 -3
- package/dist/cli/cli-launch.js +171 -0
- package/dist/{cli-parse.d.ts → cli/cli-parse.d.ts} +2 -11
- package/dist/{cli-parse.js → cli/cli-parse.js} +113 -60
- package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +12 -0
- package/dist/{cli-port.js → cli/cli-port.js} +9 -9
- package/dist/cli/cli-update-commands.d.ts +4 -0
- package/dist/cli/cli-update-commands.js +93 -0
- package/dist/{cli-verify.js → cli/cli-verify.js} +14 -14
- package/dist/{cloud-cli.js → cli/cloud-cli.js} +29 -24
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +174 -92
- package/dist/cloud/cloud-config.d.ts +0 -1
- package/dist/cloud/cloud-config.js +9 -9
- package/dist/cloud/cloud-sync.d.ts +1 -7
- package/dist/cloud/cloud-sync.js +12 -12
- package/dist/crawl/crawl-empty.d.ts +16 -0
- package/dist/crawl/crawl-empty.js +24 -0
- package/dist/crawl/crawl-tools.js +4 -1
- package/dist/crawl/crawl.js +26 -7
- package/dist/daemon/daemon-resilience.d.ts +49 -0
- package/dist/daemon/daemon-resilience.js +191 -0
- package/dist/daemon/daemon-usefulness.d.ts +61 -0
- package/dist/daemon/daemon-usefulness.js +62 -0
- package/dist/{daemon.d.ts → daemon/daemon.d.ts} +33 -8
- package/dist/{daemon.js → daemon/daemon.js} +80 -48
- package/dist/daemon/idle-grace.d.ts +32 -0
- package/dist/daemon/idle-grace.js +41 -0
- package/dist/{idle-shutdown.d.ts → daemon/idle-shutdown.d.ts} +13 -0
- package/dist/{idle-shutdown.js → daemon/idle-shutdown.js} +27 -4
- package/dist/domain/domain-model.js +2 -2
- package/dist/events/body-failures.js +8 -8
- package/dist/events/contradictions.d.ts +1 -1
- package/dist/events/contradictions.js +60 -10
- package/dist/events/echo-mismatch.js +10 -10
- package/dist/events/event-filters.js +6 -6
- package/dist/events/json-salvage.d.ts +2 -1
- package/dist/events/json-salvage.js +6 -6
- package/dist/events/observed-in-window.d.ts +12 -0
- package/dist/events/observed-in-window.js +21 -0
- package/dist/events/predicate-eval.d.ts +43 -20
- package/dist/events/predicate-eval.js +159 -55
- package/dist/events/predicate.d.ts +2 -2
- package/dist/events/predicate.js +112 -35
- package/dist/events/reconcile.js +5 -5
- package/dist/events/ring-buffer.js +1 -1
- package/dist/events/stale-response.js +6 -6
- package/dist/events/testid-near-miss.d.ts +22 -0
- package/dist/events/testid-near-miss.js +33 -0
- package/dist/events/unit-mismatch.js +8 -8
- package/dist/flows/affected-tools.js +19 -4
- package/dist/flows/affected.js +1 -1
- package/dist/flows/annotate-target.d.ts +1 -0
- package/dist/flows/annotate-target.js +20 -0
- package/dist/flows/annotate-tools.js +25 -3
- package/dist/flows/annotate.js +17 -4
- package/dist/flows/assertion-integrity.d.ts +2 -1
- package/dist/flows/assertion-tiers-store.d.ts +3 -66
- package/dist/flows/assertion-tiers-store.js +2 -2
- package/dist/flows/attributed-failure.d.ts +17 -0
- package/dist/flows/attributed-failure.js +20 -0
- package/dist/flows/buddy-status.d.ts +2 -1
- package/dist/flows/buddy-status.js +2 -2
- package/dist/flows/coverage.d.ts +3 -2
- package/dist/flows/coverage.js +2 -2
- package/dist/flows/decision.js +24 -9
- package/dist/flows/empty-flow.d.ts +6 -0
- package/dist/flows/empty-flow.js +24 -0
- package/dist/flows/flake-store.d.ts +0 -1
- package/dist/flows/flake-store.js +1 -1
- package/dist/flows/flake.d.ts +2 -1
- package/dist/flows/flake.js +2 -2
- package/dist/flows/flow-classify.js +12 -0
- package/dist/flows/flow-replay-run.js +4 -4
- package/dist/flows/flow-replay.d.ts +5 -7
- package/dist/flows/flow-replay.js +114 -47
- package/dist/flows/flow-report.js +1 -1
- package/dist/flows/flow-scope.d.ts +1 -6
- package/dist/flows/flow-step-runners.d.ts +26 -6
- package/dist/flows/flow-step-runners.js +157 -6
- package/dist/flows/flow-success.js +20 -15
- package/dist/flows/flow-tools.js +53 -7
- package/dist/flows/flows.js +15 -11
- package/dist/flows/gate.d.ts +4 -3
- package/dist/flows/gate.js +1 -1
- package/dist/flows/heal-run.d.ts +0 -8
- package/dist/flows/heal-run.js +5 -5
- package/dist/flows/heal.js +3 -3
- package/dist/flows/predicate-to-expect.d.ts +38 -0
- package/dist/flows/predicate-to-expect.js +95 -0
- package/dist/flows/replay.d.ts +16 -1
- package/dist/flows/replay.js +58 -22
- package/dist/flows/role-anchor-nearest.d.ts +6 -0
- package/dist/flows/role-anchor-nearest.js +45 -0
- package/dist/flows/server-verify.d.ts +1 -1
- package/dist/flows/server-verify.js +5 -5
- package/dist/flows/verify-change-tools.js +32 -10
- package/dist/flows/verify-change-verdict.d.ts +15 -0
- package/dist/flows/verify-change-verdict.js +25 -0
- package/dist/flows/watch-batcher.d.ts +3 -2
- package/dist/honesty/already-true.d.ts +2 -0
- package/dist/honesty/already-true.js +31 -0
- package/dist/honesty/blind-spots.d.ts +16 -3
- package/dist/honesty/blind-spots.js +24 -12
- package/dist/honesty/honesty.d.ts +3 -2
- package/dist/honesty/honesty.js +4 -4
- package/dist/honesty/uncaptured-bodies.js +1 -1
- package/dist/honesty/unread-outcome.js +2 -2
- package/dist/honesty/verified.d.ts +22 -3
- package/dist/honesty/verified.js +48 -8
- package/dist/http-server.js +14 -7
- package/dist/hunt/hunt-report.d.ts +2 -1
- package/dist/hunt/hunt-report.js +2 -2
- package/dist/index.d.ts +8 -6
- package/dist/index.js +32 -25
- package/dist/init/agent-rules.d.ts +2 -1
- package/dist/init/agent-rules.js +45 -7
- package/dist/init/app-choice.d.ts +20 -0
- package/dist/init/app-choice.js +25 -0
- package/dist/init/astro-host.d.ts +21 -0
- package/dist/init/astro-host.js +27 -0
- package/dist/init/astro-patch.d.ts +16 -0
- package/dist/init/astro-patch.js +240 -0
- package/dist/init/capabilities.js +4 -1
- package/dist/init/cra.d.ts +37 -0
- package/dist/init/cra.js +90 -0
- package/dist/init/cursor.js +39 -4
- package/dist/init/desktop-doctor.d.ts +3 -2
- package/dist/init/desktop-doctor.js +4 -4
- package/dist/init/detect.d.ts +3 -2
- package/dist/init/detect.js +16 -5
- package/dist/init/mcp-registered.d.ts +12 -0
- package/dist/init/mcp-registered.js +14 -0
- package/dist/init/mcp.d.ts +27 -2
- package/dist/init/mcp.js +40 -4
- package/dist/init/next-patch.d.ts +2 -4
- package/dist/init/next-patch.js +109 -19
- package/dist/init/node-io.js +23 -6
- package/dist/init/plan-framework.d.ts +16 -1
- package/dist/init/plan-framework.js +132 -8
- package/dist/init/plan.d.ts +73 -8
- package/dist/init/plan.js +133 -34
- package/dist/init/project-id.d.ts +5 -9
- package/dist/init/project-id.js +10 -22
- package/dist/init/run.d.ts +5 -0
- package/dist/init/run.js +210 -36
- package/dist/init/slash-command.d.ts +9 -0
- package/dist/init/slash-command.js +10 -1
- package/dist/init/snippets.d.ts +7 -10
- package/dist/init/snippets.js +44 -15
- package/dist/init/vite-config.js +1 -1
- package/dist/init/workspace-apps.d.ts +23 -0
- package/dist/init/workspace-apps.js +68 -0
- package/dist/input/driven-redaction.js +1 -1
- package/dist/input/network-detail.js +8 -8
- package/dist/input/network-mock-tools.js +2 -2
- package/dist/input/network-mock.js +4 -4
- package/dist/input/real-input.js +8 -3
- package/dist/input/scroll-find.js +2 -2
- package/dist/input/scroll-tools.d.ts +0 -5
- package/dist/input/scroll-tools.js +11 -4
- package/dist/input/viewport-tools.js +2 -2
- package/dist/journal/ambient-store.d.ts +0 -2
- package/dist/journal/ambient-store.js +1 -1
- package/dist/journal/ambient.js +1 -1
- package/dist/journal/attach-journal.d.ts +2 -1
- package/dist/journal/deviation-report.js +6 -6
- package/dist/journal/deviation-service.js +1 -1
- package/dist/journal/envelope-store.d.ts +0 -2
- package/dist/journal/envelope-store.js +1 -1
- package/dist/journal/envelope.d.ts +2 -3
- package/dist/journal/envelope.js +3 -3
- package/dist/journal/journal-query.js +1 -1
- package/dist/journal/journal-recorder.d.ts +2 -1
- package/dist/journal/journal-recorder.js +2 -2
- package/dist/journal/rollups.js +9 -9
- package/dist/journal/session-end.d.ts +2 -1
- package/dist/journal/session-journal.js +4 -4
- package/dist/license/license.d.ts +0 -14
- package/dist/license/license.js +8 -8
- package/dist/log.d.ts +10 -0
- package/dist/log.js +11 -1
- package/dist/mcp/mcp-is-error.d.ts +13 -0
- package/dist/mcp/mcp-is-error.js +18 -0
- package/dist/mcp/mcp-outage.d.ts +31 -0
- package/dist/mcp/mcp-outage.js +48 -0
- package/dist/mcp/mcp-proxy.d.ts +124 -0
- package/dist/mcp/mcp-proxy.js +697 -0
- package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
- package/dist/{mcp.js → mcp/mcp.js} +110 -35
- package/dist/mcp/proxy-handshake.d.ts +3 -0
- package/dist/mcp/proxy-handshake.js +54 -0
- package/dist/mcp/proxy-lifecycle.d.ts +64 -0
- package/dist/mcp/proxy-lifecycle.js +70 -0
- package/dist/mcp/tool-catalog-cache.d.ts +29 -0
- package/dist/mcp/tool-catalog-cache.js +55 -0
- package/dist/oracles/propose-consequences.d.ts +2 -1
- package/dist/oracles/propose-consequences.js +16 -11
- package/dist/oracles/self-instrument.d.ts +2 -1
- package/dist/oracles/self-instrument.js +1 -1
- package/dist/phenomena/phenomena.js +3 -3
- package/dist/platform.d.ts +16 -0
- package/dist/platform.js +16 -0
- package/dist/pool/playwright-launcher.d.ts +15 -2
- package/dist/pool/playwright-launcher.js +21 -2
- package/dist/project/fs-port.js +1 -1
- package/dist/project/project-tools.js +2 -2
- package/dist/runs/build-verification-run.js +1 -1
- package/dist/runs/repair-prompt.d.ts +0 -6
- package/dist/runs/repair-prompt.js +3 -3
- package/dist/runs/risk-classify.js +1 -1
- package/dist/runs/run-diff.d.ts +0 -2
- package/dist/runs/run-diff.js +3 -3
- package/dist/runs/run-tools.js +2 -2
- package/dist/runs/verification-sync.js +2 -2
- package/dist/runs/verify-http.js +1 -1
- package/dist/runs/verify-server.js +1 -1
- package/dist/session/command-timeout.d.ts +11 -3
- package/dist/session/command-timeout.js +2 -2
- package/dist/session/control-envelope.d.ts +6 -0
- package/dist/session/control-envelope.js +7 -1
- package/dist/session/dev-server-probe.d.ts +13 -0
- package/dist/session/dev-server-probe.js +52 -0
- package/dist/session/last-act.d.ts +17 -3
- package/dist/session/last-act.js +16 -4
- package/dist/session/live-control-tools.js +7 -2
- package/dist/session/live-control.js +1 -1
- package/dist/session/looks-like-dev-server.d.ts +14 -0
- package/dist/session/looks-like-dev-server.js +25 -0
- package/dist/session/no-session-diagnosis.d.ts +38 -0
- package/dist/session/no-session-diagnosis.js +70 -0
- package/dist/session/no-session-watch.d.ts +19 -0
- package/dist/session/no-session-watch.js +61 -0
- package/dist/session/observed-state.d.ts +4 -0
- package/dist/session/observed-state.js +19 -1
- package/dist/session/output-budget.js +1 -1
- package/dist/session/session-health.d.ts +8 -1
- package/dist/session/session-health.js +8 -7
- package/dist/session/session-info.d.ts +26 -7
- package/dist/session/session-info.js +42 -1
- package/dist/session/session-lease.d.ts +0 -11
- package/dist/session/session-lease.js +1 -1
- package/dist/session/session-manager.d.ts +3 -0
- package/dist/session/session-manager.js +52 -9
- package/dist/session/session-readiness.d.ts +1 -1
- package/dist/session/session-readiness.js +6 -1
- package/dist/session/session-reaper.js +1 -1
- package/dist/session/session-reconnect.d.ts +32 -0
- package/dist/session/session-reconnect.js +42 -0
- package/dist/session/session.d.ts +14 -2
- package/dist/session/session.js +69 -26
- package/dist/session/state-select.d.ts +1 -1
- package/dist/session/state-select.js +1 -1
- package/dist/status-payload.d.ts +19 -0
- package/dist/status-payload.js +11 -0
- package/dist/telemetry/argument-shape.js +10 -1
- package/dist/telemetry/browser-mode.d.ts +27 -0
- package/dist/telemetry/browser-mode.js +33 -0
- package/dist/telemetry/bug-found.d.ts +17 -21
- package/dist/telemetry/bug-found.js +120 -8
- package/dist/telemetry/cli-telemetry.d.ts +2 -12
- package/dist/telemetry/cli-telemetry.js +27 -4
- package/dist/telemetry/daemon-telemetry.d.ts +19 -0
- package/dist/telemetry/daemon-telemetry.js +12 -2
- package/dist/telemetry/dev-repo.js +4 -4
- package/dist/telemetry/error-fingerprint.js +21 -2
- package/dist/telemetry/feedback-cli.d.ts +1 -1
- package/dist/telemetry/feedback-cli.js +4 -4
- package/dist/telemetry/feedback-context.d.ts +22 -0
- package/dist/telemetry/feedback-context.js +41 -1
- package/dist/telemetry/feedback-delivery.d.ts +20 -0
- package/dist/telemetry/feedback-delivery.js +30 -0
- package/dist/telemetry/feedback-outbox.d.ts +22 -0
- package/dist/telemetry/feedback-outbox.js +87 -0
- package/dist/telemetry/feedback.d.ts +22 -1
- package/dist/telemetry/feedback.js +67 -8
- package/dist/telemetry/git-facts.js +1 -1
- package/dist/telemetry/session-metrics.d.ts +2 -0
- package/dist/telemetry/session-metrics.js +68 -6
- package/dist/telemetry/telemetry.d.ts +27 -2
- package/dist/telemetry/telemetry.js +119 -29
- package/dist/telemetry/verification-of.d.ts +22 -0
- package/dist/telemetry/verification-of.js +84 -0
- package/dist/tools/act-capsule.js +2 -2
- package/dist/tools/act-danger.d.ts +12 -0
- package/dist/tools/act-danger.js +20 -3
- package/dist/tools/act-helpers.js +4 -4
- package/dist/tools/act-tools.d.ts +0 -8
- package/dist/tools/act-tools.js +84 -115
- package/dist/tools/act-view.js +7 -7
- package/dist/tools/alias-args.d.ts +17 -0
- package/dist/tools/alias-args.js +25 -0
- package/dist/tools/assert-grade.js +9 -9
- package/dist/tools/assert-verdict.d.ts +3 -1
- package/dist/tools/assert-verdict.js +8 -5
- package/dist/tools/browser-tools.js +30 -11
- package/dist/tools/contract-tools.js +1 -1
- package/dist/tools/coverage-identity.d.ts +34 -0
- package/dist/tools/coverage-identity.js +46 -0
- package/dist/tools/coverage-tools.js +10 -14
- package/dist/tools/dynamic-tools.d.ts +2 -1
- package/dist/tools/dynamic-tools.js +90 -18
- package/dist/tools/error-recovery.d.ts +20 -2
- package/dist/tools/error-recovery.js +179 -4
- package/dist/tools/feedback-tools.d.ts +12 -1
- package/dist/tools/feedback-tools.js +28 -5
- package/dist/tools/invoke-tool.d.ts +0 -6
- package/dist/tools/invoke-tool.js +57 -32
- package/dist/tools/lease-hint.d.ts +17 -0
- package/dist/tools/lease-hint.js +24 -0
- package/dist/tools/lease-tools.js +6 -5
- package/dist/tools/merge-tools.d.ts +10 -1
- package/dist/tools/merge-tools.js +9 -3
- package/dist/tools/merged-name-redirect.d.ts +13 -0
- package/dist/tools/merged-name-redirect.js +55 -0
- package/dist/tools/navigate-result.d.ts +17 -0
- package/dist/tools/navigate-result.js +31 -0
- package/dist/tools/observe-tools.js +54 -20
- package/dist/tools/observed-nothing.d.ts +25 -0
- package/dist/tools/observed-nothing.js +33 -0
- package/dist/tools/query-paginate.js +2 -2
- package/dist/tools/query-shape.d.ts +18 -0
- package/dist/tools/query-shape.js +39 -0
- package/dist/tools/read-tools.js +81 -20
- package/dist/tools/real-input-attempt.d.ts +28 -0
- package/dist/tools/real-input-attempt.js +88 -0
- package/dist/tools/reconcile-tools.js +7 -7
- package/dist/tools/reload-result.d.ts +14 -0
- package/dist/tools/reload-result.js +29 -0
- package/dist/tools/snapshot-delta.d.ts +4 -5
- package/dist/tools/snapshot-delta.js +0 -0
- package/dist/tools/tool-kit.d.ts +8 -0
- package/dist/tools/tool-surface.d.ts +83 -0
- package/dist/tools/tool-surface.js +204 -0
- package/dist/tools/tools-helpers.js +6 -6
- package/dist/tools/tools.d.ts +15 -0
- package/dist/tools/tools.js +53 -17
- package/dist/tools/unadvertised-help.d.ts +5 -0
- package/dist/tools/unadvertised-help.js +39 -0
- package/dist/trace.d.ts +69 -0
- package/dist/trace.js +150 -0
- package/dist/update/nudge-credit.d.ts +4 -0
- package/dist/update/nudge-credit.js +53 -0
- package/dist/update/sdk-sync.d.ts +21 -0
- package/dist/update/sdk-sync.js +42 -0
- package/dist/update/update-checker.js +3 -3
- package/dist/update/update-nudge.d.ts +63 -6
- package/dist/update/update-nudge.js +128 -15
- package/dist/update/updater.d.ts +1 -9
- package/dist/update/updater.js +13 -8
- package/dist/version/peer-announce.d.ts +4 -0
- package/dist/version/peer-announce.js +30 -0
- package/dist/{server-version.js → version/server-version.js} +5 -1
- package/dist/version/version-nudge.d.ts +28 -0
- package/dist/version/version-nudge.js +40 -0
- package/dist/version/version-skew.d.ts +66 -0
- package/dist/version/version-skew.js +71 -0
- package/dist/visual/visual-diff.js +2 -2
- package/dist/visual/visual-tools.js +4 -4
- package/docs/agent-cheatsheet.md +85 -0
- package/docs/architecture.md +113 -0
- package/docs/benchmarks.md +255 -0
- package/docs/debugging.md +102 -0
- package/docs/deploy-checks.md +69 -0
- package/docs/desktop-apps.md +256 -0
- package/docs/enterprise.md +62 -0
- package/docs/fixtures.md +28 -0
- package/docs/flows.md +166 -0
- package/docs/getting-started.md +469 -0
- package/docs/human-control.md +63 -0
- package/docs/integration-patterns.md +171 -0
- package/docs/local-registry.md +126 -0
- package/docs/mint.json +61 -0
- package/docs/multi-agent-testing.md +55 -0
- package/docs/platform-integration.md +122 -0
- package/docs/telemetry-contract.md +214 -0
- package/docs/telemetry.md +184 -0
- package/docs/testing.md +82 -0
- package/docs/token-efficiency.md +80 -0
- package/docs/usage.md +1046 -0
- package/package.json +8 -5
- package/dist/cli-launch.js +0 -112
- package/dist/daemon-resilience.d.ts +0 -22
- package/dist/daemon-resilience.js +0 -85
- package/dist/mcp-proxy.d.ts +0 -67
- package/dist/mcp-proxy.js +0 -337
- package/dist/tools/profiles.d.ts +0 -37
- package/dist/tools/profiles.js +0 -139
- /package/dist/{pairing-token.d.ts → bridge/pairing-token.d.ts} +0 -0
- /package/dist/{token-auth.d.ts → bridge/token-auth.d.ts} +0 -0
- /package/dist/{token-auth.js → bridge/token-auth.js} +0 -0
- /package/dist/{cli-doctor.d.ts → cli/cli-doctor.d.ts} +0 -0
- /package/dist/{cli-verify.d.ts → cli/cli-verify.d.ts} +0 -0
- /package/dist/{cloud-cli.d.ts → cli/cloud-cli.d.ts} +0 -0
- /package/dist/{server-version.d.ts → version/server-version.d.ts} +0 -0
package/dist/tools/read-tools.js
CHANGED
|
@@ -2,18 +2,43 @@
|
|
|
2
2
|
* Read / record / replay tools — baselines + diff, recordings + replay, narrate, clock, state,
|
|
3
3
|
* explore. Split out of tools.ts; assembled back via...READ_TOOLS.
|
|
4
4
|
*/
|
|
5
|
+
import { resolveAnnotateTarget } from '../flows/annotate-target.js';
|
|
5
6
|
import { z } from 'zod';
|
|
6
7
|
import { EventType, ReticleCommand, REPLAY_PROGRAM_VERSION, SnapshotMode } from '@reticlehq/core';
|
|
7
8
|
import { ReticleTool } from './tool-names.js';
|
|
8
9
|
import { proposeConsequences } from '../oracles/propose-consequences.js';
|
|
9
10
|
import { replayProgram } from '../flows/replay.js';
|
|
10
11
|
import { diffLines } from '../project/baselines.js';
|
|
11
|
-
import { selectPath, capDepth } from '../session/state-select.js';
|
|
12
|
+
import { selectPath, capDepth, projectComponentState } from '../session/state-select.js';
|
|
12
13
|
import { costHint } from '../session/output-budget.js';
|
|
13
14
|
import { buildReactionReport } from '../events/reaction.js';
|
|
14
15
|
import { asString, asNumber, parseInteractive } from './tools-helpers.js';
|
|
15
16
|
import { sessionIdShape, commandOrThrow, snapshotTree } from './tool-kit.js';
|
|
16
17
|
import { bufferEnvelope } from '../session/session-health.js';
|
|
18
|
+
/**
|
|
19
|
+
* What record-stop says about a step that compiled to no anchor at all.
|
|
20
|
+
*
|
|
21
|
+
* `stable: false` does not mean "brittle". It means the compiler found no testid, no accessible
|
|
22
|
+
* role+name and no component/source, so the step is bound to a live `ref` — a handle that dies with
|
|
23
|
+
* the session. The replayer already states this outcome in full (see DEGRADED_STEP_REASON): the step
|
|
24
|
+
* can never resolve on replay.
|
|
25
|
+
*
|
|
26
|
+
* The old wording here — "replay may be brittle (in-session only)" — described a fatal condition as
|
|
27
|
+
* a quality note, so the agent saved the flow and learned the truth several calls later, as an
|
|
28
|
+
* unhealable `anchor_degraded` drift at flow_verify, by which point nothing on screen points back
|
|
29
|
+
* to the element that needed the attribute. Capture time is the only moment the fix is cheap: the
|
|
30
|
+
* element is still on the page and the human is still in the loop.
|
|
31
|
+
*/
|
|
32
|
+
function unanchoredWarning(count) {
|
|
33
|
+
return (`${String(count)} step(s) not bound to a testid, an accessible role+name, or a component — ` +
|
|
34
|
+
'they are pinned to a live ref, so they will replay in THIS session and can never resolve in ' +
|
|
35
|
+
'another one. Add a data-testid to those elements and record the flow again, or accept that ' +
|
|
36
|
+
'this recording is single-session only.');
|
|
37
|
+
}
|
|
38
|
+
/** Severities the presenter HUD can render. */
|
|
39
|
+
const HUD_LEVELS = ['info', 'warn', 'error'];
|
|
40
|
+
const HUD_LEVEL_LIST = HUD_LEVELS.join(' | ');
|
|
41
|
+
const hudLevelEnum = z.enum(HUD_LEVELS);
|
|
17
42
|
export const READ_TOOLS = [
|
|
18
43
|
{
|
|
19
44
|
name: ReticleTool.BASELINE_SAVE,
|
|
@@ -64,7 +89,11 @@ export const READ_TOOLS = [
|
|
|
64
89
|
buffer: z.unknown().optional(),
|
|
65
90
|
},
|
|
66
91
|
handler: async (deps, args) => {
|
|
67
|
-
|
|
92
|
+
// `name` too: the merged reticle_baseline family made this required field optional, and the
|
|
93
|
+
// SIBLING that creates a baseline calls it `name` — its description even says to reuse it
|
|
94
|
+
// here. So `{ action:"diff", name:"x" }` is a valid call that used to look up 'default' and
|
|
95
|
+
// report "no baseline named 'default'", naming something the caller never mentioned.
|
|
96
|
+
const name = asString(args['baseline']) ?? asString(args['name']) ?? 'default';
|
|
68
97
|
const base = deps.baselines.get(name);
|
|
69
98
|
if (base === undefined)
|
|
70
99
|
throw new Error(`no baseline named '${name}'`);
|
|
@@ -127,10 +156,17 @@ export const READ_TOOLS = [
|
|
|
127
156
|
},
|
|
128
157
|
handler: (deps, args) => {
|
|
129
158
|
const session = deps.sessions.resolve(asString(args['sessionId']));
|
|
130
|
-
|
|
159
|
+
// The recording actually RUNNING when there is exactly one, not the literal name `default` —
|
|
160
|
+
// the same defaulting that made `annotate` report "no steps" against a recording full of them.
|
|
161
|
+
// With several running, `default` stays the documented answer rather than a guess.
|
|
162
|
+
const name = resolveAnnotateTarget(asString(args['recordingName']), deps.recordings.active());
|
|
131
163
|
const rec = deps.recordings.stop(name);
|
|
132
|
-
if (rec === undefined)
|
|
133
|
-
|
|
164
|
+
if (rec === undefined) {
|
|
165
|
+
const active = deps.recordings.active();
|
|
166
|
+
throw new Error(0 === active.length
|
|
167
|
+
? `no active recording named '${name}' — none is in progress`
|
|
168
|
+
: `no active recording named '${name}'; in progress: ${active.map((r) => `'${r}'`).join(', ')}`);
|
|
169
|
+
}
|
|
134
170
|
const events = session.eventsSince(rec.cursor);
|
|
135
171
|
const program = {
|
|
136
172
|
name,
|
|
@@ -147,7 +183,7 @@ export const READ_TOOLS = [
|
|
|
147
183
|
program,
|
|
148
184
|
...(unstable > 0
|
|
149
185
|
? {
|
|
150
|
-
warning:
|
|
186
|
+
warning: unanchoredWarning(unstable),
|
|
151
187
|
}
|
|
152
188
|
: {}),
|
|
153
189
|
...(proposedConsequences.length > 0 ? { proposedConsequences } : {}),
|
|
@@ -186,7 +222,7 @@ export const READ_TOOLS = [
|
|
|
186
222
|
throw new Error(`no compiled recording named '${name}'`);
|
|
187
223
|
const session = deps.sessions.resolve(asString(args['sessionId']));
|
|
188
224
|
const since = session.elapsed();
|
|
189
|
-
const steps = await replayProgram(session, program, args['confirmDangerous']
|
|
225
|
+
const steps = await replayProgram(session, program, true === args['confirmDangerous']);
|
|
190
226
|
return { recordingName: name, since, steps, ok: steps.every((s) => s.ok) };
|
|
191
227
|
},
|
|
192
228
|
},
|
|
@@ -197,10 +233,11 @@ export const READ_TOOLS = [
|
|
|
197
233
|
text: z
|
|
198
234
|
.string()
|
|
199
235
|
.describe('Short sentence describing your next action, shown on the presenter HUD for the developer watching.'),
|
|
200
|
-
|
|
201
|
-
|
|
236
|
+
// Derived, like every other advertised vocabulary here: a free string let a typo through to
|
|
237
|
+
// a HUD that then rendered an unknown severity.
|
|
238
|
+
level: hudLevelEnum
|
|
202
239
|
.optional()
|
|
203
|
-
.describe(
|
|
240
|
+
.describe(`Display severity: ${HUD_LEVEL_LIST}. Default: info.`),
|
|
204
241
|
...sessionIdShape,
|
|
205
242
|
},
|
|
206
243
|
outputSchema: { ok: z.boolean() },
|
|
@@ -227,9 +264,11 @@ export const READ_TOOLS = [
|
|
|
227
264
|
reset: z.boolean().optional().describe('Restore the real clock.'),
|
|
228
265
|
...sessionIdShape,
|
|
229
266
|
},
|
|
267
|
+
// The command returns `{ frozen }`. It used to declare `{ ok, elapsed }` — neither of which any
|
|
268
|
+
// clock code path produces — and MCP strips undeclared fields from structuredContent, so a
|
|
269
|
+
// successful freeze and a failed one both validated to `{}` and became indistinguishable.
|
|
230
270
|
outputSchema: {
|
|
231
|
-
|
|
232
|
-
elapsed: z.number().optional(),
|
|
271
|
+
frozen: z.boolean().optional(),
|
|
233
272
|
},
|
|
234
273
|
handler: (deps, args) => commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.CLOCK, {
|
|
235
274
|
freeze: args['freeze'],
|
|
@@ -275,7 +314,21 @@ export const READ_TOOLS = [
|
|
|
275
314
|
// concludes the key it wants is absent when it is merely past the cap.
|
|
276
315
|
totalKeys: z.number().optional(),
|
|
277
316
|
component: z
|
|
278
|
-
.object({
|
|
317
|
+
.object({
|
|
318
|
+
ok: z.boolean(),
|
|
319
|
+
reason: z.string().optional(),
|
|
320
|
+
state: z.unknown().optional(),
|
|
321
|
+
// The component name and the projected hook VALUES — declared so a schema-strict client
|
|
322
|
+
// keeps them (they were the point of passing `ref` at all).
|
|
323
|
+
component: z.string().optional(),
|
|
324
|
+
hooks: z.array(z.unknown()).optional(),
|
|
325
|
+
// Present only when effect hooks were projected out. Declared for the same reason as the
|
|
326
|
+
// store truncation report below: a shortened list with no marker reads as a complete one.
|
|
327
|
+
truncation: z
|
|
328
|
+
.object({ droppedItems: z.number(), note: z.string() })
|
|
329
|
+
.optional()
|
|
330
|
+
.describe('Present only when effect hooks were dropped — `hooks` is a projection.'),
|
|
331
|
+
})
|
|
279
332
|
.optional(),
|
|
280
333
|
// Truncation report — present ONLY when a transport cap trimmed the value. Declared so a
|
|
281
334
|
// schema-strict client on the `full` profile KEEPS it: this is a false-green GUARD, and dropping
|
|
@@ -298,23 +351,31 @@ export const READ_TOOLS = [
|
|
|
298
351
|
// Forward path/depth so a CURRENT browser SDK scopes the read IN-PAGE, before the transport —
|
|
299
352
|
// the value never gets size-truncated in transit. (An older SDK ignores them and returns the
|
|
300
353
|
// whole store; we then scope server-side below as a back-compat fallback.)
|
|
301
|
-
const
|
|
354
|
+
const raw = await commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.STATE_READ, {
|
|
302
355
|
ref: args['ref'],
|
|
303
356
|
store,
|
|
304
357
|
path,
|
|
305
358
|
depth,
|
|
306
359
|
});
|
|
360
|
+
// Project the component hook read BEFORE anything else touches it: React hands back the raw
|
|
361
|
+
// fiber hook list, whose effect entries are chained null-filled internals an agent cannot act
|
|
362
|
+
// on (measured: 2632 -> 1459 bytes on a five-state/three-effect component). Done here rather
|
|
363
|
+
// than in the SDK so an older browser build gets the same projection. The drop is disclosed
|
|
364
|
+
// on `component.truncation`.
|
|
365
|
+
const result = 'object' === typeof raw && null !== raw && 'component' in raw
|
|
366
|
+
? { ...raw, component: projectComponentState(raw.component) }
|
|
367
|
+
: raw;
|
|
307
368
|
// Normalize storeNames to a string[] regardless of how the wire delivered it — the
|
|
308
369
|
// outputSchema requires an array, and a non-array here makes MCP reject the whole result
|
|
309
370
|
// (so the agent gets nothing instead of the state). Defensive: a string becomes a 1-element array.
|
|
310
371
|
const root = result;
|
|
311
372
|
const names = Array.isArray(root.storeNames)
|
|
312
|
-
? root.storeNames.filter((n) => typeof n
|
|
313
|
-
: typeof root.storeNames
|
|
373
|
+
? root.storeNames.filter((n) => 'string' === typeof n)
|
|
374
|
+
: 'string' === typeof root.storeNames && root.storeNames.length > 0
|
|
314
375
|
? [root.storeNames]
|
|
315
376
|
: [];
|
|
316
377
|
// The browser already scoped it in-page (the `found` shape) — pass through, just safe storeNames.
|
|
317
|
-
if (typeof root.found
|
|
378
|
+
if ('boolean' === typeof root.found) {
|
|
318
379
|
return { ...root, storeNames: names };
|
|
319
380
|
}
|
|
320
381
|
if (path === undefined && depth === undefined) {
|
|
@@ -372,7 +433,7 @@ export const READ_TOOLS = [
|
|
|
372
433
|
// The walk stops at its node cap and returns a document-order prefix, so an inventory taken
|
|
373
434
|
// from a big page is a floor, not a census — and this is the tool crawl's description points
|
|
374
435
|
// agents at first for "a non-destructive list of what is here".
|
|
375
|
-
...(snap.truncated
|
|
436
|
+
...(true === snap.truncated ? { truncated: true } : {}),
|
|
376
437
|
consoleErrors,
|
|
377
438
|
hint: 'act on each ref, observe the reaction, and report failed requests / console errors / dead controls',
|
|
378
439
|
// Buffer-honesty: the console-error count spans the whole buffer, which evicts — signal it.
|
|
@@ -412,13 +473,13 @@ export const READ_TOOLS = [
|
|
|
412
473
|
const area = asString(args['area']);
|
|
413
474
|
const key = asString(args['key']);
|
|
414
475
|
const result = await commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.STORAGE_READ, area !== undefined ? { area } : {});
|
|
415
|
-
const data = (typeof result
|
|
476
|
+
const data = ('object' === typeof result && result !== null ? result : {});
|
|
416
477
|
if (key === undefined)
|
|
417
478
|
return data;
|
|
418
479
|
// Look up the key in the scoped area, or across all three areas when none was named.
|
|
419
480
|
const areas = area !== undefined ? [data] : [data['local'], data['session'], data['cookies']];
|
|
420
481
|
for (const a of areas) {
|
|
421
|
-
if (typeof a
|
|
482
|
+
if ('object' === typeof a && a !== null && key in a) {
|
|
422
483
|
return { area, key, value: String(a[key]), found: true };
|
|
423
484
|
}
|
|
424
485
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The native-input attempt — everything that decides whether a pointer action is driven through a
|
|
3
|
+
* real input provider or falls back to the occlusion-honest synthetic path, and WHY.
|
|
4
|
+
*
|
|
5
|
+
* Split out of act-tools.ts along its natural seam: the act tools care only about the outcome
|
|
6
|
+
* (`result` defined = it went native), never about provider availability, box resolution,
|
|
7
|
+
* drag-target inspection or the reason taxonomy.
|
|
8
|
+
*/
|
|
9
|
+
import { ActionType, InputModeReason } from '@reticlehq/core';
|
|
10
|
+
import type { Session } from '../session/session.js';
|
|
11
|
+
import { type ToolDeps } from './tool-kit.js';
|
|
12
|
+
interface RealActResult {
|
|
13
|
+
/** Defined only on a successful native action; `undefined` means the synthetic path runs. */
|
|
14
|
+
result: unknown;
|
|
15
|
+
settled: boolean;
|
|
16
|
+
/** Set when a provider was available but threw — surfaces the fallback to the agent. */
|
|
17
|
+
fellBack?: boolean;
|
|
18
|
+
/** Why we went synthetic despite a configured provider (field bug #2: never a silent fallback). */
|
|
19
|
+
reason?: InputModeReason;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Attempt to drive a pointer action via native input. Returns a synthetic outcome (with a
|
|
23
|
+
* `reason` when a provider is configured) whenever the synthetic path should run — no matching
|
|
24
|
+
* page, unresolvable box, declined, etc. A throw inside the provider becomes a synthetic fallback
|
|
25
|
+
* flagged with `fellBack`. `result` is defined only on a real success.
|
|
26
|
+
*/
|
|
27
|
+
export declare function tryRealInput(deps: ToolDeps, session: Session, ref: string, action: ActionType, args: Record<string, unknown>): Promise<RealActResult>;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The native-input attempt — everything that decides whether a pointer action is driven through a
|
|
3
|
+
* real input provider or falls back to the occlusion-honest synthetic path, and WHY.
|
|
4
|
+
*
|
|
5
|
+
* Split out of act-tools.ts along its natural seam: the act tools care only about the outcome
|
|
6
|
+
* (`result` defined = it went native), never about provider availability, box resolution,
|
|
7
|
+
* drag-target inspection or the reason taxonomy.
|
|
8
|
+
*/
|
|
9
|
+
import { ActionType, InputModeReason, ReticleCommand } from '@reticlehq/core';
|
|
10
|
+
import { isPointerAction } from '../input/real-input.js';
|
|
11
|
+
import { assertDragNotDestructive, assertNotDestructive } from './act-danger.js';
|
|
12
|
+
import { NATIVE_INPUT_ARG } from '@reticlehq/core';
|
|
13
|
+
import { asString, asRecord } from './tools-helpers.js';
|
|
14
|
+
import { commandOrThrow } from './tool-kit.js';
|
|
15
|
+
import { asBox } from './act-helpers.js';
|
|
16
|
+
/** Synthetic outcome with a diagnostic reason (provider configured but native input skipped). */
|
|
17
|
+
function synthetic(reason) {
|
|
18
|
+
return reason === undefined
|
|
19
|
+
? { result: undefined, settled: false }
|
|
20
|
+
: { result: undefined, settled: false, reason };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Attempt to drive a pointer action via native input. Returns a synthetic outcome (with a
|
|
24
|
+
* `reason` when a provider is configured) whenever the synthetic path should run — no matching
|
|
25
|
+
* page, unresolvable box, declined, etc. A throw inside the provider becomes a synthetic fallback
|
|
26
|
+
* flagged with `fellBack`. `result` is defined only on a real success.
|
|
27
|
+
*/
|
|
28
|
+
export async function tryRealInput(deps, session, ref, action, args) {
|
|
29
|
+
const provider = deps.realInput;
|
|
30
|
+
if (provider === undefined)
|
|
31
|
+
return synthetic(); // real input not configured — no diagnostic
|
|
32
|
+
if (!isPointerAction(action))
|
|
33
|
+
return synthetic(InputModeReason.NOT_POINTER); // fill/type stay synthetic
|
|
34
|
+
const inner = asRecord(args['args']);
|
|
35
|
+
// "Don't click, run the code": a click/dblclick runs the occlusion-honest SYNTHETIC path by default
|
|
36
|
+
// even with a provider configured — no coordinate gesture to be intercepted by the HUD or missed
|
|
37
|
+
// off-screen. Opt into a trusted native click with args.native:true (file pickers, clipboard,
|
|
38
|
+
// isTrusted-gated handlers). hover/drag genuinely need native pointer state, so they stay real.
|
|
39
|
+
if ((action === ActionType.CLICK || action === ActionType.DBLCLICK) &&
|
|
40
|
+
inner[NATIVE_INPUT_ARG] !== true) {
|
|
41
|
+
return synthetic(InputModeReason.SYNTHETIC_CLICK_PREFERRED);
|
|
42
|
+
}
|
|
43
|
+
if (!(await provider.isAvailableFor(session.url)))
|
|
44
|
+
return synthetic(InputModeReason.PAGE_NOT_CORRELATED);
|
|
45
|
+
const inspected = await commandOrThrow(deps, session.id, ReticleCommand.INSPECT, { ref });
|
|
46
|
+
assertNotDestructive(action, inner, inspected);
|
|
47
|
+
const box = asBox(inspected);
|
|
48
|
+
if (box === undefined)
|
|
49
|
+
return synthetic(InputModeReason.ELEMENT_NOT_LOCATABLE);
|
|
50
|
+
let toBox;
|
|
51
|
+
if (action === ActionType.DRAG) {
|
|
52
|
+
const toRef = asString(inner['toRef']);
|
|
53
|
+
if (toRef === undefined)
|
|
54
|
+
return synthetic(InputModeReason.DRAG_TARGET_UNRESOLVED);
|
|
55
|
+
const targetInspected = await commandOrThrow(deps, session.id, ReticleCommand.INSPECT, {
|
|
56
|
+
ref: toRef,
|
|
57
|
+
});
|
|
58
|
+
// A drag is judged on BOTH ends: dropping onto "Trash" is destructive however innocent the
|
|
59
|
+
// thing being dragged looks.
|
|
60
|
+
assertDragNotDestructive(inner, inspected, targetInspected);
|
|
61
|
+
toBox = asBox(targetInspected);
|
|
62
|
+
if (toBox === undefined)
|
|
63
|
+
return synthetic(InputModeReason.DRAG_TARGET_UNRESOLVED);
|
|
64
|
+
}
|
|
65
|
+
const performArgs = {};
|
|
66
|
+
const value = asString(inner['value']);
|
|
67
|
+
if (value !== undefined)
|
|
68
|
+
performArgs.value = value;
|
|
69
|
+
const text = asString(inner['text']);
|
|
70
|
+
if (text !== undefined)
|
|
71
|
+
performArgs.text = text;
|
|
72
|
+
if (toBox !== undefined)
|
|
73
|
+
performArgs.toBox = toBox;
|
|
74
|
+
try {
|
|
75
|
+
const performed = await provider.perform(session.url, action, box, performArgs);
|
|
76
|
+
if (!performed.performed)
|
|
77
|
+
return synthetic(InputModeReason.PROVIDER_DECLINED);
|
|
78
|
+
return { result: { performed: true, center: performed.center, action }, settled: true };
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return {
|
|
82
|
+
result: undefined,
|
|
83
|
+
settled: false,
|
|
84
|
+
fellBack: true,
|
|
85
|
+
reason: InputModeReason.PROVIDER_ERROR,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -28,17 +28,17 @@ async function capturedBodies(session, since, urlContains) {
|
|
|
28
28
|
for (const event of events) {
|
|
29
29
|
if (event.type !== EventType.NET_REQUEST)
|
|
30
30
|
continue;
|
|
31
|
-
const url = typeof event.data['url']
|
|
31
|
+
const url = 'string' === typeof event.data['url'] ? event.data['url'] : '';
|
|
32
32
|
if (urlContains !== undefined && !url.includes(urlContains))
|
|
33
33
|
continue;
|
|
34
34
|
total += 1;
|
|
35
35
|
const raw = event.data['responseBody'];
|
|
36
|
-
if (typeof raw !== 'string' || raw.length
|
|
36
|
+
if (typeof raw !== 'string' || 0 === raw.length)
|
|
37
37
|
continue;
|
|
38
38
|
// A capped body is not an absent one. Recover the records that closed before the cut rather than
|
|
39
39
|
// reporting nothing about the page with the most data on it.
|
|
40
40
|
const salvaged = salvageJson(raw);
|
|
41
|
-
if (salvaged.values.length
|
|
41
|
+
if (0 === salvaged.values.length)
|
|
42
42
|
continue;
|
|
43
43
|
bodies.push(...salvaged.values);
|
|
44
44
|
withBody += 1;
|
|
@@ -79,11 +79,11 @@ export const RECONCILE_TOOLS = [
|
|
|
79
79
|
const { bodies, withBody, total, truncated } = await capturedBodies(session, since, asString(args['urlContains']));
|
|
80
80
|
// An empty result over data that was never read is the exact false green this tool exists to
|
|
81
81
|
// prevent, so the two cases are reported differently and neither is silent.
|
|
82
|
-
if (bodies.length
|
|
82
|
+
if (0 === bodies.length) {
|
|
83
83
|
return withControl(session, {
|
|
84
84
|
mismatches: [],
|
|
85
85
|
compared: 0,
|
|
86
|
-
note:
|
|
86
|
+
note: 0 === total
|
|
87
87
|
? 'no responses in this window matched — nothing was compared'
|
|
88
88
|
: `${String(total)} response(s) matched but NONE carried a recorded body, so nothing was compared. Enable it where your app calls connect(): \`reticle.connect({ captureNetworkBodies: true })\`, then re-run`,
|
|
89
89
|
});
|
|
@@ -92,7 +92,7 @@ export const RECONCILE_TOOLS = [
|
|
|
92
92
|
mode: SnapshotMode.FULL,
|
|
93
93
|
});
|
|
94
94
|
const tree = snapshot.tree;
|
|
95
|
-
const mismatches = reconcile(bodies, typeof tree
|
|
95
|
+
const mismatches = reconcile(bodies, 'string' === typeof tree ? tree : '');
|
|
96
96
|
// A truncated body is declared whether or not anything was found in it: "no mismatches" over a
|
|
97
97
|
// partially-read payload is a weaker statement than over a whole one, and the difference is
|
|
98
98
|
// exactly the kind of omission this layer exists to refuse.
|
|
@@ -100,7 +100,7 @@ export const RECONCILE_TOOLS = [
|
|
|
100
100
|
? {
|
|
101
101
|
note: `${String(truncated)} of ${String(withBody)} response(s) exceeded the body cap and were read only up to the cut — records after it were not compared`,
|
|
102
102
|
}
|
|
103
|
-
: mismatches.length
|
|
103
|
+
: 0 === mismatches.length
|
|
104
104
|
? {
|
|
105
105
|
note: `compared ${String(withBody)} response(s); nothing on screen contradicts them`,
|
|
106
106
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `navigate { reload: true }` reports.
|
|
3
|
+
*
|
|
4
|
+
* It answered a bare `{ ok: true }`, while the URL branch of the same tool returns `confirmed: false`
|
|
5
|
+
* plus a note — because `ok` means the browser accepted the instruction, not that the page arrived.
|
|
6
|
+
* Identical semantics, one branch disclosing them and one not, and the silent one is the path most
|
|
7
|
+
* likely to need the caveat: a reload tears the SDK down, and a caller that acts on `ok: true` hits
|
|
8
|
+
* the window before it comes back.
|
|
9
|
+
*
|
|
10
|
+
* The permanent session loss reported alongside this is fixed separately — session-continuity.ts
|
|
11
|
+
* remembers the id in sessionStorage so a reload rejoins the SAME session instead of appearing as a
|
|
12
|
+
* new one. This is the remaining half: saying that the page is not back yet.
|
|
13
|
+
*/
|
|
14
|
+
export declare function reloadResult(reconnected?: boolean): Record<string, unknown>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `navigate { reload: true }` reports.
|
|
3
|
+
*
|
|
4
|
+
* It answered a bare `{ ok: true }`, while the URL branch of the same tool returns `confirmed: false`
|
|
5
|
+
* plus a note — because `ok` means the browser accepted the instruction, not that the page arrived.
|
|
6
|
+
* Identical semantics, one branch disclosing them and one not, and the silent one is the path most
|
|
7
|
+
* likely to need the caveat: a reload tears the SDK down, and a caller that acts on `ok: true` hits
|
|
8
|
+
* the window before it comes back.
|
|
9
|
+
*
|
|
10
|
+
* The permanent session loss reported alongside this is fixed separately — session-continuity.ts
|
|
11
|
+
* remembers the id in sessionStorage so a reload rejoins the SAME session instead of appearing as a
|
|
12
|
+
* new one. This is the remaining half: saying that the page is not back yet.
|
|
13
|
+
*/
|
|
14
|
+
/** The reload's own disclosure — the same shape and the same advice the URL branch gives. */
|
|
15
|
+
const RELOAD_NOTE = 'ok means the reload was DISPATCHED, not that the page came back — the SDK is torn down by the ' +
|
|
16
|
+
'reload itself, so nothing here can see the new document yet. Call reticle_sessions to confirm ' +
|
|
17
|
+
'the session reconnected before acting; the session id is preserved across a reload, so it will ' +
|
|
18
|
+
'be the same one.';
|
|
19
|
+
/**
|
|
20
|
+
* What a CONFIRMED reload says. The page re-announced itself under the same id before this returned,
|
|
21
|
+
* so the next call is safe — which is the whole reason the tool now waits instead of advising.
|
|
22
|
+
*/
|
|
23
|
+
const RELOAD_RECONNECTED_NOTE = 'the page came back and re-announced itself under the same session id, so this session is live ' +
|
|
24
|
+
'again — no re-selection needed. Anything captured before the reload is gone with the old document.';
|
|
25
|
+
export function reloadResult(reconnected = false) {
|
|
26
|
+
return reconnected
|
|
27
|
+
? { ok: true, confirmed: true, note: RELOAD_RECONNECTED_NOTE }
|
|
28
|
+
: { ok: true, confirmed: false, note: RELOAD_NOTE };
|
|
29
|
+
}
|
|
@@ -18,13 +18,13 @@ export declare const SnapshotDeltaMode: {
|
|
|
18
18
|
readonly UNCHANGED: "unchanged";
|
|
19
19
|
};
|
|
20
20
|
export type SnapshotDeltaMode = (typeof SnapshotDeltaMode)[keyof typeof SnapshotDeltaMode];
|
|
21
|
-
|
|
21
|
+
interface SnapshotDelta {
|
|
22
22
|
added: string[];
|
|
23
23
|
removed: string[];
|
|
24
24
|
addedCount: number;
|
|
25
25
|
removedCount: number;
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
type DeltaDecision = {
|
|
28
28
|
mode: typeof SnapshotDeltaMode.FULL;
|
|
29
29
|
} | {
|
|
30
30
|
mode: typeof SnapshotDeltaMode.UNCHANGED;
|
|
@@ -43,9 +43,7 @@ export declare class SnapshotCache {
|
|
|
43
43
|
remember(key: string, route: string, tree: string): void;
|
|
44
44
|
}
|
|
45
45
|
export declare function snapshotCacheKey(sessionId: string, scope: string, mode: string): string;
|
|
46
|
-
|
|
47
|
-
export declare const CAPPED_DIFF_NOTE = "this diff covers only the first N nodes of the page (the snapshot hit its cap), so \"unchanged\" means \"unchanged in the part that was captured\" \u2014 narrow with `scope` to see the rest";
|
|
48
|
-
export interface SnapshotDeltaOpts {
|
|
46
|
+
interface SnapshotDeltaOpts {
|
|
49
47
|
sessionId: string;
|
|
50
48
|
scope: string;
|
|
51
49
|
mode: string;
|
|
@@ -58,3 +56,4 @@ export interface SnapshotDeltaOpts {
|
|
|
58
56
|
* the pure `snapshotDelta`.
|
|
59
57
|
*/
|
|
60
58
|
export declare function applySnapshotDelta(raw: unknown, opts: SnapshotDeltaOpts, cache: SnapshotCache): unknown;
|
|
59
|
+
export {};
|
|
Binary file
|
package/dist/tools/tool-kit.d.ts
CHANGED
|
@@ -35,6 +35,14 @@ export interface ToolDeps {
|
|
|
35
35
|
reticleRoot: string;
|
|
36
36
|
/** injected clock for the contract's generatedAt stamp. */
|
|
37
37
|
now: () => number;
|
|
38
|
+
/**
|
|
39
|
+
* The port this daemon's bridge listens on.
|
|
40
|
+
*
|
|
41
|
+
* Needed wherever a message has to name the OTHER half of a port mismatch — the commonest reason
|
|
42
|
+
* a leased tab loads the app and never dials in. Optional so every existing test construction of
|
|
43
|
+
* ToolDeps keeps working; absent falls back to the default port.
|
|
44
|
+
*/
|
|
45
|
+
bridgePort?: number;
|
|
38
46
|
}
|
|
39
47
|
export interface ToolDef {
|
|
40
48
|
name: string;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { ToolDef } from './tools.js';
|
|
2
|
+
/**
|
|
3
|
+
* There is ONE tool surface. This is not a menu.
|
|
4
|
+
*
|
|
5
|
+
* The advertised tool DEFINITIONS are re-sent to the model on every turn, so the surface is a
|
|
6
|
+
* per-turn cost that compounds across a loop, and fewer tools also makes the model wander less.
|
|
7
|
+
* What ships is the verify loop (navigate→look→act→observe→assert, with direct network + console +
|
|
8
|
+
* state) advertised directly, plus two meta-tools — `reticle_tools` to discover and `reticle_run` to
|
|
9
|
+
* invoke — that keep every other tool exactly one call away. Nothing is unreachable; the cold tail
|
|
10
|
+
* just is not re-sent every turn.
|
|
11
|
+
*
|
|
12
|
+
* Five profiles were tried. Four are gone, each for a measured reason rather than a taste:
|
|
13
|
+
*
|
|
14
|
+
* `core` was BYTE-IDENTICAL to the default — 16 tools, 18,183 bytes, the same list. One behaviour
|
|
15
|
+
* behind two names is how "I set it and nothing changed" becomes a support question with no answer.
|
|
16
|
+
*
|
|
17
|
+
* `standard` advertised 17 more tools directly for ~3,500 extra tokens EVERY TURN, buying only the
|
|
18
|
+
* removal of an occasional `reticle_run` hop. Nothing about that was characterisable as a use case.
|
|
19
|
+
*
|
|
20
|
+
* `dynamic` advertised the 2 meta-tools and nothing else. Not one harness, app or bench ever
|
|
21
|
+
* selected it, and this repo's own measurement (bench/agent-loop-and-replay.md) says a pure
|
|
22
|
+
* on-demand surface does NOT hold accuracy with a generic model: "it needs the hot-set schemas.
|
|
23
|
+
* On-demand is for the cold tail, not the hot path." An option that is unused and measured-worse is
|
|
24
|
+
* a trap, not a choice — it looks like a 4,000-token saving and costs correctness.
|
|
25
|
+
*
|
|
26
|
+
* ALL is what remains, and it is deliberately NOT a profile: it is a verification switch. It is the
|
|
27
|
+
* only mode that advertises `outputSchema`, which is what makes the MCP layer validate tool OUTPUT —
|
|
28
|
+
* the check that caught `reticle_verify_change` returning a payload its own schema rejected. It
|
|
29
|
+
* cannot be folded into the default: measured, carrying output schemas on the 16-tool surface costs
|
|
30
|
+
* 18,183 -> 41,117 bytes, 2.26x, +5,733 tokens per turn. And it cannot simply be deleted without
|
|
31
|
+
* losing that defect class. So it stays, named for what it is, and no user is asked to pick it.
|
|
32
|
+
*
|
|
33
|
+
* Sizes are NOT restated here — not as a current figure, not as a historical one. Four generations
|
|
34
|
+
* of this comment got them wrong. They live in surface-sizes.test.ts, which reads them off the real
|
|
35
|
+
* surface. (The numbers above are the two measurements that JUSTIFY a decision, which is a different
|
|
36
|
+
* job from documenting the current size; both were taken with a fresh daemon per reading.)
|
|
37
|
+
*/
|
|
38
|
+
export declare const TOOL_SURFACE: {
|
|
39
|
+
/** What every user gets: the verify loop, plus the 2 meta-tools that reach everything else. */
|
|
40
|
+
readonly DEFAULT: "default";
|
|
41
|
+
/** Every tool advertised directly, WITH output schemas. A verification switch — see above. */
|
|
42
|
+
readonly ALL: "all";
|
|
43
|
+
};
|
|
44
|
+
export type ToolSurface = (typeof TOOL_SURFACE)[keyof typeof TOOL_SURFACE];
|
|
45
|
+
/**
|
|
46
|
+
* The switch that turns on the full, output-schema-carrying surface. A boolean, not a menu.
|
|
47
|
+
*
|
|
48
|
+
* Named for what it does rather than which "profile" it selects, because the previous name invited
|
|
49
|
+
* users to shop among alternatives that did not meaningfully differ.
|
|
50
|
+
*/
|
|
51
|
+
export declare const ADVERTISE_ALL_ENV = "RETICLE_ADVERTISE_ALL_TOOLS";
|
|
52
|
+
/**
|
|
53
|
+
* The retired setting, still read so nobody's shell profile breaks.
|
|
54
|
+
*
|
|
55
|
+
* Every value it ever accepted resolves to something sensible: `full` to the ALL surface, everything
|
|
56
|
+
* else to the default. Silently honouring them would repeat the original sin, so `describeToolSurface`
|
|
57
|
+
* says the setting retired and what was used instead.
|
|
58
|
+
*/
|
|
59
|
+
export declare const TOOL_PROFILE_ENV = "RETICLE_TOOL_PROFILE";
|
|
60
|
+
export declare const CORE_TOOL_NAMES: ReadonlySet<string>;
|
|
61
|
+
/**
|
|
62
|
+
* Which surface is live.
|
|
63
|
+
*
|
|
64
|
+
* `explicit` is the programmatic override (tests, `advertisedTools` callers). Otherwise the ALL
|
|
65
|
+
* switch decides, and the retired setting is honoured last so an old shell profile still works.
|
|
66
|
+
*/
|
|
67
|
+
export declare function resolveToolSurface(explicit?: string): ToolSurface;
|
|
68
|
+
/** The live surface plus what chose it — see describeToolSurface. */
|
|
69
|
+
export interface ToolSurfaceOrigin {
|
|
70
|
+
active: ToolSurface;
|
|
71
|
+
source: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Which surface is live, and what chose it.
|
|
75
|
+
*
|
|
76
|
+
* These settings are read by the DAEMON at startup, never by the client, so exporting one in an
|
|
77
|
+
* agent's environment while a daemon is already running changes nothing at all — which is exactly
|
|
78
|
+
* the observation that produced a "standard and full advertise the same tools" report. Documenting
|
|
79
|
+
* that was not enough; the setting failing to take has to be VISIBLE, so this rides along in the
|
|
80
|
+
* reticle_tools catalog.
|
|
81
|
+
*/
|
|
82
|
+
export declare function describeToolSurface(active: ToolSurface, requested?: string): ToolSurfaceOrigin;
|
|
83
|
+
export declare function filterTools(tools: ToolDef[], surface: ToolSurface): ToolDef[];
|