@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
|
@@ -1,84 +1,153 @@
|
|
|
1
|
-
import { ElementQuerySchema, ElementState, EventType, } from '@reticlehq/core';
|
|
1
|
+
import { ElementQuerySchema, ElementState, EventType, PredicateKind, StreamDirection, isDevToolingUrl, } from '@reticlehq/core';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import { describeObserved } from './observed-in-window.js';
|
|
4
|
+
/**
|
|
5
|
+
* Spellings an agent plausibly reaches for, mapped to the real field.
|
|
6
|
+
*
|
|
7
|
+
* `route` spells its field `pathname` while `state`, in the same union, spells its `path`. Every one
|
|
8
|
+
* of these was silently DROPPED before, and because these kinds have all-optional fields, dropping
|
|
9
|
+
* the only key supplied left a predicate that asserts nothing and passes on anything.
|
|
10
|
+
*/
|
|
11
|
+
const PREDICATE_ALIASES = {
|
|
12
|
+
// `urlContains`/`url` reported from the field: an agent that had just written
|
|
13
|
+
// `net { urlContains }` applied the same word to `route`, which spells it `contains`, and got
|
|
14
|
+
// `unrecognized_keys` with no list of what would have worked. The parallel it assumed is a fair
|
|
15
|
+
// one — route's `contains` matches the WHOLE route (path + query + fragment), so "the URL
|
|
16
|
+
// contains this" is precisely what it does — and asserting a redirect after login is the single
|
|
17
|
+
// most common thing an agent reaches for here.
|
|
18
|
+
[PredicateKind.ROUTE]: { path: 'pathname', urlContains: 'contains', url: 'contains' },
|
|
19
|
+
[PredicateKind.NET]: { url: 'urlContains' },
|
|
20
|
+
[PredicateKind.SIGNAL]: { data: 'dataMatches' },
|
|
21
|
+
};
|
|
22
|
+
/** Rename known aliases before parse; an explicit canonical key always wins. */
|
|
23
|
+
function applyPredicateAliases(input) {
|
|
24
|
+
if (typeof input !== 'object' || null === input || Array.isArray(input))
|
|
25
|
+
return input;
|
|
26
|
+
const obj = input;
|
|
27
|
+
const aliases = PREDICATE_ALIASES['string' === typeof obj['kind'] ? obj['kind'] : ''];
|
|
28
|
+
if (aliases === undefined)
|
|
29
|
+
return input;
|
|
30
|
+
const out = { ...obj };
|
|
31
|
+
for (const [from, to] of Object.entries(aliases)) {
|
|
32
|
+
if (out[from] === undefined)
|
|
33
|
+
continue;
|
|
34
|
+
if (out[to] === undefined)
|
|
35
|
+
out[to] = out[from];
|
|
36
|
+
delete out[from];
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Strict on every branch. A key that is nobody's spelling is now a schema error naming it, instead of
|
|
42
|
+
* a stripped field and a green — see predicate-strict.test.ts for the MCP session that found this.
|
|
43
|
+
*/
|
|
44
|
+
export const PredicateSchema = z.lazy(() => z.preprocess(applyPredicateAliases, z.discriminatedUnion('kind', [
|
|
45
|
+
z
|
|
46
|
+
.object({
|
|
47
|
+
kind: z.literal(PredicateKind.ELEMENT),
|
|
6
48
|
query: ElementQuerySchema,
|
|
7
49
|
state: z.nativeEnum(ElementState).optional(),
|
|
8
50
|
absent: z.boolean().optional(),
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
|
|
51
|
+
})
|
|
52
|
+
.strict(),
|
|
53
|
+
z
|
|
54
|
+
.object({
|
|
55
|
+
kind: z.literal(PredicateKind.TEXT),
|
|
12
56
|
contains: z.string(),
|
|
13
57
|
visible: z.boolean().optional(),
|
|
14
58
|
absent: z.boolean().optional(),
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
|
|
59
|
+
})
|
|
60
|
+
.strict(),
|
|
61
|
+
z
|
|
62
|
+
.object({
|
|
63
|
+
kind: z.literal(PredicateKind.NET),
|
|
18
64
|
method: z.string().optional(),
|
|
19
65
|
urlContains: z.string().optional(),
|
|
20
66
|
status: z.number().optional(),
|
|
21
67
|
ok: z.boolean().optional(),
|
|
22
68
|
since: z.number().optional(),
|
|
23
69
|
count: z.number().int().nonnegative().optional(),
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
|
|
70
|
+
})
|
|
71
|
+
.strict(),
|
|
72
|
+
z
|
|
73
|
+
.object({
|
|
74
|
+
kind: z.literal(PredicateKind.ROUTE),
|
|
27
75
|
pathname: z.string().optional(),
|
|
28
76
|
contains: z.string().optional(),
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
77
|
+
since: z.number().optional(),
|
|
78
|
+
})
|
|
79
|
+
.strict(),
|
|
80
|
+
z
|
|
81
|
+
.object({
|
|
82
|
+
kind: z.literal(PredicateKind.CONSOLE),
|
|
32
83
|
level: z.string().optional(),
|
|
33
84
|
absent: z.boolean().optional(),
|
|
34
85
|
since: z.number().optional(),
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
|
|
86
|
+
})
|
|
87
|
+
.strict(),
|
|
88
|
+
z
|
|
89
|
+
.object({
|
|
90
|
+
kind: z.literal(PredicateKind.ANIMATION),
|
|
38
91
|
name: z.string().optional(),
|
|
39
92
|
target: z.string().optional(),
|
|
40
93
|
completed: z.boolean().optional(),
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
94
|
+
since: z.number().optional(),
|
|
95
|
+
})
|
|
96
|
+
.strict(),
|
|
97
|
+
z
|
|
98
|
+
.object({
|
|
99
|
+
kind: z.literal(PredicateKind.SIGNAL),
|
|
44
100
|
name: z.string().optional(),
|
|
45
101
|
dataMatches: z.record(z.unknown()).optional(),
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
102
|
+
since: z.number().optional(),
|
|
103
|
+
})
|
|
104
|
+
.strict(),
|
|
105
|
+
z
|
|
106
|
+
.object({
|
|
107
|
+
kind: z.literal(PredicateKind.STATE),
|
|
49
108
|
store: z.string().optional(),
|
|
50
109
|
path: z.string(),
|
|
51
110
|
equals: z.unknown().optional(),
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
z
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
111
|
+
})
|
|
112
|
+
.strict(),
|
|
113
|
+
z
|
|
114
|
+
.object({
|
|
115
|
+
kind: z.literal(PredicateKind.SETTLED),
|
|
116
|
+
quietMs: z.number().positive().optional(),
|
|
117
|
+
})
|
|
118
|
+
.strict(),
|
|
119
|
+
z
|
|
120
|
+
.object({ kind: z.literal(PredicateKind.ALL_OF), predicates: z.array(PredicateSchema) })
|
|
121
|
+
.strict(),
|
|
122
|
+
z
|
|
123
|
+
.object({ kind: z.literal(PredicateKind.ANY_OF), predicates: z.array(PredicateSchema) })
|
|
124
|
+
.strict(),
|
|
125
|
+
z.object({ kind: z.literal(PredicateKind.NOT), predicate: PredicateSchema }).strict(),
|
|
126
|
+
])));
|
|
58
127
|
function str(value) {
|
|
59
|
-
return typeof value
|
|
128
|
+
return 'string' === typeof value ? value : undefined;
|
|
60
129
|
}
|
|
61
130
|
function num(value) {
|
|
62
|
-
return typeof value
|
|
131
|
+
return 'number' === typeof value ? value : undefined;
|
|
63
132
|
}
|
|
64
133
|
/**
|
|
65
134
|
* Match one value against a pattern. Supports `*` (present), strict equality, and operators:
|
|
66
135
|
* `{$gte,$lte,$gt,$lt}` (numbers), `{$contains}` (array membership or substring), `{$length}`.
|
|
67
136
|
*/
|
|
68
137
|
export function matchValue(got, want) {
|
|
69
|
-
if (
|
|
138
|
+
if ('*' === want)
|
|
70
139
|
return got !== undefined;
|
|
71
140
|
// An object is an OPERATOR container only if it actually carries a `$`-prefixed operator. An empty
|
|
72
141
|
// `{}` (or an object with no `$` key) used to enter this branch, iterate zero recognized operators,
|
|
73
142
|
// and `return true` — so `equals: {}` / `dataMatches: {status: {}}` was a green assertion that
|
|
74
143
|
// passed against ANYTHING, undefined included: the exact false green the oracle exists to catch.
|
|
75
144
|
// Without an operator it is a literal to compare, and falls through to strict equality below.
|
|
76
|
-
const ops = typeof want
|
|
145
|
+
const ops = 'object' === typeof want && want !== null && !Array.isArray(want)
|
|
77
146
|
? Object.entries(want)
|
|
78
147
|
: undefined;
|
|
79
148
|
if (ops !== undefined && ops.some(([op]) => op.startsWith('$'))) {
|
|
80
149
|
for (const [op, val] of ops) {
|
|
81
|
-
const n = typeof got
|
|
150
|
+
const n = 'number' === typeof got ? got : NaN;
|
|
82
151
|
switch (op) {
|
|
83
152
|
case '$gte':
|
|
84
153
|
if (!(n >= val))
|
|
@@ -101,7 +170,7 @@ export function matchValue(got, want) {
|
|
|
101
170
|
if (!got.includes(val))
|
|
102
171
|
return false;
|
|
103
172
|
}
|
|
104
|
-
else if (typeof got
|
|
173
|
+
else if ('string' === typeof got) {
|
|
105
174
|
if (!got.includes(String(val)))
|
|
106
175
|
return false;
|
|
107
176
|
}
|
|
@@ -110,7 +179,7 @@ export function matchValue(got, want) {
|
|
|
110
179
|
}
|
|
111
180
|
break;
|
|
112
181
|
case '$length':
|
|
113
|
-
if (!((Array.isArray(got) || typeof got
|
|
182
|
+
if (!((Array.isArray(got) || 'string' === typeof got) && got.length === val)) {
|
|
114
183
|
return false;
|
|
115
184
|
}
|
|
116
185
|
break;
|
|
@@ -140,11 +209,27 @@ function dataMatches(actual, pattern) {
|
|
|
140
209
|
* This exists so an agent can assert on the OUTCOME rather than on a number Reticle invented.
|
|
141
210
|
*/
|
|
142
211
|
function callSucceeded(data) {
|
|
143
|
-
if (typeof data['ok']
|
|
212
|
+
if ('boolean' === typeof data['ok'])
|
|
144
213
|
return data['ok'];
|
|
145
214
|
const status = num(data['status']);
|
|
146
215
|
return status === undefined || status < 400;
|
|
147
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* One call, as the failure report should name it: `POST /api/generate-script → 500`.
|
|
219
|
+
*
|
|
220
|
+
* The status used to be dropped here, which made the most common net failure unreadable. Asserting
|
|
221
|
+
* `{status: 200}` against a call that returned 500 reported only `POST /api/generate-script` — the
|
|
222
|
+
* very field the predicate filtered on was missing from the account of what was seen, so the agent
|
|
223
|
+
* is told the call happened and left to guess why it did not match.
|
|
224
|
+
*
|
|
225
|
+
* The arrow is OMITTED when there is no status. An in-flight or aborted request genuinely has none,
|
|
226
|
+
* and `→ undefined` would be a fabricated fact about the wire.
|
|
227
|
+
*/
|
|
228
|
+
function describeCall(e) {
|
|
229
|
+
const head = `${str(e.data['method']) ?? 'GET'} ${str(e.data['url']) ?? ''}`;
|
|
230
|
+
const status = num(e.data['status']);
|
|
231
|
+
return status === undefined ? head : `${head} → ${String(status)}`;
|
|
232
|
+
}
|
|
148
233
|
export function evalNet(events, p) {
|
|
149
234
|
const since = p.since ?? 0;
|
|
150
235
|
const matches = events.filter((e) => {
|
|
@@ -183,7 +268,9 @@ export function evalNet(events, p) {
|
|
|
183
268
|
: {
|
|
184
269
|
pass: false,
|
|
185
270
|
failureReason: `no network call matched ${JSON.stringify(p)}`,
|
|
186
|
-
|
|
271
|
+
// Same reasoning as the signal miss: "no matching call" cannot be told apart from "the app
|
|
272
|
+
// made no calls at all", and those need different fixes.
|
|
273
|
+
observed: describeObserved('calls', events.filter((e) => e.type === EventType.NET_REQUEST).map(describeCall)),
|
|
187
274
|
expected: `at least one call matching ${JSON.stringify(p)}`,
|
|
188
275
|
assertion: 'net.present',
|
|
189
276
|
};
|
|
@@ -257,17 +344,17 @@ export function evalConsole(events, p) {
|
|
|
257
344
|
e.type === EventType.CONSOLE_ERROR ||
|
|
258
345
|
e.type === EventType.ERROR_UNCAUGHT);
|
|
259
346
|
}
|
|
260
|
-
if (p.level
|
|
347
|
+
if ('error' === p.level)
|
|
261
348
|
return isErr;
|
|
262
349
|
return e.type === CONSOLE_LEVEL_TYPE[p.level];
|
|
263
350
|
});
|
|
264
|
-
if (p.absent
|
|
265
|
-
return matches.length
|
|
351
|
+
if (true === p.absent) {
|
|
352
|
+
return 0 === matches.length
|
|
266
353
|
? { pass: true, evidence: { absent: true } }
|
|
267
354
|
: {
|
|
268
355
|
pass: false,
|
|
269
356
|
failureReason: `expected no ${p.level ?? 'console'} entries but found ${String(matches.length)}`,
|
|
270
|
-
observed: `${String(matches.length)} ${p.level ?? 'console'} entr${matches.length
|
|
357
|
+
observed: `${String(matches.length)} ${p.level ?? 'console'} entr${1 === matches.length ? 'y' : 'ies'}`,
|
|
271
358
|
expected: `no ${p.level ?? 'console'} entries`,
|
|
272
359
|
assertion: 'console.absent',
|
|
273
360
|
evidence: matches.map((e) => e.data),
|
|
@@ -284,7 +371,7 @@ export function evalConsole(events, p) {
|
|
|
284
371
|
};
|
|
285
372
|
}
|
|
286
373
|
export function evalAnimation(events, p) {
|
|
287
|
-
const wantType = p.completed
|
|
374
|
+
const wantType = true === p.completed ? EventType.ANIM_END : EventType.ANIM_START;
|
|
288
375
|
const hit = events.find((e) => {
|
|
289
376
|
if (e.type !== wantType)
|
|
290
377
|
return false;
|
|
@@ -330,7 +417,9 @@ export function evalSignal(events, p) {
|
|
|
330
417
|
: `no signal matched ${JSON.stringify(p)}`,
|
|
331
418
|
observed: sameName.length > 0
|
|
332
419
|
? `signal '${p.name ?? '(any)'}' fired ${String(sameName.length)}x, payload: ${JSON.stringify(sameName[0])}`
|
|
333
|
-
:
|
|
420
|
+
: // Name what DID fire: a typo'd signal name and a genuinely dead action produce the same
|
|
421
|
+
// sentence otherwise, and the agent cannot tell them apart. See observed-in-window.ts.
|
|
422
|
+
`signal '${p.name ?? '(any)'}' never fired — ${describeObserved('signals', events.filter((e) => e.type === EventType.SIGNAL).map((e) => str(e.data['name']) ?? ''))}`,
|
|
334
423
|
expected: p.dataMatches === undefined
|
|
335
424
|
? `signal '${p.name ?? '(any)'}' to fire`
|
|
336
425
|
: `signal '${p.name ?? '(any)'}' with payload matching ${JSON.stringify(p.dataMatches)}`,
|
|
@@ -364,6 +453,12 @@ const SETTLE_ACTIVITY = new Set([
|
|
|
364
453
|
EventType.DOM_REMOVED,
|
|
365
454
|
EventType.DOM_ATTR,
|
|
366
455
|
]);
|
|
456
|
+
/** The three net-shaped event types a URL can be read off — the only ones dev tooling can produce. */
|
|
457
|
+
const NET_TYPES = new Set([
|
|
458
|
+
EventType.NET_PENDING,
|
|
459
|
+
EventType.NET_REQUEST,
|
|
460
|
+
EventType.NET_STREAM,
|
|
461
|
+
]);
|
|
367
462
|
/** Default quiet window — enough to absorb a render+xhr settle without waiting on slow polls. */
|
|
368
463
|
const DEFAULT_QUIET_MS = 500;
|
|
369
464
|
/**
|
|
@@ -372,8 +467,24 @@ const DEFAULT_QUIET_MS = 500;
|
|
|
372
467
|
* now, not to any buffered event — so `now` is injected (CLAUDE.md rule 7), and the wait loop's
|
|
373
468
|
* poll interval is what eventually flips this to pass once activity stops.
|
|
374
469
|
*/
|
|
375
|
-
export function evalSettled(
|
|
470
|
+
export function evalSettled(allEvents, p, now) {
|
|
376
471
|
const quietMs = p.quietMs ?? DEFAULT_QUIET_MS;
|
|
472
|
+
// Dev-tooling traffic is the framework talking about ITSELF (see DevToolingChannel) and says
|
|
473
|
+
// nothing about whether the app finished its work — but it was holding settle open. Dropped from
|
|
474
|
+
// both halves of the calculation below (in-flight AND the quiet timer) and DISCLOSED on the
|
|
475
|
+
// evidence, never silently swallowed.
|
|
476
|
+
const ignoredDevTooling = [];
|
|
477
|
+
const events = allEvents.filter((e) => {
|
|
478
|
+
if (!NET_TYPES.has(e.type))
|
|
479
|
+
return true;
|
|
480
|
+
const url = str(e.data['url']);
|
|
481
|
+
if (!isDevToolingUrl(url))
|
|
482
|
+
return true;
|
|
483
|
+
if (url !== undefined && !ignoredDevTooling.includes(url))
|
|
484
|
+
ignoredDevTooling.push(url);
|
|
485
|
+
return false;
|
|
486
|
+
});
|
|
487
|
+
const disclosure = 0 === ignoredDevTooling.length ? {} : { ignoredDevTooling };
|
|
377
488
|
// A request that STARTED (NET_PENDING) but never completed (NET_REQUEST with the same id) is
|
|
378
489
|
// still in flight — the page is NOT settled no matter how quiet the DOM has gone. Without this,
|
|
379
490
|
// a slow save reads as "settled" the instant its spinner stops mutating the DOM: the exact
|
|
@@ -417,16 +528,16 @@ export function evalSettled(events, p, now) {
|
|
|
417
528
|
if (id === undefined)
|
|
418
529
|
continue;
|
|
419
530
|
const direction = str(e.data['direction']);
|
|
420
|
-
if (
|
|
531
|
+
if (StreamDirection.OPEN === direction)
|
|
421
532
|
openStreams.add(id);
|
|
422
|
-
else if (
|
|
533
|
+
else if (StreamDirection.CLOSE === direction)
|
|
423
534
|
openStreams.delete(id);
|
|
424
535
|
}
|
|
425
536
|
const streaming = openStreams.size;
|
|
426
537
|
if (inFlight + streaming > 0) {
|
|
427
|
-
const what =
|
|
538
|
+
const what = 0 === streaming
|
|
428
539
|
? `${String(inFlight)} request(s) still in flight`
|
|
429
|
-
:
|
|
540
|
+
: 0 === inFlight
|
|
430
541
|
? `${String(streaming)} response body(ies) still streaming`
|
|
431
542
|
: `${String(inFlight)} request(s) in flight and ${String(streaming)} response body(ies) still streaming`;
|
|
432
543
|
return {
|
|
@@ -435,7 +546,12 @@ export function evalSettled(events, p, now) {
|
|
|
435
546
|
observed: what,
|
|
436
547
|
expected: 'no requests in flight and no response bodies still streaming',
|
|
437
548
|
assertion: 'settled.in-flight',
|
|
438
|
-
evidence: {
|
|
549
|
+
evidence: {
|
|
550
|
+
settled: false,
|
|
551
|
+
inFlight,
|
|
552
|
+
...(streaming > 0 ? { streaming } : {}),
|
|
553
|
+
...disclosure,
|
|
554
|
+
},
|
|
439
555
|
};
|
|
440
556
|
}
|
|
441
557
|
let lastT = -1;
|
|
@@ -449,12 +565,15 @@ export function evalSettled(events, p, now) {
|
|
|
449
565
|
if (lastT < 0) {
|
|
450
566
|
return {
|
|
451
567
|
pass: true,
|
|
452
|
-
evidence: { settled: true, quietForMs: null, note: 'no activity to settle' },
|
|
568
|
+
evidence: { settled: true, quietForMs: null, note: 'no activity to settle', ...disclosure },
|
|
453
569
|
};
|
|
454
570
|
}
|
|
455
571
|
const quietForMs = now - lastT;
|
|
456
572
|
if (quietForMs >= quietMs) {
|
|
457
|
-
return {
|
|
573
|
+
return {
|
|
574
|
+
pass: true,
|
|
575
|
+
evidence: { settled: true, quietForMs, lastActivity: lastType, ...disclosure },
|
|
576
|
+
};
|
|
458
577
|
}
|
|
459
578
|
return {
|
|
460
579
|
pass: false,
|
|
@@ -462,6 +581,11 @@ export function evalSettled(events, p, now) {
|
|
|
462
581
|
observed: `last activity was ${String(lastType)}, ${String(quietForMs)}ms ago`,
|
|
463
582
|
expected: `${String(quietMs)}ms of quiet`,
|
|
464
583
|
assertion: 'settled.quiet',
|
|
465
|
-
evidence: { quietForMs, lastActivity: lastType },
|
|
584
|
+
evidence: { quietForMs, lastActivity: lastType, ...disclosure },
|
|
585
|
+
// The one failure in this file that knows exactly when it could stop being one: if nothing else
|
|
586
|
+
// happens, the window closes in this many ms. A waiter that re-checks THEN instead of on its next
|
|
587
|
+
// blind tick stops paying up to a full poll interval on the hottest call in the product. Only a
|
|
588
|
+
// hint — the predicate is still evaluated at that moment, and can still fail.
|
|
589
|
+
retryAfterMs: quietMs - quietForMs,
|
|
466
590
|
};
|
|
467
591
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One readable sentence when a predicate does not parse — never the zod array.
|
|
3
|
+
*
|
|
4
|
+
* Measured 2026-08-10: **9 of 58 tool errors that day were a serialized zod issue array**, all on
|
|
5
|
+
* `reticle_act_and_wait`, `reticle_wait_for` and `reticle_assert` — the three tools that produced
|
|
6
|
+
* every action-derived finding in the dataset. The least readable error we emit was landing on the
|
|
7
|
+
* highest-value path, and an agent had to `JSON.parse` an error string to learn which field it got
|
|
8
|
+
* wrong.
|
|
9
|
+
*
|
|
10
|
+
* `PredicateSchema.parse()` throws a `ZodError` whose `.message` IS that array, and three handlers
|
|
11
|
+
* call it directly. This wraps it once, so every caller gets the same shape rather than each
|
|
12
|
+
* growing its own catch — the pattern #108 asks for: name the parameter, say whether anything ran,
|
|
13
|
+
* show a valid call.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
import { PredicateSchema } from './predicate-eval.js';
|
|
17
|
+
/**
|
|
18
|
+
* Parse a predicate, or throw an Error whose message is a sentence.
|
|
19
|
+
*
|
|
20
|
+
* Deliberately still THROWS: every call site already handles a throw, and turning this into a
|
|
21
|
+
* result type would mean touching three handlers to gain nothing the message does not already say.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parsePredicate(input: unknown): z.infer<typeof PredicateSchema>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One readable sentence when a predicate does not parse — never the zod array.
|
|
3
|
+
*
|
|
4
|
+
* Measured 2026-08-10: **9 of 58 tool errors that day were a serialized zod issue array**, all on
|
|
5
|
+
* `reticle_act_and_wait`, `reticle_wait_for` and `reticle_assert` — the three tools that produced
|
|
6
|
+
* every action-derived finding in the dataset. The least readable error we emit was landing on the
|
|
7
|
+
* highest-value path, and an agent had to `JSON.parse` an error string to learn which field it got
|
|
8
|
+
* wrong.
|
|
9
|
+
*
|
|
10
|
+
* `PredicateSchema.parse()` throws a `ZodError` whose `.message` IS that array, and three handlers
|
|
11
|
+
* call it directly. This wraps it once, so every caller gets the same shape rather than each
|
|
12
|
+
* growing its own catch — the pattern #108 asks for: name the parameter, say whether anything ran,
|
|
13
|
+
* show a valid call.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
import { PredicateSchema } from './predicate-eval.js';
|
|
17
|
+
/** A valid call, short enough to sit inside an error without becoming the error. */
|
|
18
|
+
const EXAMPLE = '{ kind: "signal", name: "todos:loaded" }';
|
|
19
|
+
/** `path: ["net","urlContains"]` → `net.urlContains`; an empty path means the object itself. */
|
|
20
|
+
function pathOf(issue) {
|
|
21
|
+
return 0 === issue.path.length ? 'the predicate' : issue.path.map(String).join('.');
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* One issue, as a clause a human or an agent can act on.
|
|
25
|
+
*
|
|
26
|
+
* `unrecognized_keys` is the common case by far and the one worth spelling out — it is what a
|
|
27
|
+
* plausible-but-wrong field name produces, and the key itself is the whole answer.
|
|
28
|
+
*/
|
|
29
|
+
function describeIssue(issue) {
|
|
30
|
+
if (z.ZodIssueCode.unrecognized_keys === issue.code) {
|
|
31
|
+
return `unknown field ${issue.keys.join(', ')}`;
|
|
32
|
+
}
|
|
33
|
+
return `${pathOf(issue)}: ${issue.message}`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Parse a predicate, or throw an Error whose message is a sentence.
|
|
37
|
+
*
|
|
38
|
+
* Deliberately still THROWS: every call site already handles a throw, and turning this into a
|
|
39
|
+
* result type would mean touching three handlers to gain nothing the message does not already say.
|
|
40
|
+
*/
|
|
41
|
+
export function parsePredicate(input) {
|
|
42
|
+
const parsed = PredicateSchema.safeParse(input);
|
|
43
|
+
if (parsed.success)
|
|
44
|
+
return parsed.data;
|
|
45
|
+
const kind = 'object' === typeof input && null !== input && 'kind' in input
|
|
46
|
+
? String(input['kind'])
|
|
47
|
+
: 'unknown';
|
|
48
|
+
// Bounded on purpose: a union rejection can produce one issue per member, and pasting all of them
|
|
49
|
+
// back is how the zod array became unreadable in the first place.
|
|
50
|
+
const issues = parsed.error.issues.slice(0, 3).map(describeIssue).join('; ');
|
|
51
|
+
throw new Error(`that predicate did not parse (kind "${kind}"): ${issues}. Nothing ran — the predicate was ` +
|
|
52
|
+
`not evaluated, so no verdict was produced. Call reticle_tools for the fields this kind ` +
|
|
53
|
+
`accepts. A valid call looks like: ${EXAMPLE}`);
|
|
54
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type CommandResult, type ReticleEvent } from '@reticlehq/core';
|
|
1
|
+
import { PredicateKind, type CommandResult, type ReticleEvent } from '@reticlehq/core';
|
|
2
2
|
import type { ExpectedLink } from '../capsule/divergence.js';
|
|
3
3
|
import { type AmbientCounts } from '../journal/ambient.js';
|
|
4
4
|
import { PredicateSchema, type Predicate, type EvalResult } from './predicate-eval.js';
|
|
5
|
-
export { PredicateSchema };
|
|
5
|
+
export { PredicateSchema, PredicateKind };
|
|
6
6
|
export type { Predicate, EvalResult };
|
|
7
7
|
/** The subset of Session the predicate engine needs — keeps it testable with a fake. */
|
|
8
8
|
export interface PredicateSession {
|
|
@@ -17,6 +17,11 @@ export interface PredicateSession {
|
|
|
17
17
|
* Optional: a session without ambient learning simply omits it and settle behaves as before.
|
|
18
18
|
*/
|
|
19
19
|
ambientCounts?(): AmbientCounts;
|
|
20
|
+
/**
|
|
21
|
+
* Subscribe to session disconnect. Returns an unsubscribe function. Optional: a session without
|
|
22
|
+
* this hook (e.g. tests that never disconnect) simply leaves in-flight predicates until timeout.
|
|
23
|
+
*/
|
|
24
|
+
onDisconnect?(listener: () => void): () => void;
|
|
20
25
|
}
|
|
21
26
|
export declare function evaluatePredicate(session: PredicateSession, predicate: Predicate, since?: number, diagnose?: boolean): Promise<EvalResult>;
|
|
22
27
|
/**
|