@reticlehq/server 2.3.0 → 2.5.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 +702 -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} +1 -1
- package/dist/{bridge.js → bridge/bridge.js} +105 -15
- package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +6 -11
- package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +21 -9
- 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-doctor.js → cli/cli-doctor.js} +9 -2
- 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.d.ts +143 -0
- package/dist/{cli-parse.js → cli/cli-parse.js} +146 -65
- package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +15 -0
- package/dist/{cli-port.js → cli/cli-port.js} +29 -8
- 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.d.ts +2 -2
- package/dist/cli.js +182 -93
- 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 +49 -0
- package/dist/daemon/daemon-resilience.js +191 -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} +80 -48
- 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} +13 -0
- package/dist/{idle-shutdown.js → daemon/idle-shutdown.js} +27 -4
- 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 +43 -20
- package/dist/events/predicate-eval.js +159 -55
- package/dist/events/predicate.d.ts +2 -2
- package/dist/events/predicate.js +112 -35
- package/dist/events/reconcile.js +5 -5
- package/dist/events/ring-buffer.js +1 -1
- 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.d.ts +0 -6
- package/dist/flows/decision.js +64 -8
- 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 +5 -7
- package/dist/flows/flow-replay.js +114 -47
- 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 +157 -6
- package/dist/flows/flow-success.js +20 -15
- package/dist/flows/flow-tools.js +67 -13
- 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/server-verify.d.ts +1 -1
- package/dist/flows/server-verify.js +5 -5
- 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 +16 -3
- package/dist/honesty/blind-spots.js +24 -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 +22 -3
- package/dist/honesty/verified.js +48 -8
- package/dist/http-server.js +14 -7
- package/dist/hunt/hunt-report.d.ts +2 -1
- package/dist/hunt/hunt-report.js +2 -2
- package/dist/index.d.ts +8 -6
- package/dist/index.js +32 -25
- package/dist/init/agent-rules.d.ts +2 -1
- package/dist/init/agent-rules.js +45 -7
- 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.d.ts +17 -0
- package/dist/init/capabilities.js +54 -0
- package/dist/init/cra.d.ts +37 -0
- package/dist/init/cra.js +90 -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 +26 -0
- package/dist/init/detect.js +78 -5
- 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 +39 -0
- package/dist/init/next-patch.js +196 -0
- package/dist/init/node-io.js +48 -6
- package/dist/init/patch-kind.d.ts +20 -0
- package/dist/init/patch-kind.js +10 -0
- package/dist/init/plan-framework.d.ts +50 -0
- package/dist/init/plan-framework.js +341 -0
- package/dist/init/plan.d.ts +119 -6
- package/dist/init/plan.js +230 -131
- package/dist/init/project-id.d.ts +5 -9
- package/dist/init/project-id.js +10 -22
- package/dist/init/run.d.ts +22 -0
- package/dist/init/run.js +393 -28
- package/dist/init/slash-command.d.ts +27 -0
- package/dist/init/slash-command.js +61 -0
- package/dist/init/snippets.d.ts +41 -3
- package/dist/init/snippets.js +185 -10
- package/dist/init/vite-config.d.ts +4 -10
- package/dist/init/vite-config.js +15 -7
- package/dist/init/workspace-apps.d.ts +23 -0
- package/dist/init/workspace-apps.js +68 -0
- package/dist/input/driven-redaction.d.ts +15 -0
- package/dist/input/driven-redaction.js +76 -0
- package/dist/input/network-detail.d.ts +9 -3
- package/dist/input/network-detail.js +43 -23
- 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 +31 -0
- package/dist/mcp/mcp-outage.js +48 -0
- package/dist/mcp/mcp-proxy.d.ts +124 -0
- package/dist/mcp/mcp-proxy.js +697 -0
- package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
- package/dist/{mcp.js → mcp/mcp.js} +110 -35
- 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/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/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 +38 -0
- package/dist/session/no-session-diagnosis.js +70 -0
- package/dist/session/no-session-watch.d.ts +19 -0
- package/dist/session/no-session-watch.js +61 -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/session-health.d.ts +8 -1
- package/dist/session/session-health.js +8 -7
- package/dist/session/session-info.d.ts +26 -7
- package/dist/session/session-info.js +42 -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 +3 -0
- package/dist/session/session-manager.js +58 -9
- 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 +20 -2
- package/dist/session/session.js +76 -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/daemon-telemetry.d.ts +19 -0
- package/dist/telemetry/daemon-telemetry.js +12 -2
- package/dist/telemetry/dev-repo.js +4 -4
- package/dist/telemetry/error-fingerprint.js +21 -2
- package/dist/telemetry/feedback-cli.d.ts +1 -1
- package/dist/telemetry/feedback-cli.js +4 -4
- package/dist/telemetry/feedback-context.d.ts +22 -0
- package/dist/telemetry/feedback-context.js +41 -1
- 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.js +1 -1
- package/dist/telemetry/session-metrics.d.ts +2 -0
- package/dist/telemetry/session-metrics.js +68 -6
- package/dist/telemetry/telemetry.d.ts +27 -2
- package/dist/telemetry/telemetry.js +119 -29
- 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 +84 -115
- 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 +3 -1
- package/dist/tools/assert-verdict.js +8 -5
- package/dist/tools/browser-tools.js +30 -11
- package/dist/tools/contract-tools.js +1 -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 +90 -18
- package/dist/tools/error-recovery.d.ts +20 -2
- package/dist/tools/error-recovery.js +179 -4
- 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 -6
- package/dist/tools/invoke-tool.js +57 -32
- 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-result.d.ts +17 -0
- package/dist/tools/navigate-result.js +31 -0
- package/dist/tools/observe-tools.js +54 -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 +85 -20
- package/dist/tools/real-input-attempt.d.ts +28 -0
- package/dist/tools/real-input-attempt.js +88 -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 +8 -0
- package/dist/tools/tool-surface.d.ts +83 -0
- package/dist/tools/tool-surface.js +204 -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/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.md +28 -0
- package/docs/flows.md +166 -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/mint.json +61 -0
- package/docs/multi-agent-testing.md +55 -0
- package/docs/platform-integration.md +122 -0
- package/docs/telemetry-contract.md +214 -0
- package/docs/telemetry.md +184 -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-launch.js +0 -112
- package/dist/cli-parse.d.ts +0 -140
- package/dist/daemon-resilience.d.ts +0 -22
- package/dist/daemon-resilience.js +0 -85
- package/dist/mcp-proxy.d.ts +0 -35
- package/dist/mcp-proxy.js +0 -190
- 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-doctor.d.ts → cli/cli-doctor.d.ts} +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
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block until a reloaded page has re-announced itself under the same session id.
|
|
3
|
+
*
|
|
4
|
+
* A reload tears the SDK down. The id survives (see session-continuity), and the daemon replaces the
|
|
5
|
+
* old Session with a new one when the page says HELLO again — so "is it back?" is exactly "does a
|
|
6
|
+
* DIFFERENT object hold this id now?". Identity, not a flag: the returning page always constructs a
|
|
7
|
+
* new Session, and nothing else can claim an id it already owns.
|
|
8
|
+
*
|
|
9
|
+
* Polls a live getter rather than subscribing, because there is no reconnect event to subscribe to
|
|
10
|
+
* and inventing one for this would be a wire change for a two-second wait.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* How often to look for the reconnected session.
|
|
14
|
+
*
|
|
15
|
+
* 25ms, not 100. What is being polled is an in-memory map lookup — no I/O, no browser round-trip —
|
|
16
|
+
* while the thing being waited for is an EVENT (the reloaded page's HELLO). At 100ms the agent paid
|
|
17
|
+
* up to a full interval of dead time after the page was already back, on every navigate-with-reload.
|
|
18
|
+
* Measured across the fixture fleet, `reticle_navigate` clustered at 105 / 202-206 / 308 / 407ms —
|
|
19
|
+
* the poll grid, visible in the data. Four times the checks of something this cheap costs nothing
|
|
20
|
+
* anyone can measure.
|
|
21
|
+
*/
|
|
22
|
+
const DEFAULT_POLL_MS = 25;
|
|
23
|
+
/**
|
|
24
|
+
* How long a reload is worth waiting for before answering "not confirmed".
|
|
25
|
+
*
|
|
26
|
+
* A production build is back in well under a second; a cold dev-server route rebuild is the slow
|
|
27
|
+
* case this budget is sized for. It is a CEILING, not a delay — the common path returns on the first
|
|
28
|
+
* or second poll.
|
|
29
|
+
*/
|
|
30
|
+
export const RELOAD_RECONNECT_TIMEOUT_MS = 5000;
|
|
31
|
+
export async function waitForReconnect(opts) {
|
|
32
|
+
const poll = opts.pollMs ?? DEFAULT_POLL_MS;
|
|
33
|
+
const start = opts.now();
|
|
34
|
+
for (;;) {
|
|
35
|
+
const live = opts.current();
|
|
36
|
+
if (live !== undefined && live !== opts.previous)
|
|
37
|
+
return true;
|
|
38
|
+
if (opts.now() - start >= opts.timeoutMs)
|
|
39
|
+
return false;
|
|
40
|
+
await opts.sleep(poll);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -3,7 +3,7 @@ import { LastAct } from './last-act.js';
|
|
|
3
3
|
import { type PageRuntime } from './command-timeout.js';
|
|
4
4
|
import { type SessionHealth } from './session-health.js';
|
|
5
5
|
export type { SessionHealth };
|
|
6
|
-
import { PresenterTone, SessionState, type CommandResult, type HelloMessage, type HumanControlData, type ReticleEvent } from '@reticlehq/core';
|
|
6
|
+
import { PresenterTone, SessionState, type BrowserBrand, type CommandResult, type HelloMessage, type HumanControlData, type ReticleEvent } from '@reticlehq/core';
|
|
7
7
|
import type { JournalReader, JournalRecorder } from '../journal/journal-recorder.js';
|
|
8
8
|
import { type EventQueryOptions } from '../journal/journal-query.js';
|
|
9
9
|
import { type AmbientCounts } from '../journal/ambient.js';
|
|
@@ -27,6 +27,14 @@ export declare class Session {
|
|
|
27
27
|
title: string;
|
|
28
28
|
adapters: string[];
|
|
29
29
|
hasCapabilities: boolean;
|
|
30
|
+
/** Set when the page's SDK version differs from the daemon's (see version-skew.ts). */
|
|
31
|
+
versionSkew?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Extra key names this app declared sensitive via `connect({ redact: { keys } })`. Held so the
|
|
34
|
+
* DRIVEN path can redact them too — a request body the daemon captures from the network stack
|
|
35
|
+
* never passes through the SDK, so nothing else would.
|
|
36
|
+
*/
|
|
37
|
+
readonly redactKeys: readonly string[];
|
|
30
38
|
constructor(hello: HelloMessage, socket: WebSocket, clock: Clock);
|
|
31
39
|
/** Milliseconds since this session connected — the authoritative buffer clock. */
|
|
32
40
|
elapsed(): number;
|
|
@@ -40,10 +48,12 @@ export declare class Session {
|
|
|
40
48
|
* `runtime` is optional so an older SDK (which does not report it) still works — it simply loses
|
|
41
49
|
* the desktop-specific timeout diagnosis rather than breaking.
|
|
42
50
|
*/
|
|
43
|
-
applyHealth(hidden: boolean, focused: boolean, runtime?: string, engine?: string): void;
|
|
51
|
+
applyHealth(hidden: boolean, focused: boolean, runtime?: string, engine?: string, brand?: BrowserBrand): void;
|
|
44
52
|
/** The shell (web/electron/tauri) and rendering engine the SDK reported. Undefined on an older SDK. */
|
|
45
53
|
get runtime(): PageRuntime | undefined;
|
|
46
54
|
get engine(): string | undefined;
|
|
55
|
+
/** The browser brand the SDK reported. Absent (never guessed) when the page did not say. */
|
|
56
|
+
get brand(): BrowserBrand | undefined;
|
|
47
57
|
/** Throttled if the tab is hidden OR we have not heard from it recently. */
|
|
48
58
|
throttled(): boolean;
|
|
49
59
|
/** The attachable health block — single source of truth for the tools. */
|
|
@@ -54,6 +64,14 @@ export declare class Session {
|
|
|
54
64
|
/** Re-stamp an incoming event with server-relative time, buffer it, and fan out. */
|
|
55
65
|
pushEvent(event: ReticleEvent, byteSize?: number): void;
|
|
56
66
|
recordActedRef(ref: string): void;
|
|
67
|
+
actedLabels(): ReadonlySet<string>;
|
|
68
|
+
/**
|
|
69
|
+
* Derive the snapshot-shaped label (`button "Deploy"`) from an act reply and remember it.
|
|
70
|
+
*
|
|
71
|
+
* Same shape the interactive snapshot emits, so coverage can match a control the agent drove
|
|
72
|
+
* against the same control after a re-render gave it a different ref.
|
|
73
|
+
*/
|
|
74
|
+
private recordActedLabelFrom;
|
|
57
75
|
actedRefs(): ReadonlySet<string>;
|
|
58
76
|
noteRateLimited(dropped: number): void;
|
|
59
77
|
blindSpots(): Readonly<Record<string, number>>;
|
package/dist/session/session.js
CHANGED
|
@@ -2,7 +2,8 @@ import { LastAct } from './last-act.js';
|
|
|
2
2
|
import { commandTimeoutMessage } from './command-timeout.js';
|
|
3
3
|
import { readHealthEvent } from './session-health.js';
|
|
4
4
|
import { PendingCommands } from './pending-commands.js';
|
|
5
|
-
import {
|
|
5
|
+
import { span } from '../trace.js';
|
|
6
|
+
import { AppRuntime, EventType, HumanControlDataSchema, HumanControlKind, HumanMarkDataSchema, ReticleCommand, MessageKind, parseEventPayload, PresenterTone, SESSION_HEALTH, SESSION_LEASE, SESSION_LIFECYCLE, SessionState, } from '@reticlehq/core';
|
|
6
7
|
import { RingBuffer } from '../events/ring-buffer.js';
|
|
7
8
|
import { filterEvents, mergeEventsBySeq, } from '../journal/journal-query.js';
|
|
8
9
|
import {} from '../journal/ambient.js';
|
|
@@ -13,6 +14,7 @@ import { ReviewStore } from './review-store.js';
|
|
|
13
14
|
import { buildSessionRecommendation } from './session-recommendation.js';
|
|
14
15
|
import { buildPresenterArgs } from './presenter-args.js';
|
|
15
16
|
import { buildSessionLease } from './session-lease.js';
|
|
17
|
+
import { buildSessionInfo } from './session-info.js';
|
|
16
18
|
const DEFAULT_COMMAND_TIMEOUT_MS = 8000;
|
|
17
19
|
/** Prefix on correlated command ids (c1, c2, …) — distinguishes them from mark ids. */
|
|
18
20
|
const COMMAND_ID_PREFIX = 'c';
|
|
@@ -32,6 +34,14 @@ export class Session {
|
|
|
32
34
|
title;
|
|
33
35
|
adapters;
|
|
34
36
|
hasCapabilities;
|
|
37
|
+
/** Set when the page's SDK version differs from the daemon's (see version-skew.ts). */
|
|
38
|
+
versionSkew;
|
|
39
|
+
/**
|
|
40
|
+
* Extra key names this app declared sensitive via `connect({ redact: { keys } })`. Held so the
|
|
41
|
+
* DRIVEN path can redact them too — a request body the daemon captures from the network stack
|
|
42
|
+
* never passes through the SDK, so nothing else would.
|
|
43
|
+
*/
|
|
44
|
+
redactKeys;
|
|
35
45
|
#socket;
|
|
36
46
|
#clock;
|
|
37
47
|
#startedAt;
|
|
@@ -44,6 +54,8 @@ export class Session {
|
|
|
44
54
|
/** Which shell the page reported (PAGE_HEALTH). Undefined until the first report lands. */
|
|
45
55
|
#runtime;
|
|
46
56
|
#engine;
|
|
57
|
+
/** Which browser the page said it is (chrome/edge/arc/…). Undefined on an SDK too old to report one. */
|
|
58
|
+
#brand;
|
|
47
59
|
#focused = true;
|
|
48
60
|
/** Liveness: wall-clock of the last AGENT command (distinct from browser chatter / lastSeen). */
|
|
49
61
|
#lastAgentActivityAt;
|
|
@@ -70,6 +82,7 @@ export class Session {
|
|
|
70
82
|
this.title = hello.title;
|
|
71
83
|
this.adapters = hello.adapters;
|
|
72
84
|
this.hasCapabilities = hello.hasCapabilities ?? false;
|
|
85
|
+
this.redactKeys = hello.redactKeys ?? [];
|
|
73
86
|
this.#socket = socket;
|
|
74
87
|
this.#clock = clock;
|
|
75
88
|
this.#startedAt = clock();
|
|
@@ -94,14 +107,18 @@ export class Session {
|
|
|
94
107
|
* `runtime` is optional so an older SDK (which does not report it) still works — it simply loses
|
|
95
108
|
* the desktop-specific timeout diagnosis rather than breaking.
|
|
96
109
|
*/
|
|
97
|
-
applyHealth(hidden, focused, runtime, engine) {
|
|
110
|
+
applyHealth(hidden, focused, runtime, engine, brand) {
|
|
98
111
|
this.#hidden = hidden;
|
|
99
112
|
this.#focused = focused;
|
|
100
|
-
if (
|
|
113
|
+
if (AppRuntime.ELECTRON === runtime ||
|
|
114
|
+
AppRuntime.TAURI === runtime ||
|
|
115
|
+
AppRuntime.WEB === runtime) {
|
|
101
116
|
this.#runtime = runtime;
|
|
102
117
|
}
|
|
103
118
|
if (engine !== undefined)
|
|
104
119
|
this.#engine = engine;
|
|
120
|
+
if (brand !== undefined)
|
|
121
|
+
this.#brand = brand;
|
|
105
122
|
}
|
|
106
123
|
/** The shell (web/electron/tauri) and rendering engine the SDK reported. Undefined on an older SDK. */
|
|
107
124
|
get runtime() {
|
|
@@ -110,6 +127,10 @@ export class Session {
|
|
|
110
127
|
get engine() {
|
|
111
128
|
return this.#engine;
|
|
112
129
|
}
|
|
130
|
+
/** The browser brand the SDK reported. Absent (never guessed) when the page did not say. */
|
|
131
|
+
get brand() {
|
|
132
|
+
return this.#brand;
|
|
133
|
+
}
|
|
113
134
|
/** Throttled if the tab is hidden OR we have not heard from it recently. */
|
|
114
135
|
throttled() {
|
|
115
136
|
return this.#hidden || this.lastSeenMs() > SESSION_HEALTH.STALE_THRESHOLD_MS;
|
|
@@ -130,29 +151,19 @@ export class Session {
|
|
|
130
151
|
return recommendation === undefined ? base : { ...base, recommendation };
|
|
131
152
|
}
|
|
132
153
|
info() {
|
|
133
|
-
|
|
134
|
-
|
|
154
|
+
return buildSessionInfo({
|
|
155
|
+
id: this.id,
|
|
135
156
|
url: this.url,
|
|
136
|
-
|
|
157
|
+
projectId: this.projectId,
|
|
137
158
|
title: this.title,
|
|
138
159
|
adapters: this.adapters,
|
|
139
160
|
hasCapabilities: this.hasCapabilities,
|
|
161
|
+
versionSkew: this.versionSkew,
|
|
140
162
|
hidden: this.#hidden,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
base.cleanup_suggestion =
|
|
146
|
-
'Call reticle_session{action:"end"} to free this session before starting new work.';
|
|
147
|
-
}
|
|
148
|
-
// Surface human bug reports in reticle_sessions (only when > 0, so a clean session adds nothing).
|
|
149
|
-
const marks = this.#review.pendingCount();
|
|
150
|
-
if (marks > 0) {
|
|
151
|
-
base.pendingMarks = marks;
|
|
152
|
-
const s = marks === 1 ? '' : 's';
|
|
153
|
-
base.review_suggestion = `The human flagged ${String(marks)} issue${s} on this tab — call reticle_session{action:"review"} to see and fix ${marks === 1 ? 'it' : 'them'}.`;
|
|
154
|
-
}
|
|
155
|
-
return base;
|
|
163
|
+
health: () => this.health(),
|
|
164
|
+
staleMs: () => this.staleMs(),
|
|
165
|
+
pendingMarkCount: () => this.#review.pendingCount(),
|
|
166
|
+
});
|
|
156
167
|
}
|
|
157
168
|
/** Wall-clock age of the session in milliseconds. */
|
|
158
169
|
staleMs() {
|
|
@@ -162,7 +173,7 @@ export class Session {
|
|
|
162
173
|
pushEvent(event, byteSize) {
|
|
163
174
|
if (event.type === EventType.PAGE_HEALTH) {
|
|
164
175
|
const r = readHealthEvent(event.data);
|
|
165
|
-
this.applyHealth(r.hidden ?? this.#hidden, r.focused ?? this.#focused, r.runtime, r.engine);
|
|
176
|
+
this.applyHealth(r.hidden ?? this.#hidden, r.focused ?? this.#focused, r.runtime, r.engine, r.brand);
|
|
166
177
|
}
|
|
167
178
|
// The in-page half of Reticle reporting its own failure — recorded like a tool error
|
|
168
179
|
// (fingerprinted, variables stripped) so a broken observer is as visible as a broken tool.
|
|
@@ -188,7 +199,7 @@ export class Session {
|
|
|
188
199
|
// pushState/replaceState/popstate; without this the URL stays frozen at the hello value, and
|
|
189
200
|
// URL-based CDP correlation (real input) silently breaks after the first client-side nav.
|
|
190
201
|
const to = event.data['to'];
|
|
191
|
-
if (typeof to
|
|
202
|
+
if ('string' === typeof to && to.length > 0)
|
|
192
203
|
this.url = to;
|
|
193
204
|
}
|
|
194
205
|
const t = this.elapsed();
|
|
@@ -211,6 +222,35 @@ export class Session {
|
|
|
211
222
|
recordActedRef(ref) {
|
|
212
223
|
this.#observed.recordActedRef(ref);
|
|
213
224
|
}
|
|
225
|
+
actedLabels() {
|
|
226
|
+
return this.#observed.actedLabels();
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Derive the snapshot-shaped label (`button "Deploy"`) from an act reply and remember it.
|
|
230
|
+
*
|
|
231
|
+
* Same shape the interactive snapshot emits, so coverage can match a control the agent drove
|
|
232
|
+
* against the same control after a re-render gave it a different ref.
|
|
233
|
+
*/
|
|
234
|
+
recordActedLabelFrom(result) {
|
|
235
|
+
const payload = result.result;
|
|
236
|
+
if (typeof payload !== 'object' || null === payload)
|
|
237
|
+
return;
|
|
238
|
+
const record = payload;
|
|
239
|
+
// The TESTID first: it is the strongest identity a control has and it survives any re-render.
|
|
240
|
+
// Coverage previously matched only on `role "name"`, so a control with a testid but no accessible
|
|
241
|
+
// name — or on a stack where the act reply carried neither — was unrecognisable after a
|
|
242
|
+
// re-render, and coverage read `exercised: 0` however much work had been done.
|
|
243
|
+
const testid = record['testid'];
|
|
244
|
+
if ('string' === typeof testid && testid.length > 0)
|
|
245
|
+
this.#observed.recordActedLabel(testid);
|
|
246
|
+
const role = record['role'];
|
|
247
|
+
const name = record['name'];
|
|
248
|
+
if (typeof role !== 'string' || typeof name !== 'string')
|
|
249
|
+
return;
|
|
250
|
+
if (0 === role.length || 0 === name.length)
|
|
251
|
+
return;
|
|
252
|
+
this.#observed.recordActedLabel(`${role} "${name}"`);
|
|
253
|
+
}
|
|
214
254
|
actedRefs() {
|
|
215
255
|
return this.#observed.actedRefs();
|
|
216
256
|
}
|
|
@@ -341,7 +381,7 @@ export class Session {
|
|
|
341
381
|
// still wrong, and it made the number depend on which tool the agent happened to use.
|
|
342
382
|
if (name === ReticleCommand.ACT) {
|
|
343
383
|
const ref = args['ref'];
|
|
344
|
-
if (typeof ref
|
|
384
|
+
if ('string' === typeof ref)
|
|
345
385
|
this.recordActedRef(ref);
|
|
346
386
|
}
|
|
347
387
|
const id = this.#pending.nextId(COMMAND_ID_PREFIX);
|
|
@@ -362,7 +402,17 @@ export class Session {
|
|
|
362
402
|
}));
|
|
363
403
|
this.#socket.send(payload);
|
|
364
404
|
const sentAt = Date.now(); // browser-leg timing; see recordBrowserLatency for why it is split out
|
|
365
|
-
|
|
405
|
+
// Traced because this is the boundary that decides whether a slow tool call is OUR overhead or
|
|
406
|
+
// the app taking its time — the split telemetry reports in aggregate, made visible per call.
|
|
407
|
+
return span('browser.command', { command: name, sessionId: this.id }, () => awaited)
|
|
408
|
+
.then((result) => {
|
|
409
|
+
// The label is only knowable from the REPLY — the request carries a ref, and a ref dies with
|
|
410
|
+
// the next re-render. Recorded here so coverage survives frameworks that replace nodes.
|
|
411
|
+
if (name === ReticleCommand.ACT)
|
|
412
|
+
this.recordActedLabelFrom(result);
|
|
413
|
+
return result;
|
|
414
|
+
})
|
|
415
|
+
.finally(() => recordBrowserLatency(Date.now() - sentAt));
|
|
366
416
|
}
|
|
367
417
|
handleResult(result) {
|
|
368
418
|
this.#pending.settle(result);
|
|
@@ -483,7 +533,7 @@ export class Session {
|
|
|
483
533
|
// still wrong, and it made the number depend on which tool the agent happened to use.
|
|
484
534
|
if (name === ReticleCommand.ACT) {
|
|
485
535
|
const ref = args['ref'];
|
|
486
|
-
if (typeof ref
|
|
536
|
+
if ('string' === typeof ref)
|
|
487
537
|
this.recordActedRef(ref);
|
|
488
538
|
}
|
|
489
539
|
const id = this.#pending.nextId(COMMAND_ID_PREFIX);
|
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
* without paying the truncation tax); the server re-exports it for its back-compat fallback path
|
|
5
5
|
* (an older browser that returns the whole store) and for the predicate engine's `state` assertion.
|
|
6
6
|
*/
|
|
7
|
-
export { selectPath, capDepth, type PathSelection } from '@reticlehq/core';
|
|
7
|
+
export { selectPath, capDepth, projectComponentState, type PathSelection } from '@reticlehq/core';
|
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
* without paying the truncation tax); the server re-exports it for its back-compat fallback path
|
|
5
5
|
* (an older browser that returns the whole store) and for the predicate engine's `state` assertion.
|
|
6
6
|
*/
|
|
7
|
-
export { selectPath, capDepth } from '@reticlehq/core';
|
|
7
|
+
export { selectPath, capDepth, projectComponentState } from '@reticlehq/core';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `GET /status` answers — the daemon describing itself.
|
|
3
|
+
*
|
|
4
|
+
* Carries the daemon's OWN version, because a daemon outlives every agent attached to it: after an
|
|
5
|
+
* upgrade the new CLI attaches to the old daemon and serves its code, and until this field existed
|
|
6
|
+
* there was no surface anywhere — not /status, not `reticle status` — naming the version actually
|
|
7
|
+
* answering requests. See describeDaemonSkew.
|
|
8
|
+
*/
|
|
9
|
+
import type { SessionInfo } from './session/session-info.js';
|
|
10
|
+
interface StatusPayload {
|
|
11
|
+
running: true;
|
|
12
|
+
version: string;
|
|
13
|
+
/** The wire contract this daemon speaks — what another process compares against, not the version. */
|
|
14
|
+
contract: string;
|
|
15
|
+
sessionCount: number;
|
|
16
|
+
sessions: SessionInfo[];
|
|
17
|
+
}
|
|
18
|
+
export declare function statusPayload(sessionCount: number, sessions: SessionInfo[]): StatusPayload;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CONTRACT_FINGERPRINT } from '@reticlehq/core';
|
|
2
|
+
import { SERVER_VERSION } from './version/server-version.js';
|
|
3
|
+
export function statusPayload(sessionCount, sessions) {
|
|
4
|
+
return {
|
|
5
|
+
running: true,
|
|
6
|
+
version: SERVER_VERSION,
|
|
7
|
+
contract: CONTRACT_FINGERPRINT,
|
|
8
|
+
sessionCount,
|
|
9
|
+
sessions,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -57,10 +57,19 @@ export function describeParam(name, value) {
|
|
|
57
57
|
return name;
|
|
58
58
|
return `${name}:${allowed.has(value) ? value : OTHER_VALUE}`;
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Parameters that carry no information about how the tool is USED, and so are not counted.
|
|
62
|
+
*
|
|
63
|
+
* `sessionId` is accepted by nearly every tool and passed on nearly every call, so counting it
|
|
64
|
+
* produced a row per tool saying only "the agent addressed a session" — in one real day's export it
|
|
65
|
+
* was a third of the toolParams block. This histogram exists to answer "is anyone using the argument
|
|
66
|
+
* we shipped last release", and a parameter every call carries can never answer it.
|
|
67
|
+
*/
|
|
68
|
+
const UNINFORMATIVE_PARAMS = new Set(['sessionId']);
|
|
60
69
|
/** Every parameter an agent actually passed to one tool call, reduced to names (+ safe enums). */
|
|
61
70
|
export function describeToolParams(args) {
|
|
62
71
|
return Object.keys(args)
|
|
63
|
-
.filter((key) => args[key] !== undefined)
|
|
72
|
+
.filter((key) => args[key] !== undefined && !UNINFORMATIVE_PARAMS.has(key))
|
|
64
73
|
.map((key) => describeParam(key, args[key]))
|
|
65
74
|
.sort();
|
|
66
75
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Was this verification watched by a person, or run by a machine?
|
|
3
|
+
*
|
|
4
|
+
* A verification's cost and its meaning both depend on it. A headless run is CI or an unattended
|
|
5
|
+
* agent loop — it should be fast, and there is nobody to notice a wrong answer. A headed run has a
|
|
6
|
+
* human in front of it. And the most common case of all is neither: the SDK in somebody's own dev
|
|
7
|
+
* server, in their own browser, which Reticle never launched at all.
|
|
8
|
+
*
|
|
9
|
+
* Recorded once at daemon start, because that is when the decision is made and it does not change
|
|
10
|
+
* for the daemon's life. Defaults to ATTACHED, which is the honest answer when Reticle launched
|
|
11
|
+
* nothing: claiming "headless" for a browser we did not open would be a guess about somebody's
|
|
12
|
+
* machine.
|
|
13
|
+
*/
|
|
14
|
+
export declare const BrowserMode: {
|
|
15
|
+
/** Reticle launched the browser with no display — CI, or an unattended agent loop. */
|
|
16
|
+
readonly HEADLESS: "headless";
|
|
17
|
+
/** Reticle launched a visible browser — a human is watching. */
|
|
18
|
+
readonly HEADED: "headed";
|
|
19
|
+
/** Reticle launched nothing: the SDK connected from a browser somebody else opened. */
|
|
20
|
+
readonly ATTACHED: "attached";
|
|
21
|
+
};
|
|
22
|
+
export type BrowserMode = (typeof BrowserMode)[keyof typeof BrowserMode];
|
|
23
|
+
/** Record how this daemon drives a browser. Called once, at start. */
|
|
24
|
+
export declare function setBrowserMode(mode: BrowserMode): void;
|
|
25
|
+
export declare function getBrowserMode(): BrowserMode;
|
|
26
|
+
/** Tests only — restore the default so cases do not leak into each other. */
|
|
27
|
+
export declare function resetBrowserMode(): void;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Was this verification watched by a person, or run by a machine?
|
|
3
|
+
*
|
|
4
|
+
* A verification's cost and its meaning both depend on it. A headless run is CI or an unattended
|
|
5
|
+
* agent loop — it should be fast, and there is nobody to notice a wrong answer. A headed run has a
|
|
6
|
+
* human in front of it. And the most common case of all is neither: the SDK in somebody's own dev
|
|
7
|
+
* server, in their own browser, which Reticle never launched at all.
|
|
8
|
+
*
|
|
9
|
+
* Recorded once at daemon start, because that is when the decision is made and it does not change
|
|
10
|
+
* for the daemon's life. Defaults to ATTACHED, which is the honest answer when Reticle launched
|
|
11
|
+
* nothing: claiming "headless" for a browser we did not open would be a guess about somebody's
|
|
12
|
+
* machine.
|
|
13
|
+
*/
|
|
14
|
+
export const BrowserMode = {
|
|
15
|
+
/** Reticle launched the browser with no display — CI, or an unattended agent loop. */
|
|
16
|
+
HEADLESS: 'headless',
|
|
17
|
+
/** Reticle launched a visible browser — a human is watching. */
|
|
18
|
+
HEADED: 'headed',
|
|
19
|
+
/** Reticle launched nothing: the SDK connected from a browser somebody else opened. */
|
|
20
|
+
ATTACHED: 'attached',
|
|
21
|
+
};
|
|
22
|
+
let current = BrowserMode.ATTACHED;
|
|
23
|
+
/** Record how this daemon drives a browser. Called once, at start. */
|
|
24
|
+
export function setBrowserMode(mode) {
|
|
25
|
+
current = mode;
|
|
26
|
+
}
|
|
27
|
+
export function getBrowserMode() {
|
|
28
|
+
return current;
|
|
29
|
+
}
|
|
30
|
+
/** Tests only — restore the default so cases do not leak into each other. */
|
|
31
|
+
export function resetBrowserMode() {
|
|
32
|
+
current = BrowserMode.ATTACHED;
|
|
33
|
+
}
|
|
@@ -1,20 +1,3 @@
|
|
|
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
1
|
import { type BugFound } from '@reticlehq/core';
|
|
19
2
|
/**
|
|
20
3
|
* A defect as the CLASSIFIER sees it — everything except `repeat`.
|
|
@@ -24,10 +7,23 @@ import { type BugFound } from '@reticlehq/core';
|
|
|
24
7
|
*/
|
|
25
8
|
export type BugCandidate = Omit<BugFound, 'repeat'>;
|
|
26
9
|
/**
|
|
27
|
-
*
|
|
10
|
+
* `bug.attribution` was REMOVED, deliberately, and this note is here so it is not re-added casually.
|
|
11
|
+
*
|
|
12
|
+
* It shipped twice and was wrong both times. First it stamped `app` on every contradiction, including
|
|
13
|
+
* `request-never-settled` — which Reticle raises from the ABSENCE of a settle event, so a dev-overlay
|
|
14
|
+
* poll manufactured it with the app doing nothing wrong. That was fixed, and a real drive then found
|
|
15
|
+
* it still inverted: across two full runs, EVERY `attribution: 'app'` was a misattribution, while the
|
|
16
|
+
* one defect that genuinely was a bad agent predicate carried none. One session would have published
|
|
17
|
+
* "2 defects in the app" against a true count of 0.
|
|
18
|
+
*
|
|
19
|
+
* A metric that is confidently wrong about WHOSE fault a defect is, is worse than no metric: it is
|
|
20
|
+
* the number a founder steers on, and it points at the customer. Counting nothing is recoverable;
|
|
21
|
+
* publishing a false accusation about somebody's product is not.
|
|
28
22
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
23
|
+
* Bringing it back needs evidence that actually separates the cases. It does not exist in the payload
|
|
24
|
+
* today: `element.present` covers "the button is missing", "the API is down" and "the agent mistyped
|
|
25
|
+
* a testid" identically, and `signal.absent` covers both a signal the app never fired and a ref
|
|
26
|
+
* Reticle drove into nothing. Until a verdict carries the reason it came out that way, the honest
|
|
27
|
+
* output is no owner at all.
|
|
32
28
|
*/
|
|
33
29
|
export declare function bugsInResult(toolName: string, result: Record<string, unknown>): BugCandidate[];
|