@reticlehq/server 3.8.2 → 3.10.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 +201 -104
- package/NOTICE +5 -0
- package/README.md +1 -1
- package/SKILL.md +13 -12
- package/bin/launch.js +13 -0
- package/bin/package.json +3 -0
- package/bin/reticle.js +66 -8
- package/dist/chromium-launch-options.d.ts +25 -0
- package/dist/chromium-launch-options.js +21 -1
- package/dist/command/cli/adhoc-suite.js +2 -0
- package/dist/command/cli/adhoc-verdict.d.ts +2 -43
- package/dist/command/cli/adhoc-verdict.js +50 -160
- package/dist/command/cli/answers/gate-exit.d.ts +6 -2
- package/dist/command/cli/answers/gate-exit.js +12 -2
- package/dist/command/cli/answers/mcp-connection-hint.d.ts +2 -0
- package/dist/command/cli/answers/mcp-connection-hint.js +6 -0
- package/dist/command/cli/ci-hint.d.ts +44 -0
- package/dist/command/cli/ci-hint.js +72 -0
- package/dist/command/cli/cli-doctor.d.ts +6 -1
- package/dist/command/cli/cli-doctor.js +46 -5
- package/dist/command/cli/cli-flow-commands.d.ts +7 -1
- package/dist/command/cli/cli-flow-commands.js +39 -24
- package/dist/command/cli/cli-kill.d.ts +21 -0
- package/dist/command/cli/cli-kill.js +47 -4
- package/dist/command/cli/cli-parse-compare.d.ts +22 -0
- package/dist/command/cli/cli-parse-compare.js +75 -0
- package/dist/command/cli/cli-parse-grade.d.ts +36 -0
- package/dist/command/cli/cli-parse-grade.js +75 -0
- package/dist/command/cli/cli-parse-grammar.d.ts +2 -0
- package/dist/command/cli/cli-parse-grammar.js +18 -20
- package/dist/command/cli/cli-parse-verify.d.ts +10 -0
- package/dist/command/cli/cli-parse-verify.js +63 -14
- package/dist/command/cli/cli-parse.d.ts +22 -17
- package/dist/command/cli/cli-parse.js +54 -32
- package/dist/command/cli/cli-update-commands.d.ts +1 -1
- package/dist/command/cli/cli-update-commands.js +29 -20
- package/dist/command/cli/cli-usage.js +61 -31
- package/dist/command/cli/cli-verify.d.ts +17 -3
- package/dist/command/cli/cli-verify.js +59 -21
- package/dist/command/cli/cloud-cli.js +2 -119
- package/dist/command/cli/daemon-link/daemon-client.d.ts +45 -0
- package/dist/command/cli/daemon-link/daemon-client.js +205 -0
- package/dist/command/cli/doctor/browser/chromium-hint.d.ts +6 -1
- package/dist/command/cli/doctor/browser/chromium-hint.js +11 -5
- package/dist/command/cli/doctor/doctor-daemon-line.js +6 -3
- package/dist/command/cli/doctor/doctor-fix.d.ts +44 -0
- package/dist/command/cli/doctor/doctor-fix.js +89 -0
- package/dist/command/cli/doctor/doctor-launcher-line.d.ts +23 -0
- package/dist/command/cli/doctor/doctor-launcher-line.js +60 -0
- package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
- package/dist/command/cli/doctor/doctor-rows.js +4 -0
- package/dist/command/cli/doctor-repairs.d.ts +64 -0
- package/dist/command/cli/doctor-repairs.js +214 -0
- package/dist/command/cli/drive/drive-command.js +3 -7
- package/dist/command/cli/ensure-daemon.d.ts +26 -0
- package/dist/command/cli/ensure-daemon.js +57 -0
- package/dist/command/cli/finished-run/grade-command.d.ts +23 -0
- package/dist/command/cli/finished-run/grade-command.js +180 -0
- package/dist/command/cli/first-use-checks.d.ts +41 -0
- package/dist/command/cli/first-use-checks.js +127 -0
- package/dist/command/cli/first-verdict-node.d.ts +3 -0
- package/dist/command/cli/first-verdict-node.js +189 -0
- package/dist/command/cli/first-verdict.d.ts +126 -0
- package/dist/command/cli/first-verdict.js +267 -0
- package/dist/command/cli/launch/sdk-version-match.d.ts +3 -2
- package/dist/command/cli/launch/sdk-version-match.js +3 -2
- package/dist/command/cli/lifecycle/daemon-lifecycle.d.ts +1 -1
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +7 -6
- package/dist/command/cli/mcp-command.js +13 -4
- package/dist/command/cli/ports/port-holder.d.ts +11 -0
- package/dist/command/cli/ports/port-holder.js +36 -4
- package/dist/command/cli/setup-mcp-cli.d.ts +27 -1
- package/dist/command/cli/setup-mcp-cli.js +98 -23
- package/dist/command/cli/status/status-lines.d.ts +2 -0
- package/dist/command/cli/status/status-lines.js +72 -17
- package/dist/command/cli/status-fields.d.ts +5 -1
- package/dist/command/cli/status-fields.js +24 -6
- package/dist/command/cli/try-command.d.ts +7 -0
- package/dist/command/cli/try-command.js +11 -3
- package/dist/command/cli/two-builds/compare-command.d.ts +48 -0
- package/dist/command/cli/two-builds/compare-command.js +314 -0
- package/dist/command/cli/verify-against.d.ts +61 -0
- package/dist/command/cli/verify-against.js +187 -0
- package/dist/command/cli/verify-no-session.d.ts +2 -0
- package/dist/command/cli/verify-no-session.js +13 -0
- package/dist/command/cli/verify-results.d.ts +35 -2
- package/dist/command/cli/verify-results.js +76 -10
- package/dist/command/cli.js +112 -70
- package/dist/command/daemon/binding/daemon-status-probe.d.ts +3 -1
- package/dist/command/daemon/binding/daemon-status-probe.js +4 -2
- package/dist/command/daemon/daemon-argv.d.ts +9 -0
- package/dist/command/daemon/daemon-argv.js +11 -0
- package/dist/command/daemon/daemon-resolve.d.ts +8 -1
- package/dist/command/daemon/daemon-resolve.js +27 -1
- package/dist/command/daemon/daemon.d.ts +22 -4
- package/dist/command/daemon/daemon.js +52 -10
- package/dist/command/daemon/lifetime/daemon-exit.d.ts +24 -0
- package/dist/command/daemon/lifetime/daemon-exit.js +39 -0
- package/dist/command/daemon/lifetime/death-cause.d.ts +15 -0
- package/dist/command/daemon/lifetime/death-cause.js +149 -0
- package/dist/command/daemon/lifetime/heartbeat.d.ts +7 -15
- package/dist/command/daemon/lifetime/heartbeat.js +11 -15
- package/dist/command/daemon/lifetime/startup-failure.d.ts +29 -0
- package/dist/command/daemon/lifetime/startup-failure.js +62 -0
- package/dist/command/daemon/port-state.d.ts +14 -0
- package/dist/command/daemon/port-state.js +31 -0
- package/dist/command/setup/agent-configs.d.ts +2 -0
- package/dist/command/setup/agent-configs.js +42 -15
- package/dist/command/setup/agent-next-steps.d.ts +77 -0
- package/dist/command/setup/agent-next-steps.js +284 -0
- package/dist/command/setup/agent-writer.js +11 -6
- package/dist/command/setup/bringup/dev-server-files.d.ts +9 -0
- package/dist/command/setup/bringup/dev-server-files.js +17 -0
- package/dist/command/setup/bringup/static-page-server.d.ts +14 -2
- package/dist/command/setup/bringup/static-page-server.js +43 -9
- package/dist/command/setup/init/init-host.js +2 -0
- package/dist/command/setup/init/init-runtime.d.ts +6 -1
- package/dist/command/setup/init/init-runtime.js +63 -21
- package/dist/command/setup/mcp-launcher.d.ts +3 -0
- package/dist/command/setup/mcp-launcher.js +11 -0
- package/dist/command/setup/node-effects.d.ts +3 -2
- package/dist/command/setup/node-effects.js +9 -3
- package/dist/command/setup/remaining-steps.d.ts +8 -0
- package/dist/command/setup/remaining-steps.js +10 -0
- package/dist/command/setup/run-setup.d.ts +2 -0
- package/dist/command/setup/run-setup.js +9 -1
- package/dist/command/setup/setup-command.js +36 -15
- package/dist/command/setup/setup-mcp.d.ts +8 -0
- package/dist/command/setup/setup-mcp.js +47 -20
- package/dist/command/setup/start-dev-server.d.ts +8 -0
- package/dist/command/setup/start-dev-server.js +43 -0
- package/dist/command/update/updater.js +6 -0
- package/dist/command/version/identity/server-version.d.ts +2 -0
- package/dist/command/version/identity/server-version.js +2 -0
- package/dist/command/version/version-skew.d.ts +7 -0
- package/dist/command/version/version-skew.js +14 -3
- package/dist/features/compare/action-plan.d.ts +260 -0
- package/dist/features/compare/action-plan.js +543 -0
- package/dist/features/compare/behaviour-compare.d.ts +24 -0
- package/dist/features/compare/behaviour-compare.js +85 -0
- package/dist/features/compare/behaviour-diff.d.ts +97 -0
- package/dist/features/compare/behaviour-diff.js +202 -0
- package/dist/features/compare/behaviour-report.d.ts +40 -0
- package/dist/features/compare/behaviour-report.js +128 -0
- package/dist/features/compare/build-readings.d.ts +106 -0
- package/dist/features/compare/build-readings.js +250 -0
- package/dist/features/compare/compare-diff.d.ts +62 -0
- package/dist/features/compare/compare-diff.js +177 -0
- package/dist/features/compare/compare-report-html.d.ts +6 -0
- package/dist/features/compare/compare-report-html.js +102 -0
- package/dist/features/compare/compare-report.d.ts +15 -0
- package/dist/features/compare/compare-report.js +73 -0
- package/dist/features/compare/compare-run.d.ts +60 -0
- package/dist/features/compare/compare-run.js +123 -0
- package/dist/features/compare/outside/effect-lines.d.ts +26 -0
- package/dist/features/compare/outside/effect-lines.js +103 -0
- package/dist/features/compare/outside/state-sources.d.ts +76 -0
- package/dist/features/compare/outside/state-sources.js +164 -0
- package/dist/features/compare/outside/value-dictionary.d.ts +51 -0
- package/dist/features/compare/outside/value-dictionary.js +227 -0
- package/dist/features/compare/visible-content.d.ts +20 -0
- package/dist/features/compare/visible-content.js +125 -0
- package/dist/features/crawl/crawl-empty.js +2 -1
- package/dist/features/crawl/crawl-exhaustive.d.ts +55 -0
- package/dist/features/crawl/crawl-exhaustive.js +138 -0
- package/dist/features/crawl/crawl-tools.d.ts +9 -2
- package/dist/features/crawl/crawl-tools.js +28 -12
- package/dist/features/crawl/crawl.d.ts +8 -9
- package/dist/features/crawl/crawl.js +61 -65
- package/dist/features/exhaust/app-coverage.d.ts +5 -1
- package/dist/features/exhaust/app-coverage.js +3 -1
- package/dist/features/exhaust/code-coverage.js +8 -4
- package/dist/features/exhaust/edge-cases.d.ts +133 -0
- package/dist/features/exhaust/edge-cases.js +310 -0
- package/dist/features/exhaust/edges/edge-drive.d.ts +42 -0
- package/dist/features/exhaust/edges/edge-drive.js +364 -0
- package/dist/features/exhaust/edges/edge-run.d.ts +59 -0
- package/dist/features/exhaust/edges/edge-run.js +169 -0
- package/dist/features/exhaust/explorer.d.ts +87 -14
- package/dist/features/exhaust/explorer.js +159 -25
- package/dist/features/exhaust/failure-branches.d.ts +5 -0
- package/dist/features/exhaust/failure-branches.js +29 -11
- package/dist/features/exhaust/invariants.d.ts +112 -0
- package/dist/features/exhaust/invariants.js +188 -0
- package/dist/features/exhaust/ledger.d.ts +68 -0
- package/dist/features/exhaust/ledger.js +121 -13
- package/dist/features/exhaust/session-fold.d.ts +10 -0
- package/dist/features/exhaust/session-fold.js +46 -3
- package/dist/features/exhaust/session-port.d.ts +3 -1
- package/dist/features/exhaust/session-port.js +97 -28
- package/dist/features/grade/grade-answer.d.ts +99 -0
- package/dist/features/grade/grade-answer.js +112 -0
- package/dist/features/grade/grade-noise.d.ts +27 -0
- package/dist/features/grade/grade-noise.js +55 -0
- package/dist/features/grade/grade-renumber.d.ts +12 -0
- package/dist/features/grade/grade-renumber.js +86 -0
- package/dist/features/grade/grade-state.d.ts +50 -0
- package/dist/features/grade/grade-state.js +93 -0
- package/dist/features/grade/grade-suggest.d.ts +33 -0
- package/dist/features/grade/grade-suggest.js +98 -0
- package/dist/features/license/license.d.ts +11 -71
- package/dist/features/license/license.js +43 -136
- package/dist/features/visual/desktop-capture.d.ts +33 -0
- package/dist/features/visual/desktop-capture.js +94 -0
- package/dist/features/visual/step-shots.js +139 -35
- package/dist/features/visual/visual-tools.d.ts +0 -18
- package/dist/features/visual/visual-tools.js +67 -99
- package/dist/import-graph.js +5 -6
- package/dist/index.d.ts +3 -1
- package/dist/index.js +19 -7
- package/dist/judgement/capsule/causal-summary.js +9 -2
- package/dist/judgement/runs/artifact/replay-mapping.d.ts +13 -1
- package/dist/judgement/runs/artifact/replay-mapping.js +1 -1
- package/dist/judgement/runs/reticle-runner.js +16 -2
- package/dist/judgement/runs/run-ledger.d.ts +7 -5
- package/dist/judgement/runs/run-ledger.js +98 -69
- package/dist/judgement/runs/runner-port.d.ts +2 -0
- package/dist/judgement/runs/runner-port.js +23 -5
- package/dist/judgement/runs/verification-sync.d.ts +6 -3
- package/dist/judgement/runs/verification-sync.js +21 -10
- package/dist/language/flows/affected-tools.d.ts +1 -1
- package/dist/language/flows/affected-tools.js +49 -30
- package/dist/language/flows/change/git-changed.d.ts +2 -1
- package/dist/language/flows/change/git-changed.js +19 -2
- package/dist/language/flows/fields/flow-secret-field.d.ts +1 -13
- package/dist/language/flows/fields/flow-secret-field.js +77 -21
- package/dist/language/flows/flow-anchor.d.ts +60 -2
- package/dist/language/flows/flow-anchor.js +125 -20
- package/dist/language/flows/flow-classify.d.ts +20 -0
- package/dist/language/flows/flow-classify.js +90 -12
- package/dist/language/flows/flow-cross-step.d.ts +7 -1
- package/dist/language/flows/flow-cross-step.js +25 -1
- package/dist/language/flows/flow-journey.d.ts +38 -4
- package/dist/language/flows/flow-journey.js +138 -8
- package/dist/language/flows/flow-replay-run.d.ts +0 -16
- package/dist/language/flows/flow-replay-run.js +76 -14
- package/dist/language/flows/flow-replay-types.d.ts +4 -2
- package/dist/language/flows/flow-replay.d.ts +19 -1
- package/dist/language/flows/flow-replay.js +169 -52
- package/dist/language/flows/flow-replayable.js +7 -1
- package/dist/language/flows/flow-start-path.d.ts +34 -5
- package/dist/language/flows/flow-start-path.js +202 -15
- package/dist/language/flows/flow-step-runners.d.ts +14 -13
- package/dist/language/flows/flow-step-runners.js +184 -109
- package/dist/language/flows/flow-store-for-session.d.ts +26 -25
- package/dist/language/flows/flow-store-for-session.js +51 -5
- package/dist/language/flows/flow-tools.js +46 -33
- package/dist/language/flows/flows.js +176 -76
- package/dist/language/flows/recording/tape/recordings.d.ts +21 -16
- package/dist/language/flows/recording/tape/recordings.js +112 -49
- package/dist/language/flows/replay.d.ts +36 -12
- package/dist/language/flows/replay.js +193 -50
- package/dist/language/flows/steps/page-steps.d.ts +68 -0
- package/dist/language/flows/steps/page-steps.js +198 -0
- package/dist/language/flows/suite/sequential-run.d.ts +68 -0
- package/dist/language/flows/suite/sequential-run.js +96 -0
- package/dist/language/flows/verify-change-tools.js +26 -15
- package/dist/launch-chromium.d.ts +1 -0
- package/dist/launch-chromium.js +49 -12
- package/dist/memory/cloud/background-sync.d.ts +13 -0
- package/dist/memory/cloud/background-sync.js +24 -3
- package/dist/memory/cloud/sync-daemon.js +26 -27
- package/dist/memory/cloud/sync-screenshots.js +6 -1
- package/dist/memory/journal/attach-journal.js +2 -1
- package/dist/memory/journal/drive-flow.d.ts +7 -0
- package/dist/memory/journal/drive-flow.js +44 -13
- package/dist/memory/journal/journal-recorder.d.ts +4 -2
- package/dist/memory/journal/session-journal.d.ts +7 -0
- package/dist/memory/journal/session-journal.js +58 -10
- package/dist/memory/project/root-claims.d.ts +9 -0
- package/dist/memory/project/root-claims.js +9 -4
- package/dist/portal/bridge/bridge.d.ts +13 -4
- package/dist/portal/bridge/bridge.js +10 -9
- package/dist/portal/input/download-capture.d.ts +7 -0
- package/dist/portal/input/download-capture.js +92 -0
- package/dist/portal/input/network-detail.d.ts +6 -0
- package/dist/portal/input/network-detail.js +12 -1
- package/dist/portal/input/network-mock-tools.js +49 -13
- package/dist/portal/input/network-mock.d.ts +8 -0
- package/dist/portal/input/network-mock.js +30 -10
- package/dist/portal/input/page-capture.d.ts +24 -0
- package/dist/portal/input/page-capture.js +33 -0
- package/dist/portal/input/real-input.d.ts +35 -18
- package/dist/portal/input/real-input.js +99 -33
- package/dist/portal/input/viewport-tools.d.ts +8 -0
- package/dist/portal/input/viewport-tools.js +81 -21
- package/dist/portal/pool/browser-pool.d.ts +16 -30
- package/dist/portal/pool/browser-pool.js +64 -52
- package/dist/portal/pool/context-permissions.d.ts +34 -17
- package/dist/portal/pool/context-permissions.js +94 -1
- package/dist/portal/pool/csp-widen.d.ts +62 -0
- package/dist/portal/pool/csp-widen.js +132 -0
- package/dist/portal/pool/determinism.d.ts +52 -0
- package/dist/portal/pool/determinism.js +259 -0
- package/dist/portal/pool/lease-emulation.d.ts +34 -1
- package/dist/portal/pool/lease-emulation.js +18 -0
- package/dist/portal/pool/lease-marker-stamp.d.ts +6 -0
- package/dist/portal/pool/lease-marker-stamp.js +15 -1
- package/dist/portal/pool/lease-page-error.d.ts +56 -0
- package/dist/portal/pool/lease-page-error.js +160 -0
- package/dist/portal/pool/page-error-journal.d.ts +63 -0
- package/dist/portal/pool/page-error-journal.js +208 -0
- package/dist/portal/pool/playwright-launcher.js +71 -15
- package/dist/portal/pool/pool-contract.d.ts +49 -1
- package/dist/portal/pool/pool-lease.d.ts +70 -2
- package/dist/portal/pool/pool-lease.js +23 -0
- package/dist/portal/pool/zero-install.d.ts +8 -0
- package/dist/portal/pool/zero-install.js +91 -1
- package/dist/portal/session/dev-server/dev-command.d.ts +11 -2
- package/dist/portal/session/dev-server/dev-command.js +110 -16
- package/dist/portal/session/dev-server/dev-server-probe.d.ts +7 -0
- package/dist/portal/session/dev-server/dev-server-probe.js +9 -0
- package/dist/portal/session/dev-server/project-ports.d.ts +21 -0
- package/dist/portal/session/dev-server/project-ports.js +62 -0
- package/dist/portal/session/facts/departed-network.d.ts +66 -0
- package/dist/portal/session/facts/departed-network.js +142 -0
- package/dist/portal/session/no-session-diagnosis.d.ts +9 -0
- package/dist/portal/session/no-session-diagnosis.js +76 -27
- package/dist/portal/session/no-session-next-action.d.ts +14 -0
- package/dist/portal/session/no-session-next-action.js +56 -7
- package/dist/portal/session/no-session-watch.d.ts +6 -0
- package/dist/portal/session/no-session-watch.js +41 -4
- package/dist/portal/session/page-commands/undeclared-command.d.ts +9 -3
- package/dist/portal/session/page-commands/undeclared-command.js +16 -7
- package/dist/portal/session/recorded-gaps.d.ts +1 -1
- package/dist/portal/session/recorded-gaps.js +5 -2
- package/dist/portal/session/serving-directory.d.ts +10 -0
- package/dist/portal/session/serving-directory.js +39 -8
- package/dist/portal/session/session-manager.d.ts +10 -0
- package/dist/portal/session/session-manager.js +211 -81
- package/dist/portal/session/session.js +4 -3
- package/dist/portal/session/zero-install-first-call.d.ts +20 -1
- package/dist/portal/session/zero-install-first-call.js +34 -2
- package/dist/start-wiring.d.ts +30 -2
- package/dist/start-wiring.js +74 -9
- package/dist/surface/mcp/mcp-proxy.js +10 -2
- package/dist/surface/mcp/mcp.js +8 -5
- package/dist/surface/mcp/peer/agents-connected.d.ts +6 -0
- package/dist/surface/mcp/peer/agents-connected.js +58 -0
- package/dist/surface/mcp/proxy/proxy-daemon-probe.js +17 -5
- package/dist/surface/mcp/shared-params.d.ts +2 -0
- package/dist/surface/mcp/shared-params.js +31 -0
- package/dist/surface/tools/act/act-observation.d.ts +40 -2
- package/dist/surface/tools/act/act-observation.js +118 -12
- package/dist/surface/tools/act/act-preflight.js +38 -18
- package/dist/surface/tools/act/act-sequence-retry.d.ts +23 -2
- package/dist/surface/tools/act/act-sequence-retry.js +61 -5
- package/dist/surface/tools/act/act-target.js +3 -1
- package/dist/surface/tools/act/after-match.d.ts +10 -0
- package/dist/surface/tools/act/after-match.js +40 -0
- package/dist/surface/tools/act/already-true.js +1 -1
- package/dist/surface/tools/act/navigation/reload-result.d.ts +12 -1
- package/dist/surface/tools/act/navigation/reload-result.js +25 -2
- package/dist/surface/tools/act/resolve-target.d.ts +17 -1
- package/dist/surface/tools/act/resolve-target.js +59 -9
- package/dist/surface/tools/act/sequence-grade.d.ts +15 -1
- package/dist/surface/tools/act/sequence-grade.js +45 -27
- package/dist/surface/tools/act/settle-in-flight.js +27 -15
- package/dist/surface/tools/act-command.d.ts +23 -0
- package/dist/surface/tools/act-command.js +50 -0
- package/dist/surface/tools/act-sequence-tool.js +81 -50
- package/dist/surface/tools/act-tools.d.ts +1 -13
- package/dist/surface/tools/act-tools.js +83 -95
- package/dist/surface/tools/agent/build-staleness.d.ts +1 -1
- package/dist/surface/tools/agent/build-staleness.js +1 -1
- package/dist/surface/tools/assert/assert-verdict.js +18 -12
- package/dist/surface/tools/browser-tools.js +87 -13
- package/dist/surface/tools/compare-tools.d.ts +11 -0
- package/dist/surface/tools/compare-tools.js +94 -0
- package/dist/surface/tools/coverage-tools.js +1 -1
- package/dist/surface/tools/dynamic-tools.js +11 -3
- package/dist/surface/tools/empty-session-list.d.ts +2 -0
- package/dist/surface/tools/empty-session-list.js +4 -2
- package/dist/surface/tools/error-recovery.d.ts +12 -1
- package/dist/surface/tools/error-recovery.js +131 -40
- package/dist/surface/tools/explore-tools.js +1 -1
- package/dist/surface/tools/invoke-tool.js +29 -21
- package/dist/surface/tools/lease-coverage-tools.d.ts +49 -0
- package/dist/surface/tools/lease-coverage-tools.js +128 -0
- package/dist/surface/tools/lease-hint.d.ts +42 -1
- package/dist/surface/tools/lease-hint.js +52 -3
- package/dist/surface/tools/lease-readiness.d.ts +47 -0
- package/dist/surface/tools/lease-readiness.js +126 -0
- package/dist/surface/tools/lease-seed.d.ts +16 -1
- package/dist/surface/tools/lease-seed.js +37 -4
- package/dist/surface/tools/lease-tools.d.ts +3 -41
- package/dist/surface/tools/lease-tools.js +104 -124
- package/dist/surface/tools/lease-url-identity.d.ts +46 -0
- package/dist/surface/tools/lease-url-identity.js +97 -0
- package/dist/surface/tools/merge-tools.js +99 -2
- package/dist/surface/tools/merged-name-redirect.js +5 -1
- package/dist/surface/tools/observe-tools.js +15 -9
- package/dist/surface/tools/read/console-pre-attach.d.ts +19 -0
- package/dist/surface/tools/read/console-pre-attach.js +23 -0
- package/dist/surface/tools/read-tools.js +33 -30
- package/dist/surface/tools/real-input-attempt.d.ts +0 -8
- package/dist/surface/tools/real-input-attempt.js +143 -28
- package/dist/surface/tools/repeat-hint.d.ts +40 -0
- package/dist/surface/tools/repeat-hint.js +171 -0
- package/dist/surface/tools/run-report.d.ts +2 -2
- package/dist/surface/tools/run-report.js +27 -15
- package/dist/surface/tools/session-ports.d.ts +14 -0
- package/dist/surface/tools/session-ports.js +53 -0
- package/dist/surface/tools/tool-kit.d.ts +18 -0
- package/dist/surface/tools/tool-kit.js +9 -3
- package/dist/surface/tools/tool-surface.js +0 -1
- package/dist/surface/tools/tools.js +54 -18
- package/dist/surface/tools/type-spelling.d.ts +13 -0
- package/dist/surface/tools/type-spelling.js +36 -0
- package/dist/telemetry/agent-client.d.ts +6 -0
- package/dist/telemetry/agent-client.js +10 -0
- package/dist/telemetry/argument-shape.js +17 -7
- package/dist/telemetry/cli-telemetry.d.ts +10 -1
- package/dist/telemetry/cli-telemetry.js +15 -0
- package/dist/telemetry/init-telemetry.d.ts +2 -1
- package/dist/telemetry/init-telemetry.js +47 -2
- package/dist/telemetry/install-trace.js +23 -4
- package/dist/telemetry/onboarding-funnel.d.ts +19 -2
- package/dist/telemetry/onboarding-funnel.js +25 -3
- package/dist/telemetry/proxy-telemetry.d.ts +2 -1
- package/dist/telemetry/proxy-telemetry.js +2 -2
- package/dist/telemetry/session-metrics.d.ts +1 -1
- package/dist/telemetry/session-metrics.js +67 -27
- package/dist/telemetry/telemetry.d.ts +3 -1
- package/dist/telemetry/telemetry.js +60 -28
- package/dist/telemetry/tool-refused.d.ts +6 -3
- package/dist/telemetry/tool-refused.js +15 -3
- package/docs/actions.mdx +3 -3
- package/docs/agent-cheatsheet.md +1 -1
- package/docs/architecture.md +3 -6
- package/docs/capabilities.mdx +61 -1
- package/docs/cli/affected.mdx +9 -7
- package/docs/cli/cloud.mdx +3 -3
- package/docs/cli/compare.mdx +94 -0
- package/docs/cli/doctor.mdx +41 -2
- package/docs/cli/grade.mdx +97 -0
- package/docs/cli/help.mdx +4 -2
- package/docs/cli/license.mdx +13 -12
- package/docs/cli/restart.mdx +7 -5
- package/docs/cli/rollback.mdx +5 -5
- package/docs/cli/setup.mdx +13 -2
- package/docs/cli/status.mdx +4 -0
- package/docs/cli/stop.mdx +3 -3
- package/docs/cli/update.mdx +2 -2
- package/docs/cli/verify.mdx +23 -1
- package/docs/cli.mdx +34 -24
- package/docs/deploy-checks.md +25 -0
- package/docs/desktop.mdx +1 -1
- package/docs/enterprise.md +17 -22
- package/docs/environment.mdx +1 -0
- package/docs/first-drive.md +1 -1
- package/docs/flows.md +11 -1
- package/docs/frameworks.mdx +9 -9
- package/docs/getting-started.md +1 -1
- package/docs/install-manual.mdx +16 -1
- package/docs/license-activation.mdx +3 -3
- package/docs/packages/engine.mdx +1 -1
- package/docs/packages/server.mdx +1 -1
- package/docs/packages/tauri.mdx +1 -1
- package/docs/packages/test.mdx +1 -1
- package/docs/packages.mdx +1 -1
- package/docs/platform-integration.md +1 -1
- package/docs/predicates.mdx +1 -1
- package/docs/quickstart.mdx +68 -49
- package/docs/skill-setup.md +1 -1
- package/docs/skill.md +14 -13
- package/docs/telemetry.md +6 -4
- package/docs/tools/navigate.mdx +1 -1
- package/docs/tools/verify.mdx +4 -1
- package/docs/troubleshooting.mdx +1 -1
- package/docs/usage.md +17 -14
- package/package.json +18 -14
- package/LICENSE-ENTERPRISE +0 -37
- package/dist/features/ee/audit-log.d.ts +0 -14
- package/dist/features/ee/audit-log.js +0 -11
- package/dist/features/exhaust/exhaust-run.d.ts +0 -33
- package/dist/features/exhaust/exhaust-run.js +0 -82
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
* on stable, human-authored substrings of the thrown messages (see session-manager.ts, the flow/
|
|
9
9
|
* baseline stores). No clock, no IO — unit-testable in isolation.
|
|
10
10
|
*/
|
|
11
|
-
import { CodedRefusalSchema, PRODUCTION_REFUSAL_PREFIX, RefusalCode, RefusalReason, ReticleEnv, TRANSPORT_LIMITS, UNISSUED_REF_REFUSAL, } from '@reticlehq/core';
|
|
11
|
+
import { CodedRefusalSchema, PRODUCTION_REFUSAL_PREFIX, RefusalCode, RefusalDetail, RefusalReason, ReticleEnv, TRANSPORT_LIMITS, UNISSUED_REF_REFUSAL, } from '@reticlehq/core';
|
|
12
12
|
import { SELF_RECOVERING_MARKER } from '../../portal/session/no-session-diagnosis.js';
|
|
13
13
|
import { MSG_HARNESS_DISABLED, MSG_HARNESS_UNCLAIMED, MSG_HARNESS_UNCONFIRMED, PlatformRefusalCode, RefusalLead, } from '../../features/harness/platform/refusal.js';
|
|
14
14
|
import { BODY_CLAUSE_REFUSAL_OPENING } from '@reticlehq/engine/evidence/body-capture-remedy.js';
|
|
15
15
|
import { EMPTY_FIND_OPENING } from './read/query-shape.js';
|
|
16
16
|
import { UNKNOWN_FLOW_OPENING } from '../../language/flows/suite-selection.js';
|
|
17
|
+
import { ARTIFACT_ROOT_ABSOLUTE_REFUSAL, ARTIFACT_ROOT_MISSING_REFUSAL, } from '../../memory/project/root-claims.js';
|
|
17
18
|
import { CHROMIUM_PATH_REFUSAL_PREFIX, chromiumInstallCommand, bundledPlaywrightVersion, } from '../../command/cli/doctor/browser/chromium-hint.js';
|
|
18
19
|
/** Marks where an over-long message had its middle removed. Named so tests assert it by value. */
|
|
19
20
|
const ELISION = '… [elided] …';
|
|
@@ -32,8 +33,9 @@ const ELISION = '… [elided] …';
|
|
|
32
33
|
*/
|
|
33
34
|
function capMessage(message) {
|
|
34
35
|
const max = TRANSPORT_LIMITS.MAX_ERROR_LENGTH;
|
|
35
|
-
if (max >= message.length)
|
|
36
|
+
if (max >= message.length) {
|
|
36
37
|
return message;
|
|
38
|
+
}
|
|
37
39
|
const keep = Math.floor((max - ELISION.length) / 2);
|
|
38
40
|
return `${message.slice(0, keep)}${ELISION}${message.slice(message.length - keep)}`;
|
|
39
41
|
}
|
|
@@ -70,6 +72,11 @@ const SELF_RECOVERING = [
|
|
|
70
72
|
// Both are the caller's to fix, and the defect ask on top told an agent to file a bug about them.
|
|
71
73
|
{ match: literally(EMPTY_FIND_OPENING), reason: RefusalReason.BAD_ARGS },
|
|
72
74
|
{ match: literally(UNKNOWN_FLOW_OPENING), reason: RefusalReason.NO_MATCH },
|
|
75
|
+
// A lease `root` naming no directory on disk — relative, or absent — is the caller's to fix, and
|
|
76
|
+
// the message carries the exact path to pass instead. Both sat under the feedback ask, which
|
|
77
|
+
// invited a bug report about a mistyped path (#2085).
|
|
78
|
+
{ match: literally(ARTIFACT_ROOT_ABSOLUTE_REFUSAL), reason: RefusalReason.BAD_ARGS },
|
|
79
|
+
{ match: literally(ARTIFACT_ROOT_MISSING_REFUSAL), reason: RefusalReason.BAD_ARGS },
|
|
73
80
|
];
|
|
74
81
|
/**
|
|
75
82
|
* The refusal for a `ref` Reticle never minted — decided BEFORE every other rule, not by one inside
|
|
@@ -83,8 +90,9 @@ function isUnissuedRefRefusal(message) {
|
|
|
83
90
|
}
|
|
84
91
|
/** A message that already carries its own concrete next action, so nothing should be appended. */
|
|
85
92
|
function isSelfRecovering(message) {
|
|
86
|
-
if (message.includes(SELF_RECOVERING_MARKER))
|
|
93
|
+
if (message.includes(SELF_RECOVERING_MARKER)) {
|
|
87
94
|
return true;
|
|
95
|
+
}
|
|
88
96
|
return SELF_RECOVERING.some((rule) => rule.match.test(message));
|
|
89
97
|
}
|
|
90
98
|
/** The recovery hints, named so they are not free strings and can be asserted in tests. */
|
|
@@ -142,8 +150,9 @@ export const RECOVERY = {
|
|
|
142
150
|
* carry: which of them to reach for, and that nothing was acted on.
|
|
143
151
|
*/
|
|
144
152
|
TARGET_MISSED: 'The call was valid — the selector matched nothing on the page RIGHT NOW, and nothing was ' +
|
|
145
|
-
'acted on.
|
|
146
|
-
'
|
|
153
|
+
'acted on. If the message lists the nearest targets and one is the element you meant, retry ' +
|
|
154
|
+
'with its ref. If not, take a reticle_snapshot to see what is actually there (a view may still ' +
|
|
155
|
+
'be rendering, or the control may be named differently), then retry with what it shows. This is ' +
|
|
147
156
|
'a miss, not a Reticle defect: there is nothing to report.',
|
|
148
157
|
/**
|
|
149
158
|
* The selector was underspecified, which is the caller's to fix and the same class as a miss.
|
|
@@ -201,10 +210,12 @@ export const RECOVERY = {
|
|
|
201
210
|
'on purpose. If you mean it, send the SAME call again with ' +
|
|
202
211
|
'`args: { confirmDangerous: true }` — it goes inside the `args` object, not beside it. This is ' +
|
|
203
212
|
'a deliberate refusal, not a defect: there is nothing to report.',
|
|
204
|
-
UNSUPPORTED_SURFACE: 'That surface is
|
|
205
|
-
'
|
|
206
|
-
'
|
|
207
|
-
'
|
|
213
|
+
UNSUPPORTED_SURFACE: 'That surface is a rich-text editor: it keeps its own document model, so `fill` and `type` ' +
|
|
214
|
+
'refuse it rather than write the DOM and submit the old content. A contenteditable editor ' +
|
|
215
|
+
'(Tiptap, ProseMirror) takes `insertText` with `{ text }`: it goes through the browser editing ' +
|
|
216
|
+
'pipeline, so the editor model updates. An EditContext editor (Monaco, CodeMirror 6) cannot be ' +
|
|
217
|
+
'typed into yet, because a scripted update fires no textupdate for its model: use `press` for ' +
|
|
218
|
+
'a key. If the ref points at a wrapper, act on the editor inside it instead.',
|
|
208
219
|
HOVER_NEEDS_POINTER: 'Hover needs a real pointer: a synthetic mouseover does not apply CSS :hover, and Reticle ' +
|
|
209
220
|
'refuses rather than reporting the styles as applied. Acquire a tab with ' +
|
|
210
221
|
'reticle_run { tool: "reticle_lease", args: { action: "acquire", url } } — reticle_lease is not ' +
|
|
@@ -256,7 +267,7 @@ export const RECOVERY = {
|
|
|
256
267
|
'what is wrong with the path). The call itself was fine, so retrying it will not help, and ' +
|
|
257
268
|
'neither will installing Chromium. Ask the human to fix that path, or unset it to use ' +
|
|
258
269
|
"Playwright's own Chromium, in the environment the daemon starts from, then run " +
|
|
259
|
-
'`npx @reticlehq/server restart`. Meanwhile drive a tab the human already has open, which ' +
|
|
270
|
+
'`npx @reticlehq/server serve --restart`. Meanwhile drive a tab the human already has open, which ' +
|
|
260
271
|
'reticle_sessions lists. This is configuration, not a Reticle defect: there is nothing to report.',
|
|
261
272
|
/**
|
|
262
273
|
* The two ways a platform answer can refuse a drive. Neither is a fault, and both were telling the
|
|
@@ -322,6 +333,44 @@ const REASON_OF = {
|
|
|
322
333
|
// The call is valid; the app is not instrumented enough for the Harness yet.
|
|
323
334
|
HARNESS_LOCKED: RefusalReason.UNSUPPORTED,
|
|
324
335
|
};
|
|
336
|
+
/**
|
|
337
|
+
* Which CAUSE each recovery names, for `tool_refused`. A `Record` for the same reason as `REASON_OF`:
|
|
338
|
+
* a recovery added without a detail does not compile. A rule can name a narrower detail than its
|
|
339
|
+
* recovery (`NO_POOL` covers three causes with one hint).
|
|
340
|
+
*/
|
|
341
|
+
const DETAIL_OF = {
|
|
342
|
+
NO_SESSION: RefusalDetail.NO_SESSION,
|
|
343
|
+
MULTIPLE_SESSIONS: RefusalDetail.MULTIPLE_SESSIONS,
|
|
344
|
+
UNKNOWN_SESSION: RefusalDetail.UNKNOWN_SESSION,
|
|
345
|
+
SCOPE_MISMATCH: RefusalDetail.SCOPE_MISMATCH,
|
|
346
|
+
SESSION_GONE: RefusalDetail.SESSION_GONE,
|
|
347
|
+
THROTTLED: RefusalDetail.THROTTLED,
|
|
348
|
+
COMMAND_TIMEOUT: RefusalDetail.COMMAND_TIMEOUT,
|
|
349
|
+
NO_POOL: RefusalDetail.POOL_UNAVAILABLE,
|
|
350
|
+
CHROMIUM_PATH: RefusalDetail.CHROMIUM_PATH,
|
|
351
|
+
TOKEN_REQUIRED: RefusalDetail.TOKEN_REQUIRED,
|
|
352
|
+
MISSING_BASELINE: RefusalDetail.MISSING_BASELINE,
|
|
353
|
+
MISSING_RECORDING: RefusalDetail.MISSING_RECORDING,
|
|
354
|
+
STALE_REF: RefusalDetail.STALE_REF,
|
|
355
|
+
STALE_REF_AFTER_EDIT: RefusalDetail.STALE_REF_AFTER_EDIT,
|
|
356
|
+
UNISSUED_REF: RefusalDetail.UNISSUED_REF,
|
|
357
|
+
NO_SUCH_OPTION: RefusalDetail.NO_SUCH_OPTION,
|
|
358
|
+
TARGET_MISSED: RefusalDetail.TARGET_MISSED,
|
|
359
|
+
AMBIGUOUS_TARGET: RefusalDetail.AMBIGUOUS_TARGET,
|
|
360
|
+
FLOW_STEP_MISSING: RefusalDetail.FLOW_STEP_MISSING,
|
|
361
|
+
UNSUPPORTED_SURFACE: RefusalDetail.UNSUPPORTED_SURFACE,
|
|
362
|
+
HOVER_NEEDS_POINTER: RefusalDetail.HOVER_NEEDS_POINTER,
|
|
363
|
+
NOT_EDITABLE: RefusalDetail.NOT_EDITABLE,
|
|
364
|
+
CONFIRM_DANGEROUS: RefusalDetail.CONFIRM_DANGEROUS,
|
|
365
|
+
WRONG_TARGET: RefusalDetail.WRONG_TARGET,
|
|
366
|
+
PRODUCTION_POLICY: RefusalDetail.PRODUCTION_POLICY,
|
|
367
|
+
BAD_ARGUMENTS: RefusalDetail.BAD_ARGUMENTS,
|
|
368
|
+
INVALID_NAME: RefusalDetail.INVALID_NAME,
|
|
369
|
+
HARNESS_OFF: RefusalDetail.HARNESS_OFF,
|
|
370
|
+
HARNESS_LOCKED: RefusalDetail.HARNESS_LOCKED,
|
|
371
|
+
};
|
|
372
|
+
/** Hint text back to its detail, as `REASON_BY_HINT` does for the reason. */
|
|
373
|
+
const DETAIL_BY_HINT = new Map(Object.entries(RECOVERY).map(([key, hint]) => [hint, DETAIL_OF[key]]));
|
|
325
374
|
/** Hint text back to its reason. The hints are distinct strings, so this inverts cleanly. */
|
|
326
375
|
const REASON_BY_HINT = new Map(Object.entries(RECOVERY).map(([key, hint]) => [hint, REASON_OF[key]]));
|
|
327
376
|
/** Ordered match rules; the first hit wins. Substrings track the thrown messages they recover. */
|
|
@@ -372,9 +421,17 @@ const RULES = [
|
|
|
372
421
|
{ match: /^command '[^']*' timed out after/i, hint: RECOVERY.COMMAND_TIMEOUT },
|
|
373
422
|
// Flow replay: the recorded anchor is gone. Ordinary drift, and the tool that fixes it exists.
|
|
374
423
|
{ match: /did not resolve in current page/i, hint: RECOVERY.FLOW_STEP_MISSING },
|
|
424
|
+
// One hint for three causes: the agent's next step is the same, the fix for the user is not.
|
|
425
|
+
{ match: /browser pool unavailable/i, hint: RECOVERY.NO_POOL },
|
|
426
|
+
{
|
|
427
|
+
match: /browser pool is shut down/i,
|
|
428
|
+
hint: RECOVERY.NO_POOL,
|
|
429
|
+
detail: RefusalDetail.POOL_SHUT_DOWN,
|
|
430
|
+
},
|
|
375
431
|
{
|
|
376
|
-
match: /
|
|
432
|
+
match: /Chromium is not installed/i,
|
|
377
433
|
hint: RECOVERY.NO_POOL,
|
|
434
|
+
detail: RefusalDetail.CHROMIUM_MISSING,
|
|
378
435
|
},
|
|
379
436
|
// The commonest post-action condition there is. Unmatched, it fell through to FEEDBACK_ASK and
|
|
380
437
|
// told the agent a successful click's aftermath might be a bug in Reticle.
|
|
@@ -389,6 +446,10 @@ const RULES = [
|
|
|
389
446
|
// broken. Order matters: contenteditable and disabled/readonly are `cannot <verb> …` messages too,
|
|
390
447
|
// so they must be tested before the general wrong-target rule.
|
|
391
448
|
{ match: /contenteditable/i, hint: RECOVERY.UNSUPPORTED_SURFACE },
|
|
449
|
+
// The EditContext refusal from insertText. Its message names no `contenteditable`, so it used to
|
|
450
|
+
// fall through to the feedback ask — a deliberate refusal of a surface we cannot type into yet
|
|
451
|
+
// read as "Reticle may be broken".
|
|
452
|
+
{ match: /EditContext/i, hint: RECOVERY.UNSUPPORTED_SURFACE },
|
|
392
453
|
{ match: /cannot hover without a real pointer/i, hint: RECOVERY.HOVER_NEEDS_POINTER },
|
|
393
454
|
{ match: /cannot \w+ a (disabled|readonly) </i, hint: RECOVERY.NOT_EDITABLE },
|
|
394
455
|
// Both "action" and "native action" refusals need the same confirmation guidance.
|
|
@@ -464,15 +525,17 @@ const RULES = [
|
|
|
464
525
|
* saying a server is running and the recovery saying to go start one.
|
|
465
526
|
*/
|
|
466
527
|
export function recoveryFor(message) {
|
|
467
|
-
if (isUnissuedRefRefusal(message))
|
|
528
|
+
if (isUnissuedRefRefusal(message)) {
|
|
468
529
|
return RECOVERY.UNISSUED_REF;
|
|
469
|
-
|
|
530
|
+
}
|
|
531
|
+
if (isSelfRecovering(message)) {
|
|
470
532
|
return undefined;
|
|
471
|
-
for (const rule of RULES) {
|
|
472
|
-
if (rule.match.test(message))
|
|
473
|
-
return rule.hint;
|
|
474
533
|
}
|
|
475
|
-
return
|
|
534
|
+
return firstRule(message)?.hint;
|
|
535
|
+
}
|
|
536
|
+
/** The first rule that matches the message. The order of `RULES` decides. */
|
|
537
|
+
function firstRule(message) {
|
|
538
|
+
return RULES.find((rule) => rule.match.test(message));
|
|
476
539
|
}
|
|
477
540
|
/**
|
|
478
541
|
* WHY a tool refused, as one of the six buckets in core's `RefusalReason`.
|
|
@@ -483,27 +546,46 @@ export function recoveryFor(message) {
|
|
|
483
546
|
* this table rather than about anybody's app.
|
|
484
547
|
*/
|
|
485
548
|
export function refusalReasonFor(rawMessage, coded) {
|
|
486
|
-
|
|
487
|
-
|
|
549
|
+
return classifyRefusal(rawMessage, coded).reason;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* The bucket and, when the recovery table names one, the cause inside it. The cause comes from the
|
|
553
|
+
* same rule that chose the agent's advice, so the two cannot disagree. No detail means no rule
|
|
554
|
+
* matched, or the message diagnosed itself (`noSessionReason` carries that cause).
|
|
555
|
+
*/
|
|
556
|
+
export function classifyRefusal(rawMessage, coded) {
|
|
557
|
+
if (coded !== undefined) {
|
|
558
|
+
return { reason: REASON_OF_CODE[coded.code] };
|
|
559
|
+
}
|
|
488
560
|
const message = zodArrayAsSentence(rawMessage);
|
|
489
|
-
if (isUnissuedRefRefusal(message))
|
|
490
|
-
return RefusalReason.BAD_ARGS;
|
|
561
|
+
if (isUnissuedRefRefusal(message)) {
|
|
562
|
+
return { reason: RefusalReason.BAD_ARGS, detail: RefusalDetail.UNISSUED_REF };
|
|
563
|
+
}
|
|
491
564
|
// The no-session diagnosis inspected the machine and named the cause itself, so it never reaches
|
|
492
565
|
// the recovery table. It is the single largest refusal there is; missing it would gut the metric.
|
|
493
|
-
if (message.includes(SELF_RECOVERING_MARKER))
|
|
494
|
-
return RefusalReason.NO_SESSION;
|
|
566
|
+
if (message.includes(SELF_RECOVERING_MARKER)) {
|
|
567
|
+
return { reason: RefusalReason.NO_SESSION };
|
|
568
|
+
}
|
|
495
569
|
for (const rule of SELF_RECOVERING) {
|
|
496
|
-
if (rule.match.test(message))
|
|
497
|
-
return rule.reason;
|
|
570
|
+
if (rule.match.test(message)) {
|
|
571
|
+
return { reason: rule.reason };
|
|
572
|
+
}
|
|
498
573
|
}
|
|
499
574
|
// Same order as buildErrorPayload: a schema rejection is the agent's own call, whatever else in
|
|
500
575
|
// the message might also match.
|
|
501
|
-
if (ARGUMENT_REJECTION.test(message))
|
|
502
|
-
return RefusalReason.BAD_ARGS;
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
576
|
+
if (ARGUMENT_REJECTION.test(message)) {
|
|
577
|
+
return { reason: RefusalReason.BAD_ARGS };
|
|
578
|
+
}
|
|
579
|
+
if (INVALID_NAME_REJECTION.test(message)) {
|
|
580
|
+
return { reason: RefusalReason.BAD_ARGS, detail: RefusalDetail.INVALID_NAME };
|
|
581
|
+
}
|
|
582
|
+
const rule = firstRule(message);
|
|
583
|
+
if (rule === undefined) {
|
|
584
|
+
return { reason: RefusalReason.OTHER };
|
|
585
|
+
}
|
|
586
|
+
const reason = REASON_BY_HINT.get(rule.hint) ?? RefusalReason.OTHER;
|
|
587
|
+
const detail = rule.detail ?? DETAIL_BY_HINT.get(rule.hint);
|
|
588
|
+
return detail === undefined ? { reason } : { reason, detail };
|
|
507
589
|
}
|
|
508
590
|
/**
|
|
509
591
|
* A schema rejection: the call named a parameter that does not exist, or gave one the wrong type.
|
|
@@ -520,8 +602,9 @@ export function refusalReasonFor(rawMessage, coded) {
|
|
|
520
602
|
/** Max issues rendered — a union rejection can emit one per member, which is how the array became unreadable. */
|
|
521
603
|
const MAX_RENDERED_ISSUES = 3;
|
|
522
604
|
function isZodIssue(value) {
|
|
523
|
-
if (typeof value !== 'object' || null === value)
|
|
605
|
+
if (typeof value !== 'object' || null === value) {
|
|
524
606
|
return false;
|
|
607
|
+
}
|
|
525
608
|
const v = value;
|
|
526
609
|
return 'string' === typeof v['code'] && 'string' === typeof v['message'];
|
|
527
610
|
}
|
|
@@ -548,8 +631,9 @@ function issueClause(issue) {
|
|
|
548
631
|
*/
|
|
549
632
|
function zodArrayAsSentence(message) {
|
|
550
633
|
const text = message.trim();
|
|
551
|
-
if (!text.startsWith('['))
|
|
634
|
+
if (!text.startsWith('[')) {
|
|
552
635
|
return message;
|
|
636
|
+
}
|
|
553
637
|
let parsed;
|
|
554
638
|
try {
|
|
555
639
|
parsed = JSON.parse(text);
|
|
@@ -557,8 +641,9 @@ function zodArrayAsSentence(message) {
|
|
|
557
641
|
catch {
|
|
558
642
|
return message; // not JSON at all — e.g. prose that happens to open with a bracket
|
|
559
643
|
}
|
|
560
|
-
if (!Array.isArray(parsed) || 0 === parsed.length || !parsed.every(isZodIssue))
|
|
644
|
+
if (!Array.isArray(parsed) || 0 === parsed.length || !parsed.every(isZodIssue)) {
|
|
561
645
|
return message;
|
|
646
|
+
}
|
|
562
647
|
const shown = parsed.slice(0, MAX_RENDERED_ISSUES).map(issueClause).join('; ');
|
|
563
648
|
const rest = parsed.length - MAX_RENDERED_ISSUES;
|
|
564
649
|
return rest > 0 ? `${shown} (and ${String(rest)} more)` : shown;
|
|
@@ -613,8 +698,9 @@ const REASON_OF_CODE = {
|
|
|
613
698
|
* its sentence: the not-linked refusal was matched by its prose, and the prose was rewritten.
|
|
614
699
|
*/
|
|
615
700
|
export function codedRefusalOf(error) {
|
|
616
|
-
if (!(error instanceof Error))
|
|
701
|
+
if (!(error instanceof Error)) {
|
|
617
702
|
return undefined;
|
|
703
|
+
}
|
|
618
704
|
const parsed = CodedRefusalSchema.safeParse({
|
|
619
705
|
code: 'code' in error ? error.code : undefined,
|
|
620
706
|
next: 'next' in error ? error.next : undefined,
|
|
@@ -631,24 +717,29 @@ export function buildErrorPayload(rawMessage, coded) {
|
|
|
631
717
|
// leave an unparseable fragment as the agent's error text — the worst of both shapes.
|
|
632
718
|
const message = capMessage(zodArrayAsSentence(rawMessage));
|
|
633
719
|
// A coded refusal says who does what next itself: no hint beside it, and no bug-report ask.
|
|
634
|
-
if (coded !== undefined)
|
|
720
|
+
if (coded !== undefined) {
|
|
635
721
|
return { error: message, code: coded.code, next: coded.next };
|
|
636
|
-
|
|
722
|
+
}
|
|
723
|
+
if (isUnissuedRefRefusal(message)) {
|
|
637
724
|
return { error: message, recovery: RECOVERY.UNISSUED_REF };
|
|
725
|
+
}
|
|
638
726
|
// A self-diagnosing message gets NEITHER a generic recovery nor the feedback ask. It already
|
|
639
727
|
// inspected the machine and named the cause; a second, contradictory hint is noise, and inviting a
|
|
640
728
|
// bug report about a condition Reticle diagnosed itself is exactly backwards.
|
|
641
|
-
if (isSelfRecovering(message))
|
|
729
|
+
if (isSelfRecovering(message)) {
|
|
642
730
|
return { error: message };
|
|
731
|
+
}
|
|
643
732
|
// An argument rejection is the agent's to fix, not a Reticle defect. Reported from the field: a
|
|
644
733
|
// clean `unrecognized_keys: ["value"]` came back wrapped in "may be a defect in Reticle", which
|
|
645
734
|
// spends the agent's turn and fills the feedback channel with reports about malformed calls.
|
|
646
|
-
if (ARGUMENT_REJECTION.test(message))
|
|
735
|
+
if (ARGUMENT_REJECTION.test(message)) {
|
|
647
736
|
return { error: message, recovery: ARGUMENT_RECOVERY };
|
|
737
|
+
}
|
|
648
738
|
// Reticle's own name validators rejecting a caller's value: an argument rejection that the schema
|
|
649
739
|
// cannot express (the shape is a runtime pattern, not a type), so it needs its own arm.
|
|
650
|
-
if (INVALID_NAME_REJECTION.test(message))
|
|
740
|
+
if (INVALID_NAME_REJECTION.test(message)) {
|
|
651
741
|
return { error: message, recovery: RECOVERY.INVALID_NAME };
|
|
742
|
+
}
|
|
652
743
|
const recovery = recoveryFor(message);
|
|
653
744
|
return recovery !== undefined
|
|
654
745
|
? { error: message, recovery }
|
|
@@ -60,7 +60,7 @@ export const EXPLORE_TOOLS = [
|
|
|
60
60
|
runId: z
|
|
61
61
|
.string()
|
|
62
62
|
.optional()
|
|
63
|
-
.describe('The run id
|
|
63
|
+
.describe('The run id a call answered with; pass it to poll that run.'),
|
|
64
64
|
planId: z.string().optional().describe('Run a plan saved on the dashboard, as it stands.'),
|
|
65
65
|
stop: z.boolean().optional().describe('With runId: stop that Harness run.'),
|
|
66
66
|
say: z.string().optional().describe('With runId: a note to the running Harness.'),
|
|
@@ -17,6 +17,7 @@ import { endsRun, noteToolResult, runReportField } from './run-report.js';
|
|
|
17
17
|
import { runLedger } from '../../judgement/runs/run-ledger.js';
|
|
18
18
|
import { readAppNotes } from './agent/app-notes.js';
|
|
19
19
|
import { forTheAgent } from './agent/for-the-agent.js';
|
|
20
|
+
import { inRepeatStreak, withHintOn } from './repeat-hint.js';
|
|
20
21
|
import { feedbackAlreadyAsked, noteFeedbackAsked } from './agent/notices.js';
|
|
21
22
|
import { SKEW_SHORT_WARNING, SKEW_VERDICT_WARNING } from '../../portal/session/session-health.js';
|
|
22
23
|
import { verifyNextBaton, SUPPRESS_VERIFY_NEXT_ENV } from './verify-next-baton.js';
|
|
@@ -29,7 +30,7 @@ import { rewriteClosedAsSkew } from '../../command/version/version-skew.js';
|
|
|
29
30
|
import { noteToolCall } from '../../command/daemon/lifetime/daemon-usefulness.js';
|
|
30
31
|
import { bugsInResult, routeOf } from '../../telemetry/bug-found.js';
|
|
31
32
|
import { noteToolServed, reportToolRefused } from '../../telemetry/tool-refused.js';
|
|
32
|
-
import { buildErrorPayload,
|
|
33
|
+
import { buildErrorPayload, classifyRefusal, codedRefusalOf } from './error-recovery.js';
|
|
33
34
|
import { resultIsError } from '../mcp/faults/mcp-is-error.js';
|
|
34
35
|
import { verificationOf } from '../../telemetry/verification-of.js';
|
|
35
36
|
import { emitBugFoundHook, emitVerdictHook } from '../../hooks/hook-emit.js';
|
|
@@ -46,6 +47,7 @@ import { takeStepShot } from '../../features/visual/step-shots.js';
|
|
|
46
47
|
import { defectForToolResult, deltaForToolResult, impactSnapshot, initImpact, recordImpact, } from '../../memory/impact/impact-recorder.js';
|
|
47
48
|
import { FrictionKind, frictionOf, inviteFor } from './feedback-invite.js';
|
|
48
49
|
import { VACUOUS_BECAUSE } from '@reticlehq/engine/evidence/verified.js';
|
|
50
|
+
import { NEXT_STEP_FIELD } from './empty-session-list.js';
|
|
49
51
|
/**
|
|
50
52
|
* Emit `verification_completed` when a verification tool produced a verdict.
|
|
51
53
|
*
|
|
@@ -134,11 +136,12 @@ function reportBugsFound(toolName, result, sessionId) {
|
|
|
134
136
|
* tool's name, and then hands the same failure back out to be reported a second time as
|
|
135
137
|
* `reticle_run`. A count that doubles because of HOW a tool was reached is not a measurement.
|
|
136
138
|
*/
|
|
137
|
-
function reportRefusal(toolName, message, error) {
|
|
139
|
+
function reportRefusal(toolName, args, message, error) {
|
|
138
140
|
if (toolName === ReticleTool.RUN) {
|
|
139
141
|
return;
|
|
140
142
|
}
|
|
141
|
-
|
|
143
|
+
const { reason, detail } = classifyRefusal(message, codedRefusalOf(error));
|
|
144
|
+
reportToolRefused(toolName, reason, args, detail);
|
|
142
145
|
}
|
|
143
146
|
/**
|
|
144
147
|
* Which friction this result represents, counting the invitation if there is one.
|
|
@@ -256,25 +259,20 @@ export async function runTool(tool, deps, given, call) {
|
|
|
256
259
|
// The project of the session a call ends, read while the session still exists: releasing a
|
|
257
260
|
// tab removes it, and an unreadable project lost an unlinked user's cloud line.
|
|
258
261
|
const endedIn = agentCall && ends ? safeRoot(() => sessionRoot(deps, sessionIdFromArgs(args))) : undefined;
|
|
259
|
-
|
|
262
|
+
// `reticle_run` is counted once, as the tool it reached; never another agent's call (rule 8).
|
|
263
|
+
const owner = currentDrivenBy() === undefined && ReticleTool.RUN !== tool.name;
|
|
264
|
+
const { raw, hint } = await inRepeatStreak(owner ? deps.attachId : undefined, tool.name, args, () => loggedTool(tool, deps, args, call));
|
|
260
265
|
const attach = currentDrivenBy() === undefined ? deps.attachId : undefined;
|
|
261
266
|
const root = attach === undefined
|
|
262
267
|
? undefined
|
|
263
268
|
: safeRoot(() => sessionRoot(deps, sessionIdFromArgs(args)));
|
|
264
269
|
// The app notes before this call, so a note it learns counts as memory written.
|
|
265
270
|
const notesBefore = agentCall && root !== undefined ? readAppNotes(root) : [];
|
|
266
|
-
const answer = forTheAgent({
|
|
267
|
-
name: tool.name,
|
|
268
|
-
args,
|
|
269
|
-
result: raw,
|
|
270
|
-
attach,
|
|
271
|
-
root,
|
|
272
|
-
fold: NOTICE_FOLD,
|
|
273
|
-
});
|
|
271
|
+
const answer = withHintOn(forTheAgent({ name: tool.name, args, result: raw, attach, root, fold: NOTICE_FOLD }), hint);
|
|
274
272
|
if (!agentCall) {
|
|
275
273
|
return answer;
|
|
276
274
|
}
|
|
277
|
-
runLedger.after(deps.now());
|
|
275
|
+
runLedger.after(deps.now(), deps.attachId);
|
|
278
276
|
noteToolResult(runLedger, tool.name, args, raw);
|
|
279
277
|
const notesAfter = root === undefined ? [] : readAppNotes(root);
|
|
280
278
|
runLedger.memoryWritten(notesAfter.filter((note) => !notesBefore.includes(note)).length);
|
|
@@ -282,7 +280,10 @@ export async function runTool(tool, deps, given, call) {
|
|
|
282
280
|
if (!ends || null === answer || 'object' !== typeof answer) {
|
|
283
281
|
return answer;
|
|
284
282
|
}
|
|
285
|
-
return {
|
|
283
|
+
return {
|
|
284
|
+
...answer,
|
|
285
|
+
...runReportField(runLedger, endedIn ?? root, process.env, deps.now(), deps.attachId),
|
|
286
|
+
};
|
|
286
287
|
}));
|
|
287
288
|
}
|
|
288
289
|
/** Advisories that become once-per-session notice lines. See agent/notices.ts. */
|
|
@@ -391,7 +392,7 @@ async function dispatchTool(tool, deps, args, call, seen = {}) {
|
|
|
391
392
|
'value — a selector or an id rather than a document, or a slice of the text you need.';
|
|
392
393
|
// Refused before the handler was ever entered, and still a refusal the agent has to recover
|
|
393
394
|
// from. Reported here rather than at the return below, which this branch never reaches.
|
|
394
|
-
reportRefusal(tool.name, error);
|
|
395
|
+
reportRefusal(tool.name, args, error);
|
|
395
396
|
return { error };
|
|
396
397
|
}
|
|
397
398
|
// One driver per tab. The Harness clicking through a page while the agent clicks too is two hands
|
|
@@ -399,7 +400,7 @@ async function dispatchTool(tool, deps, args, call, seen = {}) {
|
|
|
399
400
|
const busy = ACTION_TOOLS.has(tool.name) ? harnessDriving(deps, args) : undefined;
|
|
400
401
|
if (busy !== undefined) {
|
|
401
402
|
const error = msgHarnessHasTheTab(busy);
|
|
402
|
-
reportRefusal(tool.name, error);
|
|
403
|
+
reportRefusal(tool.name, args, error);
|
|
403
404
|
return { error };
|
|
404
405
|
}
|
|
405
406
|
// An ACTION is what gets abandoned. Counted here, against verifications, so "the agent drove the
|
|
@@ -448,7 +449,7 @@ async function dispatchTool(tool, deps, args, call, seen = {}) {
|
|
|
448
449
|
// before Playwright invents a closed page. ready:true leases still hit this path.
|
|
449
450
|
if (session?.versionSkew !== undefined && CDP_TOOLS.has(tool.name)) {
|
|
450
451
|
const message = session.versionSkew;
|
|
451
|
-
reportRefusal(tool.name, message);
|
|
452
|
+
reportRefusal(tool.name, args, message);
|
|
452
453
|
throw new Error(message);
|
|
453
454
|
}
|
|
454
455
|
// A ref that was handed out by a DIFFERENT tab, on a call that named no session. Refused here, at
|
|
@@ -466,7 +467,7 @@ async function dispatchTool(tool, deps, args, call, seen = {}) {
|
|
|
466
467
|
if (wrongTab !== undefined) {
|
|
467
468
|
// Refused before the handler was entered, so it is reported here — the same shape as the
|
|
468
469
|
// oversized-argument refusal above.
|
|
469
|
-
reportRefusal(tool.name, wrongTab);
|
|
470
|
+
reportRefusal(tool.name, args, wrongTab);
|
|
470
471
|
return { error: wrongTab };
|
|
471
472
|
}
|
|
472
473
|
}
|
|
@@ -516,7 +517,7 @@ async function dispatchTool(tool, deps, args, call, seen = {}) {
|
|
|
516
517
|
const rewritten = rewriteClosedAsSkew(error, skewText);
|
|
517
518
|
const toThrow = rewritten ?? error;
|
|
518
519
|
const message = toThrow instanceof Error ? toThrow.message : String(toThrow);
|
|
519
|
-
reportRefusal(tool.name, message, toThrow);
|
|
520
|
+
reportRefusal(tool.name, args, message, toThrow);
|
|
520
521
|
// The invitation on THIS path is the one `buildErrorPayload` attaches when it does not recognise
|
|
521
522
|
// the error, and it was never counted — so the denominator excluded the commonest friction there
|
|
522
523
|
// is. Gated on the payload actually carrying the ask, because a recognised error gets a recovery
|
|
@@ -580,7 +581,7 @@ async function dispatchTool(tool, deps, args, call, seen = {}) {
|
|
|
580
581
|
// project the daemon was started in.
|
|
581
582
|
session?.pushImpact?.(() => impactSnapshot(artifactRoot));
|
|
582
583
|
if (resultIsError(raw)) {
|
|
583
|
-
reportRefusal(tool.name, raw.error);
|
|
584
|
+
reportRefusal(tool.name, args, raw.error);
|
|
584
585
|
}
|
|
585
586
|
else {
|
|
586
587
|
noteToolServed();
|
|
@@ -660,6 +661,11 @@ async function dispatchTool(tool, deps, args, call, seen = {}) {
|
|
|
660
661
|
})
|
|
661
662
|
: undefined;
|
|
662
663
|
const platformLine = platform === undefined ? nudge : nudge === undefined ? platform : `${platform}\n${nudge}`;
|
|
664
|
+
// The first call of this connection, in an unwired app with nothing attached: the offer the
|
|
665
|
+
// plugin's SessionStart hook makes, which `/reload-plugins` never fires. Always taken, so a call
|
|
666
|
+
// that already said it (the opened tab's notice, an empty list's `next_step`) still uses the once.
|
|
667
|
+
const firstOffer = agentCall && deps.attachId !== undefined ? deps.firstSessionOffer?.(deps.attachId) : undefined;
|
|
668
|
+
const offer = opened === undefined && !(NEXT_STEP_FIELD in (answer ?? {})) ? firstOffer : undefined;
|
|
663
669
|
const drives = agentCall
|
|
664
670
|
? takeDriveNotes('string' === typeof answer?.['runId'] ? answer['runId'] : undefined)
|
|
665
671
|
: [];
|
|
@@ -675,7 +681,8 @@ async function dispatchTool(tool, deps, args, call, seen = {}) {
|
|
|
675
681
|
undelivered === undefined &&
|
|
676
682
|
friction === undefined &&
|
|
677
683
|
platformLine === undefined &&
|
|
678
|
-
next === undefined
|
|
684
|
+
next === undefined &&
|
|
685
|
+
offer === undefined
|
|
679
686
|
? raw
|
|
680
687
|
: {
|
|
681
688
|
// First, so a model that truncates a long result still reads it.
|
|
@@ -696,6 +703,7 @@ async function dispatchTool(tool, deps, args, call, seen = {}) {
|
|
|
696
703
|
...(update !== undefined ? { [EnvelopeKey.UPDATE_AVAILABLE]: update } : {}),
|
|
697
704
|
...(skew !== undefined ? { [EnvelopeKey.VERSION_SKEW]: skew } : {}),
|
|
698
705
|
...(platformLine !== undefined ? { [EnvelopeKey.PLATFORM]: platformLine } : {}),
|
|
706
|
+
...(offer === undefined ? {} : { [EnvelopeKey.FIRST_SESSION_OFFER]: offer }),
|
|
699
707
|
...(0 === drives.length ? {} : { [EnvelopeKey.HARNESS]: drives.join('\n') }),
|
|
700
708
|
...(notes === undefined ? {} : { [EnvelopeKey.CONTROL]: notes }),
|
|
701
709
|
...(undelivered !== undefined
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `reticle_lease { action: "coverage" }` — which code of a leased page ran, as the JS engine counted it.
|
|
3
|
+
*
|
|
4
|
+
* A caller outside the app cannot see which branches a drive reached. The JS engine can: each script's block
|
|
5
|
+
* ranges carry a count. This reads them from the lease's own Playwright page, the way
|
|
6
|
+
* `reticle_network_mock` reaches it, so it needs no change to the app.
|
|
7
|
+
*
|
|
8
|
+
* A take returns what ran since the previous take, and coverage keeps running across a reload.
|
|
9
|
+
* Start it on acquire (`jsCoverage: true`) to see the code that runs while the page loads; a start
|
|
10
|
+
* after the load misses it.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import type { ScriptCoverage } from '../../portal/input/js-coverage.js';
|
|
14
|
+
import { type ToolDef } from './tool-kit.js';
|
|
15
|
+
export declare const LeaseCoverageMode: {
|
|
16
|
+
readonly START: "start";
|
|
17
|
+
readonly TAKE: "take";
|
|
18
|
+
};
|
|
19
|
+
/** Ranges one take returns when the caller sets no cap. */
|
|
20
|
+
export declare const DEFAULT_MAX_COVERAGE_RANGES = 20000;
|
|
21
|
+
interface Range {
|
|
22
|
+
startOffset: number;
|
|
23
|
+
endOffset: number;
|
|
24
|
+
count: number;
|
|
25
|
+
}
|
|
26
|
+
/** What a take returns: each kept script with its ranges, and what the cap and filter left out. */
|
|
27
|
+
export interface CoverageTake {
|
|
28
|
+
scripts: {
|
|
29
|
+
url: string;
|
|
30
|
+
ranges: Range[];
|
|
31
|
+
}[];
|
|
32
|
+
scriptCount: number;
|
|
33
|
+
rangeCount: number;
|
|
34
|
+
filteredOut?: number;
|
|
35
|
+
truncated?: {
|
|
36
|
+
scripts: number;
|
|
37
|
+
ranges: number;
|
|
38
|
+
maxRanges: number;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Flatten each script's functions into one range list, keep the scripts `urlContains` names, and
|
|
43
|
+
* stop at `maxRanges`. What the cap drops is counted in `truncated`, beside the value.
|
|
44
|
+
*/
|
|
45
|
+
export declare function flattenCoverage(entries: readonly ScriptCoverage[], maxRanges: number, urlContains?: string): CoverageTake;
|
|
46
|
+
/** The acquire argument that starts coverage before the page's first script. */
|
|
47
|
+
export declare const LEASE_JS_COVERAGE_ARG: z.ZodOptional<z.ZodBoolean>;
|
|
48
|
+
export declare const LEASE_COVERAGE_TOOL: ToolDef;
|
|
49
|
+
export {};
|