@reticlehq/server 3.2.0 → 3.4.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/LICENSE-ENTERPRISE +1 -1
- package/README.md +3 -3
- package/SKILL.md +23 -22
- package/dist/chromium-launch-options.d.ts +4 -3
- package/dist/chromium-launch-options.js +6 -2
- package/dist/command/cli/adhoc-suite.d.ts +41 -0
- package/dist/command/cli/adhoc-suite.js +159 -0
- package/dist/command/cli/adhoc-verdict.d.ts +58 -2
- package/dist/command/cli/adhoc-verdict.js +108 -13
- package/dist/command/cli/answers/gate-hook-message.d.ts +6 -0
- package/dist/command/cli/answers/gate-hook-message.js +6 -0
- package/dist/command/cli/auth/cloud-keystore.d.ts +0 -2
- package/dist/command/cli/auth/cloud-keystore.js +0 -3
- package/dist/command/cli/auth/cloud-session.d.ts +4 -0
- package/dist/command/cli/auth/cloud-session.js +2 -0
- package/dist/command/cli/cli-doctor.js +30 -8
- package/dist/command/cli/cli-flow-commands.d.ts +3 -6
- package/dist/command/cli/cli-flow-commands.js +67 -4
- package/dist/command/cli/cli-parse-grammar.d.ts +7 -0
- package/dist/command/cli/cli-parse-grammar.js +7 -0
- package/dist/command/cli/cli-parse-verify.d.ts +2 -5
- package/dist/command/cli/cli-parse-verify.js +86 -13
- package/dist/command/cli/cli-parse.d.ts +14 -1
- package/dist/command/cli/cli-parse.js +54 -8
- package/dist/command/cli/cli-update-commands.js +8 -1
- package/dist/command/cli/cli-verify.d.ts +80 -0
- package/dist/command/cli/cli-verify.js +181 -26
- package/dist/command/cli/cloud-cli.js +5 -2
- package/dist/command/cli/cloud-kit.d.ts +0 -2
- package/dist/command/cli/cloud-kit.js +3 -5
- package/dist/command/cli/cloud-login.js +21 -3
- package/dist/command/cli/demo/demo-page.js +6 -3
- package/dist/command/cli/doctor/browser/chromium-hint.d.ts +5 -0
- package/dist/command/cli/doctor/browser/chromium-hint.js +5 -0
- package/dist/command/cli/doctor/doctor-sessions-line.d.ts +2 -1
- package/dist/command/cli/launch/cli-launch.d.ts +9 -29
- package/dist/command/cli/launch/cli-launch.js +27 -49
- package/dist/command/cli/launch/sdk-version-match.d.ts +84 -0
- package/dist/command/cli/launch/sdk-version-match.js +206 -0
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +2 -16
- package/dist/command/cli/ports/resolve/cli-port.d.ts +38 -0
- package/dist/command/cli/ports/resolve/cli-port.js +169 -15
- package/dist/command/cli/report-command.d.ts +16 -0
- package/dist/command/cli/report-command.js +97 -0
- package/dist/command/cli/setup-mcp-cli.js +13 -13
- package/dist/command/cli/tutorial.d.ts +2 -2
- package/dist/command/cli/tutorial.js +21 -7
- package/dist/command/cli.js +67 -10
- package/dist/command/daemon/binding/daemon-status-probe.d.ts +44 -2
- package/dist/command/daemon/binding/daemon-status-probe.js +79 -6
- package/dist/command/daemon/binding/port-presence.d.ts +1 -1
- package/dist/command/daemon/daemon-resolve.d.ts +9 -0
- package/dist/command/daemon/daemon-resolve.js +1 -1
- package/dist/command/daemon/idle-shutdown.d.ts +2 -1
- package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +7 -1
- package/dist/command/daemon/lifetime/daemon-usefulness.js +30 -7
- package/dist/command/dev/stale-issue-guard.d.ts +3 -4
- package/dist/command/dev/stale-issue-guard.js +8 -8
- package/dist/command/setup/bringup/connect-lease.d.ts +17 -0
- package/dist/command/setup/bringup/connect-lease.js +38 -0
- package/dist/command/setup/bringup/dev-server-files.d.ts +68 -0
- package/dist/command/setup/bringup/dev-server-files.js +131 -0
- package/dist/command/setup/bringup/dev-server-log-cap.d.ts +35 -0
- package/dist/command/setup/bringup/dev-server-log-cap.js +121 -0
- package/dist/command/setup/bringup/ensure-daemon.d.ts +65 -4
- package/dist/command/setup/bringup/ensure-daemon.js +135 -16
- package/dist/command/setup/bringup/static-page-server.d.ts +35 -0
- package/dist/command/setup/bringup/static-page-server.js +151 -0
- package/dist/command/setup/desktop-shape.d.ts +4 -0
- package/dist/command/setup/desktop-shape.js +18 -2
- package/dist/command/setup/init/init-host.js +8 -0
- package/dist/command/setup/init/init-port.d.ts +15 -0
- package/dist/command/setup/init/init-port.js +44 -0
- package/dist/command/setup/init/init-runtime.d.ts +1 -1
- package/dist/command/setup/init/init-runtime.js +39 -2
- package/dist/command/setup/node-effects.d.ts +27 -14
- package/dist/command/setup/node-effects.js +80 -44
- package/dist/command/setup/probe/loopback-probe-urls.d.ts +7 -0
- package/dist/command/setup/probe/loopback-probe-urls.js +40 -0
- package/dist/command/setup/probe/page-probe.d.ts +13 -2
- package/dist/command/setup/probe/page-probe.js +18 -3
- package/dist/command/setup/run-setup.d.ts +26 -1
- package/dist/command/setup/run-setup.js +96 -13
- package/dist/command/setup/session-pick.d.ts +13 -0
- package/dist/command/setup/session-pick.js +20 -0
- package/dist/command/setup/setup-command.d.ts +2 -14
- package/dist/command/setup/setup-command.js +105 -31
- package/dist/command/setup/setup-mcp.js +3 -3
- package/dist/command/setup/terminal/wait-progress.d.ts +8 -0
- package/dist/command/setup/terminal/wait-progress.js +17 -0
- package/dist/features/crawl/crawl-empty.js +1 -1
- package/dist/features/crawl/crawl-tools.d.ts +6 -0
- package/dist/features/crawl/crawl-tools.js +57 -0
- package/dist/features/crawl/crawl.d.ts +2 -0
- package/dist/features/crawl/crawl.js +171 -156
- package/dist/features/exhaust/app-coverage.d.ts +33 -0
- package/dist/features/exhaust/app-coverage.js +31 -0
- package/dist/features/exhaust/code-coverage.d.ts +47 -0
- package/dist/features/exhaust/code-coverage.js +77 -0
- package/dist/features/exhaust/exhaust-run.d.ts +33 -0
- package/dist/features/exhaust/exhaust-run.js +82 -0
- package/dist/features/exhaust/explorer.d.ts +103 -0
- package/dist/features/exhaust/explorer.js +195 -0
- package/dist/features/exhaust/failure-branches.d.ts +33 -0
- package/dist/features/exhaust/failure-branches.js +92 -0
- package/dist/features/exhaust/ledger.d.ts +202 -0
- package/dist/features/exhaust/ledger.js +252 -0
- package/dist/features/exhaust/session-fold.d.ts +31 -0
- package/dist/features/exhaust/session-fold.js +79 -0
- package/dist/features/exhaust/session-port.d.ts +36 -0
- package/dist/features/exhaust/session-port.js +102 -0
- package/dist/features/harness/drive-report.d.ts +0 -9
- package/dist/features/harness/drive-report.js +18 -0
- package/dist/features/harness/driver.js +4 -7
- package/dist/features/harness/fill-values.d.ts +6 -0
- package/dist/features/harness/fill-values.js +3 -0
- package/dist/features/harness/jev-driver.js +36 -22
- package/dist/features/harness/openai-driver.js +4 -7
- package/dist/features/harness/platform-config.d.ts +10 -0
- package/dist/features/harness/platform-config.js +13 -6
- package/dist/index.d.ts +10 -1
- package/dist/index.js +78 -104
- package/dist/judgement/capsule/capsule-store.d.ts +31 -2
- package/dist/judgement/capsule/capsule-store.js +58 -6
- package/dist/judgement/capsule/capsule.js +5 -0
- package/dist/judgement/capsule/causal-summary.d.ts +13 -1
- package/dist/judgement/capsule/causal-summary.js +7 -0
- package/dist/judgement/domain/domain-model.js +40 -9
- package/dist/judgement/oracles/self-instrument.js +4 -2
- package/dist/judgement/outcome/assertion-integrity.d.ts +3 -3
- package/dist/judgement/runs/artifact/gap-report.d.ts +17 -0
- package/dist/judgement/runs/artifact/gap-report.js +46 -0
- package/dist/judgement/runs/artifact/gap-summary.d.ts +58 -0
- package/dist/judgement/runs/artifact/gap-summary.js +85 -0
- package/dist/judgement/runs/artifact/render-report.js +4 -1
- package/dist/judgement/runs/artifact/replay-mapping.d.ts +2 -2
- package/dist/judgement/runs/artifact/replay-mapping.js +44 -9
- package/dist/judgement/runs/artifact/to-artifact.d.ts +7 -2
- package/dist/judgement/runs/artifact/to-artifact.js +1 -1
- package/dist/judgement/runs/context-tools.js +21 -3
- package/dist/judgement/runs/drive-run.js +7 -2
- package/dist/judgement/runs/verification-sync.d.ts +3 -1
- package/dist/judgement/runs/verification-sync.js +1 -1
- package/dist/language/flows/annotate-notes/annotate.d.ts +0 -15
- package/dist/language/flows/annotate-notes/annotate.js +66 -18
- package/dist/language/flows/change/affected.d.ts +9 -0
- package/dist/language/flows/change/affected.js +35 -0
- package/dist/language/flows/change/gate.d.ts +20 -0
- package/dist/language/flows/change/gate.js +12 -1
- package/dist/language/flows/flow-anchor.d.ts +12 -0
- package/dist/language/flows/flow-anchor.js +20 -0
- package/dist/language/flows/flow-author.d.ts +7 -0
- package/dist/language/flows/flow-author.js +19 -0
- package/dist/language/flows/flow-expect-grammar.d.ts +2 -2
- package/dist/language/flows/flow-expect-grammar.js +92 -11
- package/dist/language/flows/flow-intent.js +1 -1
- package/dist/language/flows/flow-journey.d.ts +54 -0
- package/dist/language/flows/flow-journey.js +119 -0
- package/dist/language/flows/flow-learning.d.ts +3 -0
- package/dist/language/flows/flow-learning.js +39 -8
- package/dist/language/flows/flow-replay-run.d.ts +33 -12
- package/dist/language/flows/flow-replay-run.js +131 -52
- package/dist/language/flows/flow-replay-types.d.ts +9 -0
- package/dist/language/flows/flow-replay.d.ts +27 -12
- package/dist/language/flows/flow-replay.js +127 -111
- package/dist/language/flows/flow-result.d.ts +2 -0
- package/dist/language/flows/flow-result.js +25 -0
- package/dist/language/flows/flow-step-runners.d.ts +26 -10
- package/dist/language/flows/flow-step-runners.js +20 -4
- package/dist/language/flows/flow-success.d.ts +21 -6
- package/dist/language/flows/flow-success.js +50 -138
- package/dist/language/flows/flow-tools.js +17 -5
- package/dist/language/flows/flows.d.ts +18 -5
- package/dist/language/flows/flows.js +101 -16
- package/dist/language/flows/heal.d.ts +9 -1
- package/dist/language/flows/heal.js +24 -2
- package/dist/language/flows/learned-sources.d.ts +21 -0
- package/dist/language/flows/learned-sources.js +84 -0
- package/dist/language/flows/recording/recording-backtrack.d.ts +0 -7
- package/dist/language/flows/recording/recording-backtrack.js +1 -1
- package/dist/language/flows/recording/replay-halt.d.ts +2 -1
- package/dist/language/flows/recording/replay-halt.js +3 -1
- package/dist/language/flows/recording/tape/recordings.d.ts +31 -2
- package/dist/language/flows/recording/tape/recordings.js +55 -1
- package/dist/language/flows/replay.d.ts +19 -0
- package/dist/language/flows/replay.js +53 -13
- package/dist/language/flows/stores/annotation-store.d.ts +5 -5
- package/dist/language/flows/stores/assertion-tiers-store.js +2 -3
- package/dist/language/flows/stores/flake-store.js +2 -3
- package/dist/language/flows/suite/coverage.d.ts +1 -1
- package/dist/language/flows/suite/parallel-suite.d.ts +2 -1
- package/dist/language/flows/verify-change-tools.js +19 -2
- package/dist/launch-chromium.d.ts +80 -0
- package/dist/launch-chromium.js +218 -0
- package/dist/memory/cloud/cloud-config.d.ts +11 -2
- package/dist/memory/cloud/cloud-config.js +47 -7
- package/dist/memory/cloud/cloud-sync.d.ts +4 -3
- package/dist/memory/cloud/cloud-sync.js +7 -10
- package/dist/memory/cloud/harness-config.d.ts +2 -0
- package/dist/memory/cloud/harness-offer.js +5 -6
- package/dist/memory/cloud/harness-switch.js +5 -6
- package/dist/memory/cloud/sync-cycle.d.ts +78 -1
- package/dist/memory/cloud/sync-cycle.js +321 -53
- package/dist/memory/cloud/sync-daemon.d.ts +13 -0
- package/dist/memory/cloud/sync-daemon.js +45 -20
- package/dist/memory/cloud/sync-disk.js +27 -8
- package/dist/memory/impact/impact-store.js +6 -0
- package/dist/memory/intent/inline-intent.js +8 -3
- package/dist/memory/intent/intent-shard-store.d.ts +33 -47
- package/dist/memory/intent/intent-shard-store.js +252 -140
- package/dist/memory/intent/intent-shard.d.ts +0 -23
- package/dist/memory/intent/intent-shard.js +1 -11
- package/dist/memory/intent/intent-store.d.ts +13 -8
- package/dist/memory/intent/intent-store.js +46 -90
- package/dist/memory/intent/intent-tools.js +34 -23
- package/dist/memory/journal/ambient-store.js +2 -3
- package/dist/memory/journal/deviation-report.js +4 -1
- package/dist/memory/journal/deviation-service.js +10 -2
- package/dist/memory/journal/drive-flow.d.ts +19 -14
- package/dist/memory/journal/drive-flow.js +65 -48
- package/dist/memory/journal/envelope-store.js +2 -3
- package/dist/memory/journal/journal-recorder.d.ts +21 -0
- package/dist/memory/journal/on-disk/retain-policy.d.ts +34 -0
- package/dist/memory/journal/on-disk/retain-policy.js +44 -0
- package/dist/memory/journal/on-disk/retention.d.ts +14 -10
- package/dist/memory/journal/on-disk/retention.js +13 -12
- package/dist/memory/journal/on-disk/startup-maintenance.d.ts +42 -0
- package/dist/memory/journal/on-disk/startup-maintenance.js +14 -0
- package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +0 -11
- package/dist/memory/journal/on-disk/workspace-gitignore.js +6 -45
- package/dist/memory/journal/on-disk/workspace-tiers.d.ts +52 -0
- package/dist/memory/journal/on-disk/workspace-tiers.js +90 -0
- package/dist/memory/journal/route-template.d.ts +22 -0
- package/dist/memory/journal/route-template.js +44 -0
- package/dist/memory/journal/session-end.d.ts +13 -2
- package/dist/memory/journal/session-end.js +88 -18
- package/dist/memory/journal/session-journal.d.ts +8 -1
- package/dist/memory/journal/session-journal.js +10 -0
- package/dist/memory/project/baselines.d.ts +1 -1
- package/dist/memory/project/dir/reticle-dir.d.ts +3 -1
- package/dist/memory/project/dir/reticle-dir.js +1 -0
- package/dist/memory/project/fs/fs-port.js +44 -5
- package/dist/memory/project/fs/write-atomic.d.ts +26 -0
- package/dist/memory/project/fs/write-atomic.js +48 -0
- package/dist/memory/project/project-tools.js +3 -1
- package/dist/memory/recall/prior/connection-memory.d.ts +6 -0
- package/dist/memory/recall/prior/connection-memory.js +8 -0
- package/dist/memory/recall/registered-projects.d.ts +2 -1
- package/dist/portal/bridge/auth-failure-reason.d.ts +1 -1
- package/dist/portal/bridge/auth-failure-reason.js +9 -4
- package/dist/portal/bridge/bridge.d.ts +8 -0
- package/dist/portal/bridge/bridge.js +43 -2
- package/dist/portal/input/js-coverage.d.ts +25 -0
- package/dist/portal/input/js-coverage.js +30 -0
- package/dist/portal/input/real-input.d.ts +11 -0
- package/dist/portal/input/real-input.js +31 -5
- package/dist/portal/pool/browser-pool.d.ts +10 -0
- package/dist/portal/pool/browser-pool.js +10 -0
- package/dist/portal/pool/playwright-launcher.d.ts +6 -0
- package/dist/portal/pool/playwright-launcher.js +21 -13
- package/dist/portal/pool/pool-contract.d.ts +2 -0
- package/dist/portal/pool/storage-seed.d.ts +2 -1
- package/dist/portal/pool/zero-install.d.ts +27 -0
- package/dist/portal/pool/zero-install.js +54 -0
- package/dist/portal/realm/web-realm.js +6 -0
- package/dist/portal/session/dev-server/dev-command.d.ts +2 -2
- package/dist/portal/session/dev-server/dev-command.js +30 -12
- package/dist/portal/session/dev-server/dev-server-probe.d.ts +2 -1
- package/dist/portal/session/dev-server/dev-server-probe.js +17 -1
- package/dist/portal/session/dev-server/route-status-probe.d.ts +24 -0
- package/dist/portal/session/dev-server/route-status-probe.js +57 -0
- package/dist/portal/session/dev-server/served-document.d.ts +21 -0
- package/dist/portal/session/dev-server/served-document.js +57 -0
- package/dist/portal/session/facts/background-traffic.d.ts +9 -0
- package/dist/portal/session/facts/background-traffic.js +25 -0
- package/dist/portal/session/facts/observed-state.d.ts +11 -0
- package/dist/portal/session/facts/observed-state.js +34 -0
- package/dist/portal/session/live-control-tools.js +48 -3
- package/dist/portal/session/no-session-diagnosis.d.ts +29 -0
- package/dist/portal/session/no-session-diagnosis.js +62 -5
- package/dist/portal/session/no-session-next-action.d.ts +13 -0
- package/dist/portal/session/no-session-next-action.js +48 -9
- package/dist/portal/session/no-session-watch.d.ts +18 -0
- package/dist/portal/session/no-session-watch.js +88 -2
- package/dist/portal/session/presence/attachment-history.d.ts +13 -2
- package/dist/portal/session/session-health.d.ts +61 -0
- package/dist/portal/session/session-health.js +43 -3
- package/dist/portal/session/session-info.d.ts +6 -0
- package/dist/portal/session/session-manager.d.ts +29 -6
- package/dist/portal/session/session-manager.js +42 -5
- package/dist/portal/session/session-reaper.d.ts +28 -0
- package/dist/portal/session/session-reaper.js +49 -1
- package/dist/portal/session/session-successor.d.ts +11 -0
- package/dist/portal/session/session-successor.js +14 -1
- package/dist/portal/session/session-verdict-facts.d.ts +28 -0
- package/dist/portal/session/session-verdict-facts.js +15 -0
- package/dist/portal/session/session.d.ts +10 -0
- package/dist/portal/session/session.js +34 -26
- package/dist/surface/http-server.d.ts +2 -1
- package/dist/surface/http-server.js +4 -2
- package/dist/surface/mcp/mcp-proxy.d.ts +2 -2
- package/dist/surface/mcp/mcp-proxy.js +5 -5
- package/dist/surface/mcp/mcp.js +4 -2
- package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +13 -1
- package/dist/surface/mcp/proxy/proxy-daemon-probe.js +27 -2
- package/dist/surface/mcp/proxy-idle-exit.d.ts +2 -1
- package/dist/surface/mcp/server-instructions.js +21 -8
- package/dist/surface/tools/act/after-match.d.ts +17 -0
- package/dist/surface/tools/act/after-match.js +30 -0
- package/dist/surface/tools/act/already-true.d.ts +40 -0
- package/dist/surface/tools/act/already-true.js +36 -0
- package/dist/surface/tools/act/durable.d.ts +69 -0
- package/dist/surface/tools/act/durable.js +139 -0
- package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +19 -6
- package/dist/surface/tools/act/navigation/navigate-arrival.js +60 -10
- package/dist/surface/tools/act/navigation/navigate-result.d.ts +1 -12
- package/dist/surface/tools/act/navigation/navigate-result.js +21 -3
- package/dist/surface/tools/act/proved-controls.d.ts +9 -0
- package/dist/surface/tools/act/proved-controls.js +11 -0
- package/dist/surface/tools/act/sequence-grade.d.ts +5 -0
- package/dist/surface/tools/act/sequence-grade.js +32 -1
- package/dist/surface/tools/act/settle-in-flight.d.ts +6 -2
- package/dist/surface/tools/act/settle-in-flight.js +29 -6
- package/dist/surface/tools/act-capsule.d.ts +7 -0
- package/dist/surface/tools/act-capsule.js +68 -8
- package/dist/surface/tools/act-sequence-tool.js +25 -8
- package/dist/surface/tools/act-tools.js +51 -74
- package/dist/surface/tools/args/numeric-bounds.d.ts +15 -2
- package/dist/surface/tools/args/numeric-bounds.js +30 -3
- package/dist/surface/tools/assert/assert-grade.js +26 -3
- package/dist/surface/tools/assert/assert-verdict.js +32 -6
- package/dist/surface/tools/browser-tools.js +17 -4
- package/dist/surface/tools/coverage-tools.js +27 -1
- package/dist/surface/tools/dynamic-tools.js +6 -0
- package/dist/surface/tools/error-recovery.js +4 -4
- package/dist/surface/tools/feedback-invite.js +6 -4
- package/dist/surface/tools/feedback-tools.d.ts +2 -1
- package/dist/surface/tools/feedback-tools.js +1 -1
- package/dist/surface/tools/harness-explore.d.ts +3 -2
- package/dist/surface/tools/harness-explore.js +7 -6
- package/dist/surface/tools/invoke-tool.js +17 -4
- package/dist/surface/tools/lease-hint.d.ts +8 -0
- package/dist/surface/tools/lease-hint.js +10 -0
- package/dist/surface/tools/lease-tools.d.ts +16 -28
- package/dist/surface/tools/lease-tools.js +68 -11
- package/dist/surface/tools/lineage-tools.js +1 -1
- package/dist/surface/tools/live-call-text.js +4 -1
- package/dist/surface/tools/observe-tools.js +23 -7
- package/dist/surface/tools/real-input-attempt.d.ts +0 -5
- package/dist/surface/tools/real-input-attempt.js +1 -1
- package/dist/surface/tools/tool-kit.d.ts +5 -0
- package/dist/surface/tools/tool-kit.js +6 -1
- package/dist/surface/tools/tool-surface.js +17 -5
- package/dist/surface/tools/tools.js +68 -29
- package/dist/telemetry/argument-shape.d.ts +0 -2
- package/dist/telemetry/argument-shape.js +0 -4
- package/dist/telemetry/error-class.d.ts +2 -3
- package/dist/telemetry/error-class.js +2 -3
- package/dist/telemetry/feedback-local.d.ts +1 -0
- package/dist/telemetry/feedback-local.js +1 -3
- package/dist/telemetry/feedback.d.ts +1 -1
- package/dist/telemetry/harness-drive.d.ts +0 -2
- package/dist/telemetry/harness-drive.js +0 -4
- package/dist/telemetry/hud-metrics.d.ts +32 -0
- package/dist/telemetry/hud-metrics.js +95 -0
- package/dist/telemetry/session-metrics.d.ts +5 -0
- package/dist/telemetry/session-metrics.js +15 -1
- package/dist/wire-journal.d.ts +34 -0
- package/dist/wire-journal.js +104 -0
- package/dist/workspace-packages.d.ts +0 -2
- package/dist/workspace-packages.js +1 -9
- package/docs/README.md +5 -2
- package/docs/actions.mdx +3 -3
- package/docs/agent-cheatsheet.md +4 -4
- package/docs/architecture.md +6 -6
- package/docs/best-practices.mdx +1 -1
- package/docs/capabilities.mdx +32 -1
- package/docs/cli/cloud.mdx +21 -9
- package/docs/cli/doctor.mdx +4 -0
- package/docs/cli/feedback.mdx +2 -2
- package/docs/cli/gate.mdx +9 -4
- package/docs/cli/init.mdx +1 -0
- package/docs/cli/report.mdx +44 -0
- package/docs/cli/update.mdx +10 -0
- package/docs/cli.mdx +9 -0
- package/docs/desktop.mdx +14 -10
- package/docs/environment.mdx +87 -0
- package/docs/faq.mdx +18 -16
- package/docs/first-drive.md +5 -13
- package/docs/flows.md +32 -2
- package/docs/frameworks.mdx +140 -9
- package/docs/getting-started.md +3 -3
- package/docs/http-transport.md +6 -3
- package/docs/human-control.md +2 -2
- package/docs/index.mdx +16 -6
- package/docs/install-agentic.mdx +37 -1
- package/docs/install-manual.mdx +1 -1
- package/docs/integration-patterns.md +3 -3
- package/docs/multi-agent-testing.md +1 -1
- package/docs/packages/babel-plugin.mdx +1 -1
- package/docs/packages/browser.mdx +2 -2
- package/docs/packages/react.mdx +2 -2
- package/docs/packages/tauri.mdx +1 -1
- package/docs/packages/vite-plugin.mdx +2 -2
- package/docs/packages.mdx +9 -9
- package/docs/predicates.mdx +176 -7
- package/docs/quickstart.mdx +2 -2
- package/docs/recipes.mdx +2 -2
- package/docs/state-management.mdx +2 -2
- package/docs/system-map.md +1 -1
- package/docs/telemetry.md +1 -1
- package/docs/token-efficiency.md +3 -3
- package/docs/tools/act-and-wait.mdx +1 -0
- package/docs/tools/act-sequence.mdx +1 -1
- package/docs/tools/console.mdx +1 -1
- package/docs/tools/inspect.mdx +1 -1
- package/docs/tools/network.mdx +1 -1
- package/docs/tools/query.mdx +11 -11
- package/docs/tools/sessions.mdx +1 -1
- package/docs/tools/snapshot.mdx +1 -1
- package/docs/tools/state.mdx +1 -1
- package/docs/tools/wait-for.mdx +1 -1
- package/docs/usage.md +8 -7
- package/docs/use-cases.mdx +157 -0
- package/docs/vs-screenshots.mdx +3 -3
- package/docs/what-is-recorded.md +62 -0
- package/docs/what-is-reticle.mdx +17 -20
- package/docs/why-reticle.mdx +14 -21
- package/package.json +11 -10
- package/dist/judgement/capsule/minimize.d.ts +0 -12
- package/dist/judgement/capsule/minimize.js +0 -22
- package/dist/judgement/outcome/predicate-to-expect.d.ts +0 -44
- package/dist/judgement/outcome/predicate-to-expect.js +0 -148
- package/dist/judgement/phenomena/phenomena.d.ts +0 -26
- package/dist/judgement/phenomena/phenomena.js +0 -101
- package/dist/language/flows/flow-report.d.ts +0 -22
- package/dist/language/flows/flow-report.js +0 -106
|
@@ -3,23 +3,8 @@ import { aliasParam } from './args/alias-args.js';
|
|
|
3
3
|
import { resolveSessionWithin } from '../../portal/session/timing/resolve-within.js';
|
|
4
4
|
import { WALL_CLOCK } from '../../portal/session/timing/wall-clock.js';
|
|
5
5
|
import { timeoutMsSchema } from './args/numeric-bounds.js';
|
|
6
|
-
import { captureAct } from '../../language/flows/replay.js';
|
|
7
|
-
|
|
8
|
-
* The pathname of a session's live url, or undefined when it has none yet.
|
|
9
|
-
*
|
|
10
|
-
* Pathname rather than the whole url, because that is what `startPath` is compared against and what
|
|
11
|
-
* a hash-routed app makes meaningless in the document location — see routeOfEvent.
|
|
12
|
-
*/
|
|
13
|
-
function pathOf(url) {
|
|
14
|
-
if (url === undefined)
|
|
15
|
-
return undefined;
|
|
16
|
-
try {
|
|
17
|
-
return new URL(url).pathname;
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
|
-
return undefined;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
6
|
+
import { captureAct, captureVerdictedAct, pathOf } from '../../language/flows/replay.js';
|
|
7
|
+
import { durableArg, durableOutput, reloadAndRecheck, withDurability } from './act/durable.js';
|
|
23
8
|
import { ActionType, ActionWarning, ReticleCommand, CaptureLoss, DEFAULT_ASSERT_TIMEOUT_MS, InputMode, Verified, VerifiedReason, PredicateKind, } from '@reticlehq/core';
|
|
24
9
|
import { leanActResult, mutatedWithin } from './act/act-view.js';
|
|
25
10
|
import { ReticleTool } from '@reticlehq/core';
|
|
@@ -37,12 +22,12 @@ import { intentDebt, openSessionIntents } from '../../memory/intent/open-intents
|
|
|
37
22
|
import { dischargeInlineIntent, inlineVerdictId, linkInlineIntent, } from '../../memory/intent/inline-intent.js';
|
|
38
23
|
import { declaresState } from '@reticlehq/engine/question/predicate/predicate-asks.js';
|
|
39
24
|
import { isStateUnwatched } from '@reticlehq/engine/evidence/blind-spots.js';
|
|
40
|
-
import { inFlightRequestLabels, repeatedRequestLabels
|
|
41
|
-
import {
|
|
25
|
+
import { inFlightRequestLabels, repeatedRequestLabels } from './act/settle-in-flight.js';
|
|
26
|
+
import { finishAfterMatch } from './act/after-match.js';
|
|
27
|
+
import { noteProved } from './act/proved-controls.js';
|
|
42
28
|
import { decideVerified } from '@reticlehq/engine/evidence/verified.js';
|
|
43
29
|
import { honestyForVerdict } from '@reticlehq/engine/evidence/honesty.js';
|
|
44
30
|
import { declaredExpectations, declaresBodyIndependentChannel, } from '@reticlehq/engine/question/declared.js';
|
|
45
|
-
import { readsDomState, alreadyTrueHiddenMatch as alreadyTrueHiddenMatchOf, } from '@reticlehq/engine/evidence/already-true.js';
|
|
46
31
|
import { describeWaitTarget, namedNetIsInFlight } from '@reticlehq/engine/evidence/unsettled.js';
|
|
47
32
|
import { saveFailedAssertCapsule } from './act-capsule.js';
|
|
48
33
|
import { blastRadius, buildDivergenceCapsule, wireCapsule } from '../../judgement/capsule/capsule.js';
|
|
@@ -52,7 +37,8 @@ import { absenceBlindSpotNote, buildCoverageStatement, blindSpotsFromState, tran
|
|
|
52
37
|
import { acceptedWriteLabels } from '@reticlehq/engine/evidence/accepted-write.js';
|
|
53
38
|
import { unreadWriteLabels } from '@reticlehq/engine/evidence/unread-outcome.js';
|
|
54
39
|
import { evaluatePredicate, waitForPredicate, provenExpectedLinks, PredicateSchema, } from '@reticlehq/engine/question/predicate/predicate.js';
|
|
55
|
-
import {
|
|
40
|
+
import { sessionVerdictFacts } from '../../portal/session/session-verdict-facts.js';
|
|
41
|
+
import { currentOf, healthEnvelope, refuseIfThrottled } from '../../portal/session/session-health.js';
|
|
56
42
|
import { pausedShortCircuit, pausedOutputShape, withControl, PAUSED_NO_VERDICT, } from '../../portal/session/control-envelope.js';
|
|
57
43
|
import { asNumber, asRecord, asString } from '@reticlehq/core';
|
|
58
44
|
import { sourceOf } from './tools-helpers.js';
|
|
@@ -64,6 +50,7 @@ import { asActionType, gradeOf } from './act/act-helpers.js';
|
|
|
64
50
|
import { resolveActTarget } from './act/act-target.js';
|
|
65
51
|
import { tryRealInput, rewriteUploadArgs, HOVER_NEEDS_POINTER_MSG } from './real-input-attempt.js';
|
|
66
52
|
import { gradeOfPredicate } from './assert/assert-grade.js';
|
|
53
|
+
import { readAlreadyTrue } from './act/already-true.js';
|
|
67
54
|
/**
|
|
68
55
|
* Narrow the wire's `action` to a real ActionType, or undefined.
|
|
69
56
|
*
|
|
@@ -253,6 +240,7 @@ export const ACT_TOOLS = [
|
|
|
253
240
|
});
|
|
254
241
|
}
|
|
255
242
|
finally {
|
|
243
|
+
deps.recordings.markEnded(pathOf(session.url));
|
|
256
244
|
// Close the window on every exit (settle or throw), recording the action + settle outcome.
|
|
257
245
|
session.finishAction(undefined, settledOutcome, true === settledOutcome ? session.elapsed() - since : undefined);
|
|
258
246
|
}
|
|
@@ -285,7 +273,7 @@ export const ACT_TOOLS = [
|
|
|
285
273
|
.record(z.unknown())
|
|
286
274
|
.optional()
|
|
287
275
|
.describe('Action-specific arguments: { value } for fill/select, { text } for type/press (the key NAME, e.g. Escape or Tab), { modifiers: ["Meta","Shift"] } for a press shortcut (Meta/Control/Shift/Alt), { toRef } for drag (the ref to drop ON — without it the drag lands nowhere), { confirmDangerous: true } for a potentially destructive control. For upload: { path } is a path on disk (absolute or relative to project root; daemon reads real bytes) or { name, content?, type? } for inline bytes.'),
|
|
288
|
-
predicate: PredicateSchema.optional().describe('Alias for `until
|
|
276
|
+
predicate: PredicateSchema.optional().describe('Alias for `until`.'),
|
|
289
277
|
until: PredicateSchema.optional().describe('Predicate to wait for after the action completes (same shape as reticle_assert). OMIT to wait for the page to SETTLE — network + DOM idle — the deterministic default instead of a sleep. To assert a consequence AND settle, allOf them: { kind: "allOf", predicates: [<your predicate>, { kind: "settled" }] }.'),
|
|
290
278
|
timeout_ms: timeoutMsSchema
|
|
291
279
|
.optional()
|
|
@@ -295,9 +283,11 @@ export const ACT_TOOLS = [
|
|
|
295
283
|
.optional()
|
|
296
284
|
.describe('Throw if the tab is throttled. Default: false.'),
|
|
297
285
|
intent: intentArg,
|
|
286
|
+
durable: durableArg,
|
|
298
287
|
...sessionIdShape,
|
|
299
288
|
},
|
|
300
289
|
outputSchema: {
|
|
290
|
+
durable: durableOutput,
|
|
301
291
|
effect: z
|
|
302
292
|
.unknown()
|
|
303
293
|
.describe('The reticle_act result (dispatched, settled, inputMode, etc.).'),
|
|
@@ -428,22 +418,13 @@ export const ACT_TOOLS = [
|
|
|
428
418
|
// A verdict that lives only in the response lives only in the agent's context window, which is
|
|
429
419
|
// exactly the copy a compaction destroys — see runs/run-context.ts.
|
|
430
420
|
let verdictEffect;
|
|
431
|
-
// Was the
|
|
432
|
-
|
|
433
|
-
// past, so they need no pre-check and pay nothing. One extra query, on the path where a green
|
|
434
|
-
// is otherwise unfalsifiable. See engine/src/evidence/already-true.ts.
|
|
435
|
-
const alreadyTruePrecheck = until !== undefined && readsDomState(until)
|
|
436
|
-
? await evaluatePredicate(session, until, since, false)
|
|
437
|
-
: undefined;
|
|
438
|
-
const alreadyTrue = alreadyTruePrecheck?.pass ?? false;
|
|
421
|
+
// Was the consequence ALREADY TRUE, and what did that reading say? See act/already-true.ts.
|
|
422
|
+
const { alreadyTrue, alreadyTrueHiddenMatch, alreadyTrueEvidence, baselines } = await readAlreadyTrue(session, until, since);
|
|
439
423
|
// Same as the ACT handler: the route this step RAN on, before the action can move the app.
|
|
440
424
|
const routeBeforeWait = pathOf(session.url);
|
|
441
|
-
//
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
const alreadyTrueHiddenMatch = alreadyTrue && until !== undefined
|
|
445
|
-
? alreadyTrueHiddenMatchOf(until, alreadyTruePrecheck?.evidence)
|
|
446
|
-
: false;
|
|
425
|
+
// Recorded in `finally`, once the verdict is known — see captureVerdictedAct.
|
|
426
|
+
let dispatched;
|
|
427
|
+
let recordedVerdict;
|
|
447
428
|
try {
|
|
448
429
|
// actCommand is the single interception point for upload+path rewrite.
|
|
449
430
|
//
|
|
@@ -461,7 +442,7 @@ export const ACT_TOOLS = [
|
|
|
461
442
|
if (actResult !== null) {
|
|
462
443
|
if (!actResult.ok)
|
|
463
444
|
throw new Error(actResult.error ?? 'act failed');
|
|
464
|
-
|
|
445
|
+
dispatched = { result: actResult.result };
|
|
465
446
|
// Dispatched — now this act owns the cursor and the effect. Marking its OWN measurement
|
|
466
447
|
// also stops the spread below from inheriting an earlier reticle_act's action and
|
|
467
448
|
// mutation count.
|
|
@@ -472,8 +453,8 @@ export const ACT_TOOLS = [
|
|
|
472
453
|
let verdict = null === actResult
|
|
473
454
|
? { pass: false, observationLost: true }
|
|
474
455
|
: timeout > 0
|
|
475
|
-
? await waitForPredicate(session, until, timeout, since)
|
|
476
|
-
: await evaluatePredicate(session, until, since);
|
|
456
|
+
? await waitForPredicate(session, until, timeout, since, baselines)
|
|
457
|
+
: await evaluatePredicate(session, until, since, true, baselines);
|
|
477
458
|
// The SDK may have gone away mid-act — see act-observation.ts.
|
|
478
459
|
const followed = await followLostObservation({
|
|
479
460
|
sessions: deps.sessions,
|
|
@@ -481,40 +462,18 @@ export const ACT_TOOLS = [
|
|
|
481
462
|
verdict,
|
|
482
463
|
timeout,
|
|
483
464
|
predicateStarted,
|
|
484
|
-
reevaluate: (next, budget) => waitForPredicate(next, until, budget, 0),
|
|
465
|
+
reevaluate: (next, budget) => waitForPredicate(next, until, budget, 0, baselines),
|
|
485
466
|
});
|
|
486
467
|
if (followed.followed)
|
|
487
468
|
since = 0;
|
|
488
469
|
session = followed.session;
|
|
489
470
|
verdict = followed.verdict;
|
|
490
|
-
//
|
|
491
|
-
// while the write is still in flight — so the verdict was taken over a window the app had not
|
|
492
|
-
// finished, and came back `unknown / unsettled` asking the CALLER to re-check. A login that
|
|
493
|
-
// genuinely succeeded returned at 492ms of an 8000ms budget with every corroborating channel
|
|
494
|
-
// agreeing. Spend the rest of the budget the caller already granted.
|
|
495
|
-
//
|
|
496
|
-
// This decides nothing: it waits for the answer instead of guessing at it. A response that
|
|
497
|
-
// arrives as a FAILURE still contradicts — and now arrives INSIDE the window, where the
|
|
498
|
-
// detector can see it at all — while a request still open when the budget genuinely runs out
|
|
499
|
-
// reports unsettled exactly as before, an honest limit rather than an early exit. Costs
|
|
500
|
-
// nothing on the common path, where no request is in flight.
|
|
471
|
+
// After a match, let the app finish before the window closes — see act/after-match.ts.
|
|
501
472
|
if (verdict.pass && timeout > 0) {
|
|
502
|
-
const
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
await waitForInFlight(session, since, spent(), sleep);
|
|
507
|
-
// Waiting for the response moved the hazard rather than removing it: the response now lands
|
|
508
|
-
// inside the window BY DESIGN, and the app's re-render happens a task or two later. Close
|
|
509
|
-
// the window in that gap and every channel agrees the app took a successful write and did
|
|
510
|
-
// nothing — `response-ignored`, i.e. `verified:"no"` on a correct app, produced entirely by
|
|
511
|
-
// where we stopped looking. A false accusation is the more damaging direction of error for
|
|
512
|
-
// a verification tool: it sends someone to fix code that is not broken.
|
|
513
|
-
//
|
|
514
|
-
// So the response is not the end of the window; the app's REACTION to it is. Paid only in
|
|
515
|
-
// the shape that would otherwise be accused — a successful mutating write with nothing
|
|
516
|
-
// moved after it — and short enough that a genuinely dropped response is still reported.
|
|
517
|
-
await waitForReaction(session, since, spent(), sleep);
|
|
473
|
+
const left = () => timeout - (session.elapsed() - predicateStarted);
|
|
474
|
+
const reverted = await finishAfterMatch(session, until, since, baselines, left);
|
|
475
|
+
if (reverted !== undefined)
|
|
476
|
+
verdict = { pass: false, failureReason: reverted, observed: reverted };
|
|
518
477
|
}
|
|
519
478
|
const r = asRecord(actResult?.result);
|
|
520
479
|
if ('boolean' === typeof r['settled'])
|
|
@@ -654,17 +613,17 @@ export const ACT_TOOLS = [
|
|
|
654
613
|
currentDocumentId: session.currentDocumentId,
|
|
655
614
|
currentEditEpoch: session.currentEditEpoch,
|
|
656
615
|
appOrigin: session.url,
|
|
616
|
+
background: session.background,
|
|
657
617
|
});
|
|
658
618
|
// The single field an agent reads. Everything below it is the evidence it was derived from;
|
|
659
619
|
// this is the only one that has to be interpreted, and now it interprets itself.
|
|
660
620
|
const outcomePending = acceptedWriteLabels(windowEvents);
|
|
661
621
|
const outcomeUnread = unreadWriteLabels(windowEvents);
|
|
662
|
-
const stillInFlight = inFlightRequestLabels(windowEvents);
|
|
663
|
-
const decision = decideVerified({
|
|
622
|
+
const stillInFlight = inFlightRequestLabels(windowEvents, session.url, session.background);
|
|
623
|
+
const { decision, durable } = await withDurability(args['durable'], until, decideVerified({
|
|
664
624
|
pass: verdict.pass,
|
|
665
|
-
//
|
|
666
|
-
|
|
667
|
-
...(session.sdkVersion === undefined ? {} : { sdkVersion: session.sdkVersion }),
|
|
625
|
+
// Threaded rather than looked up: decideVerified is pure and has no session.
|
|
626
|
+
...sessionVerdictFacts(session),
|
|
668
627
|
// The caller NAMED the consequence rather than defaulting to "wait for idle". A
|
|
669
628
|
// declaration made before the action is what this tool sells, and idle-settlement was
|
|
670
629
|
// overriding it — see `declaredConsequence`. An explicit `{ kind: "settled" }` is not a
|
|
@@ -701,7 +660,9 @@ export const ACT_TOOLS = [
|
|
|
701
660
|
repeated: repeatedRequestLabels(windowEvents),
|
|
702
661
|
},
|
|
703
662
|
...(namedNetIsInFlight(until, stillInFlight) ? { namedRequestInFlight: true } : {}),
|
|
704
|
-
});
|
|
663
|
+
}), (part) => reloadAndRecheck(deps, session, part, timeout));
|
|
664
|
+
recordedVerdict = String(decision.verified);
|
|
665
|
+
noteProved(session, recordedVerdict, actResult?.result);
|
|
705
666
|
// Computed once: the verdict block reports it, and the instrumentation gaps are a second
|
|
706
667
|
// reading of the same evidence rather than a new observation.
|
|
707
668
|
const actionSummary = causalSummary(windowEvents, {
|
|
@@ -770,6 +731,16 @@ export const ACT_TOOLS = [
|
|
|
770
731
|
// which is why the two are recorded apart rather than assumed alike.
|
|
771
732
|
declaredBeforeActing: true,
|
|
772
733
|
grade: gradeOfPredicate(until),
|
|
734
|
+
// What the declared consequence READ. The run fold has only the journal, so a kind absent
|
|
735
|
+
// here was being invented there as `element`. Same field, same reason, on the assert path.
|
|
736
|
+
kind: until.kind,
|
|
737
|
+
// The deciding clause, kept — and it was NOT, on this path, the commonest one. `unknown`
|
|
738
|
+
// alone cannot tell an outcome that has not arrived from a capture that could not be
|
|
739
|
+
// read, so a fold over the journal saw a verdict it could not attribute, and the
|
|
740
|
+
// attribution is the only part of an `unknown` a reader can act on. The comment above
|
|
741
|
+
// says "same field, same reason, on the assert path" and was half true. Found by the
|
|
742
|
+
// session gap summary, whose `undecidedBy` was empty for every unknown this tool made.
|
|
743
|
+
reason: decision.verifiedReason,
|
|
773
744
|
};
|
|
774
745
|
// Recorded on the session, so a later "am I done?" can answer with what is STILL missing
|
|
775
746
|
// rather than with everything that was ever missing. An empty list closes a gap, which is
|
|
@@ -777,6 +748,8 @@ export const ACT_TOOLS = [
|
|
|
777
748
|
noteSessionGaps(session, gaps);
|
|
778
749
|
return withControl(session, {
|
|
779
750
|
...decision,
|
|
751
|
+
// WHAT was already true, not only that something was (4.1) — see act/already-true.ts.
|
|
752
|
+
...(alreadyTrueEvidence === undefined ? {} : { alreadyTrueEvidence }),
|
|
780
753
|
// An unobserved act has no effect to report, and inventing an empty one would read as
|
|
781
754
|
// "the page did nothing" — a claim about the app, from a call that never saw it.
|
|
782
755
|
...(null === actResult ? {} : { effect: leanActResult(actResult.result) }),
|
|
@@ -817,16 +790,20 @@ export const ACT_TOOLS = [
|
|
|
817
790
|
// agent cannot miss it by not asking. Omitted entirely when clean, so a healthy action
|
|
818
791
|
// pays nothing.
|
|
819
792
|
...(contradictions.length > 0 ? { contradictions } : {}),
|
|
793
|
+
...(durable === undefined ? {} : { durable }),
|
|
820
794
|
honesty: honestyForVerdict(String(decision.verified), honesty),
|
|
821
795
|
// Without its summary: it is byte-identical to `summary` two fields up. See wireCapsule.
|
|
822
796
|
...(capsule === undefined ? {} : { capsule: wireCapsule(capsule) }),
|
|
823
797
|
...(0 === greenRadius.length ? {} : { blastRadius: greenRadius }),
|
|
824
798
|
since,
|
|
825
799
|
...(session.id === actedSessionId ? {} : { sessionId: session.id }),
|
|
826
|
-
...healthEnvelope(session),
|
|
800
|
+
...healthEnvelope(currentOf(deps.sessions, session)),
|
|
827
801
|
});
|
|
828
802
|
}
|
|
829
803
|
finally {
|
|
804
|
+
if (dispatched !== undefined)
|
|
805
|
+
captureVerdictedAct(deps.recordings, args, dispatched.result, routeBeforeWait, recordedVerdict);
|
|
806
|
+
deps.recordings.markEnded(pathOf(currentOf(deps.sessions, session).url));
|
|
830
807
|
acted.finishAction(verdictEffect, settledOutcome, true === settledOutcome ? acted.elapsed() - actedSince : undefined);
|
|
831
808
|
}
|
|
832
809
|
},
|
|
@@ -31,8 +31,6 @@ export declare const MAX_BLOCKING_WAIT_MS: number;
|
|
|
31
31
|
* in the name of bounding one that never worked.
|
|
32
32
|
*/
|
|
33
33
|
export declare const MAX_STATE_DEPTH = 256;
|
|
34
|
-
/** Scroll-to-find steps. Default is 20; hundreds is searching, thousands is a hang. */
|
|
35
|
-
export declare const MAX_SCROLLS = 200;
|
|
36
34
|
/** Viewport CSS px — matches the clamp the handler already applied, now as a refusal. */
|
|
37
35
|
export declare const MIN_VIEWPORT_PX = 64;
|
|
38
36
|
export declare const MAX_VIEWPORT_PX = 10000;
|
|
@@ -45,6 +43,21 @@ export declare const cursorSchema: z.ZodNumber;
|
|
|
45
43
|
* A wait budget in ms. 0 means evaluate now (documented on assert). Negative cannot be honoured.
|
|
46
44
|
*/
|
|
47
45
|
export declare const timeoutMsSchema: z.ZodNumber;
|
|
46
|
+
/**
|
|
47
|
+
* `reticle_wait_for`'s budget, which may exceed one call: it waits at most MAX_BLOCKING_WAIT_MS per
|
|
48
|
+
* call and hands back `resume_ms` for the rest (#601, from #635).
|
|
49
|
+
*/
|
|
50
|
+
export declare const waitForTimeoutMsSchema: z.ZodNumber;
|
|
51
|
+
/**
|
|
52
|
+
* What is left of a wait that stopped at the per-call limit, or undefined when there is nothing to
|
|
53
|
+
* resume: the predicate held, the whole budget fit in this call, or the wait ended for a reason
|
|
54
|
+
* waiting longer cannot change (the page went away, or the read could not be made).
|
|
55
|
+
*/
|
|
56
|
+
export declare function resumeAfter(requestedMs: number, perCallMs: number, verdict: {
|
|
57
|
+
pass: boolean;
|
|
58
|
+
observationLost?: boolean;
|
|
59
|
+
inconclusive?: string;
|
|
60
|
+
}): number | undefined;
|
|
48
61
|
/**
|
|
49
62
|
* A count / cap. 0 means "return none", which is a real request. Negative is not.
|
|
50
63
|
* Capped at the ring-buffer size so a `limit: 1e9` cannot pretend the buffer is larger than it is.
|
|
@@ -38,8 +38,8 @@ export const MAX_TIMEOUT_MS = 120_000;
|
|
|
38
38
|
*
|
|
39
39
|
* This does not make long waits possible, and is not meant to — it makes the ADVERTISED bound one
|
|
40
40
|
* that can actually be honoured. A caller that genuinely needs to outlast this polls: several short
|
|
41
|
-
* waits, each of which returns a verdict.
|
|
42
|
-
*
|
|
41
|
+
* waits, each of which returns a verdict. `reticle_wait_for` does that for the caller: see
|
|
42
|
+
* `waitForTimeoutMsSchema` and `resumeAfter`.
|
|
43
43
|
*/
|
|
44
44
|
const MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS = 60_000;
|
|
45
45
|
export const MAX_BLOCKING_WAIT_MS = MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS - 5_000;
|
|
@@ -54,7 +54,7 @@ export const MAX_STATE_DEPTH = 256;
|
|
|
54
54
|
/** A crawl that clicks forever is not a bound. */
|
|
55
55
|
const MAX_CRAWL_STEPS = 500;
|
|
56
56
|
/** Scroll-to-find steps. Default is 20; hundreds is searching, thousands is a hang. */
|
|
57
|
-
|
|
57
|
+
const MAX_SCROLLS = 200;
|
|
58
58
|
/** Fake-clock jump. One day of timers is a test; a billion ms is not. */
|
|
59
59
|
const MAX_ADVANCE_MS = 86_400_000;
|
|
60
60
|
/** Presenter idle window. One hour is a slow app; larger values never fire. */
|
|
@@ -71,6 +71,33 @@ export const cursorSchema = z.number().finite().int().nonnegative();
|
|
|
71
71
|
* A wait budget in ms. 0 means evaluate now (documented on assert). Negative cannot be honoured.
|
|
72
72
|
*/
|
|
73
73
|
export const timeoutMsSchema = z.number().finite().int().nonnegative().max(MAX_BLOCKING_WAIT_MS);
|
|
74
|
+
/**
|
|
75
|
+
* The longest `reticle_wait_for` accepts, across as many calls as it takes. Ten minutes is a slow
|
|
76
|
+
* build or a queued job; an hour is a hang somebody forgot about.
|
|
77
|
+
*/
|
|
78
|
+
const MAX_RESUMABLE_WAIT_MS = 600_000;
|
|
79
|
+
/**
|
|
80
|
+
* `reticle_wait_for`'s budget, which may exceed one call: it waits at most MAX_BLOCKING_WAIT_MS per
|
|
81
|
+
* call and hands back `resume_ms` for the rest (#601, from #635).
|
|
82
|
+
*/
|
|
83
|
+
export const waitForTimeoutMsSchema = z
|
|
84
|
+
.number()
|
|
85
|
+
.finite()
|
|
86
|
+
.int()
|
|
87
|
+
.nonnegative()
|
|
88
|
+
.max(MAX_RESUMABLE_WAIT_MS);
|
|
89
|
+
/**
|
|
90
|
+
* What is left of a wait that stopped at the per-call limit, or undefined when there is nothing to
|
|
91
|
+
* resume: the predicate held, the whole budget fit in this call, or the wait ended for a reason
|
|
92
|
+
* waiting longer cannot change (the page went away, or the read could not be made).
|
|
93
|
+
*/
|
|
94
|
+
export function resumeAfter(requestedMs, perCallMs, verdict) {
|
|
95
|
+
if (verdict.pass || true === verdict.observationLost || verdict.inconclusive !== undefined) {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
const left = requestedMs - perCallMs;
|
|
99
|
+
return left > 0 ? left : undefined;
|
|
100
|
+
}
|
|
74
101
|
/**
|
|
75
102
|
* A count / cap. 0 means "return none", which is a real request. Negative is not.
|
|
76
103
|
* Capped at the ring-buffer size so a `limit: 1e9` cannot pretend the buffer is larger than it is.
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Pure: no IO, no clock.
|
|
12
12
|
*/
|
|
13
|
-
import { isConsequenceKind, isPresenceKind, PredicateKind } from '@reticlehq/core';
|
|
13
|
+
import { compareSourceClauses, isConsequenceKind, isPresenceKind, PredicateKind, } from '@reticlehq/core';
|
|
14
14
|
import { HonestyGrade, strongerGrade, weakerGrade } from '@reticlehq/engine/evidence/honesty.js';
|
|
15
15
|
export const PRESENCE_ONLY_ADVICE = 'This predicate only checks element/text presence, not an observable consequence. A locator healed to the wrong element (or a stale render) can satisfy it while the feature is broken. Prefer a { signal } or { net } assertion (or allOf it with one) so green means the feature actually worked.';
|
|
16
16
|
function walk(predicate, negated = false) {
|
|
@@ -27,6 +27,14 @@ function walk(predicate, negated = false) {
|
|
|
27
27
|
// never matched anything in the first place. Negation makes a presence check weaker, not stronger.
|
|
28
28
|
if (PredicateKind.NOT === predicate.kind)
|
|
29
29
|
return walk(predicate.predicate, true);
|
|
30
|
+
// A comparison grades as what its sides read: with a net/signal/state side it relates the page to
|
|
31
|
+
// the app's own record, which a wrong locator cannot fake; text against text is two readings of
|
|
32
|
+
// the same DOM. Its text side is always a content check, so it never counts as bare presence
|
|
33
|
+
// unless negated.
|
|
34
|
+
if (PredicateKind.COMPARE === predicate.kind) {
|
|
35
|
+
const consequence = compareSourceClauses(predicate).some((c) => isConsequenceKind(c.kind));
|
|
36
|
+
return { consequence, presence: !consequence && negated };
|
|
37
|
+
}
|
|
30
38
|
// Leaf: classify against the single source of truth in core. Kinds that are neither consequence
|
|
31
39
|
// nor presence (route/console/settled/animation) correctly return false for both.
|
|
32
40
|
return {
|
|
@@ -109,17 +117,32 @@ export function gradeOfPredicate(predicate) {
|
|
|
109
117
|
// verdict that proved only presence report `signal`, and a `minGrade: net` gate would trust it.
|
|
110
118
|
case PredicateKind.ANY_OF:
|
|
111
119
|
return combine(predicate.predicates, weakerGrade);
|
|
120
|
+
// Both sides had to be read and agree, so it proves as much as its stronger side.
|
|
121
|
+
case PredicateKind.COMPARE:
|
|
122
|
+
return combine(compareSourceClauses(predicate), strongerGrade);
|
|
112
123
|
// Everything else, `not` included: an absence claim is satisfied trivially by a locator that
|
|
113
124
|
// never matched anything, which is the argument `walk` already makes about negation.
|
|
114
125
|
default:
|
|
115
126
|
return HonestyGrade.PRESENCE;
|
|
116
127
|
}
|
|
117
128
|
}
|
|
118
|
-
/**
|
|
129
|
+
/**
|
|
130
|
+
* Fold a combinator's branches on the ladder. No branches proves nothing, so it stays at the floor.
|
|
131
|
+
*
|
|
132
|
+
* The floor is `NONE`, not `PRESENCE`. This sentence has been here since the function was written
|
|
133
|
+
* and the code returned one rung above it, which is the entire defect: `VACUOUS_GRADE`
|
|
134
|
+
* (`engine/src/evidence/verified.ts`) fires on `NONE`, so an empty combinator graded `PRESENCE`
|
|
135
|
+
* walked past the one guard whose job is refusing a green that rests on nothing — and reported
|
|
136
|
+
* `verified: "yes"` for a drive that asserted nothing at all.
|
|
137
|
+
*
|
|
138
|
+
* The schema refuses an empty combinator now, so this is the second defence rather than the only
|
|
139
|
+
* one. It is kept because the two stop different things: the schema stops it ENTERING through the
|
|
140
|
+
* documented door, and this stops it COUNTING if it is ever constructed rather than parsed.
|
|
141
|
+
*/
|
|
119
142
|
function combine(branches, pick) {
|
|
120
143
|
const grades = branches.map(gradeOfPredicate);
|
|
121
144
|
const first = grades[0];
|
|
122
145
|
if (first === undefined)
|
|
123
|
-
return HonestyGrade.
|
|
146
|
+
return HonestyGrade.NONE;
|
|
124
147
|
return grades.reduce(pick, first);
|
|
125
148
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { CaptureLoss,
|
|
1
|
+
import { CaptureLoss, channelsReadBy, PredicateKind } from '@reticlehq/core';
|
|
2
|
+
import { sessionVerdictFacts } from '../../../portal/session/session-verdict-facts.js';
|
|
2
3
|
import { gapsForAction } from '@reticlehq/engine/evidence/instrumentation-gaps.js';
|
|
3
4
|
import { noteSessionGaps } from '@reticlehq/engine/evidence/gap-ledger.js';
|
|
4
5
|
import { declaresState } from '@reticlehq/engine/question/predicate/predicate-asks.js';
|
|
@@ -15,6 +16,7 @@ import { describeWaitTarget, namedNetIsInFlight } from '@reticlehq/engine/eviden
|
|
|
15
16
|
import { inFlightRequestLabels, repeatedRequestLabels, } from '../act/settle-in-flight.js';
|
|
16
17
|
import { gradeOfPredicate } from './assert-grade.js';
|
|
17
18
|
import { assertSource } from './assert-source.js';
|
|
19
|
+
import { VerdictAttribution, verdictAttributionOf } from '@reticlehq/core';
|
|
18
20
|
/**
|
|
19
21
|
* The honesty verdict for a plain `reticle_assert`.
|
|
20
22
|
*
|
|
@@ -85,6 +87,7 @@ changeUndeclared) {
|
|
|
85
87
|
currentDocumentId: session.currentDocumentId,
|
|
86
88
|
currentEditEpoch: session.currentEditEpoch,
|
|
87
89
|
appOrigin: session.url,
|
|
90
|
+
background: session.background,
|
|
88
91
|
expectedFailures: declared.netFailures,
|
|
89
92
|
namedNetUrls: declared.netUrls,
|
|
90
93
|
renderProved: pass && declared.rendersContent,
|
|
@@ -114,7 +117,7 @@ changeUndeclared) {
|
|
|
114
117
|
const impeachingNotes = [impeaching.note, gap, ...crashedRuleNotes()].filter((n) => n !== undefined);
|
|
115
118
|
const outcomePending = acceptedWriteLabels(windowEvents);
|
|
116
119
|
const outcomeUnread = unreadWriteLabels(windowEvents);
|
|
117
|
-
const stillInFlight = inFlightRequestLabels(windowEvents);
|
|
120
|
+
const stillInFlight = inFlightRequestLabels(windowEvents, session.url, session.background);
|
|
118
121
|
const effectiveInconclusive = inconclusive ?? (!pass ? session.preconditionFailure?.() : undefined);
|
|
119
122
|
/**
|
|
120
123
|
* Does a green here rest on the window having been COMPLETE?
|
|
@@ -145,11 +148,10 @@ changeUndeclared) {
|
|
|
145
148
|
// first clause, and one this implementation could not run until the page started declaring.
|
|
146
149
|
// Both halves are conditional on purpose: an SDK too old to declare sends nothing, and
|
|
147
150
|
// treating that silence as an empty set would refuse every claim from every older page.
|
|
148
|
-
channelsRead:
|
|
151
|
+
channelsRead: channelsReadBy(predicate),
|
|
149
152
|
...(session.channels === undefined ? {} : { channelsObservable: session.channels }),
|
|
150
|
-
//
|
|
151
|
-
|
|
152
|
-
...(session.sdkVersion === undefined ? {} : { sdkVersion: session.sdkVersion }),
|
|
153
|
+
// Threaded rather than looked up: decideVerified is pure and has no session.
|
|
154
|
+
...sessionVerdictFacts(session),
|
|
153
155
|
// Same rule as the act path: the caller named a consequence, so a settlement-only finding must
|
|
154
156
|
// not override it. A fix that lived on one half of the verdict surface would leave the other
|
|
155
157
|
// half broken, and this is the tool agents call most.
|
|
@@ -217,6 +219,8 @@ changeUndeclared) {
|
|
|
217
219
|
pass,
|
|
218
220
|
lastActSource: session.lastAct.source(),
|
|
219
221
|
});
|
|
222
|
+
// Who can act on this verdict, derived from the clause that decided it — see `attributedTo` below.
|
|
223
|
+
const attributedTo = verdictAttributionOf(decision.verifiedReason);
|
|
220
224
|
return {
|
|
221
225
|
decision: decision,
|
|
222
226
|
contradictions,
|
|
@@ -226,6 +230,9 @@ changeUndeclared) {
|
|
|
226
230
|
claim: describeWaitTarget(predicate),
|
|
227
231
|
verified: decision.verified,
|
|
228
232
|
...(source === undefined ? {} : { source }),
|
|
233
|
+
// What answering this claim READ. Known here and nowhere later: a run folded from the journal
|
|
234
|
+
// has only what the journal kept, and without this it stamped `element` on every check.
|
|
235
|
+
kind: predicate.kind,
|
|
229
236
|
// The three facts that make a verdict something other than a pass/fail line. All three were
|
|
230
237
|
// known right here and none of them survived into the durable record, so nothing downstream
|
|
231
238
|
// could report them however well this moment understood them.
|
|
@@ -240,6 +247,25 @@ changeUndeclared) {
|
|
|
240
247
|
// arrived from a capture that could not be read, and only the first is worth asking about
|
|
241
248
|
// again -- which is what makes a later answer a CORRECTION rather than a second opinion.
|
|
242
249
|
reason: decision.verifiedReason,
|
|
250
|
+
/*
|
|
251
|
+
* WHOSE problem it is, in four values, finishing the sentence above.
|
|
252
|
+
*
|
|
253
|
+
* The reason names the deciding clause; this names who can act on it, which for an `unknown`
|
|
254
|
+
* is the only question the reader has. `environment` resolves by waiting, `could-not-see` by
|
|
255
|
+
* looking again with better coverage, `harness` by fixing Reticle or the call, and `code` is
|
|
256
|
+
* the only one that means go and change the app. Omitted on a proof, which has no owner.
|
|
257
|
+
*
|
|
258
|
+
* Derived here rather than inside the verdict: it is a pure function of a reason the engine
|
|
259
|
+
* already returns, and `core-coupling-only-shrinks` caps what the engine may borrow from core.
|
|
260
|
+
*
|
|
261
|
+
* Named `attributedTo`, not `attribution`, because two other things already carry that word:
|
|
262
|
+
* `honesty.attribution` a few lines up ("what the grade is attributed to" — the window), and
|
|
263
|
+
* `BugAttribution` in telemetry ("we found a defect, whose defect is it?"). Three meanings on
|
|
264
|
+
* one noun is how a reader ends up acting on the wrong one.
|
|
265
|
+
*/
|
|
266
|
+
...(attributedTo === undefined || VerdictAttribution.NONE === attributedTo
|
|
267
|
+
? {}
|
|
268
|
+
: { attributedTo }),
|
|
243
269
|
grade: gradeOfPredicate(predicate),
|
|
244
270
|
couldNotSee: spots.map((spot) => spot.kind),
|
|
245
271
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { carryReticleIdentity } from './lease-tools.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { navigateResult } from './act/navigation/navigate-result.js';
|
|
4
|
-
import { awaitArrival, idsAtTarget, ARRIVAL_TIMEOUT_MS, } from './act/navigation/navigate-arrival.js';
|
|
4
|
+
import { absoluteTarget, awaitArrival, idsAtTarget, ARRIVAL_TIMEOUT_MS, } from './act/navigation/navigate-arrival.js';
|
|
5
5
|
import { reloadResult } from './act/navigation/reload-result.js';
|
|
6
6
|
import { waitForReconnect, RELOAD_RECONNECT_TIMEOUT_MS, } from '../../portal/session/session-reconnect.js';
|
|
7
7
|
import { ReticleCommand } from '@reticlehq/core';
|
|
@@ -13,7 +13,7 @@ export const BROWSER_TOOLS = [
|
|
|
13
13
|
{
|
|
14
14
|
name: ReticleTool.NAVIGATE,
|
|
15
15
|
example: { url: '/settings' },
|
|
16
|
-
description: 'Navigate the connected browser tab to a URL, or reload it in place with { reload: true } (add { hard: true } to bypass the cache). `ok` means the navigation was DISPATCHED — the SDK is torn down by the navigation, so the page
|
|
16
|
+
description: 'Navigate the connected browser tab to a URL, or reload it in place with { reload: true } (add { hard: true } to bypass the cache). `ok` means the navigation was DISPATCHED — the SDK is torn down by the navigation, so the old page cannot report on it. The daemon then waits up to `timeout_ms` (default 5000) for the SDK to reconnect. `confirmed:true` with a `sessionId` means the requested page arrived and you can act immediately. `confirmed:false` with `landedOn` means the navigation arrived but the app landed at another URL, such as an authentication or route-guard redirect; use `landedOn` to understand where the browser actually ended up. `confirmed:false` without `landedOn` means the target was not observed within the wait window; a slow app may still be on its way, so increase `timeout_ms` when appropriate.',
|
|
17
17
|
inputSchema: {
|
|
18
18
|
url: z.string().optional().describe('The URL to navigate to. Omit when using reload.'),
|
|
19
19
|
reload: z
|
|
@@ -38,6 +38,10 @@ export const BROWSER_TOOLS = [
|
|
|
38
38
|
confirmed: z.boolean().optional(),
|
|
39
39
|
/** The session the SDK reconnected as, when arrival was confirmed — it is a NEW id. */
|
|
40
40
|
sessionId: z.string().optional(),
|
|
41
|
+
/**
|
|
42
|
+
* The URL where the navigated document landed when it differs from the requested target.
|
|
43
|
+
*/
|
|
44
|
+
landedOn: z.string().optional(),
|
|
41
45
|
/**
|
|
42
46
|
* On confirmed:false — the budget (ms) that expired without the page coming back. Says which
|
|
43
47
|
* of "Reticle stopped waiting" and "the page never came back" you are looking at.
|
|
@@ -58,6 +62,7 @@ export const BROWSER_TOOLS = [
|
|
|
58
62
|
// back past this point. Reported from the field as an assertion whose clauses all passed
|
|
59
63
|
// coming back `contradicted` by hundreds of 500s against resources that were already gone.
|
|
60
64
|
before.lastAct.markNavigated(before.elapsed());
|
|
65
|
+
deps.recordings.markNavigated();
|
|
61
66
|
await commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.REFRESH, {
|
|
62
67
|
hard: true === args['hard'],
|
|
63
68
|
});
|
|
@@ -89,12 +94,14 @@ export const BROWSER_TOOLS = [
|
|
|
89
94
|
// Sampled BEFORE dispatch, because that is the only moment it can be known. A session already
|
|
90
95
|
// sitting on the target is not evidence that THIS navigation arrived — and the arrival scan,
|
|
91
96
|
// which reads whatever is at the target afterwards, cannot tell the two apart on its own.
|
|
92
|
-
const
|
|
97
|
+
const target = absoluteTarget(url, session.url);
|
|
98
|
+
const priorIds = idsAtTarget(deps.sessions, target);
|
|
93
99
|
session.beginAction(ReticleTool.NAVIGATE, { url });
|
|
94
100
|
// Same floor as the reload path above, for the same reason: going to a new URL replaces the
|
|
95
101
|
// document just as thoroughly. `beginAction` attributes events to this action; it does not move
|
|
96
102
|
// the window a later assert judges over, and those are two different jobs.
|
|
97
103
|
session.lastAct.markNavigated(session.elapsed());
|
|
104
|
+
deps.recordings.markNavigated();
|
|
98
105
|
try {
|
|
99
106
|
const result = (await commandOrThrow(deps, asString(args['sessionId']), ReticleCommand.NAVIGATE, { url }));
|
|
100
107
|
// `ok` is the browser accepting the instruction, not the page arriving — see navigate-result.
|
|
@@ -103,7 +110,13 @@ export const BROWSER_TOOLS = [
|
|
|
103
110
|
// reticle_sessions itself. A refusal skips the wait: there is nothing to wait FOR.
|
|
104
111
|
const timeoutMs = asNumber(args['timeout_ms']) ?? ARRIVAL_TIMEOUT_MS;
|
|
105
112
|
const arrival = true === result.ok
|
|
106
|
-
? await awaitArrival(deps.sessions,
|
|
113
|
+
? await awaitArrival(deps.sessions, target, {
|
|
114
|
+
// Keep the original Session object and URL so arrival detection can distinguish
|
|
115
|
+
// an in-progress navigation from a document that arrived somewhere else.
|
|
116
|
+
navigatedSession: session,
|
|
117
|
+
navigatedFrom: session.url,
|
|
118
|
+
priorIds,
|
|
119
|
+
}, timeoutMs)
|
|
107
120
|
: null;
|
|
108
121
|
return navigateResult(result, arrival, timeoutMs);
|
|
109
122
|
}
|
|
@@ -10,6 +10,7 @@ import { ReticleTool } from '@reticlehq/core';
|
|
|
10
10
|
import { asString } from '@reticlehq/core';
|
|
11
11
|
import { exercisedCount } from './gaps/coverage-identity.js';
|
|
12
12
|
import { commandOrThrow, sessionIdShape } from './tool-kit.js';
|
|
13
|
+
import { foldAppCoverage } from '../../features/exhaust/app-coverage.js';
|
|
13
14
|
/**
|
|
14
15
|
* `reticle_coverage` — which interactive controls this session has driven, and which it has not.
|
|
15
16
|
*
|
|
@@ -69,8 +70,17 @@ export function buildCoverageTools(toolNames) {
|
|
|
69
70
|
name: ReticleTool.COVERAGE,
|
|
70
71
|
description: 'Which interactive controls you have driven this session, and which you have NOT. Returns { total, exercised, untouched:[{ref,label}], alsoDroveGone? } over the controls currently on the page. Use it to decide whether verification is finished: an untouched list that still holds the controls your change affects means you are not done. This is about what you did not TOUCH — distinct from the `coverage` field on an action result, which reports what the layer could not SEE.',
|
|
71
72
|
example: {},
|
|
72
|
-
inputSchema: {
|
|
73
|
+
inputSchema: {
|
|
74
|
+
app: z
|
|
75
|
+
.boolean()
|
|
76
|
+
.optional()
|
|
77
|
+
.describe('Also fold into the app-wide ledger; returns `app.levels`.'),
|
|
78
|
+
...sessionIdShape,
|
|
79
|
+
},
|
|
73
80
|
outputSchema: {
|
|
81
|
+
// The app-wide ledger — see features/exhaust/ledger.ts. Loose: run-only, and the levels
|
|
82
|
+
// carry their own shape.
|
|
83
|
+
app: z.record(z.unknown()).optional(),
|
|
74
84
|
total: z.number(),
|
|
75
85
|
exercised: z.number(),
|
|
76
86
|
untouched: z.array(z.object({ ref: z.string(), label: z.string() })),
|
|
@@ -171,6 +181,22 @@ export function buildCoverageTools(toolNames) {
|
|
|
171
181
|
...(regressed === undefined ? {} : { observabilityRegressed: regressed }),
|
|
172
182
|
featureUse,
|
|
173
183
|
toolHitRate,
|
|
184
|
+
...(true === args['app']
|
|
185
|
+
? {
|
|
186
|
+
app: await foldAppCoverage({
|
|
187
|
+
fs: deps.fs,
|
|
188
|
+
reticleRoot: sessionRoot(deps, sessionId),
|
|
189
|
+
seen: parseControls(tree).map((c) => c.label),
|
|
190
|
+
session,
|
|
191
|
+
now: deps.now,
|
|
192
|
+
...(deps.realInput?.takeCodeCoverage === undefined
|
|
193
|
+
? {}
|
|
194
|
+
: {
|
|
195
|
+
takeCode: (url) => deps.realInput?.takeCodeCoverage?.(url) ?? Promise.resolve(undefined),
|
|
196
|
+
}),
|
|
197
|
+
}),
|
|
198
|
+
}
|
|
199
|
+
: {}),
|
|
174
200
|
};
|
|
175
201
|
},
|
|
176
202
|
},
|