@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
|
@@ -19,8 +19,20 @@ import { BrowserLaunchKind, } from '@reticlehq/core';
|
|
|
19
19
|
import { errorSkeleton, fingerprintError } from './error-fingerprint.js';
|
|
20
20
|
import { describeToolParams } from './argument-shape.js';
|
|
21
21
|
import { machineSnapshot } from './machine-snapshot.js';
|
|
22
|
+
import { classifyError } from './error-class.js';
|
|
22
23
|
/** Cap the distinct error shapes held in memory — a pathological loop must not grow unbounded. */
|
|
23
24
|
const MAX_ERROR_KINDS = 40;
|
|
25
|
+
/** Distinct tool names whose repeat-runs are tracked. Its own cap: the tool surface, not error shapes. */
|
|
26
|
+
const MAX_REPEAT_TOOLS = 64;
|
|
27
|
+
/**
|
|
28
|
+
* Tool errors that all mean the same thing to a user: the agent asked, and there was no app it could
|
|
29
|
+
* reach. Three different messages, one experience — "nothing is connected" — and it is the error
|
|
30
|
+
* that ends most sessions before a single verification happens.
|
|
31
|
+
*
|
|
32
|
+
* `multiple sessions connected` belongs here too: the agent could not reach AN app because it could
|
|
33
|
+
* not tell which one, and the outcome is identical.
|
|
34
|
+
*/
|
|
35
|
+
const NO_SESSION_ERROR = /no browser session connected|no connected session with id|multiple sessions connected/i;
|
|
24
36
|
/** Cap distinct MCP clients recorded; more than a handful on one daemon is already the story. */
|
|
25
37
|
const MAX_CLIENTS = 8;
|
|
26
38
|
/** Bounds on the parameter map. Our own schemas are already finite; these are a belt-and-braces cap. */
|
|
@@ -35,6 +47,13 @@ const MAX_PARAMS_PER_TOOL = 24;
|
|
|
35
47
|
* strings and costs nothing to hold.
|
|
36
48
|
*/
|
|
37
49
|
const BREADCRUMB_LENGTH = 12;
|
|
50
|
+
/**
|
|
51
|
+
* Actions driven with no verdict before Reticle asks for one.
|
|
52
|
+
*
|
|
53
|
+
* Three, because the median verdict-less session made FOUR tool calls (2026-08-10/11). A higher
|
|
54
|
+
* threshold never fires for the sessions that need it most.
|
|
55
|
+
*/
|
|
56
|
+
const UNVERIFIED_ACTION_NUDGE_AT = 3;
|
|
38
57
|
/**
|
|
39
58
|
* Mutable counters for one daemon lifetime. A plain class, not a store: it is process-local, it never
|
|
40
59
|
* persists, and it dies with the daemon.
|
|
@@ -43,6 +62,27 @@ export class SessionMetrics {
|
|
|
43
62
|
#toolCalls = 0;
|
|
44
63
|
#toolErrors = 0;
|
|
45
64
|
#verifications = 0;
|
|
65
|
+
/**
|
|
66
|
+
* Session-LIFETIME totals for the four numbers the funnel is computed from.
|
|
67
|
+
*
|
|
68
|
+
* `reset()` zeroes every window counter on each periodic flush, but `durationMs` is measured from
|
|
69
|
+
* `#startedAt` and is never reset. So the FINAL summary — the one whose docstring promises "the
|
|
70
|
+
* whole session in a single event" — reported a 30-minute session containing zero tool calls,
|
|
71
|
+
* because it only ever carried the residue since the last flush.
|
|
72
|
+
*
|
|
73
|
+
* Measured 2026-08-10/11: **496 of 499 `daemon_stopped` rows had `toolCalls: 0`**, at a median
|
|
74
|
+
* duration of 30.5 minutes, while `session_progress` for the same daemons carried real tool
|
|
75
|
+
* histograms. Anyone computing "did this session use Reticle" off the event named for the end of
|
|
76
|
+
* the session got `no` essentially always. That is not a small skew — it is the funnel reading
|
|
77
|
+
* zero at the exact step this release exists to raise.
|
|
78
|
+
*
|
|
79
|
+
* Window semantics are unchanged: `session_progress` still reports its own window, so nothing that
|
|
80
|
+
* already sums those events double-counts. Only `final: true` swaps in the lifetime numbers.
|
|
81
|
+
*/
|
|
82
|
+
#lifetimeToolCalls = 0;
|
|
83
|
+
#lifetimeToolErrors = 0;
|
|
84
|
+
#lifetimeVerifications = 0;
|
|
85
|
+
#lifetimeBugsFound = 0;
|
|
46
86
|
#toolCounts = new Map();
|
|
47
87
|
#toolParams = new Map();
|
|
48
88
|
/** Ring of the most recent tool NAMES — the agent's approach run, for a crash report. */
|
|
@@ -58,6 +98,12 @@ export class SessionMetrics {
|
|
|
58
98
|
#concurrent = 0;
|
|
59
99
|
#peakConcurrent = 0;
|
|
60
100
|
#unknownToolCalls = 0;
|
|
101
|
+
/**
|
|
102
|
+
* Names the agent guessed at, session-LIFETIME — a guess made early must still be reported at
|
|
103
|
+
* the end, so this is deliberately not cleared by a flush.
|
|
104
|
+
*/
|
|
105
|
+
#unknownTools = new Map();
|
|
106
|
+
#lifetimeUnknownToolCalls = 0;
|
|
61
107
|
#bugsFound = 0;
|
|
62
108
|
#browserMs = 0;
|
|
63
109
|
#browserCommands = 0;
|
|
@@ -71,7 +117,52 @@ export class SessionMetrics {
|
|
|
71
117
|
* capped: the kind vocabulary is a bounded enum plus oracle names, not user data.
|
|
72
118
|
*/
|
|
73
119
|
#seenBugKinds = new Set();
|
|
120
|
+
/**
|
|
121
|
+
* Tool errors meaning "the agent could not reach an app at all" — the single biggest drop-off in
|
|
122
|
+
* the funnel, and until now reachable only by unpacking `errors[]` in HogQL. 74% of daemons never
|
|
123
|
+
* call a tool, and of the sessions that made exactly one call, most bounced on this.
|
|
124
|
+
*/
|
|
125
|
+
#noSessionErrors = 0;
|
|
126
|
+
/** Longest back-to-back run per tool — a retry loop, which `toolCounts` cannot distinguish. */
|
|
127
|
+
#repeatRuns = new Map();
|
|
128
|
+
#lastTool;
|
|
129
|
+
#currentRun = 0;
|
|
130
|
+
/**
|
|
131
|
+
* Actions driven since the last verdict — the run that is left hanging if the loop stops here.
|
|
132
|
+
*
|
|
133
|
+
* NOT `actions - verifications`. That difference ignores ORDER, so a verdict that drove nothing
|
|
134
|
+
* (a `flow_verify` over saved flows) silently paid for a genuinely abandoned action elsewhere, and
|
|
135
|
+
* a session could verify first and act after and look settled. What is abandoned is the trailing
|
|
136
|
+
* run, which is exactly what the field claims to mean.
|
|
137
|
+
*/
|
|
138
|
+
#unsettledActions = 0;
|
|
139
|
+
/** One-shot latch for the verdict nudge — see takeUnverifiedNudge. */
|
|
140
|
+
#nudgedUnverified = false;
|
|
141
|
+
/** The agent detached. The one part of `endReason` a query cannot derive. */
|
|
142
|
+
#clientLeft = false;
|
|
143
|
+
/** Feedback invitations shown, session-lifetime — the denominator for feedback_submitted. */
|
|
144
|
+
#feedbackPrompted = 0;
|
|
145
|
+
/** Error buckets by whose defect. Session-lifetime: the mix is a fact about the session. */
|
|
146
|
+
#errorClasses = new Map();
|
|
147
|
+
/**
|
|
148
|
+
* The recovery hinge. A call's outcome is only known once the NEXT one starts, so the verdict for
|
|
149
|
+
* call N-1 is resolved at the start of call N (and for the last call, at summarize).
|
|
150
|
+
*/
|
|
151
|
+
#currentCallErrored = false;
|
|
152
|
+
#priorCallErrored = false;
|
|
153
|
+
#errorsRecovered = 0;
|
|
154
|
+
#errorsRepeated = 0;
|
|
155
|
+
/**
|
|
156
|
+
* App SDK connections, session-lifetime. NOT reset by a flush: "did an app ever connect" is a
|
|
157
|
+
* fact about the session, and a page reload after a flush must not erase it.
|
|
158
|
+
*/
|
|
159
|
+
#appConnects = 0;
|
|
160
|
+
#firstAppAt;
|
|
74
161
|
#clients = new Set();
|
|
162
|
+
/** Client name -> version, session-lifetime. Never cleared: who drove is a fact about the session. */
|
|
163
|
+
#clientVersions = new Map();
|
|
164
|
+
/** Which tool surface the daemon advertised. */
|
|
165
|
+
#surface;
|
|
75
166
|
#startedAt;
|
|
76
167
|
#now;
|
|
77
168
|
/** Clock injected — this file must stay testable without a real one, per the repo's clock rule. */
|
|
@@ -116,11 +207,48 @@ export class SessionMetrics {
|
|
|
116
207
|
this.#browserCommands += 1;
|
|
117
208
|
}
|
|
118
209
|
/** A call for a tool that does not exist. Non-zero means our surface is confusing the agent. */
|
|
119
|
-
|
|
210
|
+
/**
|
|
211
|
+
* An agent reached for a tool that does not exist — and WHAT it reached for.
|
|
212
|
+
*
|
|
213
|
+
* The name is the point. A count says the surface confused someone; the name says which
|
|
214
|
+
* capability they expected us to have, in their own vocabulary. Safe to keep: it is a name from
|
|
215
|
+
* our own namespace, never app data. Bounded and truncated, because a guess is a short
|
|
216
|
+
* identifier and anything longer is not one.
|
|
217
|
+
*/
|
|
218
|
+
recordUnknownTool(name) {
|
|
120
219
|
this.#unknownToolCalls += 1;
|
|
220
|
+
this.#lifetimeUnknownToolCalls += 1;
|
|
221
|
+
if (name === undefined || 0 === name.length)
|
|
222
|
+
return;
|
|
223
|
+
const key = name.slice(0, 64);
|
|
224
|
+
const seen = this.#unknownTools.get(key);
|
|
225
|
+
if (seen !== undefined) {
|
|
226
|
+
this.#unknownTools.set(key, seen + 1);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
// Stop growing once full: a pathological loop must not balloon the payload. The head is what
|
|
230
|
+
// gets built; the tail is noise.
|
|
231
|
+
if (this.#unknownTools.size >= MAX_ERROR_KINDS)
|
|
232
|
+
return;
|
|
233
|
+
this.#unknownTools.set(key, 1);
|
|
121
234
|
}
|
|
122
235
|
recordToolCall(tool, args) {
|
|
236
|
+
// `recordToolCall` runs BEFORE a handler and `recordToolError` after it fails, so a call's
|
|
237
|
+
// outcome is only known once the NEXT call starts. Resolve the one before it here; the final
|
|
238
|
+
// call is resolved in summarize.
|
|
239
|
+
this.#resolveRecovery();
|
|
240
|
+
// A run of the same tool back to back. Five calls to reticle_act is engagement; five in a row
|
|
241
|
+
// after four failures is an agent stuck, and toolCounts reports both as "5".
|
|
242
|
+
this.#currentRun = tool === this.#lastTool ? this.#currentRun + 1 : 1;
|
|
243
|
+
this.#lastTool = tool;
|
|
244
|
+
if (this.#currentRun > 1) {
|
|
245
|
+
const best = this.#repeatRuns.get(tool) ?? 0;
|
|
246
|
+
if (this.#currentRun > best &&
|
|
247
|
+
(this.#repeatRuns.has(tool) || this.#repeatRuns.size < MAX_REPEAT_TOOLS))
|
|
248
|
+
this.#repeatRuns.set(tool, this.#currentRun);
|
|
249
|
+
}
|
|
123
250
|
this.#toolCalls += 1;
|
|
251
|
+
this.#lifetimeToolCalls += 1;
|
|
124
252
|
bump(this.#toolCounts, tool);
|
|
125
253
|
this.#inFlight = tool;
|
|
126
254
|
this.#breadcrumb.push(tool);
|
|
@@ -150,6 +278,13 @@ export class SessionMetrics {
|
|
|
150
278
|
*/
|
|
151
279
|
recordToolError(message, tool) {
|
|
152
280
|
this.#toolErrors += 1;
|
|
281
|
+
this.#lifetimeToolErrors += 1;
|
|
282
|
+
// Whose defect. Only the `schema` bucket is fixable by writing better descriptions, and it was
|
|
283
|
+
// indistinguishable from the rest inside one `toolErrors` count.
|
|
284
|
+
bump(this.#errorClasses, classifyError(message));
|
|
285
|
+
this.#currentCallErrored = true;
|
|
286
|
+
if (NO_SESSION_ERROR.test(message))
|
|
287
|
+
this.#noSessionErrors += 1;
|
|
153
288
|
const fingerprint = fingerprintError(message);
|
|
154
289
|
const existing = this.#errorKinds.get(fingerprint);
|
|
155
290
|
if (existing !== undefined) {
|
|
@@ -194,8 +329,51 @@ export class SessionMetrics {
|
|
|
194
329
|
get trail() {
|
|
195
330
|
return { breadcrumb: [...this.#breadcrumb], inFlight: this.#inFlight };
|
|
196
331
|
}
|
|
332
|
+
/**
|
|
333
|
+
* Ask the agent for a verdict, once, when it has driven the page without asking for one.
|
|
334
|
+
*
|
|
335
|
+
* Measured 2026-08-10/11: of 170 sessions that made a tool call, 140 produced no verdict — and
|
|
336
|
+
* **137 of those never called a verdict-producing tool even once.** They drove the app 269 times
|
|
337
|
+
* with `reticle_act` and never asked whether it worked. This counter already existed
|
|
338
|
+
* (`abandonedActions`, non-zero in 58 sessions); it was reported to US and never to the agent.
|
|
339
|
+
*
|
|
340
|
+
* Three is the threshold because the median verdict-less session made four tool calls: any higher
|
|
341
|
+
* and it never fires for the sessions that need it. Re-arms after a verdict, so a second
|
|
342
|
+
* abandoned run is caught — the loop can break more than once in a long session.
|
|
343
|
+
*/
|
|
344
|
+
takeUnverifiedNudge() {
|
|
345
|
+
if (this.#unsettledActions < UNVERIFIED_ACTION_NUDGE_AT || this.#nudgedUnverified) {
|
|
346
|
+
return undefined;
|
|
347
|
+
}
|
|
348
|
+
this.#nudgedUnverified = true;
|
|
349
|
+
return (`you have driven this page ${String(this.#unsettledActions)} times without asking for a ` +
|
|
350
|
+
'verdict. Only reticle_act_and_wait and reticle_assert produce one — everything else moves ' +
|
|
351
|
+
'or reads the app and proves nothing. Name the consequence you expect and check it: ' +
|
|
352
|
+
'reticle_assert({ sessionId, since, predicate }), or use reticle_act_and_wait({ ref, ' +
|
|
353
|
+
'action, until }) for the next step so the action and its check are one call.');
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* An app's SDK dialled this daemon.
|
|
357
|
+
*
|
|
358
|
+
* Zero of these at shutdown means the daemon ran and no app ever connected — a broken install.
|
|
359
|
+
* Non-zero with no tool calls is the opposite problem. See SessionSummary.appConnects.
|
|
360
|
+
*/
|
|
361
|
+
recordAppConnected() {
|
|
362
|
+
this.#appConnects += 1;
|
|
363
|
+
this.#firstAppAt ??= this.#now();
|
|
364
|
+
}
|
|
365
|
+
/** One action driven at the page. Settled by the next verdict; see #unsettledActions. */
|
|
366
|
+
recordAction() {
|
|
367
|
+
this.#unsettledActions += 1;
|
|
368
|
+
}
|
|
197
369
|
recordVerification() {
|
|
198
370
|
this.#verifications += 1;
|
|
371
|
+
this.#lifetimeVerifications += 1;
|
|
372
|
+
// A verdict settles whatever was outstanding, however many actions it took to get there.
|
|
373
|
+
this.#unsettledActions = 0;
|
|
374
|
+
// Re-arm the nudge: the loop can break more than once in an 11-hour session, and an agent that
|
|
375
|
+
// complied once and then drifted again is exactly the case worth catching.
|
|
376
|
+
this.#nudgedUnverified = false;
|
|
199
377
|
}
|
|
200
378
|
/**
|
|
201
379
|
* One defect found in the app under test — the outcome number, kept broken down by kind.
|
|
@@ -206,6 +384,7 @@ export class SessionMetrics {
|
|
|
206
384
|
*/
|
|
207
385
|
recordBug(kind) {
|
|
208
386
|
this.#bugsFound += 1;
|
|
387
|
+
this.#lifetimeBugsFound += 1;
|
|
209
388
|
if (this.#bugKinds.size < MAX_ERROR_KINDS || this.#bugKinds.has(kind))
|
|
210
389
|
bump(this.#bugKinds, kind);
|
|
211
390
|
const first = !this.#seenBugKinds.has(kind);
|
|
@@ -237,27 +416,83 @@ export class SessionMetrics {
|
|
|
237
416
|
stats.failures[failure] = (stats.failures[failure] ?? 0) + 1;
|
|
238
417
|
};
|
|
239
418
|
}
|
|
240
|
-
recordClient(name) {
|
|
419
|
+
recordClient(name, version) {
|
|
420
|
+
const key = name.slice(0, 64);
|
|
241
421
|
if (this.#clients.size < MAX_CLIENTS)
|
|
242
|
-
this.#clients.add(
|
|
422
|
+
this.#clients.add(key);
|
|
423
|
+
// The version was already in the handshake and was being dropped. A regression in agent
|
|
424
|
+
// behaviour is usually a client version, and without this it is unattributable.
|
|
425
|
+
if (version !== undefined && '' !== version && this.#clientVersions.size < MAX_CLIENTS) {
|
|
426
|
+
this.#clientVersions.set(key, version.slice(0, 32));
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* The agent's client went away.
|
|
431
|
+
*
|
|
432
|
+
* This is the only part of `endReason` that a query cannot derive from the counters: "the client
|
|
433
|
+
* detached" and "the agent stopped asking" produce identical numbers and are different findings —
|
|
434
|
+
* one is the task ending, the other is us losing them.
|
|
435
|
+
*/
|
|
436
|
+
recordClientLeft() {
|
|
437
|
+
this.#clientLeft = true;
|
|
438
|
+
}
|
|
439
|
+
/** How many times in a row the current tool has been called. Read by the friction invite. */
|
|
440
|
+
get currentRun() {
|
|
441
|
+
return this.#currentRun;
|
|
442
|
+
}
|
|
443
|
+
/** Reticle invited the agent to send feedback. The denominator for feedback_submitted. */
|
|
444
|
+
recordFeedbackPrompt() {
|
|
445
|
+
this.#feedbackPrompted += 1;
|
|
446
|
+
}
|
|
447
|
+
/** Which tool surface was advertised to agents this session. */
|
|
448
|
+
recordSurface(surface) {
|
|
449
|
+
this.#surface = surface.slice(0, 32);
|
|
243
450
|
}
|
|
244
451
|
/**
|
|
245
452
|
* Roll the counters into the event payload. `final` marks a clean shutdown; a periodic flush passes
|
|
246
453
|
* false so a session killed before it can exit is not lost entirely (see the flush note in cli.ts).
|
|
247
454
|
*/
|
|
248
|
-
summarize(final) {
|
|
455
|
+
summarize(final, exit) {
|
|
456
|
+
// The last call has no successor to resolve it, so resolve it here. Only on a FINAL summary:
|
|
457
|
+
// a periodic flush is not the end of anything and would resolve a call still in flight.
|
|
458
|
+
if (final)
|
|
459
|
+
this.#resolveRecovery();
|
|
249
460
|
const machine = machineSnapshot();
|
|
461
|
+
// A FINAL summary reports the session; a periodic flush reports its window. `durationMs` was
|
|
462
|
+
// always session-lifetime, so a windowed count next to it described a 30-minute session that
|
|
463
|
+
// made no calls. The histograms below stay windowed by design — summing them across a session's
|
|
464
|
+
// events is correct, and duplicating every map to make them lifetime would double the memory
|
|
465
|
+
// this class exists to keep small.
|
|
466
|
+
const scalars = final
|
|
467
|
+
? {
|
|
468
|
+
toolCalls: this.#lifetimeToolCalls,
|
|
469
|
+
toolErrors: this.#lifetimeToolErrors,
|
|
470
|
+
verifications: this.#lifetimeVerifications,
|
|
471
|
+
bugsFound: this.#lifetimeBugsFound,
|
|
472
|
+
}
|
|
473
|
+
: {
|
|
474
|
+
toolCalls: this.#toolCalls,
|
|
475
|
+
toolErrors: this.#toolErrors,
|
|
476
|
+
verifications: this.#verifications,
|
|
477
|
+
bugsFound: this.#bugsFound,
|
|
478
|
+
};
|
|
250
479
|
return {
|
|
251
480
|
durationMs: Math.max(0, this.#now() - this.#startedAt),
|
|
252
|
-
toolCalls:
|
|
481
|
+
toolCalls: scalars.toolCalls,
|
|
253
482
|
toolCounts: Object.fromEntries(this.#toolCounts),
|
|
254
|
-
toolErrors:
|
|
483
|
+
toolErrors: scalars.toolErrors,
|
|
255
484
|
...(this.#errorKinds.size > 0 ? { errors: [...this.#errorKinds.values()] } : {}),
|
|
256
485
|
sdkFailures: this.#sdkFailures,
|
|
257
486
|
...(this.#sdkFailureKinds.size > 0 ? { sdkErrors: [...this.#sdkFailureKinds.values()] } : {}),
|
|
258
|
-
verifications:
|
|
259
|
-
bugsFound:
|
|
487
|
+
verifications: scalars.verifications,
|
|
488
|
+
bugsFound: scalars.bugsFound,
|
|
260
489
|
...(this.#bugKinds.size > 0 ? { bugKinds: Object.fromEntries(this.#bugKinds) } : {}),
|
|
490
|
+
...(this.#noSessionErrors > 0 ? { noSessionErrors: this.#noSessionErrors } : {}),
|
|
491
|
+
...(this.#repeatRuns.size > 0
|
|
492
|
+
? { consecutiveRepeats: Object.fromEntries(this.#repeatRuns) }
|
|
493
|
+
: {}),
|
|
494
|
+
// Absent rather than zero, so the PRESENCE of the field is the signal on a dashboard.
|
|
495
|
+
...(this.#unsettledActions > 0 ? { abandonedActions: this.#unsettledActions } : {}),
|
|
261
496
|
...(this.#toolParams.size > 0
|
|
262
497
|
? {
|
|
263
498
|
toolParams: Object.fromEntries([...this.#toolParams].map(([tool, params]) => [tool, Object.fromEntries(params)])),
|
|
@@ -269,25 +504,87 @@ export class SessionMetrics {
|
|
|
269
504
|
browserMs: this.#browserMs,
|
|
270
505
|
browserCommands: this.#browserCommands,
|
|
271
506
|
peakConcurrentTools: this.#peakConcurrent,
|
|
272
|
-
unknownToolCalls: this.#unknownToolCalls,
|
|
507
|
+
unknownToolCalls: final ? this.#lifetimeUnknownToolCalls : this.#unknownToolCalls,
|
|
508
|
+
...(this.#unknownTools.size > 0
|
|
509
|
+
? { unknownTools: Object.fromEntries(this.#unknownTools) }
|
|
510
|
+
: {}),
|
|
273
511
|
...(machine !== undefined ? { machine } : {}),
|
|
274
512
|
...(this.#clients.size > 0 ? { clients: [...this.#clients] } : {}),
|
|
513
|
+
...(this.#clientVersions.size > 0
|
|
514
|
+
? { clientVersions: Object.fromEntries(this.#clientVersions) }
|
|
515
|
+
: {}),
|
|
516
|
+
...(this.#surface === undefined ? {} : { surface: this.#surface }),
|
|
517
|
+
...(final ? { endReason: this.#endReason() } : {}),
|
|
518
|
+
...(this.#feedbackPrompted > 0 ? { feedbackPrompted: this.#feedbackPrompted } : {}),
|
|
519
|
+
...(this.#errorClasses.size > 0
|
|
520
|
+
? { errorClasses: Object.fromEntries(this.#errorClasses) }
|
|
521
|
+
: {}),
|
|
522
|
+
...(this.#errorsRecovered > 0 ? { errorsRecovered: this.#errorsRecovered } : {}),
|
|
523
|
+
...(this.#errorsRepeated > 0 ? { errorsRepeated: this.#errorsRepeated } : {}),
|
|
524
|
+
// Always present, including zero: absence and "no app ever connected" must not look alike,
|
|
525
|
+
// because zero IS the finding here.
|
|
526
|
+
appConnects: this.#appConnects,
|
|
527
|
+
...(this.#firstAppAt === undefined
|
|
528
|
+
? {}
|
|
529
|
+
: { msToFirstApp: Math.max(0, this.#firstAppAt - this.#startedAt) }),
|
|
275
530
|
final,
|
|
531
|
+
// Only on a real exit. A periodic flush carrying `exit: "unknown"` would read as a daemon that
|
|
532
|
+
// died without a shutdown path, which is the one thing this field exists to make visible.
|
|
533
|
+
...(final && exit !== undefined ? { exit } : {}),
|
|
276
534
|
};
|
|
277
535
|
}
|
|
536
|
+
/**
|
|
537
|
+
* Decide whether the error before the previous call was recovered from or repeated.
|
|
538
|
+
*
|
|
539
|
+
* Called at the start of each new call (resolving the one before it) and once at summarize (for
|
|
540
|
+
* the last call). Shifting rather than counting on the spot is what makes "the agent tried
|
|
541
|
+
* something else and it worked" distinguishable from "it failed the same way again" — an earlier
|
|
542
|
+
* version counted a recovery the moment a call STARTED, so a call that then failed was recorded
|
|
543
|
+
* as a success.
|
|
544
|
+
*/
|
|
545
|
+
#resolveRecovery() {
|
|
546
|
+
if (this.#priorCallErrored) {
|
|
547
|
+
if (this.#currentCallErrored)
|
|
548
|
+
this.#errorsRepeated += 1;
|
|
549
|
+
else
|
|
550
|
+
this.#errorsRecovered += 1;
|
|
551
|
+
}
|
|
552
|
+
this.#priorCallErrored = this.#currentCallErrored;
|
|
553
|
+
this.#currentCallErrored = false;
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* What state the agent's work was in at the end. Ordered by which fact outranks which: a client
|
|
557
|
+
* that left explains everything after it, and a verdict settles whatever preceded it.
|
|
558
|
+
*/
|
|
559
|
+
#endReason() {
|
|
560
|
+
if (0 === this.#lifetimeToolCalls)
|
|
561
|
+
return 'never_used';
|
|
562
|
+
if (this.#clientLeft)
|
|
563
|
+
return 'client_left';
|
|
564
|
+
if (this.#unsettledActions > 0)
|
|
565
|
+
return 'abandoned';
|
|
566
|
+
if (this.#lifetimeVerifications > 0)
|
|
567
|
+
return 'verified';
|
|
568
|
+
return 'explored';
|
|
569
|
+
}
|
|
278
570
|
/** True when nothing at all happened — a flush of an idle daemon is not worth an event. */
|
|
279
571
|
get empty() {
|
|
280
|
-
return (this.#toolCalls
|
|
281
|
-
this.#verifications
|
|
282
|
-
this.#toolErrors
|
|
283
|
-
this.#bugsFound
|
|
284
|
-
this.#sdkFailures
|
|
572
|
+
return (0 === this.#toolCalls &&
|
|
573
|
+
0 === this.#verifications &&
|
|
574
|
+
0 === this.#toolErrors &&
|
|
575
|
+
0 === this.#bugsFound &&
|
|
576
|
+
0 === this.#sdkFailures);
|
|
285
577
|
}
|
|
286
578
|
/** Zero the counters after a non-final flush so the next flush reports the NEXT window, not a total. */
|
|
287
579
|
reset() {
|
|
288
580
|
this.#toolCalls = 0;
|
|
289
581
|
this.#toolErrors = 0;
|
|
290
582
|
this.#verifications = 0;
|
|
583
|
+
this.#noSessionErrors = 0;
|
|
584
|
+
this.#repeatRuns.clear();
|
|
585
|
+
this.#lastTool = undefined;
|
|
586
|
+
this.#currentRun = 0;
|
|
587
|
+
this.#unsettledActions = 0;
|
|
291
588
|
this.#toolCounts.clear();
|
|
292
589
|
this.#toolParams.clear();
|
|
293
590
|
this.#errorKinds.clear();
|
|
@@ -302,7 +599,10 @@ export class SessionMetrics {
|
|
|
302
599
|
this.#unknownToolCalls = 0;
|
|
303
600
|
this.#bugsFound = 0;
|
|
304
601
|
this.#bugKinds.clear();
|
|
305
|
-
|
|
602
|
+
// #seenBugKinds is deliberately NOT cleared. It is not a window counter — it is the
|
|
603
|
+
// session-lifetime memory behind `repeat` on bug_found, and zeroing it made the same defect,
|
|
604
|
+
// found again after a flush, report as a newly distinct one. Sessions run to 11.5 hours in the
|
|
605
|
+
// data, so that was up to 23 chances to count one defect many times.
|
|
306
606
|
}
|
|
307
607
|
}
|
|
308
608
|
function bump(map, key) {
|
|
@@ -1,4 +1,38 @@
|
|
|
1
|
-
import { TelemetryEventKind, type Crash, type Feedback, type Identity, type BugFound, type InitOutcome, type McpConnection, type ProjectProfile, type SessionSummary, type TelemetryActor, type Verification, type VersionChange } from '@reticlehq/core';
|
|
1
|
+
import { TelemetryEventKind, ProjectIdSource, type Crash, type Feedback, type Identity, type BugFound, type InitOutcome, type McpConnection, type McpOutage, type ProjectProfile, type SessionSummary, type TelemetryActor, type Verification, type VersionChange } from '@reticlehq/core';
|
|
2
|
+
/**
|
|
3
|
+
* Feedback gets its own, much larger budget — and a retry.
|
|
4
|
+
*
|
|
5
|
+
* 2s + drop is right for a usage counter: the metric is worthless if it costs the user latency, and
|
|
6
|
+
* losing one changes nothing. Feedback is the opposite on both counts. It is the only qualitative
|
|
7
|
+
* channel the product has, it carries an agent's entire root-cause analysis, and losing one loses
|
|
8
|
+
* work that cannot be reconstructed.
|
|
9
|
+
*
|
|
10
|
+
* Measured to the collector with a WARM DNS cache: dns 0.003s, connect 0.233s, tls 0.467s, total
|
|
11
|
+
* 0.694s — a third of the old budget gone before any payload moves, on the good path. A fresh
|
|
12
|
+
* short-lived CLI process pays cold DNS and a cold route on top, which is exactly the case that
|
|
13
|
+
* failed in the field and then succeeded on retry from a warmer process.
|
|
14
|
+
*/
|
|
15
|
+
export declare const FEEDBACK_TIMEOUT_MS = 15000;
|
|
16
|
+
export declare const FEEDBACK_RETRIES = 1;
|
|
17
|
+
export declare const FEEDBACK_RETRY_BACKOFF_MS = 750;
|
|
18
|
+
/**
|
|
19
|
+
* One-way project fingerprint: distinct-count of this = "projects Reticle is used in", reveals nothing.
|
|
20
|
+
*
|
|
21
|
+
* Prefers a hash of the git ORIGIN over a hash of the cwd. The contract in `@reticlehq/core` always
|
|
22
|
+
* said "one-way hash of the git remote (or cwd)", but the implementation only ever hashed the path —
|
|
23
|
+
* which meant the same repo cloned by four teammates, or checked out twice on one machine, counted as
|
|
24
|
+
* four separate projects. That inflates the project count and, worse, makes team adoption look like
|
|
25
|
+
* unrelated individuals. Hashing the origin dedupes a real project down to one id across every clone.
|
|
26
|
+
*
|
|
27
|
+
* Still one-way, still non-reversible, and still exactly what the published policy describes: the
|
|
28
|
+
* remote URL itself never leaves the machine, only its SHA-256. The URL is normalized first (scheme,
|
|
29
|
+
* credentials, `.git` suffix and case removed) so `git@github.com:acme/web.git` and
|
|
30
|
+
* `https://github.com/Acme/web` are recognized as the same project rather than two.
|
|
31
|
+
*/
|
|
32
|
+
export declare const projectFingerprint: (cwd: string) => {
|
|
33
|
+
projectId: string;
|
|
34
|
+
source: ProjectIdSource;
|
|
35
|
+
};
|
|
2
36
|
/** The current telemetry state and which control set it — what `reticle telemetry status` prints. */
|
|
3
37
|
export declare const describeTelemetry: (env?: NodeJS.ProcessEnv, dir?: string, cwd?: string) => {
|
|
4
38
|
enabled: boolean;
|
|
@@ -38,6 +72,8 @@ export interface TelemetryExtra {
|
|
|
38
72
|
init?: InitOutcome;
|
|
39
73
|
/** `bug_found`: one defect Reticle found in the app under test. */
|
|
40
74
|
bug?: BugFound;
|
|
75
|
+
/** `mcp_connection_lost`: the agent lost its tools — which stage, and why. */
|
|
76
|
+
outage?: McpOutage;
|
|
41
77
|
}
|
|
42
78
|
export interface Telemetry {
|
|
43
79
|
/**
|
|
@@ -45,7 +81,14 @@ export interface Telemetry {
|
|
|
45
81
|
* CLI process can exit immediately instead of waiting out the POST (use it from command entry
|
|
46
82
|
* points; daemon-side events send in-process).
|
|
47
83
|
*/
|
|
48
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Send one event. Resolves to whether it was DELIVERED.
|
|
86
|
+
*
|
|
87
|
+
* Almost every caller ignores the result and should — a lost metric must never surface to a user.
|
|
88
|
+
* `reticle_feedback` is the exception: it hands a receipt to an agent, and reporting "filed" for a
|
|
89
|
+
* send that failed loses the report and lies about it in the same breath.
|
|
90
|
+
*/
|
|
91
|
+
emit(kind: TelemetryEventKind, extra?: TelemetryExtra): Promise<boolean>;
|
|
49
92
|
readonly enabled: boolean;
|
|
50
93
|
/** True the very first run on this machine — the CLI emits INSTALL alongside the first INVOKE. */
|
|
51
94
|
readonly firstRun: boolean;
|