@reticlehq/server 2.4.0 → 2.6.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 +719 -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} +13 -1
- package/dist/{bridge.js → bridge/bridge.js} +95 -15
- package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +9 -11
- package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +18 -10
- 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/cli-doctor.d.ts +1 -0
- package/dist/cli/cli-doctor.js +135 -0
- 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/cli-parse-feedback.d.ts +31 -0
- package/dist/cli/cli-parse-feedback.js +56 -0
- package/dist/{cli-parse.d.ts → cli/cli-parse.d.ts} +6 -19
- package/dist/{cli-parse.js → cli/cli-parse.js} +118 -81
- 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/doctor-daemon-line.d.ts +37 -0
- package/dist/cli/doctor-daemon-line.js +35 -0
- package/dist/cli/port-holder.d.ts +43 -0
- package/dist/cli/port-holder.js +99 -0
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +302 -100
- 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 +73 -0
- package/dist/daemon/daemon-resilience.js +279 -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} +105 -48
- package/dist/daemon/heartbeat.d.ts +115 -0
- package/dist/daemon/heartbeat.js +141 -0
- 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} +23 -2
- package/dist/{idle-shutdown.js → daemon/idle-shutdown.js} +37 -6
- package/dist/daemon/port-presence.d.ts +76 -0
- package/dist/daemon/port-presence.js +93 -0
- package/dist/daemon/state-dir.d.ts +7 -0
- package/dist/daemon/state-dir.js +59 -0
- package/dist/daemon/unclean-predecessor.d.ts +23 -0
- package/dist/daemon/unclean-predecessor.js +27 -0
- 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 +53 -20
- package/dist/events/predicate-eval.js +179 -55
- package/dist/events/predicate-parse.d.ts +23 -0
- package/dist/events/predicate-parse.js +54 -0
- package/dist/events/predicate.d.ts +7 -2
- package/dist/events/predicate.js +126 -35
- package/dist/events/reconcile.js +5 -5
- package/dist/events/ring-buffer.js +2 -17
- 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 +6 -8
- package/dist/flows/flow-replay.js +132 -48
- 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 +156 -6
- package/dist/flows/flow-success.js +20 -15
- package/dist/flows/flow-tools.js +63 -21
- 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/role-drift-reason.d.ts +20 -0
- package/dist/flows/role-drift-reason.js +39 -0
- package/dist/flows/server-verify.d.ts +1 -1
- package/dist/flows/server-verify.js +5 -5
- package/dist/flows/suite-flakes.d.ts +33 -0
- package/dist/flows/suite-flakes.js +32 -0
- 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 +35 -3
- package/dist/honesty/blind-spots.js +57 -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 +31 -3
- package/dist/honesty/verified.js +64 -8
- package/dist/http-server.js +23 -7
- package/dist/hunt/hunt-report.d.ts +2 -1
- package/dist/hunt/hunt-report.js +2 -2
- package/dist/index.d.ts +9 -6
- package/dist/index.js +41 -25
- package/dist/init/agent-rules.d.ts +20 -1
- package/dist/init/agent-rules.js +64 -8
- 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 +50 -0
- package/dist/init/cra.js +106 -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 +9 -2
- package/dist/init/detect.js +24 -5
- package/dist/init/mcp-clients.d.ts +81 -0
- package/dist/init/mcp-clients.js +248 -0
- 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 +29 -6
- package/dist/init/plan-framework.d.ts +16 -1
- package/dist/init/plan-framework.js +166 -8
- package/dist/init/plan.d.ts +85 -6
- package/dist/init/plan.js +196 -33
- package/dist/init/project-id.d.ts +5 -9
- package/dist/init/project-id.js +10 -22
- package/dist/init/run.d.ts +23 -1
- package/dist/init/run.js +338 -47
- 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/windows-quote.d.ts +38 -0
- package/dist/init/windows-quote.js +70 -0
- 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 +32 -0
- package/dist/mcp/mcp-outage.js +55 -0
- package/dist/mcp/mcp-proxy.d.ts +134 -0
- package/dist/mcp/mcp-proxy.js +720 -0
- package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
- package/dist/{mcp.js → mcp/mcp.js} +139 -37
- 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/browser-pool.d.ts +9 -0
- package/dist/pool/browser-pool.js +38 -9
- 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/attachment-history.d.ts +46 -0
- package/dist/session/attachment-history.js +65 -0
- 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 +45 -0
- package/dist/session/no-session-diagnosis.js +120 -0
- package/dist/session/no-session-watch.d.ts +21 -0
- package/dist/session/no-session-watch.js +69 -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/pending-commands.js +1 -0
- package/dist/session/session-health.d.ts +8 -1
- package/dist/session/session-health.js +8 -7
- package/dist/session/session-info.d.ts +43 -8
- package/dist/session/session-info.js +46 -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 +6 -0
- package/dist/session/session-manager.js +124 -12
- 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 +15 -2
- package/dist/session/session.js +77 -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/crash-cause.d.ts +47 -0
- package/dist/telemetry/crash-cause.js +104 -0
- package/dist/telemetry/daemon-telemetry.d.ts +38 -1
- package/dist/telemetry/daemon-telemetry.js +37 -12
- package/dist/telemetry/dev-repo.js +4 -4
- package/dist/telemetry/error-class.d.ts +26 -0
- package/dist/telemetry/error-class.js +52 -0
- package/dist/telemetry/error-fingerprint.js +21 -2
- package/dist/telemetry/feedback-cli.d.ts +8 -3
- package/dist/telemetry/feedback-cli.js +52 -8
- package/dist/telemetry/feedback-context.d.ts +23 -6
- package/dist/telemetry/feedback-context.js +105 -5
- 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.d.ts +7 -0
- package/dist/telemetry/git-facts.js +5 -5
- package/dist/telemetry/project-profile.js +2 -1
- package/dist/telemetry/session-metrics.d.ts +47 -3
- package/dist/telemetry/session-metrics.js +315 -15
- package/dist/telemetry/telemetry.d.ts +45 -2
- package/dist/telemetry/telemetry.js +150 -37
- 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 +114 -118
- 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 +9 -1
- package/dist/tools/assert-verdict.js +21 -6
- package/dist/tools/browser-tools.js +36 -11
- package/dist/tools/contract-tools.d.ts +0 -5
- package/dist/tools/contract-tools.js +27 -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 +96 -19
- package/dist/tools/error-recovery.d.ts +34 -2
- package/dist/tools/error-recovery.js +255 -4
- package/dist/tools/feedback-invite.d.ts +48 -0
- package/dist/tools/feedback-invite.js +71 -0
- 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 -12
- package/dist/tools/invoke-tool.js +126 -33
- 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-arrival.d.ts +26 -0
- package/dist/tools/navigate-arrival.js +60 -0
- package/dist/tools/navigate-result.d.ts +31 -0
- package/dist/tools/navigate-result.js +38 -0
- package/dist/tools/observe-tools.js +72 -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 +93 -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 +16 -0
- package/dist/tools/tool-surface.d.ts +83 -0
- package/dist/tools/tool-surface.js +217 -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/README.md +55 -0
- 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-dispatch-receiver.yml +76 -0
- package/docs/fixtures.md +45 -0
- package/docs/flows.md +166 -0
- package/docs/gate-plan.md +98 -0
- package/docs/gates.md +117 -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/matrix/2.5.0/claude-code-machine.json +19 -0
- package/docs/matrix/2.5.0/codex-machine.json +20 -0
- package/docs/matrix/2.5.0/cursor-machine.json +22 -0
- package/docs/matrix/2.5.0/gemini-machine.json +22 -0
- package/docs/matrix/2.5.0/opencode-machine.json +22 -0
- package/docs/matrix/2.5.0/vscode-machine.json +22 -0
- package/docs/matrix/2.5.0/windsurf-machine.json +22 -0
- package/docs/matrix/MATRIX.md +26 -0
- package/docs/matrix/README.md +59 -0
- package/docs/mint.json +61 -0
- package/docs/multi-agent-testing.md +55 -0
- package/docs/platform-integration.md +122 -0
- package/docs/system-map.md +152 -0
- package/docs/telemetry-contract.md +214 -0
- package/docs/telemetry.md +191 -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-doctor.d.ts +0 -6
- package/dist/cli-doctor.js +0 -60
- 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-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
|
@@ -2,12 +2,15 @@
|
|
|
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';
|
|
10
12
|
import { evaluatePredicate, waitForPredicate, PredicateSchema } from '../events/predicate.js';
|
|
13
|
+
import { parsePredicate } from '../events/predicate-parse.js';
|
|
11
14
|
import { matchNet, matchConsole, isConsoleEvent, eventMatchesFilters, netEmptyHint, consoleEmptyHint, reconcileNet, projectNetCall, projectConsoleLog, } from '../events/event-filters.js';
|
|
12
15
|
import { applyEventBudget, costHint, withSizeCost, DEFAULT_QUERY_LIMIT, } from '../session/output-budget.js';
|
|
13
16
|
import { healthEnvelope, bufferEnvelope } from '../session/session-health.js';
|
|
@@ -54,11 +57,21 @@ function lastActSourceOnFailure(session, pass) {
|
|
|
54
57
|
* really do interleave; it is only redundant at this boundary.
|
|
55
58
|
*/
|
|
56
59
|
function withoutConstantSessionId(event) {
|
|
57
|
-
if (typeof event !== 'object' ||
|
|
60
|
+
if (typeof event !== 'object' || null === event)
|
|
58
61
|
return event;
|
|
59
62
|
const { sessionId: _sessionId, ...rest } = event;
|
|
60
63
|
return rest;
|
|
61
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* The console levels, derived from core's console EventTypes — see CONSOLE_LEVELS.
|
|
67
|
+
*
|
|
68
|
+
* A free string here filtered by building `console.${level}`, so `level:'ERROR'` or `level:'fatal'`
|
|
69
|
+
* matched nothing and returned an empty log list. On a page that HAS logs the zero-match hint saves
|
|
70
|
+
* it (it reports which levels are present), but on a quiet page the answer is identical to a genuine
|
|
71
|
+
* all-clear. Refusing the value outright is the only reading with no ambiguity.
|
|
72
|
+
*/
|
|
73
|
+
const CONSOLE_LEVEL_LIST = CONSOLE_LEVELS.join(' | ');
|
|
74
|
+
const consoleLevelEnum = z.enum(CONSOLE_LEVELS);
|
|
62
75
|
export const OBSERVE_TOOLS = [
|
|
63
76
|
{
|
|
64
77
|
name: ReticleTool.OBSERVE,
|
|
@@ -180,10 +193,12 @@ export const OBSERVE_TOOLS = [
|
|
|
180
193
|
},
|
|
181
194
|
{
|
|
182
195
|
name: ReticleTool.WAIT_FOR,
|
|
183
|
-
example: { predicate: { kind:
|
|
196
|
+
example: { predicate: { kind: PredicateKind.STATE, path: 'todos.length', equals: 3 } },
|
|
184
197
|
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
198
|
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.'),
|
|
199
|
+
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.'),
|
|
200
|
+
// Same concept, the neighbouring tool's name. See alias-args.ts.
|
|
201
|
+
until: PredicateSchema.optional().describe("Alias for `predicate` (act_and_wait's name)."),
|
|
187
202
|
timeout_ms: z.number().optional().describe('Maximum wait in milliseconds. Default: 4000.'),
|
|
188
203
|
since: z
|
|
189
204
|
.number()
|
|
@@ -195,6 +210,10 @@ export const OBSERVE_TOOLS = [
|
|
|
195
210
|
pass: z.boolean(),
|
|
196
211
|
evidence: z.unknown().optional(),
|
|
197
212
|
failureReason: z.string().optional(),
|
|
213
|
+
observationLost: z
|
|
214
|
+
.boolean()
|
|
215
|
+
.optional()
|
|
216
|
+
.describe('The tab disconnected mid-wait, so this was never observed — the verdict is UNKNOWN, not a failure of the app.'),
|
|
198
217
|
session: z
|
|
199
218
|
.object({ lastSeenMs: z.number(), throttled: z.boolean(), focused: z.boolean() })
|
|
200
219
|
.optional(),
|
|
@@ -218,7 +237,8 @@ export const OBSERVE_TOOLS = [
|
|
|
218
237
|
},
|
|
219
238
|
handler: async (deps, args) => {
|
|
220
239
|
const session = deps.sessions.resolve(asString(args['sessionId']));
|
|
221
|
-
|
|
240
|
+
// `until` is act_and_wait's name for this — see alias-args.ts.
|
|
241
|
+
const predicate = parsePredicate(aliasParam(args, 'predicate', ['until'])['predicate']);
|
|
222
242
|
// Honesty: explicit since wins; else default to the last act's cursor; else the whole buffer.
|
|
223
243
|
const since = asNumber(args['since']) ?? session.lastAct.cursor() ?? 0;
|
|
224
244
|
const verdict = await waitForPredicate(session, predicate, asNumber(args['timeout_ms']) ?? DEFAULT_ASSERT_TIMEOUT_MS, since);
|
|
@@ -234,10 +254,20 @@ export const OBSERVE_TOOLS = [
|
|
|
234
254
|
},
|
|
235
255
|
{
|
|
236
256
|
name: ReticleTool.ASSERT,
|
|
237
|
-
example: { predicate: { kind:
|
|
257
|
+
example: { predicate: { kind: PredicateKind.SIGNAL, name: 'todos:loaded' } },
|
|
238
258
|
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
259
|
inputSchema: {
|
|
240
|
-
predicate: PredicateSchema.describe(
|
|
260
|
+
predicate: PredicateSchema.optional().describe(
|
|
261
|
+
// Every kind, each with the field that carries its argument. Five of the nine were
|
|
262
|
+
// undocumented here, including `route` — and "did submitting the login form navigate away"
|
|
263
|
+
// is the most common thing an agent wants to assert. A field report reached us from an agent
|
|
264
|
+
// that guessed `urlContains` on route (net's spelling) and got unrecognized_keys.
|
|
265
|
+
'Predicate to evaluate. Kinds: { signal, name } { net, urlContains|method|status|count } ' +
|
|
266
|
+
'{ state, path|equals } { route, pathname (exact) | contains (path+query+hash) } ' +
|
|
267
|
+
'{ element, testid|role|text } { text } { console, level|absent } { animation, name } ' +
|
|
268
|
+
'{ settled } — combine with { allOf | anyOf | not }. Prefer a signal/net/state consequence ' +
|
|
269
|
+
'over element/text presence.'),
|
|
270
|
+
until: PredicateSchema.optional().describe("Alias for `predicate` (act_and_wait's name)."),
|
|
241
271
|
timeout_ms: z
|
|
242
272
|
.number()
|
|
243
273
|
.optional()
|
|
@@ -252,6 +282,10 @@ export const OBSERVE_TOOLS = [
|
|
|
252
282
|
pass: z.boolean(),
|
|
253
283
|
evidence: z.unknown().optional(),
|
|
254
284
|
failureReason: z.string().optional(),
|
|
285
|
+
observationLost: z
|
|
286
|
+
.boolean()
|
|
287
|
+
.optional()
|
|
288
|
+
.describe('The tab disconnected mid-wait, so this was never observed — the verdict is UNKNOWN, not a failure of the app.'),
|
|
255
289
|
advice: z
|
|
256
290
|
.string()
|
|
257
291
|
.optional()
|
|
@@ -287,7 +321,8 @@ export const OBSERVE_TOOLS = [
|
|
|
287
321
|
},
|
|
288
322
|
handler: async (deps, args) => {
|
|
289
323
|
const session = deps.sessions.resolve(asString(args['sessionId']));
|
|
290
|
-
|
|
324
|
+
// `until` is act_and_wait's name for this — see alias-args.ts.
|
|
325
|
+
const predicate = parsePredicate(aliasParam(args, 'predicate', ['until'])['predicate']);
|
|
291
326
|
const timeout = asNumber(args['timeout_ms']) ?? 0;
|
|
292
327
|
// Honesty: explicit since wins; else default to the last act's cursor; else the whole buffer.
|
|
293
328
|
const since = asNumber(args['since']) ?? session.lastAct.cursor() ?? 0;
|
|
@@ -306,7 +341,7 @@ export const OBSERVE_TOOLS = [
|
|
|
306
341
|
: assertsDerivedIpcStatus(predicate)
|
|
307
342
|
? { advice: DERIVED_IPC_STATUS_ADVICE }
|
|
308
343
|
: {};
|
|
309
|
-
const { decision, contradictions, coverage } = await assertVerdict(session, predicate, verdict.pass, since);
|
|
344
|
+
const { decision, contradictions, coverage } = await assertVerdict(session, predicate, verdict.pass, since, verdict.inconclusive, verdict.observationLost);
|
|
310
345
|
return withControl(session, {
|
|
311
346
|
...decision,
|
|
312
347
|
...verdict,
|
|
@@ -374,7 +409,7 @@ export const OBSERVE_TOOLS = [
|
|
|
374
409
|
const method = asString(args['method']);
|
|
375
410
|
const urlContains = asString(args['urlContains']);
|
|
376
411
|
const status = asNumber(args['status']);
|
|
377
|
-
const ok = typeof args['ok']
|
|
412
|
+
const ok = 'boolean' === typeof args['ok'] ? args['ok'] : undefined;
|
|
378
413
|
const limit = asNumber(args['limit']);
|
|
379
414
|
const buffer = bufferEnvelope(session);
|
|
380
415
|
// Completed calls + unresolved in-flight requests (a hung request shows as pending).
|
|
@@ -385,18 +420,21 @@ export const OBSERVE_TOOLS = [
|
|
|
385
420
|
}));
|
|
386
421
|
const matched = allNet.filter((e) => matchNet(e, method, urlContains, status, ok));
|
|
387
422
|
// zero-match filter returns what DID fire, not a bare [].
|
|
388
|
-
if (matched.length
|
|
423
|
+
if (0 === matched.length && allNet.length > 0) {
|
|
389
424
|
return withSizeCost({ calls: matched, hint: netEmptyHint(allNet), ...buffer });
|
|
390
425
|
}
|
|
391
426
|
// Default the cap so an omitted `limit` can't dump a whole flooded session (since defaults to 0).
|
|
392
427
|
const { events: budgeted, droppedOldest } = applyEventBudget(matched, limit ?? DEFAULT_QUERY_LIMIT);
|
|
393
428
|
const calls = budgeted.map(projectNetCall);
|
|
394
|
-
|
|
429
|
+
// A zero-match FILTER already reports what did fire (netEmptyHint above). Zero calls at all
|
|
430
|
+
// fell through as a bare `[]`, which is indistinguishable from an observer that is not
|
|
431
|
+
// recording — and those need opposite responses. Say the look happened.
|
|
432
|
+
return withSizeCost(noteEmptyRead({
|
|
395
433
|
calls,
|
|
396
434
|
...(droppedOldest > 0 ? { total: matched.length, droppedOldest } : {}),
|
|
397
435
|
...bodiesNotCaptured(calls),
|
|
398
436
|
...buffer,
|
|
399
|
-
});
|
|
437
|
+
}, 'calls', { noun: 'network calls' }));
|
|
400
438
|
},
|
|
401
439
|
},
|
|
402
440
|
{
|
|
@@ -404,10 +442,9 @@ export const OBSERVE_TOOLS = [
|
|
|
404
442
|
example: { level: 'error' },
|
|
405
443
|
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
444
|
inputSchema: {
|
|
407
|
-
level:
|
|
408
|
-
.string()
|
|
445
|
+
level: consoleLevelEnum
|
|
409
446
|
.optional()
|
|
410
|
-
.describe(
|
|
447
|
+
.describe(`Log level filter: ${CONSOLE_LEVEL_LIST}. Omit to return all levels.`),
|
|
411
448
|
since: z
|
|
412
449
|
.number()
|
|
413
450
|
.optional()
|
|
@@ -451,15 +488,19 @@ export const OBSERVE_TOOLS = [
|
|
|
451
488
|
})).filter(isConsoleEvent);
|
|
452
489
|
const matched = allConsole.filter((e) => matchConsole(e, level));
|
|
453
490
|
// zero matches at this level → report what levels ARE present (not a bare []).
|
|
454
|
-
if (matched.length
|
|
491
|
+
if (0 === matched.length && allConsole.length > 0) {
|
|
455
492
|
return withSizeCost({ logs: matched, hint: consoleEmptyHint(allConsole), ...buffer });
|
|
456
493
|
}
|
|
457
494
|
// Default the cap so an omitted `limit` can't dump a whole flooded session (since defaults to 0).
|
|
458
495
|
const { events: budgeted, droppedOldest } = applyEventBudget(matched, limit ?? DEFAULT_QUERY_LIMIT);
|
|
459
496
|
const logs = budgeted.map(projectConsoleLog);
|
|
460
|
-
|
|
497
|
+
// Say the look HAPPENED when it found nothing. A quiet page and a dead console observer both
|
|
498
|
+
// produced `{ logs: [] }`, and "no console errors" is the claim agents lean on most — see
|
|
499
|
+
// observed-nothing.ts, whose own header names this exact case and which every other array-
|
|
500
|
+
// returning read here was already wired to.
|
|
501
|
+
return withSizeCost(noteEmptyRead(droppedOldest > 0
|
|
461
502
|
? { logs, total: matched.length, droppedOldest, ...buffer }
|
|
462
|
-
: { logs, ...buffer });
|
|
503
|
+
: { logs, ...buffer }, 'logs', { noun: 'console lines' }));
|
|
463
504
|
},
|
|
464
505
|
},
|
|
465
506
|
{
|
|
@@ -469,6 +510,17 @@ export const OBSERVE_TOOLS = [
|
|
|
469
510
|
outputSchema: {
|
|
470
511
|
animations: z.array(z.unknown()),
|
|
471
512
|
},
|
|
472
|
-
handler: (deps, args) =>
|
|
513
|
+
handler: async (deps, args) => {
|
|
514
|
+
const result = await commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.ANIMATIONS, {});
|
|
515
|
+
// A page with nothing animating and an observer that is not watching both return `[]`, and the
|
|
516
|
+
// second means the run should not be trusted. Say the look happened.
|
|
517
|
+
return isPlainRecord(result)
|
|
518
|
+
? noteEmptyRead(result, 'animations', { noun: 'animations running or completed' })
|
|
519
|
+
: result;
|
|
520
|
+
},
|
|
473
521
|
},
|
|
474
522
|
];
|
|
523
|
+
/** Narrow a command result to something noteEmptyRead can annotate. */
|
|
524
|
+
function isPlainRecord(value) {
|
|
525
|
+
return 'object' === typeof value && value !== null && !Array.isArray(value);
|
|
526
|
+
}
|
|
@@ -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
|
+
}
|
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 {};
|