@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
package/dist/tools/act-tools.js
CHANGED
|
@@ -1,104 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Action tools — reticle_act, reticle_act_sequence, reticle_act_and_wait
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Action tools — reticle_act, reticle_act_sequence, reticle_act_and_wait. Split out of tools.ts to keep
|
|
3
|
+
* that file under the line cap and assembled back into the tool list there via ...ACT_TOOLS; the
|
|
4
|
+
* native-input attempt itself lives in real-input-attempt.ts for the same reason.
|
|
5
5
|
*/
|
|
6
6
|
import { z } from 'zod';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { aliasParam } from './alias-args.js';
|
|
8
|
+
import { captureAct, compileSequenceStep } from '../flows/replay.js';
|
|
9
|
+
import { ActionType, ActionWarning, DEFAULT_ASSERT_TIMEOUT_MS, InputMode, ReticleCommand, Verified, PredicateKind, } from '@reticlehq/core';
|
|
10
|
+
import { assertNativeInputSupported } from './act-danger.js';
|
|
10
11
|
import { leanActResult, mutatedWithin } from './act-view.js';
|
|
11
12
|
import { ReticleTool } from './tool-names.js';
|
|
12
13
|
import { buildReactionReport, summarizeReaction } from '../events/reaction.js';
|
|
14
|
+
import { parsePredicate } from '../events/predicate-parse.js';
|
|
13
15
|
import { causalSummary } from '../capsule/causal-summary.js';
|
|
14
16
|
import { findContradictions } from '../events/contradictions.js';
|
|
15
17
|
import { decideVerified } from '../honesty/verified.js';
|
|
18
|
+
import { readsDomState } from '../honesty/already-true.js';
|
|
16
19
|
import { saveFailedAssertCapsule } from './act-capsule.js';
|
|
17
20
|
import { buildDivergenceCapsule } from '../capsule/capsule.js';
|
|
18
21
|
import { predicateToExpectedLinks } from '../capsule/predicate-to-links.js';
|
|
19
22
|
import { buildHonestyBlock } from '../honesty/honesty.js';
|
|
20
|
-
import { buildCoverageStatement, blindSpotsFromState, impeachesCapture, } from '../honesty/blind-spots.js';
|
|
23
|
+
import { buildCoverageStatement, blindSpotsFromState, transportGapNote, Coverage, impeachesCapture, } from '../honesty/blind-spots.js';
|
|
21
24
|
import { hasAcceptedWrite } from '../honesty/accepted-write.js';
|
|
22
25
|
import { hasUnreadWriteOutcome } from '../honesty/unread-outcome.js';
|
|
23
|
-
import { assertDragNotDestructive, assertNotDestructive } from './act-danger.js';
|
|
24
26
|
import { evaluatePredicate, waitForPredicate, provenExpectedLinks, PredicateSchema, } from '../events/predicate.js';
|
|
25
27
|
import { healthEnvelope, refuseIfThrottled } from '../session/session-health.js';
|
|
26
|
-
import { pausedShortCircuit, pausedOutputShape, withControl } from '../session/control-envelope.js';
|
|
28
|
+
import { pausedShortCircuit, pausedOutputShape, withControl, PAUSED_NO_VERDICT, } from '../session/control-envelope.js';
|
|
27
29
|
import { asString, asNumber, asRecord, sourceOf } from './tools-helpers.js';
|
|
28
|
-
import { sessionIdShape
|
|
29
|
-
import { asActionType,
|
|
30
|
-
|
|
31
|
-
function synthetic(reason) {
|
|
32
|
-
return reason === undefined
|
|
33
|
-
? { result: undefined, settled: false }
|
|
34
|
-
: { result: undefined, settled: false, reason };
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Attempt to drive a pointer action via native input. Returns a synthetic outcome (with a
|
|
38
|
-
* `reason` when a provider is configured) whenever the synthetic path should run — no matching
|
|
39
|
-
* page, unresolvable box, declined, etc. A throw inside the provider becomes a synthetic fallback
|
|
40
|
-
* flagged with `fellBack`. `result` is defined only on a real success.
|
|
41
|
-
*/
|
|
42
|
-
async function tryRealInput(deps, session, ref, action, args) {
|
|
43
|
-
const provider = deps.realInput;
|
|
44
|
-
if (provider === undefined)
|
|
45
|
-
return synthetic(); // real input not configured — no diagnostic
|
|
46
|
-
if (!isPointerAction(action))
|
|
47
|
-
return synthetic(InputModeReason.NOT_POINTER); // fill/type stay synthetic
|
|
48
|
-
const inner = asRecord(args['args']);
|
|
49
|
-
// "Don't click, run the code": a click/dblclick runs the occlusion-honest SYNTHETIC path by default
|
|
50
|
-
// even with a provider configured — no coordinate gesture to be intercepted by the HUD or missed
|
|
51
|
-
// off-screen. Opt into a trusted native click with args.native:true (file pickers, clipboard,
|
|
52
|
-
// isTrusted-gated handlers). hover/drag genuinely need native pointer state, so they stay real.
|
|
53
|
-
if ((action === ActionType.CLICK || action === ActionType.DBLCLICK) && inner['native'] !== true) {
|
|
54
|
-
return synthetic(InputModeReason.SYNTHETIC_CLICK_PREFERRED);
|
|
55
|
-
}
|
|
56
|
-
if (!(await provider.isAvailableFor(session.url)))
|
|
57
|
-
return synthetic(InputModeReason.PAGE_NOT_CORRELATED);
|
|
58
|
-
const inspected = await commandOrThrow(deps, session.id, ReticleCommand.INSPECT, { ref });
|
|
59
|
-
assertNotDestructive(action, inner, inspected);
|
|
60
|
-
const box = asBox(inspected);
|
|
61
|
-
if (box === undefined)
|
|
62
|
-
return synthetic(InputModeReason.ELEMENT_NOT_LOCATABLE);
|
|
63
|
-
let toBox;
|
|
64
|
-
if (action === ActionType.DRAG) {
|
|
65
|
-
const toRef = asString(inner['toRef']);
|
|
66
|
-
if (toRef === undefined)
|
|
67
|
-
return synthetic(InputModeReason.DRAG_TARGET_UNRESOLVED);
|
|
68
|
-
const targetInspected = await commandOrThrow(deps, session.id, ReticleCommand.INSPECT, {
|
|
69
|
-
ref: toRef,
|
|
70
|
-
});
|
|
71
|
-
// A drag is judged on BOTH ends: dropping onto "Trash" is destructive however innocent the
|
|
72
|
-
// thing being dragged looks.
|
|
73
|
-
assertDragNotDestructive(inner, inspected, targetInspected);
|
|
74
|
-
toBox = asBox(targetInspected);
|
|
75
|
-
if (toBox === undefined)
|
|
76
|
-
return synthetic(InputModeReason.DRAG_TARGET_UNRESOLVED);
|
|
77
|
-
}
|
|
78
|
-
const performArgs = {};
|
|
79
|
-
const value = asString(inner['value']);
|
|
80
|
-
if (value !== undefined)
|
|
81
|
-
performArgs.value = value;
|
|
82
|
-
const text = asString(inner['text']);
|
|
83
|
-
if (text !== undefined)
|
|
84
|
-
performArgs.text = text;
|
|
85
|
-
if (toBox !== undefined)
|
|
86
|
-
performArgs.toBox = toBox;
|
|
87
|
-
try {
|
|
88
|
-
const performed = await provider.perform(session.url, action, box, performArgs);
|
|
89
|
-
if (!performed.performed)
|
|
90
|
-
return synthetic(InputModeReason.PROVIDER_DECLINED);
|
|
91
|
-
return { result: { performed: true, center: performed.center, action }, settled: true };
|
|
92
|
-
}
|
|
93
|
-
catch {
|
|
94
|
-
return {
|
|
95
|
-
result: undefined,
|
|
96
|
-
settled: false,
|
|
97
|
-
fellBack: true,
|
|
98
|
-
reason: InputModeReason.PROVIDER_ERROR,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
}
|
|
30
|
+
import { sessionIdShape } from './tool-kit.js';
|
|
31
|
+
import { asActionType, gradeOf } from './act-helpers.js';
|
|
32
|
+
import { tryRealInput } from './real-input-attempt.js';
|
|
102
33
|
/**
|
|
103
34
|
* Narrow the wire's `action` to a real ActionType, or undefined.
|
|
104
35
|
*
|
|
@@ -107,22 +38,33 @@ async function tryRealInput(deps, session, ref, action, args) {
|
|
|
107
38
|
* as a generic failure rather than "that is not an action". Validate at the boundary, per the project's
|
|
108
39
|
* unknown-plus-narrowing rule, so a typo is rejected where it can still be explained.
|
|
109
40
|
*/
|
|
41
|
+
/**
|
|
42
|
+
* The action vocabulary, derived from ActionType — never retyped.
|
|
43
|
+
*
|
|
44
|
+
* The description used to list thirteen actions while ActionType had seventeen: blur, upload, drag
|
|
45
|
+
* and webmcp were real, callable, and undocumented, because a hand-copied list drifts the moment
|
|
46
|
+
* someone adds an arm. Deriving both the schema and the prose from the enum makes that impossible.
|
|
47
|
+
*
|
|
48
|
+
* The handler already refused an unknown action with a good message; the schema now refuses it
|
|
49
|
+
* one layer earlier, before any session is resolved or any work is done.
|
|
50
|
+
*/
|
|
51
|
+
const ACTION_TYPE_VALUES = Object.values(ActionType);
|
|
52
|
+
const ACTION_TYPE_LIST = ACTION_TYPE_VALUES.join(' | ');
|
|
53
|
+
const actionTypeEnum = z.enum(ACTION_TYPE_VALUES);
|
|
110
54
|
export const ACT_TOOLS = [
|
|
111
55
|
{
|
|
112
56
|
name: ReticleTool.ACT,
|
|
113
57
|
example: { ref: 'e42', action: 'fill', args: { value: 'hello' } },
|
|
114
|
-
description: '
|
|
58
|
+
description: 'Act WITHOUT checking the result — if the action is supposed to cause something, use reticle_act_and_wait { until } instead and get the verdict in the same call. This tool returns immediately with a `since` cursor; observe the reaction yourself with reticle_observe. Use it for actions with no observable consequence to assert (focus, hover, scrollIntoView, a fill you are about to submit). One action against a ref: click|dblclick|hover|focus|fill|type|clear|select|check|uncheck|submit|press|scrollIntoView. Carries effect:{dispatched,targetMatched,visible,enabled,focusMoved,valueChanged,domMutatedWithin,occluded,occludedBy,scrolledIntoView} to tell "action missed" from "app didn\'t react"; dispatched=landed, settled=a real frame flushed, and a settle timeout never fails the tool. Fields at their uninformative default are OMITTED so a clean action collapses to its consequence: an absent dispatched/targetMatched/visible/enabled means true, an absent occluded/scrolledIntoView/valueChanged/defaultPrevented means false, an absent focusMoved/occludedBy means null. occluded=true means the click point is covered by another element (a real user could not click it) — synthetic dispatch still delivered the event; scrolledIntoView=true means an off-viewport target was scrolled in first. inputMode is "real" (native CDP, no synthetic effect block) or "synthetic"; clicks default to the occlusion-honest synthetic path even when CDP is configured — pass args.native:true to force a trusted native click (file pickers, clipboard). args.holdMs keeps the pointer DOWN for that long between mousedown and mouseup — the only way to drive a hold-to-confirm control (hold-to-delete, hold-to-record, long-press); effect.heldMs reports the hold actually achieved, which a throttled background tab can stretch. args.confirmDangerous is a permission gate and NOT a duration: it allows a destructive control, it does not hold one. inputModeReason explains any real→synthetic choice so it is never silent. Full model (real-input, throttled tabs, `reticle drive`): docs/usage.md §18.',
|
|
115
59
|
inputSchema: {
|
|
116
60
|
ref: z
|
|
117
61
|
.string()
|
|
118
62
|
.describe(`Element ref (e.g. 'e42') from reticle_snapshot/reticle_query — stable until the element leaves the DOM, so no re-snapshot between actions.`),
|
|
119
|
-
action:
|
|
120
|
-
.string()
|
|
121
|
-
.describe('Action to perform: click | dblclick | hover | focus | fill | type | clear | select | check | uncheck | submit | press | scrollIntoView'),
|
|
63
|
+
action: actionTypeEnum.describe(`Action to perform: ${ACTION_TYPE_LIST}`),
|
|
122
64
|
args: z
|
|
123
65
|
.record(z.unknown())
|
|
124
66
|
.optional()
|
|
125
|
-
.describe('Action-specific arguments: { value } for fill/select, { text } for type/press, { native: true } to force a trusted native click, { confirmDangerous: true } to allow a potentially destructive control.'),
|
|
67
|
+
.describe('Action-specific arguments: { value } for fill/select, { text } for type/press, { native: true } to force a trusted native click, { holdMs: N } to keep the pointer DOWN for N ms (hold-to-confirm controls; effect.heldMs reports what was achieved), { confirmDangerous: true } to allow a potentially destructive control — a permission gate, NOT a duration.'),
|
|
126
68
|
refuseWhenThrottled: z
|
|
127
69
|
.boolean()
|
|
128
70
|
.optional()
|
|
@@ -163,10 +105,8 @@ export const ACT_TOOLS = [
|
|
|
163
105
|
return paused;
|
|
164
106
|
refuseIfThrottled(session, args['refuseWhenThrottled']);
|
|
165
107
|
const since = session.elapsed();
|
|
166
|
-
|
|
167
|
-
//
|
|
168
|
-
// measurement standing, which would judge this window with the last one's evidence.
|
|
169
|
-
session.lastAct.markEffect(asString(args['action']), undefined);
|
|
108
|
+
// The act cursor + effect are marked only once the action has actually DISPATCHED (below, on
|
|
109
|
+
// each success path) — a refused act must leave nothing behind for the next observe to judge.
|
|
170
110
|
const ref = asString(args['ref']) ?? '';
|
|
171
111
|
// Open the journal's action-attribution window BEFORE dispatching, so it covers the native path
|
|
172
112
|
// too. It used to open only on the synthetic path, and the native path returned above it — so a
|
|
@@ -181,10 +121,11 @@ export const ACT_TOOLS = [
|
|
|
181
121
|
// drive native pointer input when a provider is available; otherwise fall back.
|
|
182
122
|
const real = await tryRealInput(deps, session, ref, action, args);
|
|
183
123
|
if (real.result !== undefined) {
|
|
184
|
-
|
|
185
|
-
deps.recordings.capture(compileActStep(args, real.result));
|
|
186
|
-
}
|
|
124
|
+
captureAct(deps.recordings, args, real.result);
|
|
187
125
|
settledOutcome = real.settled ?? undefined;
|
|
126
|
+
// Native input reports no synthetic effect block, so nothing measured in-target: undefined
|
|
127
|
+
// (the weaker empty-window test), never a fabricated zero.
|
|
128
|
+
session.lastAct.markActed(since, action, undefined);
|
|
188
129
|
return withControl(session, {
|
|
189
130
|
since,
|
|
190
131
|
inputMode: InputMode.REAL,
|
|
@@ -202,17 +143,15 @@ export const ACT_TOOLS = [
|
|
|
202
143
|
});
|
|
203
144
|
if (!result.ok)
|
|
204
145
|
throw new Error(result.error ?? 'act failed');
|
|
205
|
-
|
|
206
|
-
deps.recordings.capture(compileActStep(args, result.result));
|
|
207
|
-
}
|
|
146
|
+
captureAct(deps.recordings, args, result.result);
|
|
208
147
|
// lift dispatch/settle status to the envelope (a settle timeout is NOT a failure).
|
|
209
148
|
const r = asRecord(result.result);
|
|
210
|
-
if (typeof r['settled']
|
|
149
|
+
if ('boolean' === typeof r['settled'])
|
|
211
150
|
settledOutcome = r['settled'];
|
|
212
151
|
// Keep what only this call measured, so the observe that judges this window can ask whether
|
|
213
152
|
// anything happened INSIDE the target — the one fact that separates a dead control from a
|
|
214
153
|
// page that was merely busy with something else.
|
|
215
|
-
session.lastAct.
|
|
154
|
+
session.lastAct.markActed(since, action, mutatedWithin(r));
|
|
216
155
|
return withControl(session, {
|
|
217
156
|
since,
|
|
218
157
|
inputMode: InputMode.SYNTHETIC,
|
|
@@ -222,19 +161,30 @@ export const ACT_TOOLS = [
|
|
|
222
161
|
settled: r['settled'] ?? null,
|
|
223
162
|
settleReason: r['settleReason'] ?? null,
|
|
224
163
|
result: leanActResult(result.result),
|
|
225
|
-
...(real.fellBack
|
|
164
|
+
...(true === real.fellBack ? { warning: ActionWarning.REAL_INPUT_FELL_BACK } : {}),
|
|
226
165
|
...healthEnvelope(session),
|
|
227
166
|
});
|
|
228
167
|
}
|
|
229
168
|
finally {
|
|
230
169
|
// Close the window on every exit (settle or throw), recording the action + settle outcome.
|
|
231
|
-
session.finishAction(undefined, settledOutcome,
|
|
170
|
+
session.finishAction(undefined, settledOutcome, true === settledOutcome ? session.elapsed() - since : undefined);
|
|
232
171
|
}
|
|
233
172
|
},
|
|
234
173
|
},
|
|
235
174
|
{
|
|
236
175
|
name: ReticleTool.ACT_SEQUENCE,
|
|
237
|
-
|
|
176
|
+
// The example is required for a core tool, and this one carries weight: the measured loop it
|
|
177
|
+
// replaces is literally a login form driven as three separate reticle_act calls (98 clicks and
|
|
178
|
+
// 21 fills inside looping sessions, 2026-08-10/11). Showing fill -> fill -> click is showing the
|
|
179
|
+
// exact shape an agent otherwise spends three round trips on.
|
|
180
|
+
example: {
|
|
181
|
+
steps: [
|
|
182
|
+
{ ref: 'e12', action: 'fill', args: { value: 'a@b.com' } },
|
|
183
|
+
{ ref: 'e13', action: 'fill', args: { value: 'hunter2' } },
|
|
184
|
+
{ ref: 'e14', action: 'click' },
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
description: 'Run multiple actions in order (fill -> fill -> submit) in ONE round-trip. Prefer this over repeating reticle_act for a multi-step journey, then assert its consequence once. Returns per-step effects[] (see reticle_act).',
|
|
238
188
|
inputSchema: {
|
|
239
189
|
steps: z
|
|
240
190
|
.array(z.record(z.unknown()))
|
|
@@ -258,12 +208,15 @@ export const ACT_TOOLS = [
|
|
|
258
208
|
if (paused !== undefined)
|
|
259
209
|
return paused;
|
|
260
210
|
const since = session.elapsed();
|
|
261
|
-
session.lastAct.markCursor(since); // honesty: a later wait_for/assert floors at this cursor
|
|
262
211
|
session.beginAction(ReticleTool.ACT_SEQUENCE, asRecord(args));
|
|
263
212
|
try {
|
|
264
213
|
const result = await session.command(ReticleCommand.ACT_SEQUENCE, { steps: args['steps'] });
|
|
265
214
|
if (!result.ok)
|
|
266
215
|
throw new Error(result.error ?? 'act_sequence failed');
|
|
216
|
+
// Marked only once the sequence ran: a refused sequence must leave no cursor behind for a
|
|
217
|
+
// later observe to judge. No single action and no in-target measurement here — per-step
|
|
218
|
+
// effects live in steps[] — so the effect is cleared rather than inherited from an earlier act.
|
|
219
|
+
session.lastAct.markActed(since, undefined, undefined);
|
|
267
220
|
if (deps.recordings.active().length > 0) {
|
|
268
221
|
deps.recordings.capture(compileSequenceStep(args, result.result));
|
|
269
222
|
}
|
|
@@ -283,7 +236,11 @@ export const ACT_TOOLS = [
|
|
|
283
236
|
},
|
|
284
237
|
{
|
|
285
238
|
name: ReticleTool.ACT_AND_WAIT,
|
|
286
|
-
example: {
|
|
239
|
+
example: {
|
|
240
|
+
ref: 'e42',
|
|
241
|
+
action: 'click',
|
|
242
|
+
until: { kind: PredicateKind.SIGNAL, name: 'todos:loaded' },
|
|
243
|
+
},
|
|
287
244
|
description: 'Act on a ref, then wait for a predicate to hold — one hop for the act->observe->assert loop. ' +
|
|
288
245
|
'Omit `until` to wait for the page to settle (network + DOM idle) — use this instead of a fixed sleep. ' +
|
|
289
246
|
'Returns { effect } (the action result), { verdict } (predicate pass/evidence/near-miss), ' +
|
|
@@ -294,13 +251,12 @@ export const ACT_TOOLS = [
|
|
|
294
251
|
ref: z
|
|
295
252
|
.string()
|
|
296
253
|
.describe(`Element ref (e.g. 'e42') from reticle_snapshot/reticle_query — stable until the element leaves the DOM, so no re-snapshot between actions.`),
|
|
297
|
-
action:
|
|
298
|
-
.string()
|
|
299
|
-
.describe('Action to perform: click | dblclick | hover | focus | fill | type | clear | select | check | uncheck | submit | press | scrollIntoView'),
|
|
254
|
+
action: actionTypeEnum.describe(`Action to perform: ${ACTION_TYPE_LIST}`),
|
|
300
255
|
args: z
|
|
301
256
|
.record(z.unknown())
|
|
302
257
|
.optional()
|
|
303
258
|
.describe('Action-specific arguments: { value } for fill/select, { text } for type/press, { confirmDangerous: true } for a potentially destructive control.'),
|
|
259
|
+
predicate: PredicateSchema.optional().describe('Alias for `until` (the name reticle_assert / reticle_wait_for use).'),
|
|
304
260
|
until: PredicateSchema.optional().describe('Predicate to wait for after the action completes (same shape as reticle_assert). OMIT to wait for the page to SETTLE — network + DOM idle — the deterministic default instead of a sleep. To assert a consequence AND settle, allOf them: { kind: "allOf", predicates: [<your predicate>, { kind: "settled" }] }.'),
|
|
305
261
|
timeout_ms: z
|
|
306
262
|
.number()
|
|
@@ -320,6 +276,10 @@ export const ACT_TOOLS = [
|
|
|
320
276
|
pass: z.boolean(),
|
|
321
277
|
evidence: z.unknown().optional(),
|
|
322
278
|
failureReason: z.string().optional(),
|
|
279
|
+
observationLost: z
|
|
280
|
+
.boolean()
|
|
281
|
+
.optional()
|
|
282
|
+
.describe('The tab disconnected mid-wait, so this was never observed — the verdict is UNKNOWN, not a failure of the app.'),
|
|
323
283
|
// The STRUCTURED cause — observed / expected / assertion — is what the repair literature ranks
|
|
324
284
|
// above the prose failureReason (structured feedback beat narrative by 10.5pp) and above a bare
|
|
325
285
|
// pointer. `verdict` is `await waitForPredicate(...)`, whose EvalResult carries these on a
|
|
@@ -374,26 +334,44 @@ export const ACT_TOOLS = [
|
|
|
374
334
|
handler: async (deps, args) => {
|
|
375
335
|
const session = deps.sessions.resolve(asString(args['sessionId']));
|
|
376
336
|
// Live-control: refuse to drive the page (no act, no predicate eval) while paused.
|
|
337
|
+
//
|
|
338
|
+
// A VERDICT rides out with the refusal. This is the one tool here that promises `verified`,
|
|
339
|
+
// and the bare pause payload omitted it — so an agent reading `result.verified` got undefined
|
|
340
|
+
// from a call that carried no error, which is neither yes, no, nor unknown. It also broke this
|
|
341
|
+
// tool's own outputSchema, where `because` is required.
|
|
377
342
|
const paused = pausedShortCircuit(session);
|
|
378
|
-
if (paused !== undefined)
|
|
379
|
-
return paused;
|
|
343
|
+
if (paused !== undefined) {
|
|
344
|
+
return { ...paused, verified: Verified.UNKNOWN, because: PAUSED_NO_VERDICT };
|
|
345
|
+
}
|
|
380
346
|
refuseIfThrottled(session, args['refuseWhenThrottled']);
|
|
381
347
|
// Omitting `until` waits for the page to settle (idle) — the deterministic default vs a sleep.
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
348
|
+
// `predicate` is what reticle_assert / reticle_wait_for call this — see alias-args.ts.
|
|
349
|
+
const withUntil = aliasParam(args, 'until', ['predicate']);
|
|
350
|
+
const until = withUntil['until'] !== undefined
|
|
351
|
+
? parsePredicate(withUntil['until'])
|
|
352
|
+
: { kind: PredicateKind.SETTLED };
|
|
385
353
|
const timeout = asNumber(args['timeout_ms']) ?? DEFAULT_ASSERT_TIMEOUT_MS;
|
|
354
|
+
// Before anything is driven: this path cannot honour a native-input request, and taking the
|
|
355
|
+
// argument and ignoring it told the agent its trusted click had happened. See act-danger.
|
|
356
|
+
assertNativeInputSupported(asRecord(args['args']));
|
|
386
357
|
const since = session.elapsed();
|
|
387
358
|
// `dropped` is cumulative for the SESSION, so comparing against a pre-action reading is what
|
|
388
359
|
// asks "did the buffer lose anything while THIS action was observed?" — the question the
|
|
389
360
|
// honesty block means. Reading the raw total pinned every later verdict to `unknown` after a
|
|
390
361
|
// single early eviction (measured on the Next.js demo at dropped:51, windows intact).
|
|
391
362
|
const droppedBefore = session.bufferHealth().dropped;
|
|
392
|
-
|
|
363
|
+
// The cursor + effect are marked after the act dispatches (below) — a refused act leaves none.
|
|
393
364
|
// The attribution window stays open across the settle wait below, so post-dispatch async events
|
|
394
365
|
// (the whole point of act_and_wait) attribute to this action. finishAction fires after the wait.
|
|
395
366
|
session.beginAction(ReticleTool.ACT_AND_WAIT, asRecord(args));
|
|
396
367
|
let settledOutcome;
|
|
368
|
+
// Was the declared consequence ALREADY TRUE? Only asked for predicates that read live DOM
|
|
369
|
+
// state — event-based ones are floored at this act's cursor and cannot be satisfied by the
|
|
370
|
+
// past, so they need no pre-check and pay nothing. One extra query, on the path where a green
|
|
371
|
+
// is otherwise unfalsifiable. See honesty/already-true.
|
|
372
|
+
const alreadyTrue = until !== undefined && readsDomState(until)
|
|
373
|
+
? (await evaluatePredicate(session, until, since, false)).pass
|
|
374
|
+
: false;
|
|
397
375
|
try {
|
|
398
376
|
const actResult = await session.command(ReticleCommand.ACT, {
|
|
399
377
|
ref: args['ref'],
|
|
@@ -402,12 +380,16 @@ export const ACT_TOOLS = [
|
|
|
402
380
|
});
|
|
403
381
|
if (!actResult.ok)
|
|
404
382
|
throw new Error(actResult.error ?? 'act failed');
|
|
383
|
+
captureAct(deps.recordings, args, actResult.result);
|
|
384
|
+
// Dispatched — now this act owns the cursor and the effect. Marking its OWN measurement also
|
|
385
|
+
// stops the spread below from inheriting an earlier reticle_act's action and mutation count.
|
|
386
|
+
session.lastAct.markActed(since, asString(args['action']), mutatedWithin(asRecord(actResult.result)));
|
|
405
387
|
// Honesty: floor the predicate at this act's cursor so a stale buffered event can't satisfy it.
|
|
406
388
|
const verdict = timeout > 0
|
|
407
389
|
? await waitForPredicate(session, until, timeout, since)
|
|
408
390
|
: await evaluatePredicate(session, until, since);
|
|
409
391
|
const r = asRecord(actResult.result);
|
|
410
|
-
if (typeof r['settled']
|
|
392
|
+
if ('boolean' === typeof r['settled'])
|
|
411
393
|
settledOutcome = r['settled'];
|
|
412
394
|
// Where the acted element is written. Captured at act time alongside the anchor, so it is
|
|
413
395
|
// available even when the action unmounted its own target.
|
|
@@ -438,12 +420,19 @@ export const ACT_TOOLS = [
|
|
|
438
420
|
// structural boundary (virtualized rows, a cross-origin frame) is reported as coverage and
|
|
439
421
|
// must not downgrade a verdict about what WAS observed.
|
|
440
422
|
const impeaching = buildCoverageStatement(spots.filter((s) => impeachesCapture(s.kind)));
|
|
423
|
+
// Same rule as reticle_assert: a browser-side transport gap means part of this window was
|
|
424
|
+
// never seen, which is what `blindSpots` exists to say. `truncated` above covers the SERVER
|
|
425
|
+
// ring buffer evicting; this covers the BROWSER queue overflowing, and they are not the same
|
|
426
|
+
// loss — an act_and_wait that graded `proved` over 34 dropped events said so in a sentence
|
|
427
|
+
// whose own words were "over a clean capture".
|
|
428
|
+
const gapNote = transportGapNote(windowEvents);
|
|
429
|
+
const impeachingNotes = [impeaching.note, gapNote].filter((n) => n !== undefined);
|
|
441
430
|
const honesty = buildHonestyBlock({
|
|
442
431
|
grade: gradeOf(gradedLinks),
|
|
443
432
|
attribution: 'window',
|
|
444
433
|
truncated: session.bufferHealth().dropped > droppedBefore,
|
|
445
|
-
coveragePartial:
|
|
446
|
-
...(
|
|
434
|
+
coveragePartial: Coverage.PARTIAL === coverage.coverage,
|
|
435
|
+
...(0 === impeachingNotes.length ? {} : { blindSpots: impeachingNotes }),
|
|
447
436
|
});
|
|
448
437
|
const capsuleSaved = await saveFailedAssertCapsule({
|
|
449
438
|
deps,
|
|
@@ -467,6 +456,13 @@ export const ACT_TOOLS = [
|
|
|
467
456
|
const outcomeUnread = hasUnreadWriteOutcome(windowEvents);
|
|
468
457
|
const decision = decideVerified({
|
|
469
458
|
pass: verdict.pass,
|
|
459
|
+
...(alreadyTrue ? { alreadyTrue } : {}),
|
|
460
|
+
// An assertion nobody could evaluate must not be reported as one the app failed.
|
|
461
|
+
...(verdict.inconclusive === undefined ? {} : { inconclusive: verdict.inconclusive }),
|
|
462
|
+
// Nor must one nobody could OBSERVE. This is the act path, so it is the one that produced
|
|
463
|
+
// the measured false red: a reload mid-wait, graded assertion_failed at the clicked
|
|
464
|
+
// component's own file and line.
|
|
465
|
+
...(true === verdict.observationLost ? { observationLost: true } : {}),
|
|
470
466
|
honesty,
|
|
471
467
|
contradictions,
|
|
472
468
|
...(outcomePending ? { outcomePending } : {}),
|
|
@@ -505,7 +501,7 @@ export const ACT_TOOLS = [
|
|
|
505
501
|
});
|
|
506
502
|
}
|
|
507
503
|
finally {
|
|
508
|
-
session.finishAction(undefined, settledOutcome,
|
|
504
|
+
session.finishAction(undefined, settledOutcome, true === settledOutcome ? session.elapsed() - since : undefined);
|
|
509
505
|
}
|
|
510
506
|
},
|
|
511
507
|
},
|
package/dist/tools/act-view.js
CHANGED
|
@@ -23,11 +23,11 @@ const NULL_NOISE = new Set(['occludedBy', 'focusMoved']);
|
|
|
23
23
|
function leanEffect(effect) {
|
|
24
24
|
const out = {};
|
|
25
25
|
for (const [k, v] of Object.entries(effect)) {
|
|
26
|
-
if (TRUE_NOISE.has(k) &&
|
|
26
|
+
if (TRUE_NOISE.has(k) && true === v)
|
|
27
27
|
continue;
|
|
28
|
-
if (FALSE_NOISE.has(k) &&
|
|
28
|
+
if (FALSE_NOISE.has(k) && false === v)
|
|
29
29
|
continue;
|
|
30
|
-
if (NULL_NOISE.has(k) &&
|
|
30
|
+
if (NULL_NOISE.has(k) && null === v)
|
|
31
31
|
continue;
|
|
32
32
|
out[k] = v;
|
|
33
33
|
}
|
|
@@ -35,11 +35,11 @@ function leanEffect(effect) {
|
|
|
35
35
|
}
|
|
36
36
|
/** Return a copy of an act command result with its `effect` block leaned. Non-objects pass through. */
|
|
37
37
|
export function leanActResult(result) {
|
|
38
|
-
if (
|
|
38
|
+
if (null === result || typeof result !== 'object')
|
|
39
39
|
return result;
|
|
40
40
|
const r = result;
|
|
41
41
|
const effect = r['effect'];
|
|
42
|
-
if (
|
|
42
|
+
if (null === effect || typeof effect !== 'object')
|
|
43
43
|
return result;
|
|
44
44
|
return { ...r, effect: leanEffect(effect) };
|
|
45
45
|
}
|
|
@@ -51,8 +51,8 @@ export function leanActResult(result) {
|
|
|
51
51
|
*/
|
|
52
52
|
export function mutatedWithin(result) {
|
|
53
53
|
const effect = result['effect'];
|
|
54
|
-
if (typeof effect !== 'object' ||
|
|
54
|
+
if (typeof effect !== 'object' || null === effect)
|
|
55
55
|
return undefined;
|
|
56
56
|
const value = effect['domMutatedWithin'];
|
|
57
|
-
return typeof value
|
|
57
|
+
return 'number' === typeof value ? value : 0;
|
|
58
58
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accepting a neighbouring tool's spelling for the same parameter.
|
|
3
|
+
*
|
|
4
|
+
* Reticle's surface has a few places where one concept has two names, and every one of them is a
|
|
5
|
+
* rejected call for an agent that learned the other spelling from the tool next door:
|
|
6
|
+
*
|
|
7
|
+
* reticle_act_and_wait { until } vs reticle_wait_for / reticle_assert { predicate }
|
|
8
|
+
* reticle_annotate { flow } vs every other flow tool { flowName }
|
|
9
|
+
*
|
|
10
|
+
* Both cross a path the product prescribes — `act_and_wait` is the most-used tool, and
|
|
11
|
+
* `reticle_flow_save`'s own description tells the agent to go and call `reticle_annotate`.
|
|
12
|
+
*
|
|
13
|
+
* Aliasing, not renaming: the canonical name stays the contract, an explicit canonical value always
|
|
14
|
+
* wins, and a call carrying neither is left untouched so the schema error still names what was
|
|
15
|
+
* missing instead of being replaced by a guess.
|
|
16
|
+
*/
|
|
17
|
+
export declare function aliasParam(args: Record<string, unknown>, canonical: string, aliases: readonly string[]): Record<string, unknown>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accepting a neighbouring tool's spelling for the same parameter.
|
|
3
|
+
*
|
|
4
|
+
* Reticle's surface has a few places where one concept has two names, and every one of them is a
|
|
5
|
+
* rejected call for an agent that learned the other spelling from the tool next door:
|
|
6
|
+
*
|
|
7
|
+
* reticle_act_and_wait { until } vs reticle_wait_for / reticle_assert { predicate }
|
|
8
|
+
* reticle_annotate { flow } vs every other flow tool { flowName }
|
|
9
|
+
*
|
|
10
|
+
* Both cross a path the product prescribes — `act_and_wait` is the most-used tool, and
|
|
11
|
+
* `reticle_flow_save`'s own description tells the agent to go and call `reticle_annotate`.
|
|
12
|
+
*
|
|
13
|
+
* Aliasing, not renaming: the canonical name stays the contract, an explicit canonical value always
|
|
14
|
+
* wins, and a call carrying neither is left untouched so the schema error still names what was
|
|
15
|
+
* missing instead of being replaced by a guess.
|
|
16
|
+
*/
|
|
17
|
+
export function aliasParam(args, canonical, aliases) {
|
|
18
|
+
if (args[canonical] !== undefined)
|
|
19
|
+
return args;
|
|
20
|
+
for (const alias of aliases) {
|
|
21
|
+
if (args[alias] !== undefined)
|
|
22
|
+
return { ...args, [canonical]: args[alias] };
|
|
23
|
+
}
|
|
24
|
+
return args;
|
|
25
|
+
}
|
|
@@ -10,18 +10,18 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Pure: no IO, no clock.
|
|
12
12
|
*/
|
|
13
|
-
import { isConsequenceKind, isPresenceKind } from '@reticlehq/core';
|
|
13
|
+
import { isConsequenceKind, isPresenceKind, PredicateKind } from '@reticlehq/core';
|
|
14
14
|
import { HonestyGrade } from '../honesty/honesty.js';
|
|
15
15
|
export const PRESENCE_ONLY_ADVICE = 'This predicate only checks element/text presence, not an observable consequence. A locator healed to the wrong element (or a stale render) can satisfy it while the feature is broken. Prefer a { signal } or { net } assertion — or allOf it with one — so green means the feature actually worked.';
|
|
16
16
|
function walk(predicate) {
|
|
17
|
-
if (
|
|
17
|
+
if (PredicateKind.ALL_OF === predicate.kind || PredicateKind.ANY_OF === predicate.kind) {
|
|
18
18
|
const subs = predicate.predicates.map(walk);
|
|
19
19
|
return {
|
|
20
20
|
consequence: subs.some((s) => s.consequence),
|
|
21
21
|
presence: subs.some((s) => s.presence),
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
|
-
if (
|
|
24
|
+
if (PredicateKind.NOT === predicate.kind)
|
|
25
25
|
return walk(predicate.predicate);
|
|
26
26
|
// Leaf: classify against the single source of truth in core. Kinds that are neither consequence
|
|
27
27
|
// nor presence (route/console/settled/animation) correctly return false for both.
|
|
@@ -50,12 +50,12 @@ export const DERIVED_IPC_STATUS_ADVICE = 'This asserts on a status code Reticle
|
|
|
50
50
|
* Recognised by the `ipc://` scheme, so a genuine HTTP status is never second-guessed.
|
|
51
51
|
*/
|
|
52
52
|
export function assertsDerivedIpcStatus(predicate) {
|
|
53
|
-
if (
|
|
53
|
+
if (PredicateKind.ALL_OF === predicate.kind || PredicateKind.ANY_OF === predicate.kind) {
|
|
54
54
|
return predicate.predicates.some(assertsDerivedIpcStatus);
|
|
55
55
|
}
|
|
56
|
-
if (
|
|
56
|
+
if (PredicateKind.NOT === predicate.kind)
|
|
57
57
|
return assertsDerivedIpcStatus(predicate.predicate);
|
|
58
|
-
if (predicate.kind !==
|
|
58
|
+
if (predicate.kind !== PredicateKind.NET)
|
|
59
59
|
return false;
|
|
60
60
|
return (predicate.status !== undefined &&
|
|
61
61
|
predicate.ok === undefined &&
|
|
@@ -74,11 +74,11 @@ export function isPresenceOnlyAssertion(predicate) {
|
|
|
74
74
|
*/
|
|
75
75
|
export function gradeOfPredicate(predicate) {
|
|
76
76
|
switch (predicate.kind) {
|
|
77
|
-
case
|
|
77
|
+
case PredicateKind.SIGNAL:
|
|
78
78
|
return HonestyGrade.SIGNAL;
|
|
79
|
-
case
|
|
79
|
+
case PredicateKind.NET:
|
|
80
80
|
return HonestyGrade.NET;
|
|
81
|
-
case
|
|
81
|
+
case PredicateKind.STATE:
|
|
82
82
|
return HonestyGrade.STATE;
|
|
83
83
|
default:
|
|
84
84
|
return HonestyGrade.PRESENCE;
|
|
@@ -14,7 +14,15 @@ import { type Contradiction } from '../events/contradictions.js';
|
|
|
14
14
|
* consult it. Asserting a moment earlier — while the POST was still open — is the same story with a
|
|
15
15
|
* different name: `request-never-settled`, also unreported.
|
|
16
16
|
*/
|
|
17
|
-
export declare function assertVerdict(session: Session, predicate: Predicate, pass: boolean, since: number
|
|
17
|
+
export declare function assertVerdict(session: Session, predicate: Predicate, pass: boolean, since: number,
|
|
18
|
+
/** Set when the assertion was never evaluated — see honesty/verified.ts. */
|
|
19
|
+
inconclusive?: string,
|
|
20
|
+
/**
|
|
21
|
+
* Set when the tab went away mid-wait, so the assertion was never OBSERVED. `reticle_assert` and
|
|
22
|
+
* `reticle_wait_for` reach the same disconnect path as the act tools, and a verdict that blames
|
|
23
|
+
* the app for a lost connection is no more honest on this route than on that one.
|
|
24
|
+
*/
|
|
25
|
+
observationLost?: boolean): Promise<{
|
|
18
26
|
decision: Record<string, unknown>;
|
|
19
27
|
contradictions: Contradiction[];
|
|
20
28
|
coverage: Record<string, unknown>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { findContradictions } from '../events/contradictions.js';
|
|
2
|
-
import { blindSpotsFromState, buildCoverageStatement, impeachesCapture, } from '../honesty/blind-spots.js';
|
|
2
|
+
import { blindSpotsFromState, buildCoverageStatement, Coverage, impeachesCapture, transportGapNote, } from '../honesty/blind-spots.js';
|
|
3
3
|
import { buildHonestyBlock } from '../honesty/honesty.js';
|
|
4
4
|
import { hasAcceptedWrite } from '../honesty/accepted-write.js';
|
|
5
5
|
import { hasUnreadWriteOutcome } from '../honesty/unread-outcome.js';
|
|
@@ -18,7 +18,15 @@ import { gradeOfPredicate } from './assert-grade.js';
|
|
|
18
18
|
* consult it. Asserting a moment earlier — while the POST was still open — is the same story with a
|
|
19
19
|
* different name: `request-never-settled`, also unreported.
|
|
20
20
|
*/
|
|
21
|
-
export async function assertVerdict(session, predicate, pass, since
|
|
21
|
+
export async function assertVerdict(session, predicate, pass, since,
|
|
22
|
+
/** Set when the assertion was never evaluated — see honesty/verified.ts. */
|
|
23
|
+
inconclusive,
|
|
24
|
+
/**
|
|
25
|
+
* Set when the tab went away mid-wait, so the assertion was never OBSERVED. `reticle_assert` and
|
|
26
|
+
* `reticle_wait_for` reach the same disconnect path as the act tools, and a verdict that blames
|
|
27
|
+
* the app for a lost connection is no more honest on this route than on that one.
|
|
28
|
+
*/
|
|
29
|
+
observationLost) {
|
|
22
30
|
// Scope caveat, stated because it is a real limitation and not a bug: blind spots are tracked per
|
|
23
31
|
// SESSION, not per assertion window, so a cross-origin iframe seen once marks every later verdict
|
|
24
32
|
// in that session partial — including ones about a region it cannot affect. That errs toward
|
|
@@ -28,9 +36,9 @@ export async function assertVerdict(session, predicate, pass, since) {
|
|
|
28
36
|
const statement = buildCoverageStatement(spots);
|
|
29
37
|
// Omitted entirely when coverage is full, so an intact page pays nothing and the field's PRESENCE
|
|
30
38
|
// is the warning.
|
|
31
|
-
const coverage =
|
|
39
|
+
const coverage = Coverage.PARTIAL === statement.coverage
|
|
32
40
|
? {
|
|
33
|
-
coverage: statement.note ??
|
|
41
|
+
coverage: statement.note ?? Coverage.PARTIAL,
|
|
34
42
|
coverage_spots: statement.spots.map((sp) => ({ kind: sp.kind, count: sp.count })),
|
|
35
43
|
}
|
|
36
44
|
: {};
|
|
@@ -44,15 +52,22 @@ export async function assertVerdict(session, predicate, pass, since) {
|
|
|
44
52
|
// Only a spot that IMPEACHES the capture downgrades a verdict. A structural boundary (virtualized
|
|
45
53
|
// rows, a cross-origin frame) is reported as coverage and must not impugn what WAS observed.
|
|
46
54
|
const impeaching = buildCoverageStatement(spots.filter((sp) => impeachesCapture(sp.kind)));
|
|
55
|
+
// A gap in the WINDOW, as opposed to a standing limit of the page. Both mean the same thing to the
|
|
56
|
+
// rule — part of what happened was not seen — so both belong in `blindSpots`, which is the only
|
|
57
|
+
// input `decideVerified` reads for that.
|
|
58
|
+
const gap = transportGapNote(windowEvents);
|
|
59
|
+
const impeachingNotes = [impeaching.note, gap].filter((n) => n !== undefined);
|
|
47
60
|
const outcomePending = hasAcceptedWrite(windowEvents);
|
|
48
61
|
const outcomeUnread = hasUnreadWriteOutcome(windowEvents);
|
|
49
62
|
const decision = decideVerified({
|
|
50
63
|
pass,
|
|
64
|
+
...(inconclusive === undefined ? {} : { inconclusive }),
|
|
65
|
+
...(true === observationLost ? { observationLost: true } : {}),
|
|
51
66
|
honesty: buildHonestyBlock({
|
|
52
67
|
grade: gradeOfPredicate(predicate),
|
|
53
68
|
attribution: 'window',
|
|
54
|
-
coveragePartial:
|
|
55
|
-
...(
|
|
69
|
+
coveragePartial: Coverage.PARTIAL === statement.coverage,
|
|
70
|
+
...(0 === impeachingNotes.length ? {} : { blindSpots: impeachingNotes }),
|
|
56
71
|
}),
|
|
57
72
|
contradictions,
|
|
58
73
|
...(outcomePending ? { outcomePending } : {}),
|