@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
|
@@ -43,17 +43,53 @@ the first flow. It never drives: the Harness is opt-in and runs at any instrumen
|
|
|
43
43
|
const VERIFY_DETAIL = `Drives the URL and verifies the saved flows. Exit 0 means every one passed.
|
|
44
44
|
|
|
45
45
|
--explore [--persona <who>] no saved flows? let Reticle drive the app and record them
|
|
46
|
+
--against <reference-url> compare the URL with a reference build: drive both with the same
|
|
47
|
+
actions, and report each difference in what users see (exit 1)
|
|
46
48
|
--select <label> repeatable: verify only flows carrying these labels
|
|
47
49
|
--results-json <file> also write one verdict per journey as JSON, for CI
|
|
48
50
|
--confirm-dangerous this run may press what the replay guard holds as destructive
|
|
51
|
+
--require-start-control fail a flow whose first control is not on its freshly loaded start page
|
|
52
|
+
--sweep judge every step, also after one fails (the results score counts them all)
|
|
49
53
|
--storage-state <file> start signed in
|
|
50
|
-
--session-id <id>, --timeout
|
|
54
|
+
--session-id <id>, --timeout <ms>, --headed, --port N
|
|
51
55
|
--expect '<json predicate>' | --expect-file <path>
|
|
52
56
|
one verdict, no saved flows needed. Asks a running daemon,
|
|
53
57
|
never starts one, and waits up to --timeout ms (default 4000)
|
|
54
58
|
for it to come true. Exit 0 only on verified:"yes". For an
|
|
55
59
|
action --expect cannot do, use the HTTP MCP transport:
|
|
56
60
|
https://docs.reticle.sh/http-transport.md`;
|
|
61
|
+
const GRADE_DETAIL = `Grades a finished run of an app from snapshots of its stored data. It needs no
|
|
62
|
+
daemon and no browser.
|
|
63
|
+
|
|
64
|
+
grade snapshot --state <file> --out <file> [--url <url>]
|
|
65
|
+
read the declared state sources (and the page the run ended on) into a snapshot
|
|
66
|
+
grade judge --reference <file> --again <file> --candidate <file>
|
|
67
|
+
[--expect <file>] [--answer <text>] [--json]
|
|
68
|
+
compare the candidate snapshot with two snapshots of the correct run. A line that
|
|
69
|
+
differs between the two correct runs is ignored. --expect declares a source whose
|
|
70
|
+
rows are the correct answer, read now. Exit 0 = pass, 1 = fail, 2 = unverified
|
|
71
|
+
grade tables --list <command> --rows <template> [--container <name>] [--skip <prefix,...>]
|
|
72
|
+
--out <file>
|
|
73
|
+
write a declaration with one source for each table; {table} in the template is
|
|
74
|
+
the table name; --skip leaves out the tables whose name starts with a prefix
|
|
75
|
+
grade suggest --state <file> --reference <file> --again <file> --out <file>
|
|
76
|
+
keep only the sources that read the same on two correct runs`;
|
|
77
|
+
const COMPARE_DETAIL = `Drives two running builds of one app the same way, for example main and a pull request
|
|
78
|
+
preview, and reports each difference in what a person sees and in the requests and console
|
|
79
|
+
errors the app made. Install nothing in the app.
|
|
80
|
+
|
|
81
|
+
It plans every action on every control of the reference, drives the plan on the reference two
|
|
82
|
+
times and on the candidate one time, and ignores what changes between the two reference runs.
|
|
83
|
+
Point it at builds whose data you can change: it presses every button it finds.
|
|
84
|
+
|
|
85
|
+
--base <url> the build before the change: tag each difference as a regression, a missed
|
|
86
|
+
target or a change, and print a score
|
|
87
|
+
--state <file> a JSON file { "sources": [...] } that declares how to read the app's stored
|
|
88
|
+
data (kind command, http or file). Compare reads it after each sequence on
|
|
89
|
+
every build, so a change to a record that no page shows is a difference.
|
|
90
|
+
Start each row with the record id, so a changed row names its record
|
|
91
|
+
--json print one JSON object
|
|
92
|
+
Exit 0 = same, 1 = different, 2 = the run proves nothing (a lost browser session, or an error).`;
|
|
57
93
|
const BROWSER_NOTE = `The browser Reticle opens for your agent is shown so you can watch the run. --headless hides
|
|
58
94
|
it; CI, RETICLE_HEADLESS=1, or a Linux machine with no display hides it too.`;
|
|
59
95
|
/** What `--http` starts. MCP is already on the bridge port; this flag is the verify endpoint. */
|
|
@@ -92,26 +128,43 @@ const COMMANDS = [
|
|
|
92
128
|
{
|
|
93
129
|
name: 'verify',
|
|
94
130
|
synopsis: 'verify <url> [--explore] [--expect <json>]',
|
|
95
|
-
summary: 'Check
|
|
131
|
+
summary: 'Check saved flows, or one claim with --expect, against the running app; exit 0 = pass',
|
|
96
132
|
group: HelpGroup.CHECK,
|
|
97
133
|
detail: VERIFY_DETAIL,
|
|
98
134
|
},
|
|
135
|
+
{
|
|
136
|
+
name: 'compare',
|
|
137
|
+
synopsis: 'compare <reference-url> <candidate-url> [--base <url>] [--state <file>] [--json] [--report <file>]',
|
|
138
|
+
summary: 'Drive two builds the same way and list what users would see change',
|
|
139
|
+
group: HelpGroup.CHECK,
|
|
140
|
+
detail: COMPARE_DETAIL,
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: 'grade',
|
|
144
|
+
synopsis: 'grade <snapshot|judge|tables|suggest> [flags]',
|
|
145
|
+
summary: "Grade a finished run from snapshots of the app's stored data",
|
|
146
|
+
group: HelpGroup.MORE,
|
|
147
|
+
detail: GRADE_DETAIL,
|
|
148
|
+
},
|
|
99
149
|
{
|
|
100
150
|
name: 'gate',
|
|
101
|
-
synopsis: 'gate [--since <ref>] [--accept-coverage] [--hook] [file...]',
|
|
151
|
+
synopsis: 'gate [--list] [--since <ref>] [--accept-coverage] [--hook] [file...]',
|
|
102
152
|
summary: 'Fail unless passing checks cover the flows your changes touch',
|
|
103
153
|
group: HelpGroup.CHECK,
|
|
154
|
+
detail: '--list names the saved flows your changes touch, and checks nothing.',
|
|
104
155
|
},
|
|
105
156
|
{
|
|
106
157
|
name: 'status',
|
|
107
158
|
synopsis: 'status [--json] [--port N]',
|
|
108
159
|
summary: 'Is Reticle running, is your app connected, are you signed in',
|
|
160
|
+
detail: 'Shows the enterprise license when a key is set. --json always carries it.',
|
|
109
161
|
group: HelpGroup.MACHINE,
|
|
110
162
|
},
|
|
111
163
|
{
|
|
112
164
|
name: 'doctor',
|
|
113
|
-
synopsis: 'doctor [--port N]',
|
|
165
|
+
synopsis: 'doctor [--fix] [--port N]',
|
|
114
166
|
summary: 'Find what is wrong with the setup, and what is missing from coverage',
|
|
167
|
+
detail: '--fix repairs what Reticle can repair safely, and names the step for the rest.',
|
|
115
168
|
group: HelpGroup.MACHINE,
|
|
116
169
|
},
|
|
117
170
|
{
|
|
@@ -131,17 +184,12 @@ const COMMANDS = [
|
|
|
131
184
|
"With --force, frees the port by the Reticle daemon LISTENING on it, never the agent's MCP\n" +
|
|
132
185
|
'proxy, and refuses a listener that is not Reticle.',
|
|
133
186
|
},
|
|
134
|
-
{
|
|
135
|
-
name: 'restart',
|
|
136
|
-
synopsis: 'restart [--force] [--port N]',
|
|
137
|
-
summary: 'Stop Reticle, then start it and wait until it is listening',
|
|
138
|
-
group: HelpGroup.MACHINE,
|
|
139
|
-
},
|
|
140
187
|
{
|
|
141
188
|
name: 'update',
|
|
142
|
-
synopsis: 'update',
|
|
189
|
+
synopsis: 'update [--rollback]',
|
|
143
190
|
summary: 'Install the latest version and restart',
|
|
144
191
|
group: HelpGroup.MACHINE,
|
|
192
|
+
detail: '--rollback restores the previous version and restarts.',
|
|
145
193
|
},
|
|
146
194
|
{
|
|
147
195
|
name: 'logout',
|
|
@@ -169,7 +217,7 @@ const COMMANDS = [
|
|
|
169
217
|
synopsis: 'sync [--watch] [--move-history]',
|
|
170
218
|
summary: 'Send local runs to the dashboard and collect decisions',
|
|
171
219
|
group: HelpGroup.MORE,
|
|
172
|
-
detail: '
|
|
220
|
+
detail: ' --watch keep sending as runs are written\n' +
|
|
173
221
|
' --move-history also send runs, flows and records made under the previous link',
|
|
174
222
|
},
|
|
175
223
|
{
|
|
@@ -190,12 +238,6 @@ const COMMANDS = [
|
|
|
190
238
|
summary: 'What this project sends to the dashboard',
|
|
191
239
|
group: HelpGroup.MORE,
|
|
192
240
|
},
|
|
193
|
-
{
|
|
194
|
-
name: 'affected',
|
|
195
|
-
synopsis: 'affected [--since <ref>] [file...]',
|
|
196
|
-
summary: 'Which saved flows must re-verify for the changed files',
|
|
197
|
-
group: HelpGroup.MORE,
|
|
198
|
-
},
|
|
199
241
|
{
|
|
200
242
|
name: 'report',
|
|
201
243
|
synopsis: 'report [--session <id>] [--hook]',
|
|
@@ -235,7 +277,7 @@ const COMMANDS = [
|
|
|
235
277
|
synopsis: 'serve [--port N] [--drive <url>] [--headless] [--headed] [--http] [--http-port N] [--http-token T]',
|
|
236
278
|
summary: 'Start the daemon in the background; returns once it answers',
|
|
237
279
|
group: HelpGroup.MORE,
|
|
238
|
-
detail: DAEMON_DETAIL
|
|
280
|
+
detail: `--restart [--force] stops Reticle, then starts it and waits until it listens.\n\n${DAEMON_DETAIL}`,
|
|
239
281
|
},
|
|
240
282
|
{
|
|
241
283
|
name: 'drive',
|
|
@@ -249,18 +291,6 @@ const COMMANDS = [
|
|
|
249
291
|
summary: 'Register the MCP server with the coding agents on this machine',
|
|
250
292
|
group: HelpGroup.MORE,
|
|
251
293
|
},
|
|
252
|
-
{
|
|
253
|
-
name: 'license',
|
|
254
|
-
synopsis: 'license',
|
|
255
|
-
summary: 'Show the enterprise license status',
|
|
256
|
-
group: HelpGroup.MORE,
|
|
257
|
-
},
|
|
258
|
-
{
|
|
259
|
-
name: 'rollback',
|
|
260
|
-
synopsis: 'rollback',
|
|
261
|
-
summary: 'Restore the previous version and restart',
|
|
262
|
-
group: HelpGroup.MORE,
|
|
263
|
-
},
|
|
264
294
|
{
|
|
265
295
|
name: 'version',
|
|
266
296
|
synopsis: 'version',
|
|
@@ -39,6 +39,11 @@ export interface VerifyConnection {
|
|
|
39
39
|
* only the connection can read one.
|
|
40
40
|
*/
|
|
41
41
|
listFlows(select?: readonly string[]): Promise<string[]>;
|
|
42
|
+
/**
|
|
43
|
+
* Each named flow's saved step count, for the results score: without it a replay that stopped at
|
|
44
|
+
* step 2 of 10 reads as a 2-step journey. Optional; a name it cannot read is left out.
|
|
45
|
+
*/
|
|
46
|
+
plannedSteps?(names: readonly string[]): Promise<ReadonlyMap<string, number>>;
|
|
42
47
|
/**
|
|
43
48
|
* Drive the app with a model and save what it drove. Present only when a model is configured.
|
|
44
49
|
*
|
|
@@ -190,8 +195,8 @@ export declare function routeVerify(args: {
|
|
|
190
195
|
hasPredicate: boolean;
|
|
191
196
|
/**
|
|
192
197
|
* True when the caller asked for something only a browser of OUR OWN can do: `--headed` or
|
|
193
|
-
* `--storage-state
|
|
194
|
-
* silently ignore the request.
|
|
198
|
+
* `--storage-state`, or a rule its replay tool does not take (`--require-start-control`). The
|
|
199
|
+
* running daemon's tab can honour none of them, so replaying there would silently ignore the request.
|
|
195
200
|
*/
|
|
196
201
|
wantsOwnBrowser?: boolean;
|
|
197
202
|
/**
|
|
@@ -230,5 +235,14 @@ export declare function handleVerify(parsed: {
|
|
|
230
235
|
resultsJson?: string;
|
|
231
236
|
/** Acknowledge the replay guard's destructive steps ("Place order") for this run only. */
|
|
232
237
|
confirmDangerous?: boolean;
|
|
233
|
-
|
|
238
|
+
/** Fail a flow whose step 1 control is missing on its freshly loaded start page. */
|
|
239
|
+
requireStartControl?: boolean;
|
|
240
|
+
/** Judge every step, also after one fails. */
|
|
241
|
+
sweep?: boolean;
|
|
242
|
+
},
|
|
243
|
+
/**
|
|
244
|
+
* Called once, after the last verdict line and before the exit. `cli.ts` passes the CI line:
|
|
245
|
+
* `telemetry` already reaches this directory, so this directory does not reach back.
|
|
246
|
+
*/
|
|
247
|
+
beforeExit?: () => void): void;
|
|
234
248
|
export {};
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { cliRunAuthor } from '../../judgement/runs/verification-sync.js';
|
|
13
13
|
import { join, basename } from 'node:path';
|
|
14
14
|
import { readFileSync } from 'node:fs';
|
|
15
|
+
import { noSessionMessage } from './verify-no-session.js';
|
|
15
16
|
import { runAdhocVerdict } from './adhoc-verdict.js';
|
|
16
17
|
import { callerArtifactRoot } from '../../memory/project/link-directory.js';
|
|
17
18
|
import { verifyResults } from './verify-results.js';
|
|
@@ -59,9 +60,6 @@ const DEFAULT_PROJECT_NAME = 'app';
|
|
|
59
60
|
export function verifyProjectName(linked, configured, folder) {
|
|
60
61
|
return linked ?? configured ?? (folder || DEFAULT_PROJECT_NAME);
|
|
61
62
|
}
|
|
62
|
-
const MSG_NO_SESSION = 'No app connected: Reticle drove the URL but no @reticlehq/browser session dialed back.\n' +
|
|
63
|
-
' Make sure the SDK is in the build and reticle.connect() runs on the preview page' +
|
|
64
|
-
' (for a non-localhost preview: allowNonLocalhost + a pairing token).';
|
|
65
63
|
const MSG_NO_FLOWS = 'No saved flows to verify (.reticle/flows is empty), so refusing to report a pass for verifying nothing.\n' +
|
|
66
64
|
' Flows are recorded interactively by an agent (reticle_record{action:"start"} → act → reticle_flow_save via the\n' +
|
|
67
65
|
' MCP tools), then committed to .reticle/flows/. In CI, check those files in and re-run `reticle verify`.\n' +
|
|
@@ -86,8 +84,9 @@ async function openConnection(ports) {
|
|
|
86
84
|
/** Orchestration: boot → wait for a session → replay flows → verdict → exit code. Browser-free. */
|
|
87
85
|
export async function runVerify(args, outer) {
|
|
88
86
|
const conn = await openConnection(outer);
|
|
89
|
-
if (conn === undefined)
|
|
87
|
+
if (conn === undefined) {
|
|
90
88
|
return;
|
|
89
|
+
}
|
|
91
90
|
/*
|
|
92
91
|
* The exit is held until the connection has closed. The live exit is process.exit, and close()
|
|
93
92
|
* runs the last cloud sync cycle that sends this run's flows and screenshots: exiting first skipped
|
|
@@ -103,7 +102,7 @@ export async function runVerify(args, outer) {
|
|
|
103
102
|
try {
|
|
104
103
|
const ready = await conn.sessionReady(args.timeoutMs);
|
|
105
104
|
if (!ready) {
|
|
106
|
-
ports.fail(
|
|
105
|
+
ports.fail(noSessionMessage(args.timeoutMs));
|
|
107
106
|
ports.exit(EXIT_FAIL);
|
|
108
107
|
return;
|
|
109
108
|
}
|
|
@@ -132,8 +131,9 @@ export async function runVerify(args, outer) {
|
|
|
132
131
|
*/
|
|
133
132
|
if (0 === names.length && (true === args.explore || args.persona !== undefined)) {
|
|
134
133
|
const explored = await explore(conn, args, ports);
|
|
135
|
-
if (!explored)
|
|
134
|
+
if (!explored) {
|
|
136
135
|
return;
|
|
136
|
+
}
|
|
137
137
|
names = await conn.listFlows();
|
|
138
138
|
}
|
|
139
139
|
if (0 === names.length) {
|
|
@@ -180,7 +180,7 @@ export async function runVerify(args, outer) {
|
|
|
180
180
|
// The run's OWN injected timestamp — no wall clock is read in this path (rule 7).
|
|
181
181
|
[{ phase: VerifyPhase.PUSHED, at: run.createdAt }], cloud, cloudFetch).catch(() => undefined);
|
|
182
182
|
if (args.resultsJson !== undefined && ports.writeResults !== undefined) {
|
|
183
|
-
await ports.writeResults(args.resultsJson, `${JSON.stringify(verifyResults(run, pushed), null, 2)}\n`);
|
|
183
|
+
await ports.writeResults(args.resultsJson, `${JSON.stringify(verifyResults(run, pushed, (await conn.plannedSteps?.(run.flows.map((f) => f.name))) ?? new Map()), null, 2)}\n`);
|
|
184
184
|
}
|
|
185
185
|
ports.out(renderRunReport(run));
|
|
186
186
|
ports.exit(run.verdict.status === VerdictStatus.PASS ? EXIT_PASS : EXIT_FAIL);
|
|
@@ -192,8 +192,9 @@ export async function runVerify(args, outer) {
|
|
|
192
192
|
finally {
|
|
193
193
|
await conn.close().catch(() => undefined);
|
|
194
194
|
// In the finally, so the early refusals that `return` from the try exit too.
|
|
195
|
-
if (exitCode !== undefined)
|
|
195
|
+
if (exitCode !== undefined) {
|
|
196
196
|
outer.exit(exitCode);
|
|
197
|
+
}
|
|
197
198
|
}
|
|
198
199
|
}
|
|
199
200
|
/**
|
|
@@ -269,8 +270,9 @@ function delay(ms) {
|
|
|
269
270
|
async function waitForSession(sessions, timeoutMs, now) {
|
|
270
271
|
const deadline = now() + timeoutMs;
|
|
271
272
|
while (now() < deadline) {
|
|
272
|
-
if (sessions.count() > 0)
|
|
273
|
+
if (sessions.count() > 0) {
|
|
273
274
|
return true;
|
|
275
|
+
}
|
|
274
276
|
await delay(SESSION_POLL_MS);
|
|
275
277
|
}
|
|
276
278
|
return sessions.count() > 0;
|
|
@@ -298,8 +300,9 @@ export function buildVerifyDeps(running, reticleRoot, now) {
|
|
|
298
300
|
// RETICLE_API_KEY was told to run `reticle connect` when asking the Harness to drive.
|
|
299
301
|
linkedCloud: linkedCloudPort(fs, reticleRoot, homedir(), process.env),
|
|
300
302
|
};
|
|
301
|
-
if (running.realInput !== undefined)
|
|
303
|
+
if (running.realInput !== undefined) {
|
|
302
304
|
deps.realInput = running.realInput;
|
|
305
|
+
}
|
|
303
306
|
return deps;
|
|
304
307
|
}
|
|
305
308
|
/** Split a drive URL into its origin + whether it's loopback — decides token/injection pairing. */
|
|
@@ -347,9 +350,24 @@ async function openLiveConnection(opts) {
|
|
|
347
350
|
});
|
|
348
351
|
const deps = buildVerifyDeps(running, opts.reticleRoot, opts.now);
|
|
349
352
|
const harnessEnv = await withLinkedCredential(deps, process.env);
|
|
350
|
-
const runner = new ReticleRunner(createRunnerPort(deps, opts.sessionId, {
|
|
353
|
+
const runner = new ReticleRunner(createRunnerPort(deps, opts.sessionId, {
|
|
354
|
+
confirmDangerous: true === opts.confirmDangerous,
|
|
355
|
+
requireStartControl: true === opts.requireStartControl,
|
|
356
|
+
sweep: true === opts.sweep,
|
|
357
|
+
}));
|
|
351
358
|
return {
|
|
352
359
|
sessionReady: (timeoutMs) => waitForSession(deps.sessions, timeoutMs, opts.now),
|
|
360
|
+
plannedSteps: async (names) => {
|
|
361
|
+
const planned = new Map();
|
|
362
|
+
for (const name of names) {
|
|
363
|
+
const loaded = await deps.flows.load(name).catch(() => undefined);
|
|
364
|
+
if (true === loaded?.ok) {
|
|
365
|
+
// A sequence counts its sub-steps, as the score does.
|
|
366
|
+
planned.set(name, loaded.value.steps.reduce((n, step) => n + (step.steps?.length ?? 1), 0));
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return planned;
|
|
370
|
+
},
|
|
353
371
|
listFlows: async (select) => select === undefined || 0 === select.length
|
|
354
372
|
? deps.flows.list()
|
|
355
373
|
: (await resolveSuiteSelection(deps, projectOnly(undefined), { labels: [...select] })).run,
|
|
@@ -471,7 +489,7 @@ export function expectNeedsDaemonMessage(port, presence) {
|
|
|
471
489
|
export function daemonLacksKeyMessage(port) {
|
|
472
490
|
return (`${ReticleEnv.API_KEY} is set in this shell, but the daemon on port ${String(port)} was ` +
|
|
473
491
|
'started without it, and the daemon is what asks the platform to drive. Restart it from this ' +
|
|
474
|
-
`shell so it inherits the key: npx @reticlehq/server restart --port ${String(port)}`);
|
|
492
|
+
`shell so it inherits the key: npx @reticlehq/server serve --restart --port ${String(port)}`);
|
|
475
493
|
}
|
|
476
494
|
/** What `verify` does next, once the options and the state of the port are both known. */
|
|
477
495
|
export const VerifyRoute = {
|
|
@@ -501,8 +519,9 @@ export function routeVerify(args) {
|
|
|
501
519
|
? { route: VerifyRoute.ADHOC }
|
|
502
520
|
: { route: VerifyRoute.REFUSE, message: expectNeedsDaemonMessage(args.port, args.presence) };
|
|
503
521
|
}
|
|
504
|
-
if (args.presence !== PortPresence.DAEMON)
|
|
522
|
+
if (args.presence !== PortPresence.DAEMON) {
|
|
505
523
|
return { route: VerifyRoute.FLOWS };
|
|
524
|
+
}
|
|
506
525
|
if (true === args.explore && true !== args.wantsOwnBrowser && true !== args.hasSavedFlows) {
|
|
507
526
|
return { route: VerifyRoute.ADHOC_EXPLORE };
|
|
508
527
|
}
|
|
@@ -512,7 +531,12 @@ export function routeVerify(args) {
|
|
|
512
531
|
? { route: VerifyRoute.REFUSE, message: portBusyMessage(args.port) }
|
|
513
532
|
: { route: VerifyRoute.ADHOC_SUITE };
|
|
514
533
|
}
|
|
515
|
-
export function handleVerify(parsed
|
|
534
|
+
export function handleVerify(parsed,
|
|
535
|
+
/**
|
|
536
|
+
* Called once, after the last verdict line and before the exit. `cli.ts` passes the CI line:
|
|
537
|
+
* `telemetry` already reaches this directory, so this directory does not reach back.
|
|
538
|
+
*/
|
|
539
|
+
beforeExit = () => undefined) {
|
|
516
540
|
const now = () => Date.now();
|
|
517
541
|
/*
|
|
518
542
|
* `--expect-file` is `--expect` with the shell taken out of the loop.
|
|
@@ -556,10 +580,15 @@ export function handleVerify(parsed) {
|
|
|
556
580
|
...(parsed.storageState !== undefined ? { storageState: parsed.storageState } : {}),
|
|
557
581
|
...(parsed.sessionId !== undefined ? { sessionId: parsed.sessionId } : {}),
|
|
558
582
|
...(true === parsed.confirmDangerous ? { confirmDangerous: true } : {}),
|
|
583
|
+
...(true === parsed.requireStartControl ? { requireStartControl: true } : {}),
|
|
584
|
+
...(true === parsed.sweep ? { sweep: true } : {}),
|
|
559
585
|
}),
|
|
560
586
|
out: (line) => process.stdout.write(`${line}\n`),
|
|
561
587
|
fail: (line) => process.stderr.write(`${line}\n`),
|
|
562
|
-
exit: (code) =>
|
|
588
|
+
exit: (code) => {
|
|
589
|
+
beforeExit();
|
|
590
|
+
process.exit(code);
|
|
591
|
+
},
|
|
563
592
|
cloud: linkedRunsCloudPort(createNodeFileSystem(), reticleRoot, homedir(), process.env),
|
|
564
593
|
dashboardUrl: () => readDashboardUrl(reticleRoot),
|
|
565
594
|
writeResults: (path, text) => writeFile(path, text, 'utf8'),
|
|
@@ -569,8 +598,9 @@ export function handleVerify(parsed) {
|
|
|
569
598
|
// this used to reach the user as a raw node stack rather than as an answer.
|
|
570
599
|
void (async () => {
|
|
571
600
|
const keyNote = (await resolveProjectCloud(createNodeFileSystem(), reticleRoot, homedir(), process.env)).note;
|
|
572
|
-
if (keyNote !== undefined)
|
|
601
|
+
if (keyNote !== undefined) {
|
|
573
602
|
process.stderr.write(`${keyNote}\n`);
|
|
603
|
+
}
|
|
574
604
|
const port = parsed.port ?? RETICLE_DEFAULT_PORT;
|
|
575
605
|
// A lease opened for this verdict writes its runs into this folder's project, not `unmatched/`.
|
|
576
606
|
const root = callerArtifactRoot(process.cwd());
|
|
@@ -578,7 +608,11 @@ export function handleVerify(parsed) {
|
|
|
578
608
|
const presence = await probePresence(port, { tcpOpen: probeDaemon, status: fetchStatus });
|
|
579
609
|
const plan = routeVerify({
|
|
580
610
|
hasPredicate: expectation !== undefined,
|
|
581
|
-
|
|
611
|
+
// `--require-start-control` too: the daemon's replay tool does not take that rule.
|
|
612
|
+
wantsOwnBrowser: !parsed.headless ||
|
|
613
|
+
parsed.storageState !== undefined ||
|
|
614
|
+
true === parsed.requireStartControl ||
|
|
615
|
+
true === parsed.sweep,
|
|
582
616
|
explore: true === parsed.explore || parsed.persona !== undefined,
|
|
583
617
|
hasSavedFlows: 0 <
|
|
584
618
|
(await new FlowStore(createNodeFileSystem(), reticleRoot, { now: Date.now }).list()).length,
|
|
@@ -613,8 +647,9 @@ export function handleVerify(parsed) {
|
|
|
613
647
|
...(parsed.sessionId === undefined ? {} : { sessionId: parsed.sessionId }),
|
|
614
648
|
...((t) => (t === undefined || 0 === t.length ? {} : { token: t }))(readOrCreatePairingTokenSync(defaultPairingTokenDir())),
|
|
615
649
|
});
|
|
616
|
-
for (const line of verdict.lines)
|
|
650
|
+
for (const line of verdict.lines) {
|
|
617
651
|
ports.out(line);
|
|
652
|
+
}
|
|
618
653
|
ports.exit(verdict.code);
|
|
619
654
|
return;
|
|
620
655
|
}
|
|
@@ -631,8 +666,9 @@ export function handleVerify(parsed) {
|
|
|
631
666
|
...(parsed.sessionId === undefined ? {} : { sessionId: parsed.sessionId }),
|
|
632
667
|
...((t) => (t === undefined || 0 === t.length ? {} : { token: t }))(readOrCreatePairingTokenSync(defaultPairingTokenDir())),
|
|
633
668
|
});
|
|
634
|
-
for (const line of suite.lines)
|
|
669
|
+
for (const line of suite.lines) {
|
|
635
670
|
ports.out(line);
|
|
671
|
+
}
|
|
636
672
|
ports.exit(suite.code);
|
|
637
673
|
return;
|
|
638
674
|
}
|
|
@@ -647,15 +683,17 @@ export function handleVerify(parsed) {
|
|
|
647
683
|
...callerRoot,
|
|
648
684
|
...((t) => (t === undefined || 0 === t.length ? {} : { token: t }))(readOrCreatePairingTokenSync(defaultPairingTokenDir())),
|
|
649
685
|
});
|
|
650
|
-
for (const line of explored.lines)
|
|
686
|
+
for (const line of explored.lines) {
|
|
651
687
|
ports.out(line);
|
|
688
|
+
}
|
|
652
689
|
// The drive runs INSIDE the daemon, so the key has to be in ITS environment. A reader who
|
|
653
690
|
// exported it in this shell and was told to link has been told to do the thing they just
|
|
654
691
|
// did; say where the key is actually missing.
|
|
655
692
|
if (0 !== explored.code && harnessAvailable(process.env)) {
|
|
656
693
|
const refusedForKey = explored.lines.some((line) => line.includes(MSG_NO_HARNESS_KEY));
|
|
657
|
-
if (refusedForKey)
|
|
694
|
+
if (refusedForKey) {
|
|
658
695
|
ports.fail(daemonLacksKeyMessage(port));
|
|
696
|
+
}
|
|
659
697
|
}
|
|
660
698
|
ports.exit(explored.code);
|
|
661
699
|
return;
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* `credentials.json` (per-project api keys from `reticle link`). The non-secret repo binding + sync policy
|
|
6
6
|
* is `<repo>/.reticle/cloud.json`. Auth for a command = `RETICLE_API_KEY` env (agent) OR the login token.
|
|
7
7
|
*/
|
|
8
|
-
import { CreatedProjectSchema } from './project-name.js';
|
|
9
8
|
import { keyRefusalAtLastSync } from '../../memory/project/sync-status.js';
|
|
10
9
|
import { ReticleEnv, apiKeyFrom } from '@reticlehq/core';
|
|
11
10
|
import { writeHarnessSwitch } from '../../memory/cloud/harness-switch.js';
|
|
@@ -24,11 +23,10 @@ import { RETICLE_CONFIG_BASENAME } from './ports/resolve/cli-port.js';
|
|
|
24
23
|
import { cmdLink, validateKey } from './cloud-link.js';
|
|
25
24
|
// `link` moved to its own module; the CLI entry still imports it from here.
|
|
26
25
|
export { cmdLink } from './cloud-link.js';
|
|
27
|
-
import { normalizeUrl } from './auth/cloud-session.js';
|
|
28
26
|
import { chooseWorkspace, cmdLogin, cmdLogout } from './cloud-login.js';
|
|
29
27
|
import { cmdTry } from './try-command.js';
|
|
30
28
|
import { CLOUD_COMMANDS } from './cli-parse-grammar.js';
|
|
31
|
-
import { api, baseUrl,
|
|
29
|
+
import { api, baseUrl, emit, err, flags, hint, readJson, readSession, readSessionFor, RETICLE_DIR, } from './cloud-kit.js';
|
|
32
30
|
import { syncRequest } from '../../memory/cloud/cloud-sync.js';
|
|
33
31
|
import { GateExit, gateExitWith } from './answers/gate-exit.js';
|
|
34
32
|
import { brokenOf } from './known-regression.js';
|
|
@@ -36,7 +34,7 @@ import { describeUnsyncedBriefly } from '../../memory/cloud/unsynced-roots.js';
|
|
|
36
34
|
import { machineUnsyncedRoots } from '../../memory/project/sync-status.js';
|
|
37
35
|
import { runSyncCycle } from '../../memory/cloud/sync-cycle.js';
|
|
38
36
|
import { describeSync } from '../../memory/cloud/sync-describe.js';
|
|
39
|
-
import { diskSink, diskSource, policyScreenshots,
|
|
37
|
+
import { diskSink, diskSource, policyScreenshots, readCloudState, } from '../../memory/cloud/sync-disk.js';
|
|
40
38
|
import { fetchPlatformRun } from '../../features/harness/platform/platform-drives.js';
|
|
41
39
|
import { SERVER_VERSION } from '../version/identity/server-version.js';
|
|
42
40
|
/**
|
|
@@ -82,48 +80,6 @@ const linkedRoot = () => {
|
|
|
82
80
|
const onlyHere = !existsSync(join(project, CLOUD_LINK_FILE)) && existsSync(join(here, CLOUD_LINK_FILE));
|
|
83
81
|
return onlyHere ? here : project;
|
|
84
82
|
};
|
|
85
|
-
/**
|
|
86
|
-
* `reticle whoami` — the one call an agent (or a confused human) makes to know its state: who am I logged
|
|
87
|
-
* in as, and is THIS repo attached to a cloud project (and with what sync policy / verify mode)?
|
|
88
|
-
*/
|
|
89
|
-
const cmdWhoami = async () => {
|
|
90
|
-
const session = await readSession();
|
|
91
|
-
const fs = createNodeFileSystem();
|
|
92
|
-
const cloud = await resolveProjectCloud(fs, linkedRoot(), homedir(), process.env);
|
|
93
|
-
/*
|
|
94
|
-
* The sync half of "what is my state". Without it the honest answer to "why does the dashboard
|
|
95
|
-
* look old?" was to go and read a JSON file — and the two failure modes a person actually hits
|
|
96
|
-
* (nothing has synced yet, and the last attempt errored) looked identical from out here.
|
|
97
|
-
*/
|
|
98
|
-
const reticleRoot = linkedRoot();
|
|
99
|
-
const state = readCloudState(reticleRoot);
|
|
100
|
-
const decisions = Object.keys(readCloudIssues(reticleRoot).triage).length;
|
|
101
|
-
emit({
|
|
102
|
-
loggedInAs: session?.orgName ?? null,
|
|
103
|
-
sync: {
|
|
104
|
-
lastPushAt: state.lastPushAt ?? null,
|
|
105
|
-
lastPullAt: state.lastPullAt ?? null,
|
|
106
|
-
/** Present only when the machine is behind BECAUSE something failed, which is the useful case. */
|
|
107
|
-
...(state.lastError === undefined ? {} : { lastError: state.lastError }),
|
|
108
|
-
/** Decisions collected from the dashboard and readable locally. */
|
|
109
|
-
decisionsHeld: decisions,
|
|
110
|
-
neverSynced: state.lastPullAt === undefined,
|
|
111
|
-
},
|
|
112
|
-
repo: {
|
|
113
|
-
attached: cloud.config !== null,
|
|
114
|
-
projectId: cloud.projectId,
|
|
115
|
-
url: cloud.config?.url ?? null,
|
|
116
|
-
sync: cloud.policy,
|
|
117
|
-
verify: cloud.verify,
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
// Signed out, `link` refuses with "run reticle login first"; `connect` does both in one go.
|
|
121
|
-
if (null === cloud.config)
|
|
122
|
-
hint(null === session
|
|
123
|
-
? 'this repo is not attached — run `reticle connect` (signs in and links in one step)'
|
|
124
|
-
: 'this repo is not attached — run `reticle connect`');
|
|
125
|
-
return 0;
|
|
126
|
-
};
|
|
127
83
|
/**
|
|
128
84
|
* Who is signed in and which project this repo is linked to, for `reticle status`. Local files
|
|
129
85
|
* only: status must answer with no network.
|
|
@@ -146,58 +102,6 @@ export const accountStatusFields = async () => {
|
|
|
146
102
|
...(refused === undefined ? {} : { keyRefused: refused }),
|
|
147
103
|
};
|
|
148
104
|
};
|
|
149
|
-
/** `reticle project ls` / `reticle project create <name>` — key- or session-authed. */
|
|
150
|
-
const cmdProject = async (argv) => {
|
|
151
|
-
const active = await readSession();
|
|
152
|
-
const url = baseUrl(active);
|
|
153
|
-
const session = await readSessionFor(url);
|
|
154
|
-
const token = bearer(session);
|
|
155
|
-
if (null === token) {
|
|
156
|
-
// Name BOTH hosts when there is a session for a different one. "Run reticle login" on its own is
|
|
157
|
-
// baffling to somebody who just did — the useful fact is that they logged in somewhere else.
|
|
158
|
-
err(null !== active && normalizeUrl(active.url) !== url
|
|
159
|
-
? `signed in to ${normalizeUrl(active.url)}, but this command targets ${url} — run \`reticle connect --url ${url}\`, or set RETICLE_API_KEY`
|
|
160
|
-
: `not signed in to ${url} — run \`reticle connect --url ${url}\`, or set RETICLE_API_KEY`);
|
|
161
|
-
return 2;
|
|
162
|
-
}
|
|
163
|
-
const sub = argv[0];
|
|
164
|
-
if ('ls' === sub) {
|
|
165
|
-
emit(await api('GET', `${url}/v1/projects`, token));
|
|
166
|
-
return 0;
|
|
167
|
-
}
|
|
168
|
-
if ('create' === sub) {
|
|
169
|
-
const name = argv.slice(1).join(' ').trim();
|
|
170
|
-
if (0 === name.length) {
|
|
171
|
-
err('usage: reticle project create <name>');
|
|
172
|
-
return 2;
|
|
173
|
-
}
|
|
174
|
-
const created = CreatedProjectSchema.parse(await api('POST', `${url}/v1/projects`, token, { name }));
|
|
175
|
-
emit(created);
|
|
176
|
-
hint(`next: \`reticle connect --project ${created.projectId}\` to bind this repo`);
|
|
177
|
-
return 0;
|
|
178
|
-
}
|
|
179
|
-
if ('rename' === sub) {
|
|
180
|
-
const id = argv[1];
|
|
181
|
-
const name = argv.slice(2).join(' ').trim();
|
|
182
|
-
if (id === undefined || 0 === name.length) {
|
|
183
|
-
err('usage: reticle project rename <projectId> <new name>');
|
|
184
|
-
return 2;
|
|
185
|
-
}
|
|
186
|
-
emit(await api('PATCH', `${url}/v1/projects/${encodeURIComponent(id)}`, token, { name }));
|
|
187
|
-
return 0;
|
|
188
|
-
}
|
|
189
|
-
if ('rm' === sub || 'delete' === sub) {
|
|
190
|
-
const id = argv[1];
|
|
191
|
-
if (id === undefined) {
|
|
192
|
-
err('usage: reticle project rm <projectId>');
|
|
193
|
-
return 2;
|
|
194
|
-
}
|
|
195
|
-
emit(await api('DELETE', `${url}/v1/projects/${encodeURIComponent(id)}`, token));
|
|
196
|
-
return 0;
|
|
197
|
-
}
|
|
198
|
-
err('usage: reticle project <ls|create <name>|rename <id> <name>|rm <id>>');
|
|
199
|
-
return 2;
|
|
200
|
-
};
|
|
201
105
|
const NO_INSTALL = '--no-install';
|
|
202
106
|
/** Whether `reticle connect`'s init half installs the packages: not under `--no-install`. */
|
|
203
107
|
export const connectInstalls = (argv) => !argv.includes(NO_INSTALL);
|
|
@@ -577,10 +481,6 @@ export const runCloudCommand = async (argv) => {
|
|
|
577
481
|
const [cmd, ...rest] = argv;
|
|
578
482
|
try {
|
|
579
483
|
switch (cmd) {
|
|
580
|
-
case 'login':
|
|
581
|
-
// The linker is passed in rather than imported by cloud-login: login ends by linking and
|
|
582
|
-
// link needs a session, so the cycle is broken at this one call site.
|
|
583
|
-
return await cmdLogin(rest, cmdLink);
|
|
584
484
|
case 'connect':
|
|
585
485
|
return await cmdConnect(rest);
|
|
586
486
|
case 'try':
|
|
@@ -590,29 +490,12 @@ export const runCloudCommand = async (argv) => {
|
|
|
590
490
|
});
|
|
591
491
|
case 'logout':
|
|
592
492
|
return await cmdLogout(rest);
|
|
593
|
-
case 'whoami':
|
|
594
|
-
return await cmdWhoami();
|
|
595
|
-
case 'project':
|
|
596
|
-
return await cmdProject(rest);
|
|
597
|
-
case 'link':
|
|
598
|
-
return await cmdLink(rest);
|
|
599
493
|
case 'config':
|
|
600
494
|
return await cmdConfig(rest);
|
|
601
|
-
// `push` is the name people type, so it takes `--watch` too: the help and the README say so.
|
|
602
|
-
case 'push':
|
|
603
|
-
return await cmdSync(rest);
|
|
604
495
|
case 'sync':
|
|
605
496
|
return await cmdSync(rest);
|
|
606
497
|
case 'runs':
|
|
607
498
|
return await cmdRunsFamily(rest);
|
|
608
|
-
case 'issues':
|
|
609
|
-
return await cmdIssues(rest);
|
|
610
|
-
case 'memory':
|
|
611
|
-
return await cmdMemory(rest);
|
|
612
|
-
case 'regression':
|
|
613
|
-
return await cmdRegression();
|
|
614
|
-
case 'share':
|
|
615
|
-
return await cmdShare(rest);
|
|
616
499
|
default:
|
|
617
500
|
err(`unknown cloud command '${cmd ?? ''}'`);
|
|
618
501
|
return 2;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export declare const leaseFailedLine: (url: string) => string;
|
|
2
|
+
/**
|
|
3
|
+
* Open `url` in a Reticle-leased browser unconditionally: `{ leased }` names the lease, which the
|
|
4
|
+
* caller hands to `releaseLease`; `{ failed }` is the lease's own refusal, as lines to print.
|
|
5
|
+
* `init`'s connect proof on a machine with no system browser takes this path directly.
|
|
6
|
+
*/
|
|
7
|
+
export declare function acquireLease(caller: ToolCaller, url: string,
|
|
8
|
+
/** Open it in a window somebody can watch, whatever the daemon was started as. */
|
|
9
|
+
headed?: boolean,
|
|
10
|
+
/** The `.reticle` the lease's runs belong in: the caller's project, not wherever the page resolves. */
|
|
11
|
+
root?: string): Promise<{
|
|
12
|
+
leased: string;
|
|
13
|
+
zeroInstall: boolean;
|
|
14
|
+
} | {
|
|
15
|
+
failed: string[];
|
|
16
|
+
}>;
|
|
17
|
+
/** Hand back a lease `leaseIfNoTab` opened. Best-effort: an expired lease is already gone. */
|
|
18
|
+
export declare function releaseLease(caller: ToolCaller, sessionId: string): Promise<void>;
|
|
19
|
+
/** The narrow slice of an MCP client this needs — one call, then close. */
|
|
20
|
+
export interface ToolCaller {
|
|
21
|
+
call(name: string, args: Record<string, unknown>, timeoutMs?: number): Promise<unknown>;
|
|
22
|
+
close(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export declare function endpointFor(port: number, token: string | undefined): URL;
|
|
25
|
+
export declare function connectOverSse(endpoint: URL): Promise<ToolCaller>;
|
|
26
|
+
/**
|
|
27
|
+
* The report object an MCP tool result carries, or undefined when the shape is not one.
|
|
28
|
+
*
|
|
29
|
+
* `field` is the key that makes a payload the report this caller wants: `verified` for a one-shot
|
|
30
|
+
* verdict, `status` for a suite. It is a parameter rather than a fixed name because the suite path
|
|
31
|
+
* reproduced this function's own incident the moment it reused it — the headline printed
|
|
32
|
+
* `unverifiable` while the JSON under it said `"status":"fail"` with 74 failing flows, because a
|
|
33
|
+
* suite report has no `verified` key and the text reader would only accept one that did.
|
|
34
|
+
*/
|
|
35
|
+
export declare function verdictOf(result: unknown, field?: string): Record<string, unknown> | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* The tool's own words when it refused, rather than the envelope carrying them.
|
|
38
|
+
*
|
|
39
|
+
* A refusal from these tools is the most useful text they produce — it names the cause and the next
|
|
40
|
+
* action — and printing the MCP result object around it buries that in JSON escaping. The reader is
|
|
41
|
+
* at a terminal; give them the sentence.
|
|
42
|
+
*/
|
|
43
|
+
export declare function refusalText(result: unknown): string | undefined;
|
|
44
|
+
/** The payload of a tool result: its structured content, or the JSON object in its text. */
|
|
45
|
+
export declare function payloadOf(result: unknown): Record<string, unknown>;
|