@reticlehq/server 2.2.1 → 2.3.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/README.md +1 -1
- package/dist/bridge-security.d.ts +0 -1
- package/dist/bridge-security.js +0 -1
- package/dist/bridge.d.ts +0 -1
- package/dist/bridge.js +60 -10
- package/dist/bridge.test-harness.d.ts +0 -1
- package/dist/bridge.test-harness.js +0 -1
- package/dist/capsule/capsule-store.d.ts +2 -3
- package/dist/capsule/capsule-store.js +0 -1
- package/dist/capsule/capsule.d.ts +0 -1
- package/dist/capsule/capsule.js +0 -1
- package/dist/capsule/causal-summary.d.ts +21 -1
- package/dist/capsule/causal-summary.js +20 -2
- package/dist/capsule/divergence.d.ts +0 -1
- package/dist/capsule/divergence.js +0 -1
- package/dist/capsule/minimize.d.ts +0 -1
- package/dist/capsule/minimize.js +0 -1
- package/dist/capsule/predicate-to-links.d.ts +0 -1
- package/dist/capsule/predicate-to-links.js +0 -1
- package/dist/cli-doctor.d.ts +6 -0
- package/dist/cli-doctor.js +60 -0
- package/dist/cli-flow-commands.d.ts +0 -1
- package/dist/cli-flow-commands.js +0 -1
- package/dist/cli-launch.d.ts +0 -1
- package/dist/cli-launch.js +7 -3
- package/dist/cli-parse.d.ts +34 -2
- package/dist/cli-parse.js +107 -1
- package/dist/cli-port.d.ts +0 -1
- package/dist/cli-port.js +0 -1
- package/dist/cli-verify.d.ts +0 -1
- package/dist/cli-verify.js +1 -2
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +79 -67
- package/dist/cloud/cloud-config.d.ts +0 -1
- package/dist/cloud/cloud-config.js +0 -1
- package/dist/cloud/cloud-sync.d.ts +4 -5
- package/dist/cloud/cloud-sync.js +0 -1
- package/dist/cloud-cli.d.ts +0 -1
- package/dist/cloud-cli.js +9 -2
- package/dist/crawl/crawl-tools.d.ts +0 -1
- package/dist/crawl/crawl-tools.js +1 -2
- package/dist/crawl/crawl.d.ts +17 -3
- package/dist/crawl/crawl.js +43 -4
- package/dist/daemon-resilience.d.ts +6 -1
- package/dist/daemon-resilience.js +63 -1
- package/dist/daemon.d.ts +23 -3
- package/dist/daemon.js +36 -24
- package/dist/domain/domain-model.d.ts +0 -1
- package/dist/domain/domain-model.js +1 -2
- package/dist/domain/domain-tools.d.ts +0 -7
- package/dist/domain/domain-tools.js +21 -4
- package/dist/domain/flow-risk.d.ts +0 -1
- package/dist/domain/flow-risk.js +0 -1
- package/dist/ee/audit-log.d.ts +0 -1
- package/dist/ee/audit-log.js +0 -1
- package/dist/events/body-failures.d.ts +4 -0
- package/dist/events/body-failures.js +113 -0
- package/dist/events/contradictions.d.ts +53 -0
- package/dist/events/contradictions.js +282 -0
- package/dist/events/echo-mismatch.d.ts +4 -0
- package/dist/events/echo-mismatch.js +138 -0
- package/dist/events/event-filters.d.ts +17 -3
- package/dist/events/event-filters.js +13 -3
- package/dist/events/json-salvage.d.ts +32 -0
- package/dist/events/json-salvage.js +96 -0
- package/dist/events/predicate-eval.d.ts +2 -1
- package/dist/events/predicate-eval.js +56 -9
- package/dist/events/predicate.d.ts +0 -1
- package/dist/events/predicate.js +56 -2
- package/dist/events/reaction.d.ts +0 -1
- package/dist/events/reaction.js +0 -1
- package/dist/events/reconcile.d.ts +39 -0
- package/dist/events/reconcile.js +211 -0
- package/dist/events/ring-buffer.d.ts +0 -1
- package/dist/events/ring-buffer.js +0 -1
- package/dist/events/stale-response.d.ts +4 -0
- package/dist/events/stale-response.js +139 -0
- package/dist/events/unit-mismatch.d.ts +16 -0
- package/dist/events/unit-mismatch.js +167 -0
- package/dist/flows/affected-tools.d.ts +18 -0
- package/dist/flows/affected-tools.js +52 -0
- package/dist/flows/affected.d.ts +0 -1
- package/dist/flows/affected.js +0 -1
- package/dist/flows/annotate-tools.d.ts +0 -1
- package/dist/flows/annotate-tools.js +21 -3
- package/dist/flows/annotate.d.ts +0 -1
- package/dist/flows/annotate.js +0 -1
- package/dist/flows/annotation-store.d.ts +0 -1
- package/dist/flows/annotation-store.js +0 -1
- package/dist/flows/assertion-integrity.d.ts +0 -1
- package/dist/flows/assertion-integrity.js +0 -1
- package/dist/flows/assertion-tiers-store.d.ts +0 -1
- package/dist/flows/assertion-tiers-store.js +0 -1
- package/dist/flows/buddy-status.d.ts +0 -1
- package/dist/flows/buddy-status.js +0 -1
- package/dist/flows/coverage.d.ts +0 -1
- package/dist/flows/coverage.js +0 -1
- package/dist/flows/decision.d.ts +0 -1
- package/dist/flows/decision.js +0 -1
- package/dist/flows/flake-store.d.ts +0 -1
- package/dist/flows/flake-store.js +0 -1
- package/dist/flows/flake.d.ts +0 -1
- package/dist/flows/flake.js +0 -1
- package/dist/flows/flow-classify.d.ts +0 -1
- package/dist/flows/flow-classify.js +0 -1
- package/dist/flows/flow-replay-run.d.ts +0 -1
- package/dist/flows/flow-replay-run.js +2 -3
- package/dist/flows/flow-replay.d.ts +20 -4
- package/dist/flows/flow-replay.js +9 -43
- package/dist/flows/flow-report.d.ts +0 -1
- package/dist/flows/flow-report.js +0 -1
- package/dist/flows/flow-scope.d.ts +0 -1
- package/dist/flows/flow-scope.js +0 -1
- package/dist/flows/flow-sources.d.ts +0 -1
- package/dist/flows/flow-sources.js +0 -1
- package/dist/flows/flow-step-runners.d.ts +23 -0
- package/dist/flows/flow-step-runners.js +102 -0
- package/dist/flows/flow-success.d.ts +0 -1
- package/dist/flows/flow-success.js +0 -1
- package/dist/flows/flow-tools.d.ts +0 -1
- package/dist/flows/flow-tools.js +30 -8
- package/dist/flows/flows.d.ts +6 -2
- package/dist/flows/flows.js +15 -2
- package/dist/flows/gate.d.ts +0 -1
- package/dist/flows/gate.js +0 -1
- package/dist/flows/git-changed.d.ts +0 -1
- package/dist/flows/git-changed.js +0 -1
- package/dist/flows/heal-run.d.ts +0 -1
- package/dist/flows/heal-run.js +0 -1
- package/dist/flows/heal.d.ts +0 -1
- package/dist/flows/heal.js +0 -1
- package/dist/flows/parallel-suite.d.ts +0 -1
- package/dist/flows/parallel-suite.js +0 -1
- package/dist/flows/recordings.d.ts +0 -1
- package/dist/flows/recordings.js +0 -1
- package/dist/flows/replay.d.ts +0 -1
- package/dist/flows/replay.js +71 -4
- package/dist/flows/server-verify.d.ts +0 -1
- package/dist/flows/server-verify.js +0 -1
- package/dist/flows/verify-change-tools.d.ts +2 -0
- package/dist/flows/verify-change-tools.js +187 -0
- package/dist/flows/watch-batcher.d.ts +0 -1
- package/dist/flows/watch-batcher.js +0 -1
- package/dist/honesty/accepted-write.d.ts +14 -0
- package/dist/honesty/accepted-write.js +17 -0
- package/dist/honesty/blind-spots.d.ts +18 -1
- package/dist/honesty/blind-spots.js +47 -5
- package/dist/honesty/honesty.d.ts +0 -1
- package/dist/honesty/honesty.js +0 -1
- package/dist/honesty/uncaptured-bodies.d.ts +19 -0
- package/dist/honesty/uncaptured-bodies.js +30 -0
- package/dist/honesty/unread-outcome.d.ts +2 -0
- package/dist/honesty/unread-outcome.js +50 -0
- package/dist/honesty/verified.d.ts +40 -0
- package/dist/honesty/verified.js +86 -0
- package/dist/http-server.d.ts +0 -1
- package/dist/http-server.js +5 -1
- package/dist/hunt/hunt-report.d.ts +50 -0
- package/dist/hunt/hunt-report.js +84 -0
- package/dist/idle-shutdown.d.ts +0 -1
- package/dist/idle-shutdown.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/init/agent-rules.d.ts +0 -1
- package/dist/init/agent-rules.js +4 -2
- package/dist/init/cursor.d.ts +0 -1
- package/dist/init/cursor.js +0 -1
- package/dist/init/desktop-doctor.d.ts +40 -0
- package/dist/init/desktop-doctor.js +198 -0
- package/dist/init/detect.d.ts +0 -1
- package/dist/init/detect.js +0 -1
- package/dist/init/mcp.d.ts +0 -1
- package/dist/init/mcp.js +0 -1
- package/dist/init/node-io.d.ts +0 -1
- package/dist/init/node-io.js +0 -1
- package/dist/init/plan.d.ts +4 -1
- package/dist/init/plan.js +23 -5
- package/dist/init/project-id.d.ts +0 -1
- package/dist/init/project-id.js +0 -1
- package/dist/init/run.d.ts +0 -1
- package/dist/init/run.js +31 -3
- package/dist/init/snippets.d.ts +5 -1
- package/dist/init/snippets.js +5 -1
- package/dist/init/vite-config.d.ts +0 -1
- package/dist/init/vite-config.js +0 -1
- package/dist/input/network-detail.d.ts +0 -1
- package/dist/input/network-detail.js +0 -1
- package/dist/input/network-mock-tools.d.ts +0 -1
- package/dist/input/network-mock-tools.js +3 -4
- package/dist/input/network-mock.d.ts +0 -1
- package/dist/input/network-mock.js +0 -1
- package/dist/input/real-input.d.ts +14 -1
- package/dist/input/real-input.js +45 -3
- package/dist/input/scroll-find.d.ts +0 -1
- package/dist/input/scroll-find.js +0 -1
- package/dist/input/scroll-tools.d.ts +0 -1
- package/dist/input/scroll-tools.js +0 -1
- package/dist/input/viewport-tools.d.ts +0 -1
- package/dist/input/viewport-tools.js +3 -4
- package/dist/journal/ambient-store.d.ts +0 -1
- package/dist/journal/ambient-store.js +0 -1
- package/dist/journal/ambient.d.ts +0 -1
- package/dist/journal/ambient.js +0 -1
- package/dist/journal/attach-journal.d.ts +0 -1
- package/dist/journal/attach-journal.js +0 -1
- package/dist/journal/deviation-report.d.ts +0 -1
- package/dist/journal/deviation-report.js +0 -1
- package/dist/journal/deviation-service.d.ts +0 -1
- package/dist/journal/deviation-service.js +0 -1
- package/dist/journal/envelope-store.d.ts +0 -1
- package/dist/journal/envelope-store.js +0 -1
- package/dist/journal/envelope.d.ts +8 -9
- package/dist/journal/envelope.js +0 -1
- package/dist/journal/journal-query.d.ts +0 -1
- package/dist/journal/journal-query.js +0 -1
- package/dist/journal/journal-recorder.d.ts +0 -1
- package/dist/journal/journal-recorder.js +0 -1
- package/dist/journal/retention.d.ts +0 -1
- package/dist/journal/retention.js +0 -1
- package/dist/journal/rollups.d.ts +0 -1
- package/dist/journal/rollups.js +0 -1
- package/dist/journal/session-end.d.ts +0 -1
- package/dist/journal/session-end.js +0 -1
- package/dist/journal/session-journal.d.ts +0 -1
- package/dist/journal/session-journal.js +0 -1
- package/dist/license/license.d.ts +0 -1
- package/dist/license/license.js +0 -1
- package/dist/log.d.ts +0 -1
- package/dist/log.js +0 -1
- package/dist/mcp-proxy.d.ts +0 -1
- package/dist/mcp-proxy.js +0 -1
- package/dist/mcp.d.ts +15 -1
- package/dist/mcp.js +145 -17
- package/dist/oracles/flow-instrument-gaps.d.ts +0 -1
- package/dist/oracles/flow-instrument-gaps.js +0 -1
- package/dist/oracles/propose-consequences.d.ts +0 -1
- package/dist/oracles/propose-consequences.js +0 -1
- package/dist/oracles/self-instrument.d.ts +0 -1
- package/dist/oracles/self-instrument.js +0 -1
- package/dist/pairing-token.d.ts +0 -1
- package/dist/pairing-token.js +0 -1
- package/dist/phenomena/phenomena.d.ts +0 -1
- package/dist/phenomena/phenomena.js +0 -1
- package/dist/pool/browser-pool.d.ts +0 -1
- package/dist/pool/browser-pool.js +0 -1
- package/dist/pool/lease-reaper.d.ts +0 -1
- package/dist/pool/lease-reaper.js +0 -1
- package/dist/pool/playwright-launcher.d.ts +0 -1
- package/dist/pool/playwright-launcher.js +10 -2
- package/dist/project/baselines.d.ts +0 -1
- package/dist/project/baselines.js +0 -1
- package/dist/project/file-lock.d.ts +2 -1
- package/dist/project/file-lock.js +12 -2
- package/dist/project/fs-port.d.ts +0 -1
- package/dist/project/fs-port.js +0 -1
- package/dist/project/project-store.d.ts +0 -1
- package/dist/project/project-store.js +0 -1
- package/dist/project/project-tools.d.ts +0 -1
- package/dist/project/project-tools.js +29 -4
- package/dist/project/reticle-dir.d.ts +0 -1
- package/dist/project/reticle-dir.js +0 -1
- package/dist/runs/build-verification-run.d.ts +0 -1
- package/dist/runs/build-verification-run.js +0 -1
- package/dist/runs/profile-redact.d.ts +0 -1
- package/dist/runs/profile-redact.js +0 -1
- package/dist/runs/render-report.d.ts +0 -1
- package/dist/runs/render-report.js +0 -1
- package/dist/runs/repair-prompt.d.ts +0 -1
- package/dist/runs/repair-prompt.js +0 -1
- package/dist/runs/replay-mapping.d.ts +0 -1
- package/dist/runs/replay-mapping.js +0 -1
- package/dist/runs/reticle-runner.d.ts +0 -1
- package/dist/runs/reticle-runner.js +4 -2
- package/dist/runs/risk-classify.d.ts +0 -1
- package/dist/runs/risk-classify.js +0 -1
- package/dist/runs/run-diff.d.ts +0 -1
- package/dist/runs/run-diff.js +0 -1
- package/dist/runs/run-store.d.ts +0 -1
- package/dist/runs/run-store.js +0 -1
- package/dist/runs/run-tools.d.ts +0 -1
- package/dist/runs/run-tools.js +0 -1
- package/dist/runs/runner-port.d.ts +0 -1
- package/dist/runs/runner-port.js +0 -1
- package/dist/runs/verification-sync.d.ts +0 -1
- package/dist/runs/verification-sync.js +0 -1
- package/dist/runs/verify-http.d.ts +0 -1
- package/dist/runs/verify-http.js +0 -1
- package/dist/runs/verify-server.d.ts +0 -1
- package/dist/runs/verify-server.js +0 -1
- package/dist/server-version.d.ts +0 -1
- package/dist/server-version.js +0 -1
- package/dist/session/command-timeout.d.ts +35 -0
- package/dist/session/command-timeout.js +41 -0
- package/dist/session/control-envelope.d.ts +2 -3
- package/dist/session/control-envelope.js +2 -3
- package/dist/session/last-act.d.ts +31 -0
- package/dist/session/last-act.js +24 -0
- package/dist/session/live-control-tools.d.ts +0 -1
- package/dist/session/live-control-tools.js +3 -4
- package/dist/session/live-control.d.ts +0 -1
- package/dist/session/live-control.js +0 -1
- package/dist/session/observed-state.d.ts +12 -2
- package/dist/session/observed-state.js +29 -2
- package/dist/session/output-budget.d.ts +0 -1
- package/dist/session/output-budget.js +0 -1
- package/dist/session/pending-commands.d.ts +12 -0
- package/dist/session/pending-commands.js +36 -0
- package/dist/session/presenter-args.d.ts +0 -1
- package/dist/session/presenter-args.js +0 -1
- package/dist/session/review-store.d.ts +0 -1
- package/dist/session/review-store.js +0 -1
- package/dist/session/session-health.d.ts +26 -2
- package/dist/session/session-health.js +13 -1
- package/dist/session/session-info.d.ts +29 -0
- package/dist/session/session-info.js +1 -0
- package/dist/session/session-lease.d.ts +25 -0
- package/dist/session/session-lease.js +14 -0
- package/dist/session/session-manager.d.ts +7 -19
- package/dist/session/session-manager.js +29 -2
- package/dist/session/session-readiness.d.ts +0 -1
- package/dist/session/session-readiness.js +3 -4
- package/dist/session/session-reaper.d.ts +0 -1
- package/dist/session/session-reaper.js +0 -1
- package/dist/session/session-recommendation.d.ts +0 -1
- package/dist/session/session-recommendation.js +0 -1
- package/dist/session/session-tools.d.ts +0 -1
- package/dist/session/session-tools.js +2 -3
- package/dist/session/session.d.ts +27 -53
- package/dist/session/session.js +95 -66
- package/dist/session/state-select.d.ts +0 -1
- package/dist/session/state-select.js +0 -1
- package/dist/telemetry/argument-shape.d.ts +41 -0
- package/dist/telemetry/argument-shape.js +87 -0
- package/dist/telemetry/bug-found.d.ts +33 -0
- package/dist/telemetry/bug-found.js +95 -0
- package/dist/telemetry/cli-telemetry.d.ts +13 -0
- package/dist/telemetry/cli-telemetry.js +43 -0
- package/dist/telemetry/connect-failure.d.ts +16 -0
- package/dist/telemetry/connect-failure.js +44 -0
- package/dist/telemetry/daemon-telemetry.d.ts +19 -0
- package/dist/telemetry/daemon-telemetry.js +76 -0
- package/dist/telemetry/dev-repo.d.ts +10 -0
- package/dist/telemetry/dev-repo.js +80 -0
- package/dist/telemetry/error-fingerprint.d.ts +24 -0
- package/dist/telemetry/error-fingerprint.js +88 -0
- package/dist/telemetry/feedback-cli.d.ts +31 -0
- package/dist/telemetry/feedback-cli.js +102 -0
- package/dist/telemetry/feedback-context.d.ts +32 -0
- package/dist/telemetry/feedback-context.js +143 -0
- package/dist/telemetry/feedback.d.ts +66 -0
- package/dist/telemetry/feedback.js +175 -0
- package/dist/telemetry/git-facts.d.ts +21 -0
- package/dist/telemetry/git-facts.js +109 -0
- package/dist/telemetry/identify.d.ts +22 -0
- package/dist/telemetry/identify.js +73 -0
- package/dist/telemetry/init-telemetry.d.ts +26 -0
- package/dist/telemetry/init-telemetry.js +33 -0
- package/dist/telemetry/machine-snapshot.d.ts +6 -0
- package/dist/telemetry/machine-snapshot.js +39 -0
- package/dist/telemetry/mcp-connection.d.ts +5 -0
- package/dist/telemetry/mcp-connection.js +44 -0
- package/dist/telemetry/project-profile.d.ts +44 -0
- package/dist/telemetry/project-profile.js +205 -0
- package/dist/telemetry/run-telemetry.d.ts +21 -0
- package/dist/telemetry/run-telemetry.js +62 -0
- package/dist/telemetry/session-metrics.d.ts +103 -0
- package/dist/telemetry/session-metrics.js +329 -0
- package/dist/telemetry/telemetry.d.ts +35 -8
- package/dist/telemetry/telemetry.js +105 -12
- package/dist/token-auth.d.ts +0 -1
- package/dist/token-auth.js +0 -1
- package/dist/tools/act-capsule.d.ts +23 -0
- package/dist/tools/act-capsule.js +47 -0
- package/dist/tools/act-danger.d.ts +7 -0
- package/dist/tools/act-danger.js +44 -0
- package/dist/tools/act-helpers.d.ts +17 -0
- package/dist/tools/act-helpers.js +40 -0
- package/dist/tools/act-tools.d.ts +8 -1
- package/dist/tools/act-tools.js +96 -98
- package/dist/tools/act-view.d.ts +7 -1
- package/dist/tools/act-view.js +13 -1
- package/dist/tools/assert-grade.d.ts +22 -1
- package/dist/tools/assert-grade.js +46 -1
- package/dist/tools/assert-verdict.d.ts +21 -0
- package/dist/tools/assert-verdict.js +62 -0
- package/dist/tools/browser-tools.d.ts +0 -1
- package/dist/tools/browser-tools.js +2 -2
- package/dist/tools/contract-tools.d.ts +0 -1
- package/dist/tools/contract-tools.js +0 -1
- package/dist/tools/coverage-tools.d.ts +9 -0
- package/dist/tools/coverage-tools.js +92 -0
- package/dist/tools/dynamic-tools.d.ts +0 -1
- package/dist/tools/dynamic-tools.js +21 -2
- package/dist/tools/error-recovery.d.ts +18 -2
- package/dist/tools/error-recovery.js +42 -7
- package/dist/tools/feedback-tools.d.ts +24 -0
- package/dist/tools/feedback-tools.js +180 -0
- package/dist/tools/invoke-tool.d.ts +0 -1
- package/dist/tools/invoke-tool.js +115 -5
- package/dist/tools/lease-tools.d.ts +0 -1
- package/dist/tools/lease-tools.js +6 -5
- package/dist/tools/merge-tools.d.ts +0 -1
- package/dist/tools/merge-tools.js +0 -1
- package/dist/tools/observe-tools.d.ts +0 -1
- package/dist/tools/observe-tools.js +91 -39
- package/dist/tools/profiles.d.ts +1 -2
- package/dist/tools/profiles.js +43 -16
- package/dist/tools/query-paginate.d.ts +0 -1
- package/dist/tools/query-paginate.js +0 -1
- package/dist/tools/read-tools.d.ts +0 -1
- package/dist/tools/read-tools.js +10 -8
- package/dist/tools/reconcile-tools.d.ts +2 -0
- package/dist/tools/reconcile-tools.js +111 -0
- package/dist/tools/snapshot-delta.d.ts +0 -1
- package/dist/tools/snapshot-delta.js +0 -0
- package/dist/tools/tool-invoker.d.ts +0 -1
- package/dist/tools/tool-invoker.js +0 -1
- package/dist/tools/tool-kit.d.ts +16 -1
- package/dist/tools/tool-kit.js +8 -2
- package/dist/tools/tool-names.d.ts +6 -1
- package/dist/tools/tool-names.js +6 -1
- package/dist/tools/tools-helpers.d.ts +0 -1
- package/dist/tools/tools-helpers.js +0 -1
- package/dist/tools/tools.d.ts +0 -1
- package/dist/tools/tools.js +24 -4
- package/dist/update/update-checker.d.ts +0 -1
- package/dist/update/update-checker.js +0 -1
- package/dist/update/update-nudge.d.ts +20 -0
- package/dist/update/update-nudge.js +72 -0
- package/dist/update/updater.d.ts +14 -1
- package/dist/update/updater.js +33 -2
- package/dist/visual/visual-diff.d.ts +0 -1
- package/dist/visual/visual-diff.js +0 -1
- package/dist/visual/visual-store.d.ts +0 -1
- package/dist/visual/visual-store.js +0 -1
- package/dist/visual/visual-tools.d.ts +0 -1
- package/dist/visual/visual-tools.js +103 -16
- package/package.json +2 -2
- package/dist/bridge-security.d.ts.map +0 -1
- package/dist/bridge-security.js.map +0 -1
- package/dist/bridge.d.ts.map +0 -1
- package/dist/bridge.js.map +0 -1
- package/dist/bridge.test-harness.d.ts.map +0 -1
- package/dist/bridge.test-harness.js.map +0 -1
- package/dist/capsule/capsule-store.d.ts.map +0 -1
- package/dist/capsule/capsule-store.js.map +0 -1
- package/dist/capsule/capsule.d.ts.map +0 -1
- package/dist/capsule/capsule.js.map +0 -1
- package/dist/capsule/causal-summary.d.ts.map +0 -1
- package/dist/capsule/causal-summary.js.map +0 -1
- package/dist/capsule/divergence.d.ts.map +0 -1
- package/dist/capsule/divergence.js.map +0 -1
- package/dist/capsule/minimize.d.ts.map +0 -1
- package/dist/capsule/minimize.js.map +0 -1
- package/dist/capsule/predicate-to-links.d.ts.map +0 -1
- package/dist/capsule/predicate-to-links.js.map +0 -1
- package/dist/cli-flow-commands.d.ts.map +0 -1
- package/dist/cli-flow-commands.js.map +0 -1
- package/dist/cli-launch.d.ts.map +0 -1
- package/dist/cli-launch.js.map +0 -1
- package/dist/cli-parse.d.ts.map +0 -1
- package/dist/cli-parse.js.map +0 -1
- package/dist/cli-port.d.ts.map +0 -1
- package/dist/cli-port.js.map +0 -1
- package/dist/cli-verify.d.ts.map +0 -1
- package/dist/cli-verify.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cloud/cloud-config.d.ts.map +0 -1
- package/dist/cloud/cloud-config.js.map +0 -1
- package/dist/cloud/cloud-sync.d.ts.map +0 -1
- package/dist/cloud/cloud-sync.js.map +0 -1
- package/dist/cloud-cli.d.ts.map +0 -1
- package/dist/cloud-cli.js.map +0 -1
- package/dist/crawl/crawl-tools.d.ts.map +0 -1
- package/dist/crawl/crawl-tools.js.map +0 -1
- package/dist/crawl/crawl.d.ts.map +0 -1
- package/dist/crawl/crawl.js.map +0 -1
- package/dist/daemon-resilience.d.ts.map +0 -1
- package/dist/daemon-resilience.js.map +0 -1
- package/dist/daemon.d.ts.map +0 -1
- package/dist/daemon.js.map +0 -1
- package/dist/domain/domain-model.d.ts.map +0 -1
- package/dist/domain/domain-model.js.map +0 -1
- package/dist/domain/domain-tools.d.ts.map +0 -1
- package/dist/domain/domain-tools.js.map +0 -1
- package/dist/domain/flow-risk.d.ts.map +0 -1
- package/dist/domain/flow-risk.js.map +0 -1
- package/dist/ee/audit-log.d.ts.map +0 -1
- package/dist/ee/audit-log.js.map +0 -1
- package/dist/events/event-filters.d.ts.map +0 -1
- package/dist/events/event-filters.js.map +0 -1
- package/dist/events/predicate-eval.d.ts.map +0 -1
- package/dist/events/predicate-eval.js.map +0 -1
- package/dist/events/predicate.d.ts.map +0 -1
- package/dist/events/predicate.js.map +0 -1
- package/dist/events/reaction.d.ts.map +0 -1
- package/dist/events/reaction.js.map +0 -1
- package/dist/events/ring-buffer.d.ts.map +0 -1
- package/dist/events/ring-buffer.js.map +0 -1
- package/dist/flows/affected.d.ts.map +0 -1
- package/dist/flows/affected.js.map +0 -1
- package/dist/flows/annotate-tools.d.ts.map +0 -1
- package/dist/flows/annotate-tools.js.map +0 -1
- package/dist/flows/annotate.d.ts.map +0 -1
- package/dist/flows/annotate.js.map +0 -1
- package/dist/flows/annotation-store.d.ts.map +0 -1
- package/dist/flows/annotation-store.js.map +0 -1
- package/dist/flows/assertion-integrity.d.ts.map +0 -1
- package/dist/flows/assertion-integrity.js.map +0 -1
- package/dist/flows/assertion-tiers-store.d.ts.map +0 -1
- package/dist/flows/assertion-tiers-store.js.map +0 -1
- package/dist/flows/buddy-status.d.ts.map +0 -1
- package/dist/flows/buddy-status.js.map +0 -1
- package/dist/flows/coverage.d.ts.map +0 -1
- package/dist/flows/coverage.js.map +0 -1
- package/dist/flows/decision.d.ts.map +0 -1
- package/dist/flows/decision.js.map +0 -1
- package/dist/flows/flake-store.d.ts.map +0 -1
- package/dist/flows/flake-store.js.map +0 -1
- package/dist/flows/flake.d.ts.map +0 -1
- package/dist/flows/flake.js.map +0 -1
- package/dist/flows/flow-classify.d.ts.map +0 -1
- package/dist/flows/flow-classify.js.map +0 -1
- package/dist/flows/flow-replay-run.d.ts.map +0 -1
- package/dist/flows/flow-replay-run.js.map +0 -1
- package/dist/flows/flow-replay.d.ts.map +0 -1
- package/dist/flows/flow-replay.js.map +0 -1
- package/dist/flows/flow-report.d.ts.map +0 -1
- package/dist/flows/flow-report.js.map +0 -1
- package/dist/flows/flow-scope.d.ts.map +0 -1
- package/dist/flows/flow-scope.js.map +0 -1
- package/dist/flows/flow-sources.d.ts.map +0 -1
- package/dist/flows/flow-sources.js.map +0 -1
- package/dist/flows/flow-success.d.ts.map +0 -1
- package/dist/flows/flow-success.js.map +0 -1
- package/dist/flows/flow-tools.d.ts.map +0 -1
- package/dist/flows/flow-tools.js.map +0 -1
- package/dist/flows/flows.d.ts.map +0 -1
- package/dist/flows/flows.js.map +0 -1
- package/dist/flows/gate.d.ts.map +0 -1
- package/dist/flows/gate.js.map +0 -1
- package/dist/flows/git-changed.d.ts.map +0 -1
- package/dist/flows/git-changed.js.map +0 -1
- package/dist/flows/heal-run.d.ts.map +0 -1
- package/dist/flows/heal-run.js.map +0 -1
- package/dist/flows/heal.d.ts.map +0 -1
- package/dist/flows/heal.js.map +0 -1
- package/dist/flows/parallel-suite.d.ts.map +0 -1
- package/dist/flows/parallel-suite.js.map +0 -1
- package/dist/flows/recordings.d.ts.map +0 -1
- package/dist/flows/recordings.js.map +0 -1
- package/dist/flows/replay.d.ts.map +0 -1
- package/dist/flows/replay.js.map +0 -1
- package/dist/flows/server-verify.d.ts.map +0 -1
- package/dist/flows/server-verify.js.map +0 -1
- package/dist/flows/watch-batcher.d.ts.map +0 -1
- package/dist/flows/watch-batcher.js.map +0 -1
- package/dist/honesty/blind-spots.d.ts.map +0 -1
- package/dist/honesty/blind-spots.js.map +0 -1
- package/dist/honesty/honesty.d.ts.map +0 -1
- package/dist/honesty/honesty.js.map +0 -1
- package/dist/http-server.d.ts.map +0 -1
- package/dist/http-server.js.map +0 -1
- package/dist/idle-shutdown.d.ts.map +0 -1
- package/dist/idle-shutdown.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/init/agent-rules.d.ts.map +0 -1
- package/dist/init/agent-rules.js.map +0 -1
- package/dist/init/cursor.d.ts.map +0 -1
- package/dist/init/cursor.js.map +0 -1
- package/dist/init/detect.d.ts.map +0 -1
- package/dist/init/detect.js.map +0 -1
- package/dist/init/mcp.d.ts.map +0 -1
- package/dist/init/mcp.js.map +0 -1
- package/dist/init/node-io.d.ts.map +0 -1
- package/dist/init/node-io.js.map +0 -1
- package/dist/init/plan.d.ts.map +0 -1
- package/dist/init/plan.js.map +0 -1
- package/dist/init/project-id.d.ts.map +0 -1
- package/dist/init/project-id.js.map +0 -1
- package/dist/init/run.d.ts.map +0 -1
- package/dist/init/run.js.map +0 -1
- package/dist/init/snippets.d.ts.map +0 -1
- package/dist/init/snippets.js.map +0 -1
- package/dist/init/vite-config.d.ts.map +0 -1
- package/dist/init/vite-config.js.map +0 -1
- package/dist/input/network-detail.d.ts.map +0 -1
- package/dist/input/network-detail.js.map +0 -1
- package/dist/input/network-mock-tools.d.ts.map +0 -1
- package/dist/input/network-mock-tools.js.map +0 -1
- package/dist/input/network-mock.d.ts.map +0 -1
- package/dist/input/network-mock.js.map +0 -1
- package/dist/input/real-input.d.ts.map +0 -1
- package/dist/input/real-input.js.map +0 -1
- package/dist/input/scroll-find.d.ts.map +0 -1
- package/dist/input/scroll-find.js.map +0 -1
- package/dist/input/scroll-tools.d.ts.map +0 -1
- package/dist/input/scroll-tools.js.map +0 -1
- package/dist/input/viewport-tools.d.ts.map +0 -1
- package/dist/input/viewport-tools.js.map +0 -1
- package/dist/journal/ambient-store.d.ts.map +0 -1
- package/dist/journal/ambient-store.js.map +0 -1
- package/dist/journal/ambient.d.ts.map +0 -1
- package/dist/journal/ambient.js.map +0 -1
- package/dist/journal/attach-journal.d.ts.map +0 -1
- package/dist/journal/attach-journal.js.map +0 -1
- package/dist/journal/deviation-report.d.ts.map +0 -1
- package/dist/journal/deviation-report.js.map +0 -1
- package/dist/journal/deviation-service.d.ts.map +0 -1
- package/dist/journal/deviation-service.js.map +0 -1
- package/dist/journal/envelope-store.d.ts.map +0 -1
- package/dist/journal/envelope-store.js.map +0 -1
- package/dist/journal/envelope.d.ts.map +0 -1
- package/dist/journal/envelope.js.map +0 -1
- package/dist/journal/journal-query.d.ts.map +0 -1
- package/dist/journal/journal-query.js.map +0 -1
- package/dist/journal/journal-recorder.d.ts.map +0 -1
- package/dist/journal/journal-recorder.js.map +0 -1
- package/dist/journal/retention.d.ts.map +0 -1
- package/dist/journal/retention.js.map +0 -1
- package/dist/journal/rollups.d.ts.map +0 -1
- package/dist/journal/rollups.js.map +0 -1
- package/dist/journal/session-end.d.ts.map +0 -1
- package/dist/journal/session-end.js.map +0 -1
- package/dist/journal/session-journal.d.ts.map +0 -1
- package/dist/journal/session-journal.js.map +0 -1
- package/dist/license/license.d.ts.map +0 -1
- package/dist/license/license.js.map +0 -1
- package/dist/log.d.ts.map +0 -1
- package/dist/log.js.map +0 -1
- package/dist/mcp-proxy.d.ts.map +0 -1
- package/dist/mcp-proxy.js.map +0 -1
- package/dist/mcp.d.ts.map +0 -1
- package/dist/mcp.js.map +0 -1
- package/dist/oracles/flow-instrument-gaps.d.ts.map +0 -1
- package/dist/oracles/flow-instrument-gaps.js.map +0 -1
- package/dist/oracles/propose-consequences.d.ts.map +0 -1
- package/dist/oracles/propose-consequences.js.map +0 -1
- package/dist/oracles/self-instrument.d.ts.map +0 -1
- package/dist/oracles/self-instrument.js.map +0 -1
- package/dist/pairing-token.d.ts.map +0 -1
- package/dist/pairing-token.js.map +0 -1
- package/dist/phenomena/phenomena.d.ts.map +0 -1
- package/dist/phenomena/phenomena.js.map +0 -1
- package/dist/pool/browser-pool.d.ts.map +0 -1
- package/dist/pool/browser-pool.js.map +0 -1
- package/dist/pool/lease-reaper.d.ts.map +0 -1
- package/dist/pool/lease-reaper.js.map +0 -1
- package/dist/pool/playwright-launcher.d.ts.map +0 -1
- package/dist/pool/playwright-launcher.js.map +0 -1
- package/dist/project/baselines.d.ts.map +0 -1
- package/dist/project/baselines.js.map +0 -1
- package/dist/project/file-lock.d.ts.map +0 -1
- package/dist/project/file-lock.js.map +0 -1
- package/dist/project/fs-port.d.ts.map +0 -1
- package/dist/project/fs-port.js.map +0 -1
- package/dist/project/project-store.d.ts.map +0 -1
- package/dist/project/project-store.js.map +0 -1
- package/dist/project/project-tools.d.ts.map +0 -1
- package/dist/project/project-tools.js.map +0 -1
- package/dist/project/reticle-dir.d.ts.map +0 -1
- package/dist/project/reticle-dir.js.map +0 -1
- package/dist/runs/build-verification-run.d.ts.map +0 -1
- package/dist/runs/build-verification-run.js.map +0 -1
- package/dist/runs/profile-redact.d.ts.map +0 -1
- package/dist/runs/profile-redact.js.map +0 -1
- package/dist/runs/render-report.d.ts.map +0 -1
- package/dist/runs/render-report.js.map +0 -1
- package/dist/runs/repair-prompt.d.ts.map +0 -1
- package/dist/runs/repair-prompt.js.map +0 -1
- package/dist/runs/replay-mapping.d.ts.map +0 -1
- package/dist/runs/replay-mapping.js.map +0 -1
- package/dist/runs/reticle-runner.d.ts.map +0 -1
- package/dist/runs/reticle-runner.js.map +0 -1
- package/dist/runs/risk-classify.d.ts.map +0 -1
- package/dist/runs/risk-classify.js.map +0 -1
- package/dist/runs/run-diff.d.ts.map +0 -1
- package/dist/runs/run-diff.js.map +0 -1
- package/dist/runs/run-store.d.ts.map +0 -1
- package/dist/runs/run-store.js.map +0 -1
- package/dist/runs/run-tools.d.ts.map +0 -1
- package/dist/runs/run-tools.js.map +0 -1
- package/dist/runs/runner-port.d.ts.map +0 -1
- package/dist/runs/runner-port.js.map +0 -1
- package/dist/runs/verification-sync.d.ts.map +0 -1
- package/dist/runs/verification-sync.js.map +0 -1
- package/dist/runs/verify-http.d.ts.map +0 -1
- package/dist/runs/verify-http.js.map +0 -1
- package/dist/runs/verify-server.d.ts.map +0 -1
- package/dist/runs/verify-server.js.map +0 -1
- package/dist/server-version.d.ts.map +0 -1
- package/dist/server-version.js.map +0 -1
- package/dist/session/control-envelope.d.ts.map +0 -1
- package/dist/session/control-envelope.js.map +0 -1
- package/dist/session/live-control-tools.d.ts.map +0 -1
- package/dist/session/live-control-tools.js.map +0 -1
- package/dist/session/live-control.d.ts.map +0 -1
- package/dist/session/live-control.js.map +0 -1
- package/dist/session/observed-state.d.ts.map +0 -1
- package/dist/session/observed-state.js.map +0 -1
- package/dist/session/output-budget.d.ts.map +0 -1
- package/dist/session/output-budget.js.map +0 -1
- package/dist/session/presenter-args.d.ts.map +0 -1
- package/dist/session/presenter-args.js.map +0 -1
- package/dist/session/review-store.d.ts.map +0 -1
- package/dist/session/review-store.js.map +0 -1
- package/dist/session/session-health.d.ts.map +0 -1
- package/dist/session/session-health.js.map +0 -1
- package/dist/session/session-manager.d.ts.map +0 -1
- package/dist/session/session-manager.js.map +0 -1
- package/dist/session/session-readiness.d.ts.map +0 -1
- package/dist/session/session-readiness.js.map +0 -1
- package/dist/session/session-reaper.d.ts.map +0 -1
- package/dist/session/session-reaper.js.map +0 -1
- package/dist/session/session-recommendation.d.ts.map +0 -1
- package/dist/session/session-recommendation.js.map +0 -1
- package/dist/session/session-tools.d.ts.map +0 -1
- package/dist/session/session-tools.js.map +0 -1
- package/dist/session/session.d.ts.map +0 -1
- package/dist/session/session.js.map +0 -1
- package/dist/session/state-select.d.ts.map +0 -1
- package/dist/session/state-select.js.map +0 -1
- package/dist/telemetry/telemetry.d.ts.map +0 -1
- package/dist/telemetry/telemetry.js.map +0 -1
- package/dist/token-auth.d.ts.map +0 -1
- package/dist/token-auth.js.map +0 -1
- package/dist/tools/act-tools.d.ts.map +0 -1
- package/dist/tools/act-tools.js.map +0 -1
- package/dist/tools/act-view.d.ts.map +0 -1
- package/dist/tools/act-view.js.map +0 -1
- package/dist/tools/assert-grade.d.ts.map +0 -1
- package/dist/tools/assert-grade.js.map +0 -1
- package/dist/tools/browser-tools.d.ts.map +0 -1
- package/dist/tools/browser-tools.js.map +0 -1
- package/dist/tools/contract-tools.d.ts.map +0 -1
- package/dist/tools/contract-tools.js.map +0 -1
- package/dist/tools/dynamic-tools.d.ts.map +0 -1
- package/dist/tools/dynamic-tools.js.map +0 -1
- package/dist/tools/error-recovery.d.ts.map +0 -1
- package/dist/tools/error-recovery.js.map +0 -1
- package/dist/tools/invoke-tool.d.ts.map +0 -1
- package/dist/tools/invoke-tool.js.map +0 -1
- package/dist/tools/lease-tools.d.ts.map +0 -1
- package/dist/tools/lease-tools.js.map +0 -1
- package/dist/tools/merge-tools.d.ts.map +0 -1
- package/dist/tools/merge-tools.js.map +0 -1
- package/dist/tools/observe-tools.d.ts.map +0 -1
- package/dist/tools/observe-tools.js.map +0 -1
- package/dist/tools/profiles.d.ts.map +0 -1
- package/dist/tools/profiles.js.map +0 -1
- package/dist/tools/query-paginate.d.ts.map +0 -1
- package/dist/tools/query-paginate.js.map +0 -1
- package/dist/tools/read-tools.d.ts.map +0 -1
- package/dist/tools/read-tools.js.map +0 -1
- package/dist/tools/snapshot-delta.d.ts.map +0 -1
- package/dist/tools/snapshot-delta.js.map +0 -1
- package/dist/tools/tool-invoker.d.ts.map +0 -1
- package/dist/tools/tool-invoker.js.map +0 -1
- package/dist/tools/tool-kit.d.ts.map +0 -1
- package/dist/tools/tool-kit.js.map +0 -1
- package/dist/tools/tool-names.d.ts.map +0 -1
- package/dist/tools/tool-names.js.map +0 -1
- package/dist/tools/tools-helpers.d.ts.map +0 -1
- package/dist/tools/tools-helpers.js.map +0 -1
- package/dist/tools/tools.d.ts.map +0 -1
- package/dist/tools/tools.js.map +0 -1
- package/dist/update/update-checker.d.ts.map +0 -1
- package/dist/update/update-checker.js.map +0 -1
- package/dist/update/updater.d.ts.map +0 -1
- package/dist/update/updater.js.map +0 -1
- package/dist/visual/visual-diff.d.ts.map +0 -1
- package/dist/visual/visual-diff.js.map +0 -1
- package/dist/visual/visual-store.d.ts.map +0 -1
- package/dist/visual/visual-store.js.map +0 -1
- package/dist/visual/visual-tools.d.ts.map +0 -1
- package/dist/visual/visual-tools.js.map +0 -1
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which flags and parameters people actually use — WITHOUT ever sending what they set them to.
|
|
3
|
+
*
|
|
4
|
+
* This is the most dangerous data in the product to collect, and the split that makes it safe is
|
|
5
|
+
* NAMES versus VALUES:
|
|
6
|
+
*
|
|
7
|
+
* - A flag or parameter NAME comes from a closed vocabulary we wrote ourselves. `--headed`,
|
|
8
|
+
* `--port`, `ref`, `timeout_ms` — there are a few dozen, none of them describe the user, and
|
|
9
|
+
* knowing which ones get used is the whole product question ("is anyone passing `fullPage`?
|
|
10
|
+
* does anybody use `--storage-state`?").
|
|
11
|
+
* - A VALUE is the user's. `--http-token` holds a secret. `--drive` holds a URL. `reticle_act`'s
|
|
12
|
+
* `args` holds the text being typed into the app, which on a login form is a password. A rule
|
|
13
|
+
* like "send short values, they're probably enums" would leak all three.
|
|
14
|
+
*
|
|
15
|
+
* So values are never sent, with one narrow exception: a handful of parameters whose values ARE our
|
|
16
|
+
* own enums, listed explicitly below. `action: "click"` is our vocabulary, not the user's, and it
|
|
17
|
+
* answers a real question. Membership in that list is opt-in per parameter and each entry names the
|
|
18
|
+
* exact values allowed — anything outside the list is reported as `other`, so a schema change can
|
|
19
|
+
* never quietly start forwarding free text.
|
|
20
|
+
*/
|
|
21
|
+
import { ActionType, FeedbackKind, QueryBy, SnapshotMode } from '@reticlehq/core';
|
|
22
|
+
/**
|
|
23
|
+
* Parameters whose values are enums WE define, and the exact values allowed on the wire. An
|
|
24
|
+
* unrecognized value reports `other` rather than itself; that fallback is what makes this safe
|
|
25
|
+
* against a future where one of these params starts accepting free text.
|
|
26
|
+
*/
|
|
27
|
+
const SAFE_ENUM_PARAMS = new Map([
|
|
28
|
+
// Every entry DERIVED from the enum core already owns, never hand-listed. The first version listed
|
|
29
|
+
// them literally and was wrong on the day it shipped, not merely at risk: `action` was missing
|
|
30
|
+
// `fill`, `dblclick`, `submit`, `scrollIntoView`, `drag` and `webmcp` — so `fill`, one of the most
|
|
31
|
+
// common actions there is, silently reported as `other` — while carrying a `scroll` that
|
|
32
|
+
// `ActionType` does not define. `mode` mixed SnapshotMode with unrelated session-lifecycle values.
|
|
33
|
+
// Deriving is not tidiness here; it is the difference between the data being right and being wrong.
|
|
34
|
+
['action', new Set(Object.values(ActionType))],
|
|
35
|
+
['by', new Set(Object.values(QueryBy))],
|
|
36
|
+
['mode', new Set(Object.values(SnapshotMode))],
|
|
37
|
+
['kind', new Set(Object.values(FeedbackKind))],
|
|
38
|
+
// `level` has no core enum — console levels come from the DOM console API, not from us. Listed
|
|
39
|
+
// literally BECAUSE there is nothing to derive from, which is a different situation from the four
|
|
40
|
+
// above and the reason it is called out rather than left looking like an oversight.
|
|
41
|
+
['level', new Set(['error', 'warn', 'info', 'log', 'debug'])],
|
|
42
|
+
]);
|
|
43
|
+
export const OTHER_VALUE = 'other';
|
|
44
|
+
/** True for anything we are willing to report a value for. */
|
|
45
|
+
export function isSafeEnumParam(name) {
|
|
46
|
+
return SAFE_ENUM_PARAMS.has(name);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The reportable form of one parameter: `name` on its own, or `name:value` when the parameter is a
|
|
50
|
+
* known enum. Never the raw value of anything else.
|
|
51
|
+
*/
|
|
52
|
+
export function describeParam(name, value) {
|
|
53
|
+
const allowed = SAFE_ENUM_PARAMS.get(name);
|
|
54
|
+
if (allowed === undefined)
|
|
55
|
+
return name;
|
|
56
|
+
if (typeof value !== 'string')
|
|
57
|
+
return name;
|
|
58
|
+
return `${name}:${allowed.has(value) ? value : OTHER_VALUE}`;
|
|
59
|
+
}
|
|
60
|
+
/** Every parameter an agent actually passed to one tool call, reduced to names (+ safe enums). */
|
|
61
|
+
export function describeToolParams(args) {
|
|
62
|
+
return Object.keys(args)
|
|
63
|
+
.filter((key) => args[key] !== undefined)
|
|
64
|
+
.map((key) => describeParam(key, args[key]))
|
|
65
|
+
.sort();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The flags PRESENT on a CLI invocation, by name only.
|
|
69
|
+
*
|
|
70
|
+
* Values are dropped without exception here — no enum allowlist — because the CLI's flag values are
|
|
71
|
+
* uniformly the user's: a port, a URL, a file path, a pairing token. `--http-token` alone is reason
|
|
72
|
+
* enough to make this rule absolute rather than case-by-case.
|
|
73
|
+
*
|
|
74
|
+
* Anything not starting with `--` is an argument, not a flag, and is dropped entirely: that is where
|
|
75
|
+
* the URL, the file list, and the feedback message live.
|
|
76
|
+
*/
|
|
77
|
+
export function describeCliFlags(argv) {
|
|
78
|
+
const flags = new Set();
|
|
79
|
+
for (const arg of argv) {
|
|
80
|
+
if (!arg.startsWith('--'))
|
|
81
|
+
continue;
|
|
82
|
+
// `--port=9000` — split so the NAME is reported and the value is discarded with everything else.
|
|
83
|
+
const name = arg.split('=')[0] ?? arg;
|
|
84
|
+
flags.add(name);
|
|
85
|
+
}
|
|
86
|
+
return [...flags].sort();
|
|
87
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Counting the defects Reticle actually finds.
|
|
3
|
+
*
|
|
4
|
+
* Every other metric in this product measures whether Reticle is USED. This one measures whether it
|
|
5
|
+
* WORKS — and it is the only number that can honestly be put in front of an investor or published,
|
|
6
|
+
* because it counts outcomes for users rather than activity by them.
|
|
7
|
+
*
|
|
8
|
+
* It is read off tool RESULTS at the single chokepoint every tool already crosses, rather than
|
|
9
|
+
* emitted from the four places that produce findings. That is deliberate: the detectors are pure
|
|
10
|
+
* functions and should stay that way, and reading results means a fifth source of findings is covered
|
|
11
|
+
* the day it starts returning one of these shapes, instead of the day someone remembers to instrument
|
|
12
|
+
* it.
|
|
13
|
+
*
|
|
14
|
+
* What is sent is the KIND from Reticle's own findings vocabulary — `signal-contradicted`,
|
|
15
|
+
* `console-error`, `duplicate-request`. Never a selector, a URL, an element, or a description of
|
|
16
|
+
* anyone's app: that a class of defect was found, never what it was found in.
|
|
17
|
+
*/
|
|
18
|
+
import { type BugFound } from '@reticlehq/core';
|
|
19
|
+
/**
|
|
20
|
+
* A defect as the CLASSIFIER sees it — everything except `repeat`.
|
|
21
|
+
*
|
|
22
|
+
* Whether a kind is new belongs to the session, and these detectors are pure functions that know
|
|
23
|
+
* nothing about sessions and should stay that way. The emission site owns the dedup flag.
|
|
24
|
+
*/
|
|
25
|
+
export type BugCandidate = Omit<BugFound, 'repeat'>;
|
|
26
|
+
/**
|
|
27
|
+
* The defects in one tool result.
|
|
28
|
+
*
|
|
29
|
+
* Ordering matters for the false-green flag: a contradiction found alongside a PASSING assertion is
|
|
30
|
+
* the case the product exists for — the screen looked right, the write failed, and every other tool
|
|
31
|
+
* on the market would have called it green. That pairing is what `falseGreen` marks.
|
|
32
|
+
*/
|
|
33
|
+
export declare function bugsInResult(toolName: string, result: Record<string, unknown>): BugCandidate[];
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Counting the defects Reticle actually finds.
|
|
3
|
+
*
|
|
4
|
+
* Every other metric in this product measures whether Reticle is USED. This one measures whether it
|
|
5
|
+
* WORKS — and it is the only number that can honestly be put in front of an investor or published,
|
|
6
|
+
* because it counts outcomes for users rather than activity by them.
|
|
7
|
+
*
|
|
8
|
+
* It is read off tool RESULTS at the single chokepoint every tool already crosses, rather than
|
|
9
|
+
* emitted from the four places that produce findings. That is deliberate: the detectors are pure
|
|
10
|
+
* functions and should stay that way, and reading results means a fifth source of findings is covered
|
|
11
|
+
* the day it starts returning one of these shapes, instead of the day someone remembers to instrument
|
|
12
|
+
* it.
|
|
13
|
+
*
|
|
14
|
+
* What is sent is the KIND from Reticle's own findings vocabulary — `signal-contradicted`,
|
|
15
|
+
* `console-error`, `duplicate-request`. Never a selector, a URL, an element, or a description of
|
|
16
|
+
* anyone's app: that a class of defect was found, never what it was found in.
|
|
17
|
+
*/
|
|
18
|
+
import { BugSource, ContradictionKind } from '@reticlehq/core';
|
|
19
|
+
/** Cap per tool call — a pathological crawl must not turn one call into a thousand events. */
|
|
20
|
+
const MAX_BUGS_PER_CALL = 25;
|
|
21
|
+
function kindsOf(value) {
|
|
22
|
+
if (!Array.isArray(value))
|
|
23
|
+
return [];
|
|
24
|
+
return value
|
|
25
|
+
.map((entry) => {
|
|
26
|
+
const kind = entry?.kind;
|
|
27
|
+
return typeof kind === 'string' ? kind : undefined;
|
|
28
|
+
})
|
|
29
|
+
.filter((kind) => kind !== undefined);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The defects in one tool result.
|
|
33
|
+
*
|
|
34
|
+
* Ordering matters for the false-green flag: a contradiction found alongside a PASSING assertion is
|
|
35
|
+
* the case the product exists for — the screen looked right, the write failed, and every other tool
|
|
36
|
+
* on the market would have called it green. That pairing is what `falseGreen` marks.
|
|
37
|
+
*/
|
|
38
|
+
export function bugsInResult(toolName, result) {
|
|
39
|
+
const bugs = [];
|
|
40
|
+
const passed = result['pass'] === true;
|
|
41
|
+
// 1. Contradictions — channels disagreeing. Invisible to a human watching the screen.
|
|
42
|
+
for (const kind of kindsOf(result['contradictions'])) {
|
|
43
|
+
bugs.push({ source: BugSource.CONTRADICTION, kind, falseGreen: passed, tool: toolName });
|
|
44
|
+
}
|
|
45
|
+
// 2. Crawl anomalies — found autonomously, with nobody writing a test. Crawl reports its own
|
|
46
|
+
// contradictions inside `anomalies` too, so classify by kind rather than by which array it sat in.
|
|
47
|
+
for (const kind of kindsOf(result['anomalies'])) {
|
|
48
|
+
bugs.push({
|
|
49
|
+
source: BugSource.CRAWL,
|
|
50
|
+
kind,
|
|
51
|
+
// A crawl contradiction presents as success too — the click looked fine and its write did not
|
|
52
|
+
// — even though no assertion was made. See the definition on `falseGreen`.
|
|
53
|
+
falseGreen: CONTRADICTION_KINDS.has(kind),
|
|
54
|
+
tool: toolName,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
// 3. A failed assertion — the agent declared a consequence and it did not hold.
|
|
58
|
+
// Only when nothing above already explained it, or one defect would be counted twice.
|
|
59
|
+
if (result['pass'] === false && bugs.length === 0) {
|
|
60
|
+
const reason = result['assertion'];
|
|
61
|
+
bugs.push({
|
|
62
|
+
source: BugSource.ASSERTION,
|
|
63
|
+
kind: typeof reason === 'string' && reason.length > 0 ? reason.slice(0, 64) : 'assertion-failed',
|
|
64
|
+
falseGreen: false,
|
|
65
|
+
tool: toolName,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
// 4. Replay failures — a saved flow that used to pass no longer does. That is a regression caught,
|
|
69
|
+
// which is a different and stronger claim than "a check failed".
|
|
70
|
+
if (result['status'] === 'fail' && Array.isArray(result['failures'])) {
|
|
71
|
+
for (const _failure of result['failures'].slice(0, MAX_BUGS_PER_CALL)) {
|
|
72
|
+
bugs.push({
|
|
73
|
+
source: BugSource.REPLAY,
|
|
74
|
+
kind: 'flow-regression',
|
|
75
|
+
falseGreen: false,
|
|
76
|
+
tool: toolName,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return bugs.slice(0, MAX_BUGS_PER_CALL);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Crawl anomaly kinds that are CONTRADICTIONS rather than single-channel faults.
|
|
84
|
+
*
|
|
85
|
+
* `reticle_crawl` returns both classes in one `anomalies` array — a console error is one channel
|
|
86
|
+
* complaining, while a UI that advanced over a failed write is two channels disagreeing. Only the
|
|
87
|
+
* second presents as success, and collapsing them would inflate the one claim that has to be exact.
|
|
88
|
+
*
|
|
89
|
+
* DERIVED from core's `ContradictionKind`, never hand-listed. The first version copied the twelve
|
|
90
|
+
* strings into a literal here, which matched on the day it was written and would have silently
|
|
91
|
+
* misclassified the thirteenth: a new contradiction kind would have been counted as an ordinary
|
|
92
|
+
* fault, quietly deflating the exact number we intend to publish. A copied enum is a drift hazard
|
|
93
|
+
* wherever it appears; it is a correctness hazard when the thing that drifts is a public claim.
|
|
94
|
+
*/
|
|
95
|
+
const CONTRADICTION_KINDS = new Set(Object.values(ContradictionKind));
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Report that a person ran a `reticle` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* `_daemon` is EXCLUDED, and that exclusion is the whole point of this function. `reticle mcp` and
|
|
5
|
+
* `reticle serve` start the daemon by re-running this very binary, so the child re-entered the CLI
|
|
6
|
+
* entry point and emitted a second event for what a person experienced as ONE action. The old
|
|
7
|
+
* `invoke` metric was therefore inflated ~2x — and inflated worst on the agent-driven sessions that
|
|
8
|
+
* matter most, while one-shot commands like `version` counted once. That skewed the RATIO between
|
|
9
|
+
* commands, not merely the scale, which is the kind of error you cannot correct for after the fact.
|
|
10
|
+
* The daemon\'s own lifecycle is already reported by `daemon_started` / `daemon_stopped`; a spawned
|
|
11
|
+
* daemon is not a CLI run.
|
|
12
|
+
*/
|
|
13
|
+
export declare function reportCliRun(argv: readonly string[]): void;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one telemetry event a human directly causes: they typed a `reticle` command.
|
|
3
|
+
*
|
|
4
|
+
* Lives in its own module so `cli.ts` stays a dispatcher, and so the `_daemon` exclusion below sits
|
|
5
|
+
* next to the explanation of why it exists rather than buried in a startup function.
|
|
6
|
+
*/
|
|
7
|
+
import { TelemetryActor, TelemetryEventKind } from '@reticlehq/core';
|
|
8
|
+
import { DAEMON_INNER_COMMAND, knownCommand } from '../cli-parse.js';
|
|
9
|
+
import { getTelemetry } from './telemetry.js';
|
|
10
|
+
import { describeCliFlags } from './argument-shape.js';
|
|
11
|
+
/**
|
|
12
|
+
* Report that a person ran a `reticle` subcommand.
|
|
13
|
+
*
|
|
14
|
+
* `_daemon` is EXCLUDED, and that exclusion is the whole point of this function. `reticle mcp` and
|
|
15
|
+
* `reticle serve` start the daemon by re-running this very binary, so the child re-entered the CLI
|
|
16
|
+
* entry point and emitted a second event for what a person experienced as ONE action. The old
|
|
17
|
+
* `invoke` metric was therefore inflated ~2x — and inflated worst on the agent-driven sessions that
|
|
18
|
+
* matter most, while one-shot commands like `version` counted once. That skewed the RATIO between
|
|
19
|
+
* commands, not merely the scale, which is the kind of error you cannot correct for after the fact.
|
|
20
|
+
* The daemon\'s own lifecycle is already reported by `daemon_started` / `daemon_stopped`; a spawned
|
|
21
|
+
* daemon is not a CLI run.
|
|
22
|
+
*/
|
|
23
|
+
export function reportCliRun(argv) {
|
|
24
|
+
const firstArg = argv[0];
|
|
25
|
+
if (firstArg === DAEMON_INNER_COMMAND)
|
|
26
|
+
return;
|
|
27
|
+
const telemetry = getTelemetry();
|
|
28
|
+
// `detach` so a quick command (`version`/`gate`) exits immediately instead of waiting out the POST.
|
|
29
|
+
if (telemetry.firstRun)
|
|
30
|
+
void telemetry.emit(TelemetryEventKind.RETICLE_INSTALLED, { detach: true });
|
|
31
|
+
void telemetry.emit(TelemetryEventKind.CLI_COMMAND_RUN, {
|
|
32
|
+
detach: true,
|
|
33
|
+
actor: TelemetryActor.HUMAN,
|
|
34
|
+
// A fixed, low-cardinality vocabulary WE define, so it is safe to send whole and it is the closest
|
|
35
|
+
// honest read we have on intent: `verify` and `gate` mean something very different from `status`.
|
|
36
|
+
// An unrecognized first arg reports as `unknown` rather than being echoed — an echo would put
|
|
37
|
+
// whatever someone mistyped, including a path or a URL, straight onto the wire.
|
|
38
|
+
command: knownCommand(firstArg),
|
|
39
|
+
// Which flags were PRESENT, by name only — never their values. `--http-token` alone makes that
|
|
40
|
+
// rule absolute rather than case-by-case; `--drive` and `--storage-state` carry a URL and a path.
|
|
41
|
+
flags: describeCliFlags(argv),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classifying WHY a browser connection failed, into causes that each have a different fix.
|
|
3
|
+
*
|
|
4
|
+
* A raw error message cannot be sent — it carries CDP URLs, executable paths, and home directories —
|
|
5
|
+
* and would be useless if it could, because the same cause arrives worded five different ways from
|
|
6
|
+
* Playwright, Node and the OS. What we need is the small set of THINGS THAT ACTUALLY GO WRONG:
|
|
7
|
+
* a missing browser binary is a docs problem, a refused CDP endpoint is a configuration problem, a
|
|
8
|
+
* pool timeout is a capacity problem. Three very different responses from us.
|
|
9
|
+
*
|
|
10
|
+
* `OTHER` is the bucket to watch. A large `OTHER` count means the classifier has a blind spot and
|
|
11
|
+
* this list needs another entry — which is a signal in itself, and the reason it is never merged
|
|
12
|
+
* into one of the known causes.
|
|
13
|
+
*/
|
|
14
|
+
import { ConnectFailure } from '@reticlehq/core';
|
|
15
|
+
/** The cause behind a connection error, or `OTHER` when we do not recognize it. */
|
|
16
|
+
export declare function classifyConnectFailure(error: unknown): ConnectFailure;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classifying WHY a browser connection failed, into causes that each have a different fix.
|
|
3
|
+
*
|
|
4
|
+
* A raw error message cannot be sent — it carries CDP URLs, executable paths, and home directories —
|
|
5
|
+
* and would be useless if it could, because the same cause arrives worded five different ways from
|
|
6
|
+
* Playwright, Node and the OS. What we need is the small set of THINGS THAT ACTUALLY GO WRONG:
|
|
7
|
+
* a missing browser binary is a docs problem, a refused CDP endpoint is a configuration problem, a
|
|
8
|
+
* pool timeout is a capacity problem. Three very different responses from us.
|
|
9
|
+
*
|
|
10
|
+
* `OTHER` is the bucket to watch. A large `OTHER` count means the classifier has a blind spot and
|
|
11
|
+
* this list needs another entry — which is a signal in itself, and the reason it is never merged
|
|
12
|
+
* into one of the known causes.
|
|
13
|
+
*/
|
|
14
|
+
import { ConnectFailure } from '@reticlehq/core';
|
|
15
|
+
/** Ordered most-specific first; the first match wins. Patterns track messages we have actually seen. */
|
|
16
|
+
const RULES = [
|
|
17
|
+
// Playwright's own wording when the browser was never downloaded.
|
|
18
|
+
{
|
|
19
|
+
match: /executable doesn.?t exist|playwright install|browsertype\.launch/i,
|
|
20
|
+
cause: ConnectFailure.CHROMIUM_MISSING,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
match: /cannot find module ['"]?playwright|playwright is not installed/i,
|
|
24
|
+
cause: ConnectFailure.PLAYWRIGHT_MISSING,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
match: /econnrefused|connect over cdp|websocket error|failed to connect|enotfound|etimedout/i,
|
|
28
|
+
cause: ConnectFailure.CDP_UNREACHABLE,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
match: /target (?:page|closed)|browser has been closed|browser has disconnected|crashed/i,
|
|
32
|
+
cause: ConnectFailure.BROWSER_CRASHED,
|
|
33
|
+
},
|
|
34
|
+
{ match: /pool|lease.*timed out|timed out waiting/i, cause: ConnectFailure.POOL_TIMEOUT },
|
|
35
|
+
];
|
|
36
|
+
/** The cause behind a connection error, or `OTHER` when we do not recognize it. */
|
|
37
|
+
export function classifyConnectFailure(error) {
|
|
38
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
39
|
+
for (const rule of RULES) {
|
|
40
|
+
if (rule.match.test(message))
|
|
41
|
+
return rule.cause;
|
|
42
|
+
}
|
|
43
|
+
return ConnectFailure.OTHER;
|
|
44
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Stops the timers this installed. Called from the daemon's shutdown path. */
|
|
2
|
+
export interface DaemonTelemetry {
|
|
3
|
+
/**
|
|
4
|
+
* Emit the final, rich session summary and stop flushing. Safe to call more than once.
|
|
5
|
+
*
|
|
6
|
+
* AWAITABLE, and the daemon must await it. Every other send in the product is fire-and-forget
|
|
7
|
+
* because losing one counter never matters — but this one carries the whole session, and the
|
|
8
|
+
* process calls `process.exit(0)` immediately afterwards, which kills an in-flight POST. Verified
|
|
9
|
+
* against a local capture server: fire-and-forget lost the event every single time. A send that
|
|
10
|
+
* fails or hangs still cannot block the exit, because `emit` swallows its own errors and is bounded
|
|
11
|
+
* by its own request timeout.
|
|
12
|
+
*/
|
|
13
|
+
shutdown(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Report the daemon as started, profile the project once, and keep the session counters flushing.
|
|
17
|
+
* Every timer is `unref`'d so telemetry can never be the reason a daemon refuses to exit.
|
|
18
|
+
*/
|
|
19
|
+
export declare function installDaemonTelemetry(cwd: string, now?: () => number): DaemonTelemetry;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The daemon's telemetry lifecycle, in one place: start, the periodic flush that survives a kill, the
|
|
3
|
+
* one-shot project profile, and the rich summary on shutdown.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from `cli.ts` because it is a cohesive unit with its own timers and its own failure rule
|
|
6
|
+
* (nothing here may ever be able to fail a daemon start), and because `cli.ts` is a dispatcher — the
|
|
7
|
+
* more of this that lives there, the harder it is to see what a command actually does.
|
|
8
|
+
*/
|
|
9
|
+
import { TelemetryEventKind } from '@reticlehq/core';
|
|
10
|
+
import { getTelemetry } from './telemetry.js';
|
|
11
|
+
import { getSessionMetrics } from './session-metrics.js';
|
|
12
|
+
import { profileProject } from './project-profile.js';
|
|
13
|
+
import { startUpdateCheck } from '../update/update-nudge.js';
|
|
14
|
+
import { markDaemonStart } from './mcp-connection.js';
|
|
15
|
+
/** Let the daemon finish coming up before walking the source tree for a profile. */
|
|
16
|
+
const PROJECT_PROFILE_DELAY_MS = 5_000;
|
|
17
|
+
/**
|
|
18
|
+
* How often a long-lived daemon flushes its counters.
|
|
19
|
+
*
|
|
20
|
+
* ponytail: coarse on purpose. A daemon that is SIGKILLed — OOM, a closed laptop, `kill -9` — never
|
|
21
|
+
* reaches its shutdown handler, so without this the whole session's counters die with it. Thirty
|
|
22
|
+
* minutes bounds that loss to one window while keeping the event volume near zero for the common case
|
|
23
|
+
* (most daemons stop cleanly and send exactly one summary). If the lost windows ever show up as a
|
|
24
|
+
* real gap, the upgrade is a small on-disk journal replayed at the next start, not a shorter timer.
|
|
25
|
+
*/
|
|
26
|
+
const SESSION_FLUSH_MS = 30 * 60 * 1000;
|
|
27
|
+
/**
|
|
28
|
+
* Report the daemon as started, profile the project once, and keep the session counters flushing.
|
|
29
|
+
* Every timer is `unref`'d so telemetry can never be the reason a daemon refuses to exit.
|
|
30
|
+
*/
|
|
31
|
+
export function installDaemonTelemetry(cwd, now = () => Date.now()) {
|
|
32
|
+
const metrics = getSessionMetrics(now);
|
|
33
|
+
void getTelemetry().emit(TelemetryEventKind.DAEMON_STARTED);
|
|
34
|
+
// Ask npm whether a newer Reticle exists, so the agent can tell the human. Nothing checked before
|
|
35
|
+
// this, so a published fix was invisible until someone manually ran `reticle update`.
|
|
36
|
+
startUpdateCheck(now);
|
|
37
|
+
markDaemonStart(now());
|
|
38
|
+
// One profile per daemon start: what kind of project this is and how deeply Reticle is used in it.
|
|
39
|
+
// Deferred off the boot path — it walks the source tree, and nothing about a daemon coming up
|
|
40
|
+
// should wait on a filesystem scan.
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
try {
|
|
43
|
+
void getTelemetry().emit(TelemetryEventKind.PROJECT_PROFILED, {
|
|
44
|
+
project: profileProject(cwd, now()),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
/* a profile is a nice-to-have; it must never touch the daemon */
|
|
49
|
+
}
|
|
50
|
+
}, PROJECT_PROFILE_DELAY_MS).unref();
|
|
51
|
+
const flush = setInterval(() => {
|
|
52
|
+
if (metrics.empty)
|
|
53
|
+
return; // an idle window is not worth an event
|
|
54
|
+
void getTelemetry().emit(TelemetryEventKind.DAEMON_STOPPED, {
|
|
55
|
+
session: metrics.summarize(false),
|
|
56
|
+
});
|
|
57
|
+
metrics.reset();
|
|
58
|
+
}, SESSION_FLUSH_MS);
|
|
59
|
+
flush.unref();
|
|
60
|
+
let stopped;
|
|
61
|
+
return {
|
|
62
|
+
shutdown() {
|
|
63
|
+
// Both SIGTERM and the idle-shutdown path can call this; the second caller awaits the first
|
|
64
|
+
// send rather than emitting a duplicate summary.
|
|
65
|
+
stopped ??= (async () => {
|
|
66
|
+
clearInterval(flush);
|
|
67
|
+
// The rich one: the whole session in a single event — duration, the tool histogram, error
|
|
68
|
+
// shapes, verifications, browser launches. This is what replaced the per-tool-call event.
|
|
69
|
+
await getTelemetry().emit(TelemetryEventKind.DAEMON_STOPPED, {
|
|
70
|
+
session: metrics.summarize(true),
|
|
71
|
+
});
|
|
72
|
+
})();
|
|
73
|
+
return stopped;
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Walk up from `cwd` to the filesystem root, looking for a package.json that names this monorepo. */
|
|
2
|
+
export declare function isReticleSourceCheckout(cwd: string): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Load `<dir>/.env` into `env`. Best-effort and deliberately minimal — no expansion, no multiline.
|
|
5
|
+
*
|
|
6
|
+
* A variable already present in the environment ALWAYS wins. A .env that overrode an explicit
|
|
7
|
+
* `RETICLE_PORT` from the caller's shell would bind the daemon somewhere the caller never asked for,
|
|
8
|
+
* which is a worse surprise than the convenience is worth.
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadDotEnv(dir: string, env?: NodeJS.ProcessEnv): void;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, parse } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Two guards that keep Reticle's own development off its telemetry.
|
|
5
|
+
*
|
|
6
|
+
* `.env` is the convenient one and is useful to every user: put `RETICLE_TELEMETRY=0` in a project's
|
|
7
|
+
* `.env` and the daemon honours it. But `.env` is gitignored, so it exists only on the machine that
|
|
8
|
+
* created it — a fresh clone of this repo would phone home on the first `reticle serve` a
|
|
9
|
+
* contributor runs. `isReticleSourceCheckout` closes that: the marker is the committed root
|
|
10
|
+
* package.json, so the guarantee travels with the repository instead of with one developer's
|
|
11
|
+
* untracked file.
|
|
12
|
+
*/
|
|
13
|
+
/** The monorepo's root package name — the one committed marker that says "this IS Reticle". */
|
|
14
|
+
const MONOREPO_NAME = 'reticle-monorepo';
|
|
15
|
+
/** Walk up from `cwd` to the filesystem root, looking for a package.json that names this monorepo. */
|
|
16
|
+
export function isReticleSourceCheckout(cwd) {
|
|
17
|
+
let dir = cwd;
|
|
18
|
+
const { root } = parse(cwd);
|
|
19
|
+
for (;;) {
|
|
20
|
+
const pkg = join(dir, 'package.json');
|
|
21
|
+
if (existsSync(pkg)) {
|
|
22
|
+
try {
|
|
23
|
+
const parsed = JSON.parse(readFileSync(pkg, 'utf8'));
|
|
24
|
+
const name = typeof parsed === 'object' && parsed !== null
|
|
25
|
+
? parsed.name
|
|
26
|
+
: undefined;
|
|
27
|
+
if (name === MONOREPO_NAME)
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
/* an unreadable/!JSON package.json simply is not the marker */
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (dir === root)
|
|
35
|
+
return false;
|
|
36
|
+
const next = dirname(dir);
|
|
37
|
+
if (next === dir)
|
|
38
|
+
return false;
|
|
39
|
+
dir = next;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Strip one layer of matching quotes from a .env value. */
|
|
43
|
+
function unquote(value) {
|
|
44
|
+
const first = value[0];
|
|
45
|
+
if ((first === '"' || first === "'") && value.endsWith(first) && value.length >= 2) {
|
|
46
|
+
return value.slice(1, -1);
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Load `<dir>/.env` into `env`. Best-effort and deliberately minimal — no expansion, no multiline.
|
|
52
|
+
*
|
|
53
|
+
* A variable already present in the environment ALWAYS wins. A .env that overrode an explicit
|
|
54
|
+
* `RETICLE_PORT` from the caller's shell would bind the daemon somewhere the caller never asked for,
|
|
55
|
+
* which is a worse surprise than the convenience is worth.
|
|
56
|
+
*/
|
|
57
|
+
export function loadDotEnv(dir, env = process.env) {
|
|
58
|
+
const file = join(dir, '.env');
|
|
59
|
+
let text;
|
|
60
|
+
try {
|
|
61
|
+
if (!existsSync(file))
|
|
62
|
+
return;
|
|
63
|
+
text = readFileSync(file, 'utf8');
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
for (const raw of text.split('\n')) {
|
|
69
|
+
const line = raw.trim();
|
|
70
|
+
if (line.length === 0 || line.startsWith('#'))
|
|
71
|
+
continue;
|
|
72
|
+
const eq = line.indexOf('=');
|
|
73
|
+
if (eq <= 0)
|
|
74
|
+
continue; // not a KEY=value pair — skip rather than fail the whole file
|
|
75
|
+
const key = line.slice(0, eq).trim();
|
|
76
|
+
if (key.length === 0 || env[key] !== undefined)
|
|
77
|
+
continue;
|
|
78
|
+
env[key] = unquote(line.slice(eq + 1).trim());
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** The skeleton of a message: variable parts blanked, whitespace collapsed, length bounded. */
|
|
2
|
+
export declare function errorSkeleton(message: string): string;
|
|
3
|
+
/** A stable, opaque group key for an error message. Same defect ⇒ same key, on every machine. */
|
|
4
|
+
export declare function fingerprintError(message: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Frames from a stack trace that belong to RETICLE, reduced to `basename:line`.
|
|
7
|
+
*
|
|
8
|
+
* A crash stack is mostly the user's own application and node internals; neither is ours to collect,
|
|
9
|
+
* and the user's frames are the ones that would carry their directory layout and module names. Only
|
|
10
|
+
* frames inside a `@reticlehq/*` package or a `reticle` dist path survive, and even those keep just
|
|
11
|
+
* the file basename — enough to point a maintainer at the right file, never enough to describe
|
|
12
|
+
* anyone's machine.
|
|
13
|
+
*/
|
|
14
|
+
export declare function reticleFrames(stack: string): string[];
|
|
15
|
+
/** How many of our own frames to carry. The innermost few are where the defect is. */
|
|
16
|
+
export declare const MAX_REPORTED_FRAMES = 12;
|
|
17
|
+
/**
|
|
18
|
+
* A crash fingerprint from the error's type and its Reticle-owned frames. Falls back to the message
|
|
19
|
+
* skeleton when a stack has no Reticle frames at all (a crash from deep inside a dependency), so a
|
|
20
|
+
* crash is never dropped for lack of a clean attribution.
|
|
21
|
+
*/
|
|
22
|
+
export declare function fingerprintCrash(errorType: string, stack: string, message: string): string;
|
|
23
|
+
/** The error's constructor name (`TypeError`), or `Unknown` for a thrown non-Error. */
|
|
24
|
+
export declare function errorTypeOf(error: unknown): string;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning errors into something we can COUNT without carrying anything anyone wrote.
|
|
3
|
+
*
|
|
4
|
+
* An error message is the most tempting thing to send and the most dangerous: it is where a selector,
|
|
5
|
+
* a URL, a customer id, a file path, or a snippet of someone's app ends up. But "which error is
|
|
6
|
+
* hurting people most" is genuinely the highest-value product question we can ask, and it needs
|
|
7
|
+
* grouping — a thousand machines hitting the same defect have to collapse into one row before anyone
|
|
8
|
+
* can rank it.
|
|
9
|
+
*
|
|
10
|
+
* A fingerprint gives us the grouping without the content: strip every variable part, keep the
|
|
11
|
+
* skeleton, hash it. `no baseline named 'checkout-v3'` and `no baseline named 'login'` both become
|
|
12
|
+
* the same fingerprint, and neither flow name leaves the machine. The output is a short hex string,
|
|
13
|
+
* so even the skeleton is not readable on our side — it is an opaque group key, and its only power is
|
|
14
|
+
* that identical failures share it.
|
|
15
|
+
*/
|
|
16
|
+
import { createHash } from 'node:crypto';
|
|
17
|
+
/**
|
|
18
|
+
* The variable parts, replaced before hashing. Order matters: quoted strings go first, because a
|
|
19
|
+
* quoted value often contains the very numbers and paths the later rules would only partly catch.
|
|
20
|
+
*/
|
|
21
|
+
const VARIABLE_PARTS = [
|
|
22
|
+
/"[^"]*"|'[^']*'|`[^`]*`/g, // quoted values — names, selectors, snippets
|
|
23
|
+
/\b[a-z][a-z0-9+.-]*:\/\/\S+/gi, // URLs
|
|
24
|
+
/(?:\/[\w.-]+){2,}\/?/g, // POSIX-ish paths
|
|
25
|
+
/[A-Za-z]:\\[^\s]*/g, // Windows paths
|
|
26
|
+
/\b[0-9a-f]{8,}\b/gi, // hex ids, hashes, uuids-without-dashes
|
|
27
|
+
/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi, // uuids
|
|
28
|
+
/\d+/g, // any remaining number — ports, counts, timeouts
|
|
29
|
+
];
|
|
30
|
+
/** The skeleton of a message: variable parts blanked, whitespace collapsed, length bounded. */
|
|
31
|
+
export function errorSkeleton(message) {
|
|
32
|
+
let skeleton = message;
|
|
33
|
+
for (const pattern of VARIABLE_PARTS)
|
|
34
|
+
skeleton = skeleton.replace(pattern, '*');
|
|
35
|
+
return skeleton.replace(/\s+/g, ' ').trim().slice(0, 200);
|
|
36
|
+
}
|
|
37
|
+
/** A stable, opaque group key for an error message. Same defect ⇒ same key, on every machine. */
|
|
38
|
+
export function fingerprintError(message) {
|
|
39
|
+
return createHash('sha256').update(errorSkeleton(message)).digest('hex').slice(0, 12);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Frames from a stack trace that belong to RETICLE, reduced to `basename:line`.
|
|
43
|
+
*
|
|
44
|
+
* A crash stack is mostly the user's own application and node internals; neither is ours to collect,
|
|
45
|
+
* and the user's frames are the ones that would carry their directory layout and module names. Only
|
|
46
|
+
* frames inside a `@reticlehq/*` package or a `reticle` dist path survive, and even those keep just
|
|
47
|
+
* the file basename — enough to point a maintainer at the right file, never enough to describe
|
|
48
|
+
* anyone's machine.
|
|
49
|
+
*/
|
|
50
|
+
export function reticleFrames(stack) {
|
|
51
|
+
const frames = [];
|
|
52
|
+
for (const line of stack.split('\n')) {
|
|
53
|
+
if (!/@reticlehq[/\\]|[/\\]reticle[/\\]dist[/\\]/.test(line))
|
|
54
|
+
continue;
|
|
55
|
+
const location = line.match(/([\w.-]+\.(?:js|mjs|cjs|ts)):(\d+)/);
|
|
56
|
+
if (location === null)
|
|
57
|
+
continue;
|
|
58
|
+
// `at Object.runTool (/path/to/invoke-tool.js:88:3)` → `runTool`. The function name is half the
|
|
59
|
+
// value of a frame in an RCA — "it died in act-tools.js" narrows to a file, "it died in
|
|
60
|
+
// resolveAnchor" names the thing that broke. Anonymous frames just report the location.
|
|
61
|
+
const fn = line.match(/at\s+(?:async\s+)?(?:new\s+)?([\w.$<>[\]]+)\s+\(/)?.[1];
|
|
62
|
+
const where = `${location[1] ?? ''}:${location[2] ?? ''}`;
|
|
63
|
+
// `Object.` / `Module.` prefixes are V8 noise that make the same function look like two.
|
|
64
|
+
const name = fn?.replace(/^(?:Object|Module|Function)\./, '');
|
|
65
|
+
frames.push(name === undefined || name === '' ? where : `${name}@${where}`);
|
|
66
|
+
}
|
|
67
|
+
return frames;
|
|
68
|
+
}
|
|
69
|
+
/** How many of our own frames to carry. The innermost few are where the defect is. */
|
|
70
|
+
export const MAX_REPORTED_FRAMES = 12;
|
|
71
|
+
/**
|
|
72
|
+
* A crash fingerprint from the error's type and its Reticle-owned frames. Falls back to the message
|
|
73
|
+
* skeleton when a stack has no Reticle frames at all (a crash from deep inside a dependency), so a
|
|
74
|
+
* crash is never dropped for lack of a clean attribution.
|
|
75
|
+
*/
|
|
76
|
+
export function fingerprintCrash(errorType, stack, message) {
|
|
77
|
+
const frames = reticleFrames(stack);
|
|
78
|
+
const basis = frames.length > 0
|
|
79
|
+
? `${errorType}|${frames.join('|')}`
|
|
80
|
+
: `${errorType}|${errorSkeleton(message)}`;
|
|
81
|
+
return createHash('sha256').update(basis).digest('hex').slice(0, 12);
|
|
82
|
+
}
|
|
83
|
+
/** The error's constructor name (`TypeError`), or `Unknown` for a thrown non-Error. */
|
|
84
|
+
export function errorTypeOf(error) {
|
|
85
|
+
if (error instanceof Error)
|
|
86
|
+
return error.constructor.name.slice(0, 64);
|
|
87
|
+
return 'Unknown';
|
|
88
|
+
}
|