@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
|
@@ -33,17 +33,23 @@ export function applyMerges(tools, plans, retired = []) {
|
|
|
33
33
|
actions[action] = member;
|
|
34
34
|
consumed.add(memberName);
|
|
35
35
|
}
|
|
36
|
-
merged.push(mergeTools({
|
|
36
|
+
merged.push(mergeTools({
|
|
37
|
+
name: plan.name,
|
|
38
|
+
description: plan.description,
|
|
39
|
+
actions,
|
|
40
|
+
...(plan.example === undefined ? {} : { example: plan.example }),
|
|
41
|
+
}));
|
|
37
42
|
}
|
|
38
43
|
return [...tools.filter((t) => !consumed.has(t.name)), ...merged];
|
|
39
44
|
}
|
|
40
45
|
export function mergeTools(spec) {
|
|
41
46
|
const actionNames = Object.keys(spec.actions);
|
|
42
|
-
if (actionNames.length
|
|
47
|
+
if (0 === actionNames.length)
|
|
43
48
|
throw new Error(`mergeTools(${spec.name}): no actions`);
|
|
44
49
|
return {
|
|
45
50
|
name: spec.name,
|
|
46
51
|
description: spec.description,
|
|
52
|
+
...(spec.example === undefined ? {} : { example: spec.example }),
|
|
47
53
|
inputSchema: {
|
|
48
54
|
action: z
|
|
49
55
|
.enum(actionNames)
|
|
@@ -52,7 +58,7 @@ export function mergeTools(spec) {
|
|
|
52
58
|
},
|
|
53
59
|
handler: (deps, args) => {
|
|
54
60
|
const action = args['action'];
|
|
55
|
-
const chosen = typeof action
|
|
61
|
+
const chosen = 'string' === typeof action ? spec.actions[action] : undefined;
|
|
56
62
|
if (chosen === undefined) {
|
|
57
63
|
return Promise.resolve({
|
|
58
64
|
error: `unknown action '${String(action)}' for ${spec.name}`,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface MergedNameRedirect {
|
|
2
|
+
/** The tool to call instead. */
|
|
3
|
+
tool: string;
|
|
4
|
+
/** The action that selects the old behaviour, when the name was merged rather than retired. */
|
|
5
|
+
action?: string;
|
|
6
|
+
/** Why there is no direct replacement, for a retired name. */
|
|
7
|
+
note?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Where `name` went, or undefined when it is a live tool or not ours. */
|
|
10
|
+
export declare function mergedNameRedirect(name: string): MergedNameRedirect | undefined;
|
|
11
|
+
/** The sentence handed to an agent that called `name`. */
|
|
12
|
+
export declare function mergedNameMessage(name: string, redirect: MergedNameRedirect): string;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a merged or retired tool's old name went.
|
|
3
|
+
*
|
|
4
|
+
* Twenty-two names exported from `ReticleTool` are no longer tools: `reticle_record_start` became
|
|
5
|
+
* `reticle_record { action: "start" }`, `reticle_diff` became `reticle_baseline { action: "diff" }`,
|
|
6
|
+
* and three were retired outright. Confirmed live in a field sweep, they all answered `unknown tool`
|
|
7
|
+
* — which is the wrong answer, because the capability exists and only moved. An agent trained on an
|
|
8
|
+
* earlier release, or reading the merged tool's own description (which names every action), reaches
|
|
9
|
+
* for exactly these.
|
|
10
|
+
*
|
|
11
|
+
* DERIVED from `MERGE_PLANS` and `RETIRED_FROM_SURFACE` rather than written out, so the next merge is
|
|
12
|
+
* covered the day it lands instead of the day someone notices.
|
|
13
|
+
*/
|
|
14
|
+
import { MERGE_PLANS, RETIRED_FROM_SURFACE } from './tools.js';
|
|
15
|
+
import { ReticleTool } from './tool-names.js';
|
|
16
|
+
/** Retired names, and where the capability actually lives now. */
|
|
17
|
+
const RETIRED_NOTE = {
|
|
18
|
+
[ReticleTool.REFRESH]: {
|
|
19
|
+
tool: ReticleTool.NAVIGATE,
|
|
20
|
+
note: 'reloading was absorbed into reticle_navigate { reload: true }',
|
|
21
|
+
},
|
|
22
|
+
[ReticleTool.RUN_RECORD]: {
|
|
23
|
+
tool: ReticleTool.PROJECT,
|
|
24
|
+
note: 'run outcomes are persisted automatically by reticle_flow_replay; read them with reticle_project',
|
|
25
|
+
},
|
|
26
|
+
[ReticleTool.WAIT_READY]: {
|
|
27
|
+
tool: ReticleTool.SESSIONS,
|
|
28
|
+
note: 'waiting is implicit — the first live call already blocks until the session is ready',
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
const BY_OLD_NAME = (() => {
|
|
32
|
+
const map = new Map();
|
|
33
|
+
for (const plan of MERGE_PLANS) {
|
|
34
|
+
for (const [action, oldName] of Object.entries(plan.members)) {
|
|
35
|
+
map.set(oldName, { tool: plan.name, action });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
for (const name of RETIRED_FROM_SURFACE) {
|
|
39
|
+
const known = RETIRED_NOTE[name];
|
|
40
|
+
if (known !== undefined)
|
|
41
|
+
map.set(name, known);
|
|
42
|
+
}
|
|
43
|
+
return map;
|
|
44
|
+
})();
|
|
45
|
+
/** Where `name` went, or undefined when it is a live tool or not ours. */
|
|
46
|
+
export function mergedNameRedirect(name) {
|
|
47
|
+
return BY_OLD_NAME.get(name);
|
|
48
|
+
}
|
|
49
|
+
/** The sentence handed to an agent that called `name`. */
|
|
50
|
+
export function mergedNameMessage(name, redirect) {
|
|
51
|
+
return redirect.action === undefined
|
|
52
|
+
? `${name} no longer exists — ${redirect.note ?? `use ${redirect.tool}`}.`
|
|
53
|
+
: `${name} was merged into ${redirect.tool}. Call ${redirect.tool} { action: "${redirect.action}", ... } — ` +
|
|
54
|
+
`through reticle_run if it is not advertised under this profile.`;
|
|
55
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The honest envelope for a navigation nobody can confirm.
|
|
3
|
+
*
|
|
4
|
+
* `window.location.assign(url)` returns before the page moves, and the SDK that would report on the
|
|
5
|
+
* new document is destroyed by the navigation itself. So a successful NAVIGATE means the browser
|
|
6
|
+
* accepted the instruction — not that anything arrived. Driven against a dead URL it returned
|
|
7
|
+
* `{"ok":true}` while the session died, which is the worst combination available: the agent believes
|
|
8
|
+
* it navigated, is looking at nothing, and has lost Reticle.
|
|
9
|
+
*
|
|
10
|
+
* `reticle_act` already draws this line — `dispatched` (sent) versus `settled` (a frame flushed).
|
|
11
|
+
* This gives navigate the same honesty without changing what it does.
|
|
12
|
+
*/
|
|
13
|
+
export declare function navigateResult(result: {
|
|
14
|
+
ok?: unknown;
|
|
15
|
+
url?: unknown;
|
|
16
|
+
reason?: unknown;
|
|
17
|
+
}): Record<string, unknown>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The honest envelope for a navigation nobody can confirm.
|
|
3
|
+
*
|
|
4
|
+
* `window.location.assign(url)` returns before the page moves, and the SDK that would report on the
|
|
5
|
+
* new document is destroyed by the navigation itself. So a successful NAVIGATE means the browser
|
|
6
|
+
* accepted the instruction — not that anything arrived. Driven against a dead URL it returned
|
|
7
|
+
* `{"ok":true}` while the session died, which is the worst combination available: the agent believes
|
|
8
|
+
* it navigated, is looking at nothing, and has lost Reticle.
|
|
9
|
+
*
|
|
10
|
+
* `reticle_act` already draws this line — `dispatched` (sent) versus `settled` (a frame flushed).
|
|
11
|
+
* This gives navigate the same honesty without changing what it does.
|
|
12
|
+
*/
|
|
13
|
+
export function navigateResult(result) {
|
|
14
|
+
const ok = true === result.ok;
|
|
15
|
+
const base = {
|
|
16
|
+
ok,
|
|
17
|
+
...('string' === typeof result.url ? { url: result.url } : {}),
|
|
18
|
+
...('string' === typeof result.reason ? { reason: result.reason } : {}),
|
|
19
|
+
};
|
|
20
|
+
// A refusal is conclusive: the page never moved, so there is nothing unconfirmed to report.
|
|
21
|
+
if (!ok)
|
|
22
|
+
return base;
|
|
23
|
+
return {
|
|
24
|
+
...base,
|
|
25
|
+
confirmed: false,
|
|
26
|
+
note: 'ok means the navigation was DISPATCHED, not that the page arrived — the SDK is torn down by ' +
|
|
27
|
+
'the navigation itself, so nothing here can see the new document. Call reticle_sessions to ' +
|
|
28
|
+
'confirm a session reconnected at the new URL before acting; if none appears, the page did ' +
|
|
29
|
+
'not load or is not instrumented.',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
* Observe / wait / assert tools — reticle_observe, reticle_wait_for, reticle_assert, reticle_network,
|
|
3
3
|
* reticle_console, reticle_animations. Split out of tools.ts; assembled back via...OBSERVE_TOOLS.
|
|
4
4
|
*/
|
|
5
|
+
import { noteEmptyRead } from './observed-nothing.js';
|
|
5
6
|
import { z } from 'zod';
|
|
6
|
-
import {
|
|
7
|
+
import { aliasParam } from './alias-args.js';
|
|
8
|
+
import { CONSOLE_LEVELS, ReticleCommand, DEFAULT_ASSERT_TIMEOUT_MS, PredicateKind, } from '@reticlehq/core';
|
|
7
9
|
import { ReticleTool } from './tool-names.js';
|
|
8
10
|
import { buildReactionReport } from '../events/reaction.js';
|
|
9
11
|
import { findContradictions } from '../events/contradictions.js';
|
|
@@ -54,11 +56,21 @@ function lastActSourceOnFailure(session, pass) {
|
|
|
54
56
|
* really do interleave; it is only redundant at this boundary.
|
|
55
57
|
*/
|
|
56
58
|
function withoutConstantSessionId(event) {
|
|
57
|
-
if (typeof event !== 'object' ||
|
|
59
|
+
if (typeof event !== 'object' || null === event)
|
|
58
60
|
return event;
|
|
59
61
|
const { sessionId: _sessionId, ...rest } = event;
|
|
60
62
|
return rest;
|
|
61
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* The console levels, derived from core's console EventTypes — see CONSOLE_LEVELS.
|
|
66
|
+
*
|
|
67
|
+
* A free string here filtered by building `console.${level}`, so `level:'ERROR'` or `level:'fatal'`
|
|
68
|
+
* matched nothing and returned an empty log list. On a page that HAS logs the zero-match hint saves
|
|
69
|
+
* it (it reports which levels are present), but on a quiet page the answer is identical to a genuine
|
|
70
|
+
* all-clear. Refusing the value outright is the only reading with no ambiguity.
|
|
71
|
+
*/
|
|
72
|
+
const CONSOLE_LEVEL_LIST = CONSOLE_LEVELS.join(' | ');
|
|
73
|
+
const consoleLevelEnum = z.enum(CONSOLE_LEVELS);
|
|
62
74
|
export const OBSERVE_TOOLS = [
|
|
63
75
|
{
|
|
64
76
|
name: ReticleTool.OBSERVE,
|
|
@@ -180,10 +192,12 @@ export const OBSERVE_TOOLS = [
|
|
|
180
192
|
},
|
|
181
193
|
{
|
|
182
194
|
name: ReticleTool.WAIT_FOR,
|
|
183
|
-
example: { predicate: { kind:
|
|
195
|
+
example: { predicate: { kind: PredicateKind.STATE, path: 'todos.length', equals: 3 } },
|
|
184
196
|
description: 'Block until a predicate is satisfied (or already true in the recent buffer), else time out. Returns matching evidence or a near-miss diagnosis. By default it only counts events since your last act, so a signal buffered BEFORE the action can never fake a pass; pass `since` (an observe/act cursor) to widen or narrow that window explicitly.',
|
|
185
197
|
inputSchema: {
|
|
186
|
-
predicate: PredicateSchema.describe('Predicate to wait for: { signal }, { net }, { element }, { kind: "net", ok: false } (assert on the OUTCOME — the honest field for IPC, which has no status code), { kind: "state", store, path, equals } (assert a registered store\'s value directly — the source of truth no DOM read can reach; equals takes a literal or { $gte | $contains | $length } pattern), { kind: "settled", quietMs } (deterministic network + DOM idle — prefer this over a fixed sleep), or a combination via allOf/anyOf.'),
|
|
198
|
+
predicate: PredicateSchema.optional().describe('Predicate to wait for: { signal }, { net }, { element }, { kind: "net", ok: false } (assert on the OUTCOME — the honest field for IPC, which has no status code), { kind: "state", store, path, equals } (assert a registered store\'s value directly — the source of truth no DOM read can reach; equals takes a literal or { $gte | $contains | $length } pattern), { kind: "settled", quietMs } (deterministic network + DOM idle — prefer this over a fixed sleep), or a combination via allOf/anyOf.'),
|
|
199
|
+
// Same concept, the neighbouring tool's name. See alias-args.ts.
|
|
200
|
+
until: PredicateSchema.optional().describe("Alias for `predicate` (act_and_wait's name)."),
|
|
187
201
|
timeout_ms: z.number().optional().describe('Maximum wait in milliseconds. Default: 4000.'),
|
|
188
202
|
since: z
|
|
189
203
|
.number()
|
|
@@ -218,7 +232,8 @@ export const OBSERVE_TOOLS = [
|
|
|
218
232
|
},
|
|
219
233
|
handler: async (deps, args) => {
|
|
220
234
|
const session = deps.sessions.resolve(asString(args['sessionId']));
|
|
221
|
-
|
|
235
|
+
// `until` is act_and_wait's name for this — see alias-args.ts.
|
|
236
|
+
const predicate = PredicateSchema.parse(aliasParam(args, 'predicate', ['until'])['predicate']);
|
|
222
237
|
// Honesty: explicit since wins; else default to the last act's cursor; else the whole buffer.
|
|
223
238
|
const since = asNumber(args['since']) ?? session.lastAct.cursor() ?? 0;
|
|
224
239
|
const verdict = await waitForPredicate(session, predicate, asNumber(args['timeout_ms']) ?? DEFAULT_ASSERT_TIMEOUT_MS, since);
|
|
@@ -234,10 +249,11 @@ export const OBSERVE_TOOLS = [
|
|
|
234
249
|
},
|
|
235
250
|
{
|
|
236
251
|
name: ReticleTool.ASSERT,
|
|
237
|
-
example: { predicate: { kind:
|
|
252
|
+
example: { predicate: { kind: PredicateKind.SIGNAL, name: 'todos:loaded' } },
|
|
238
253
|
description: 'Evaluate a predicate (optionally waiting up to timeout_ms). Returns { pass, evidence, failureReason? }. The end of every verify loop. Prefer a { signal } or { net } consequence over { element }/{ text } presence — a passing presence-only assertion returns `advice` because a wrong/healed element can fake it. By default it only counts events since your last act, so a stale buffered signal can never fake a pass; pass `since` (an observe/act cursor) to set the window explicitly.',
|
|
239
254
|
inputSchema: {
|
|
240
|
-
predicate: PredicateSchema.describe('Predicate to evaluate: { signal }, { net }, { element } or a combination.'),
|
|
255
|
+
predicate: PredicateSchema.optional().describe('Predicate to evaluate: { signal }, { net }, { element } or a combination.'),
|
|
256
|
+
until: PredicateSchema.optional().describe("Alias for `predicate` (act_and_wait's name)."),
|
|
241
257
|
timeout_ms: z
|
|
242
258
|
.number()
|
|
243
259
|
.optional()
|
|
@@ -287,7 +303,8 @@ export const OBSERVE_TOOLS = [
|
|
|
287
303
|
},
|
|
288
304
|
handler: async (deps, args) => {
|
|
289
305
|
const session = deps.sessions.resolve(asString(args['sessionId']));
|
|
290
|
-
|
|
306
|
+
// `until` is act_and_wait's name for this — see alias-args.ts.
|
|
307
|
+
const predicate = PredicateSchema.parse(aliasParam(args, 'predicate', ['until'])['predicate']);
|
|
291
308
|
const timeout = asNumber(args['timeout_ms']) ?? 0;
|
|
292
309
|
// Honesty: explicit since wins; else default to the last act's cursor; else the whole buffer.
|
|
293
310
|
const since = asNumber(args['since']) ?? session.lastAct.cursor() ?? 0;
|
|
@@ -306,7 +323,7 @@ export const OBSERVE_TOOLS = [
|
|
|
306
323
|
: assertsDerivedIpcStatus(predicate)
|
|
307
324
|
? { advice: DERIVED_IPC_STATUS_ADVICE }
|
|
308
325
|
: {};
|
|
309
|
-
const { decision, contradictions, coverage } = await assertVerdict(session, predicate, verdict.pass, since);
|
|
326
|
+
const { decision, contradictions, coverage } = await assertVerdict(session, predicate, verdict.pass, since, verdict.inconclusive);
|
|
310
327
|
return withControl(session, {
|
|
311
328
|
...decision,
|
|
312
329
|
...verdict,
|
|
@@ -374,7 +391,7 @@ export const OBSERVE_TOOLS = [
|
|
|
374
391
|
const method = asString(args['method']);
|
|
375
392
|
const urlContains = asString(args['urlContains']);
|
|
376
393
|
const status = asNumber(args['status']);
|
|
377
|
-
const ok = typeof args['ok']
|
|
394
|
+
const ok = 'boolean' === typeof args['ok'] ? args['ok'] : undefined;
|
|
378
395
|
const limit = asNumber(args['limit']);
|
|
379
396
|
const buffer = bufferEnvelope(session);
|
|
380
397
|
// Completed calls + unresolved in-flight requests (a hung request shows as pending).
|
|
@@ -385,18 +402,21 @@ export const OBSERVE_TOOLS = [
|
|
|
385
402
|
}));
|
|
386
403
|
const matched = allNet.filter((e) => matchNet(e, method, urlContains, status, ok));
|
|
387
404
|
// zero-match filter returns what DID fire, not a bare [].
|
|
388
|
-
if (matched.length
|
|
405
|
+
if (0 === matched.length && allNet.length > 0) {
|
|
389
406
|
return withSizeCost({ calls: matched, hint: netEmptyHint(allNet), ...buffer });
|
|
390
407
|
}
|
|
391
408
|
// Default the cap so an omitted `limit` can't dump a whole flooded session (since defaults to 0).
|
|
392
409
|
const { events: budgeted, droppedOldest } = applyEventBudget(matched, limit ?? DEFAULT_QUERY_LIMIT);
|
|
393
410
|
const calls = budgeted.map(projectNetCall);
|
|
394
|
-
|
|
411
|
+
// A zero-match FILTER already reports what did fire (netEmptyHint above). Zero calls at all
|
|
412
|
+
// fell through as a bare `[]`, which is indistinguishable from an observer that is not
|
|
413
|
+
// recording — and those need opposite responses. Say the look happened.
|
|
414
|
+
return withSizeCost(noteEmptyRead({
|
|
395
415
|
calls,
|
|
396
416
|
...(droppedOldest > 0 ? { total: matched.length, droppedOldest } : {}),
|
|
397
417
|
...bodiesNotCaptured(calls),
|
|
398
418
|
...buffer,
|
|
399
|
-
});
|
|
419
|
+
}, 'calls', { noun: 'network calls' }));
|
|
400
420
|
},
|
|
401
421
|
},
|
|
402
422
|
{
|
|
@@ -404,10 +424,9 @@ export const OBSERVE_TOOLS = [
|
|
|
404
424
|
example: { level: 'error' },
|
|
405
425
|
description: 'Console/error log. Fast path for "were there any errors during this flow?". When a level filter matches nothing, returns a `hint` { totalInWindow, byLevel } so 0 errors is distinguishable from a silent page.',
|
|
406
426
|
inputSchema: {
|
|
407
|
-
level:
|
|
408
|
-
.string()
|
|
427
|
+
level: consoleLevelEnum
|
|
409
428
|
.optional()
|
|
410
|
-
.describe(
|
|
429
|
+
.describe(`Log level filter: ${CONSOLE_LEVEL_LIST}. Omit to return all levels.`),
|
|
411
430
|
since: z
|
|
412
431
|
.number()
|
|
413
432
|
.optional()
|
|
@@ -451,15 +470,19 @@ export const OBSERVE_TOOLS = [
|
|
|
451
470
|
})).filter(isConsoleEvent);
|
|
452
471
|
const matched = allConsole.filter((e) => matchConsole(e, level));
|
|
453
472
|
// zero matches at this level → report what levels ARE present (not a bare []).
|
|
454
|
-
if (matched.length
|
|
473
|
+
if (0 === matched.length && allConsole.length > 0) {
|
|
455
474
|
return withSizeCost({ logs: matched, hint: consoleEmptyHint(allConsole), ...buffer });
|
|
456
475
|
}
|
|
457
476
|
// Default the cap so an omitted `limit` can't dump a whole flooded session (since defaults to 0).
|
|
458
477
|
const { events: budgeted, droppedOldest } = applyEventBudget(matched, limit ?? DEFAULT_QUERY_LIMIT);
|
|
459
478
|
const logs = budgeted.map(projectConsoleLog);
|
|
460
|
-
|
|
479
|
+
// Say the look HAPPENED when it found nothing. A quiet page and a dead console observer both
|
|
480
|
+
// produced `{ logs: [] }`, and "no console errors" is the claim agents lean on most — see
|
|
481
|
+
// observed-nothing.ts, whose own header names this exact case and which every other array-
|
|
482
|
+
// returning read here was already wired to.
|
|
483
|
+
return withSizeCost(noteEmptyRead(droppedOldest > 0
|
|
461
484
|
? { logs, total: matched.length, droppedOldest, ...buffer }
|
|
462
|
-
: { logs, ...buffer });
|
|
485
|
+
: { logs, ...buffer }, 'logs', { noun: 'console lines' }));
|
|
463
486
|
},
|
|
464
487
|
},
|
|
465
488
|
{
|
|
@@ -469,6 +492,17 @@ export const OBSERVE_TOOLS = [
|
|
|
469
492
|
outputSchema: {
|
|
470
493
|
animations: z.array(z.unknown()),
|
|
471
494
|
},
|
|
472
|
-
handler: (deps, args) =>
|
|
495
|
+
handler: async (deps, args) => {
|
|
496
|
+
const result = await commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.ANIMATIONS, {});
|
|
497
|
+
// A page with nothing animating and an observer that is not watching both return `[]`, and the
|
|
498
|
+
// second means the run should not be trusted. Say the look happened.
|
|
499
|
+
return isPlainRecord(result)
|
|
500
|
+
? noteEmptyRead(result, 'animations', { noun: 'animations running or completed' })
|
|
501
|
+
: result;
|
|
502
|
+
},
|
|
473
503
|
},
|
|
474
504
|
];
|
|
505
|
+
/** Narrow a command result to something noteEmptyRead can annotate. */
|
|
506
|
+
function isPlainRecord(value) {
|
|
507
|
+
return 'object' === typeof value && value !== null && !Array.isArray(value);
|
|
508
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Say that the look HAPPENED, when the look found nothing.
|
|
3
|
+
*
|
|
4
|
+
* A quiet page and a dead observer produce the same JSON: `[]`. Reported across seven tools in a
|
|
5
|
+
* field sweep — network with 0 calls, console with 0 logs, reconcile comparing 0, crawl with 0 steps,
|
|
6
|
+
* an empty message inbox — none of which could be told apart from the observer not working. Those
|
|
7
|
+
* need opposite responses: one means "the app did nothing", the other means "stop trusting this run".
|
|
8
|
+
*
|
|
9
|
+
* One shared shape rather than a field per tool: an empty read states the window it watched. "I
|
|
10
|
+
* watched 2000ms and saw nothing" is a finding. `[]` is an absence of information wearing the same
|
|
11
|
+
* clothes as one.
|
|
12
|
+
*/
|
|
13
|
+
interface EmptyReadContext {
|
|
14
|
+
/** The observation window, when the read has one. */
|
|
15
|
+
windowMs?: number;
|
|
16
|
+
/** What was being counted, in the agent's words: "console lines", "network calls". */
|
|
17
|
+
noun: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Add `observed: true` and a note when `key` holds an EMPTY array. Returns the result untouched
|
|
21
|
+
* otherwise — including when it is a refusal, where "I observed nothing" would be actively
|
|
22
|
+
* misleading on top of an error that already explains itself.
|
|
23
|
+
*/
|
|
24
|
+
export declare function noteEmptyRead(result: Record<string, unknown>, key: string, context: EmptyReadContext): Record<string, unknown>;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Say that the look HAPPENED, when the look found nothing.
|
|
3
|
+
*
|
|
4
|
+
* A quiet page and a dead observer produce the same JSON: `[]`. Reported across seven tools in a
|
|
5
|
+
* field sweep — network with 0 calls, console with 0 logs, reconcile comparing 0, crawl with 0 steps,
|
|
6
|
+
* an empty message inbox — none of which could be told apart from the observer not working. Those
|
|
7
|
+
* need opposite responses: one means "the app did nothing", the other means "stop trusting this run".
|
|
8
|
+
*
|
|
9
|
+
* One shared shape rather than a field per tool: an empty read states the window it watched. "I
|
|
10
|
+
* watched 2000ms and saw nothing" is a finding. `[]` is an absence of information wearing the same
|
|
11
|
+
* clothes as one.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Add `observed: true` and a note when `key` holds an EMPTY array. Returns the result untouched
|
|
15
|
+
* otherwise — including when it is a refusal, where "I observed nothing" would be actively
|
|
16
|
+
* misleading on top of an error that already explains itself.
|
|
17
|
+
*/
|
|
18
|
+
export function noteEmptyRead(result, key, context) {
|
|
19
|
+
if ('string' === typeof result['error'])
|
|
20
|
+
return result;
|
|
21
|
+
const value = result[key];
|
|
22
|
+
if (!Array.isArray(value) || value.length > 0)
|
|
23
|
+
return result;
|
|
24
|
+
if (result['note'] !== undefined)
|
|
25
|
+
return result;
|
|
26
|
+
const window = context.windowMs === undefined ? '' : ` over the last ${String(context.windowMs)}ms`;
|
|
27
|
+
return {
|
|
28
|
+
...result,
|
|
29
|
+
// The distinction the field sweep could not make: this is a RESULT, not a failure to look.
|
|
30
|
+
observed: true,
|
|
31
|
+
note: `no ${context.noun}${window} — the observation ran and found none, which is a result, not a missing reading`,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* number that is silently wrong. `count` survives because it is a scalar. Trust it over the array.
|
|
20
20
|
*/
|
|
21
21
|
export function paginateQueryResult(result, limit, countOnly) {
|
|
22
|
-
if (typeof result !== 'object' ||
|
|
22
|
+
if (typeof result !== 'object' || null === result)
|
|
23
23
|
return result;
|
|
24
24
|
const record = result;
|
|
25
25
|
const elements = record['elements'];
|
|
@@ -28,7 +28,7 @@ export function paginateQueryResult(result, limit, countOnly) {
|
|
|
28
28
|
const counted = record['count'];
|
|
29
29
|
// Older browser SDKs (and the zero-match hint path) may not carry `count`; fall back rather than
|
|
30
30
|
// report nothing, but never prefer the array when the browser told us the real number.
|
|
31
|
-
const total = typeof counted
|
|
31
|
+
const total = 'number' === typeof counted ? counted : elements.length;
|
|
32
32
|
const truncatedOnWire = total > elements.length;
|
|
33
33
|
if (countOnly) {
|
|
34
34
|
const { elements: _dropped, ...rest } = record;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accepting the element-query shape the rest of the surface teaches.
|
|
3
|
+
*
|
|
4
|
+
* `reticle_query` asks for a strategy and a value — `{ by: 'text', value: 'Deploy' }`. Every
|
|
5
|
+
* predicate asks for named fields — `{ text: 'Deploy' }`, `{ testid: 'submit' }` — and that is where
|
|
6
|
+
* an agent meets element queries most often (`act_and_wait { until: { kind:'element', query } }`,
|
|
7
|
+
* `reticle_assert`, `wait_for`). Carrying the predicate's spelling to `reticle_query` earns
|
|
8
|
+
* `-32602: Unknown parameter for reticle_query: text`.
|
|
9
|
+
*
|
|
10
|
+
* It is a small thing that lands in an expensive place: of the sessions that called any tool in a
|
|
11
|
+
* day, HALF made exactly one call and stopped. A rejected first call is a bounced session, and the
|
|
12
|
+
* agent has no way to know the rejection was about spelling rather than the page.
|
|
13
|
+
*
|
|
14
|
+
* Translation only — `by`/`value` remain the tool's contract, an explicit pair always wins, and a
|
|
15
|
+
* call carrying neither shape is left alone so the schema error still explains itself rather than
|
|
16
|
+
* being replaced by a confident wrong query.
|
|
17
|
+
*/
|
|
18
|
+
export declare function normalizeQueryArgs(args: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accepting the element-query shape the rest of the surface teaches.
|
|
3
|
+
*
|
|
4
|
+
* `reticle_query` asks for a strategy and a value — `{ by: 'text', value: 'Deploy' }`. Every
|
|
5
|
+
* predicate asks for named fields — `{ text: 'Deploy' }`, `{ testid: 'submit' }` — and that is where
|
|
6
|
+
* an agent meets element queries most often (`act_and_wait { until: { kind:'element', query } }`,
|
|
7
|
+
* `reticle_assert`, `wait_for`). Carrying the predicate's spelling to `reticle_query` earns
|
|
8
|
+
* `-32602: Unknown parameter for reticle_query: text`.
|
|
9
|
+
*
|
|
10
|
+
* It is a small thing that lands in an expensive place: of the sessions that called any tool in a
|
|
11
|
+
* day, HALF made exactly one call and stopped. A rejected first call is a bounced session, and the
|
|
12
|
+
* agent has no way to know the rejection was about spelling rather than the page.
|
|
13
|
+
*
|
|
14
|
+
* Translation only — `by`/`value` remain the tool's contract, an explicit pair always wins, and a
|
|
15
|
+
* call carrying neither shape is left alone so the schema error still explains itself rather than
|
|
16
|
+
* being replaced by a confident wrong query.
|
|
17
|
+
*/
|
|
18
|
+
/** Most specific first: the order Reticle prefers anchors everywhere else (testid is gold). */
|
|
19
|
+
const FIELD_TO_STRATEGY = [
|
|
20
|
+
['testid', 'testid'],
|
|
21
|
+
['label', 'label'],
|
|
22
|
+
['placeholder', 'placeholder'],
|
|
23
|
+
['alt', 'alt'],
|
|
24
|
+
['text', 'text'],
|
|
25
|
+
['role', 'role'],
|
|
26
|
+
];
|
|
27
|
+
export function normalizeQueryArgs(args) {
|
|
28
|
+
// An explicit pair is the contract; never second-guess it.
|
|
29
|
+
if ('string' === typeof args['by'] && 'string' === typeof args['value'])
|
|
30
|
+
return args;
|
|
31
|
+
for (const [field, strategy] of FIELD_TO_STRATEGY) {
|
|
32
|
+
const value = args[field];
|
|
33
|
+
if ('string' === typeof value && value.length > 0) {
|
|
34
|
+
// `name` stays as-is: with role it is the accessible-name filter the predicate also uses.
|
|
35
|
+
return { ...args, by: strategy, value };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return args;
|
|
39
|
+
}
|