@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
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type ToolCaller } from './daemon-link/daemon-client.js';
|
|
2
|
+
export { acquireLease, connectOverSse, endpointFor, refusalText, releaseLease, verdictOf, type ToolCaller, } from './daemon-link/daemon-client.js';
|
|
1
3
|
/**
|
|
2
4
|
* A verdict from the CLI, against the daemon that is already running.
|
|
3
5
|
*
|
|
@@ -83,54 +85,12 @@ root?: string): Promise<{
|
|
|
83
85
|
} | {
|
|
84
86
|
failed: string[];
|
|
85
87
|
}>;
|
|
86
|
-
/**
|
|
87
|
-
* Open `url` in a Reticle-leased browser unconditionally: `{ leased }` names the lease, which the
|
|
88
|
-
* caller hands to `releaseLease`; `{ failed }` is the lease's own refusal, as lines to print.
|
|
89
|
-
* `init`'s connect proof on a machine with no system browser takes this path directly.
|
|
90
|
-
*/
|
|
91
|
-
export declare function acquireLease(caller: ToolCaller, url: string,
|
|
92
|
-
/** Open it in a window somebody can watch, whatever the daemon was started as. */
|
|
93
|
-
headed?: boolean,
|
|
94
|
-
/** The `.reticle` the lease's runs belong in: the caller's project, not wherever the page resolves. */
|
|
95
|
-
root?: string): Promise<{
|
|
96
|
-
leased: string;
|
|
97
|
-
zeroInstall: boolean;
|
|
98
|
-
} | {
|
|
99
|
-
failed: string[];
|
|
100
|
-
}>;
|
|
101
|
-
/** Hand back a lease `leaseIfNoTab` opened. Best-effort: an expired lease is already gone. */
|
|
102
|
-
export declare function releaseLease(caller: ToolCaller, sessionId: string): Promise<void>;
|
|
103
88
|
/**
|
|
104
89
|
* The longest one `reticle_assert` call waits: its `timeout_ms` cap, one MCP request less slack.
|
|
105
90
|
* Named here rather than imported, because this directory does not reach the tool layer; pinned
|
|
106
91
|
* equal to `MAX_BLOCKING_WAIT_MS` by adhoc-verdict.test.ts so the two cannot drift apart.
|
|
107
92
|
*/
|
|
108
93
|
export declare const ASSERT_MAX_WAIT_MS = 55000;
|
|
109
|
-
/** The narrow slice of an MCP client this needs — one call, then close. */
|
|
110
|
-
export interface ToolCaller {
|
|
111
|
-
call(name: string, args: Record<string, unknown>, timeoutMs?: number): Promise<unknown>;
|
|
112
|
-
close(): Promise<void>;
|
|
113
|
-
}
|
|
114
|
-
export declare function endpointFor(port: number, token: string | undefined): URL;
|
|
115
|
-
export declare function connectOverSse(endpoint: URL): Promise<ToolCaller>;
|
|
116
|
-
/**
|
|
117
|
-
* The report object an MCP tool result carries, or undefined when the shape is not one.
|
|
118
|
-
*
|
|
119
|
-
* `field` is the key that makes a payload the report this caller wants: `verified` for a one-shot
|
|
120
|
-
* verdict, `status` for a suite. It is a parameter rather than a fixed name because the suite path
|
|
121
|
-
* reproduced this function's own incident the moment it reused it — the headline printed
|
|
122
|
-
* `unverifiable` while the JSON under it said `"status":"fail"` with 74 failing flows, because a
|
|
123
|
-
* suite report has no `verified` key and the text reader would only accept one that did.
|
|
124
|
-
*/
|
|
125
|
-
export declare function verdictOf(result: unknown, field?: string): Record<string, unknown> | undefined;
|
|
126
|
-
/**
|
|
127
|
-
* The tool's own words when it refused, rather than the envelope carrying them.
|
|
128
|
-
*
|
|
129
|
-
* A refusal from these tools is the most useful text they produce — it names the cause and the next
|
|
130
|
-
* action — and printing the MCP result object around it buries that in JSON escaping. The reader is
|
|
131
|
-
* at a terminal; give them the sentence.
|
|
132
|
-
*/
|
|
133
|
-
export declare function refusalText(result: unknown): string | undefined;
|
|
134
94
|
/**
|
|
135
95
|
* Navigate (optionally) and assert, against the daemon already on this port.
|
|
136
96
|
*
|
|
@@ -146,4 +106,3 @@ export declare function runAdhocVerdict(options: AdhocVerdictOptions): Promise<A
|
|
|
146
106
|
* caller that wants the finished report asks again by `runId` rather than starting a second drive.
|
|
147
107
|
*/
|
|
148
108
|
export declare function exploreToEnd(caller: ToolCaller, args: Record<string, unknown>, budgetMs: number, now?: () => number): Promise<unknown>;
|
|
149
|
-
export {};
|
|
@@ -1,19 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CLI_CLIENT_NAME } from '../../judgement/runs/verification-sync.js';
|
|
3
|
-
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
4
|
-
import { DEFAULT_ASSERT_TIMEOUT_MS, LOOPBACK_HOST, MCP_SSE_PATH } from '@reticlehq/core';
|
|
5
|
-
import { TOKEN_QUERY_PARAM } from '../../portal/bridge/token-auth.js';
|
|
6
|
-
import { ReticleTool, asString as asText } from '@reticlehq/core';
|
|
1
|
+
import { DEFAULT_ASSERT_TIMEOUT_MS, ReticleTool, asString as asText } from '@reticlehq/core';
|
|
7
2
|
import { decideOpen } from './launch/cli-launch.js';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* Generous on purpose: on a machine with no Chrome, Edge or Playwright Chromium the FIRST lease
|
|
12
|
-
* downloads Chromium before it can open anything (see launch-chromium), which outlives the MCP
|
|
13
|
-
* client's 60s default and would report a timeout for a lease that was about to succeed.
|
|
14
|
-
*/
|
|
15
|
-
const LEASE_TIMEOUT_MS = 300_000;
|
|
16
|
-
const leaseFailedLine = (url) => `could not open ${url} in a Reticle browser, so nothing was checked:`;
|
|
3
|
+
import { acquireLease, connectOverSse, endpointFor, refusalText, releaseLease, verdictOf, } from './daemon-link/daemon-client.js';
|
|
4
|
+
// Re-exported so every existing importer of the daemon link through this file is unaffected.
|
|
5
|
+
export { acquireLease, connectOverSse, endpointFor, refusalText, releaseLease, verdictOf, } from './daemon-link/daemon-client.js';
|
|
17
6
|
/**
|
|
18
7
|
* Open `url` in a Reticle-leased browser when the daemon has no tab on its origin.
|
|
19
8
|
*
|
|
@@ -64,48 +53,6 @@ function sameDocument(a, b) {
|
|
|
64
53
|
return false;
|
|
65
54
|
}
|
|
66
55
|
}
|
|
67
|
-
/**
|
|
68
|
-
* Open `url` in a Reticle-leased browser unconditionally: `{ leased }` names the lease, which the
|
|
69
|
-
* caller hands to `releaseLease`; `{ failed }` is the lease's own refusal, as lines to print.
|
|
70
|
-
* `init`'s connect proof on a machine with no system browser takes this path directly.
|
|
71
|
-
*/
|
|
72
|
-
export async function acquireLease(caller, url,
|
|
73
|
-
/** Open it in a window somebody can watch, whatever the daemon was started as. */
|
|
74
|
-
headed,
|
|
75
|
-
/** The `.reticle` the lease's runs belong in: the caller's project, not wherever the page resolves. */
|
|
76
|
-
root) {
|
|
77
|
-
const acquired = await caller.call(ReticleTool.RUN, {
|
|
78
|
-
tool: ReticleTool.LEASE,
|
|
79
|
-
args: {
|
|
80
|
-
action: LeaseAction.ACQUIRE,
|
|
81
|
-
url,
|
|
82
|
-
...(true === headed ? { headed } : {}),
|
|
83
|
-
...(root === undefined ? {} : { root }),
|
|
84
|
-
},
|
|
85
|
-
}, LEASE_TIMEOUT_MS);
|
|
86
|
-
const report = verdictOf(acquired, 'sessionId');
|
|
87
|
-
const sessionId = report?.['sessionId'];
|
|
88
|
-
// `zeroInstall`: the page never dialled in, so the lease supplied Reticle's own reader.
|
|
89
|
-
if ('string' === typeof sessionId) {
|
|
90
|
-
return { leased: sessionId, zeroInstall: true === report?.['zeroInstall'] };
|
|
91
|
-
}
|
|
92
|
-
const why = verdictOf(acquired, 'error')?.['error'];
|
|
93
|
-
return {
|
|
94
|
-
failed: [
|
|
95
|
-
leaseFailedLine(url),
|
|
96
|
-
'string' === typeof why ? why : (refusalText(acquired) ?? JSON.stringify(acquired)),
|
|
97
|
-
],
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
/** Hand back a lease `leaseIfNoTab` opened. Best-effort: an expired lease is already gone. */
|
|
101
|
-
export async function releaseLease(caller, sessionId) {
|
|
102
|
-
await caller
|
|
103
|
-
.call(ReticleTool.RUN, {
|
|
104
|
-
tool: ReticleTool.LEASE,
|
|
105
|
-
args: { action: LeaseAction.RELEASE, sessionId },
|
|
106
|
-
})
|
|
107
|
-
.catch(() => undefined);
|
|
108
|
-
}
|
|
109
56
|
/** How long `--expect` waits without a `--timeout`: the wait form's own default. */
|
|
110
57
|
const DEFAULT_EXPECT_WAIT_MS = DEFAULT_ASSERT_TIMEOUT_MS;
|
|
111
58
|
/** Room for the daemon to answer after the wait it was given has run out. */
|
|
@@ -125,31 +72,55 @@ function runRefusal(result) {
|
|
|
125
72
|
const said = verdictOf(result, 'error')?.['error'];
|
|
126
73
|
return refusalText(result) ?? ('string' === typeof said ? said : undefined);
|
|
127
74
|
}
|
|
75
|
+
/** The `reticle_assert` action that waits for a predicate within a budget. */
|
|
76
|
+
const ASSERT_WAIT_ACTION = 'wait';
|
|
77
|
+
/**
|
|
78
|
+
* The refusal of a daemon whose `reticle_assert` takes no `action`: every surface but the merged
|
|
79
|
+
* one, where `reticle_wait_for` is still a tool of its own.
|
|
80
|
+
*/
|
|
81
|
+
const REFUSES_ACTION = /unknown parameter[^\n]*\baction\b/i;
|
|
82
|
+
/**
|
|
83
|
+
* One wait for the predicate, through `reticle_assert { action: "wait" }` (#2144).
|
|
84
|
+
*
|
|
85
|
+
* It went through `reticle_run { tool: "reticle_wait_for" }`. That name was merged into
|
|
86
|
+
* `reticle_assert`, and a 3.9.0 daemon answered it with "reticle_wait_for was merged into
|
|
87
|
+
* reticle_assert", so every `--expect` with a long `--timeout` printed `verified: unknown`. A daemon
|
|
88
|
+
* whose `reticle_assert` takes no action still has `reticle_wait_for` as a tool, so that is the
|
|
89
|
+
* one place the name is still used.
|
|
90
|
+
*/
|
|
91
|
+
async function waitOnce(caller, args, timeoutMs) {
|
|
92
|
+
const waited = await caller.call(ReticleTool.ASSERT, { action: ASSERT_WAIT_ACTION, ...args }, timeoutMs);
|
|
93
|
+
const refused = runRefusal(waited);
|
|
94
|
+
if (refused === undefined || !REFUSES_ACTION.test(refused)) {
|
|
95
|
+
return waited;
|
|
96
|
+
}
|
|
97
|
+
return caller.call(ReticleTool.RUN, { tool: ReticleTool.WAIT_FOR, args }, timeoutMs);
|
|
98
|
+
}
|
|
128
99
|
/**
|
|
129
100
|
* Wait for the expectation, then grade it with ONE `reticle_assert` (#1533).
|
|
130
101
|
*
|
|
131
|
-
* The grade is `reticle_assert`'s
|
|
132
|
-
*
|
|
133
|
-
* `
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* either: both default to the same last-act cursor, and nothing here acts in between.
|
|
102
|
+
* The grade is the final `reticle_assert`'s: it journals, captures the assertion, and carries
|
|
103
|
+
* `verifiedReason`, contradictions and coverage. `reticle_assert` already waits when
|
|
104
|
+
* `timeout_ms > 0`, up to one request. A longer budget spends the part one assert cannot hold in
|
|
105
|
+
* `reticle_assert { action: "wait" }` first, following `resume_ms`, and then asserts. No `since` is
|
|
106
|
+
* passed by either: both default to the same last-act cursor, and nothing here acts in between.
|
|
137
107
|
*/
|
|
138
108
|
async function waitForExpectation(caller, predicate, pin, timeoutMs) {
|
|
139
109
|
const budget = Math.max(0, timeoutMs ?? DEFAULT_EXPECT_WAIT_MS);
|
|
140
110
|
let settle = budget - ASSERT_MAX_WAIT_MS;
|
|
141
111
|
while (0 < settle) {
|
|
142
|
-
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
settle + WAIT_CALL_SLACK_MS);
|
|
112
|
+
// The daemon blocks no longer than one request allows and answers resume_ms past that, so the
|
|
113
|
+
// budget plus slack always outlasts the call.
|
|
114
|
+
const waited = await waitOnce(caller, { predicate, timeout_ms: settle, ...pin }, settle + WAIT_CALL_SLACK_MS);
|
|
146
115
|
const refused = runRefusal(waited);
|
|
147
|
-
if (refused !== undefined)
|
|
116
|
+
if (refused !== undefined) {
|
|
148
117
|
return { refused };
|
|
149
|
-
|
|
150
|
-
|
|
118
|
+
}
|
|
119
|
+
// In the shape `reticle_assert` answers: a final answer carries `verified`, and only a wait
|
|
120
|
+
// that the per-call cap stopped carries `resume_ms` without one.
|
|
121
|
+
const report = verdictOf(waited, 'resume_ms');
|
|
151
122
|
const resume = report?.['resume_ms'];
|
|
152
|
-
if (
|
|
123
|
+
if (report?.['verified'] !== undefined ||
|
|
153
124
|
'number' !== typeof resume ||
|
|
154
125
|
resume <= 0 ||
|
|
155
126
|
resume >= settle) {
|
|
@@ -164,91 +135,6 @@ async function waitForExpectation(caller, predicate, pin, timeoutMs) {
|
|
|
164
135
|
}
|
|
165
136
|
/** `verified` is the only field that decides the exit code. Everything else is for the reader. */
|
|
166
137
|
const PROVED = 'yes';
|
|
167
|
-
export function endpointFor(port, token) {
|
|
168
|
-
const url = new URL(`http://${LOOPBACK_HOST}:${String(port)}${MCP_SSE_PATH}`);
|
|
169
|
-
if (token !== undefined && token.length > 0)
|
|
170
|
-
url.searchParams.set(TOKEN_QUERY_PARAM, token);
|
|
171
|
-
return url;
|
|
172
|
-
}
|
|
173
|
-
export async function connectOverSse(endpoint) {
|
|
174
|
-
const client = new Client({ name: CLI_CLIENT_NAME, version: '1' }, { capabilities: {} });
|
|
175
|
-
await client.connect(new SSEClientTransport(endpoint));
|
|
176
|
-
return {
|
|
177
|
-
call: async (name, args, timeoutMs) => await client.callTool({ name, arguments: args }, undefined, timeoutMs === undefined ? undefined : { timeout: timeoutMs }),
|
|
178
|
-
close: async () => {
|
|
179
|
-
await client.close();
|
|
180
|
-
},
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* The report object an MCP tool result carries, or undefined when the shape is not one.
|
|
185
|
-
*
|
|
186
|
-
* `field` is the key that makes a payload the report this caller wants: `verified` for a one-shot
|
|
187
|
-
* verdict, `status` for a suite. It is a parameter rather than a fixed name because the suite path
|
|
188
|
-
* reproduced this function's own incident the moment it reused it — the headline printed
|
|
189
|
-
* `unverifiable` while the JSON under it said `"status":"fail"` with 74 failing flows, because a
|
|
190
|
-
* suite report has no `verified` key and the text reader would only accept one that did.
|
|
191
|
-
*/
|
|
192
|
-
export function verdictOf(result, field = 'verified') {
|
|
193
|
-
const structured = result?.structuredContent;
|
|
194
|
-
if ('object' === typeof structured && null !== structured) {
|
|
195
|
-
return structured;
|
|
196
|
-
}
|
|
197
|
-
// A daemon that answers with the verdict as TEXT left this undefined, so the headline read
|
|
198
|
-
// `verified: unknown` while the JSON printed underneath it said `"verified":"no"` — one response
|
|
199
|
-
// giving two answers to the same question. The text is the same object, so read it.
|
|
200
|
-
return verdictFromText(result, field);
|
|
201
|
-
}
|
|
202
|
-
/** The report object inside an MCP text part, when the result carried it there instead. */
|
|
203
|
-
function verdictFromText(result, field) {
|
|
204
|
-
const content = result?.content;
|
|
205
|
-
if (!Array.isArray(content))
|
|
206
|
-
return undefined;
|
|
207
|
-
for (const part of content) {
|
|
208
|
-
const text = part.text;
|
|
209
|
-
if ('string' !== typeof text)
|
|
210
|
-
continue;
|
|
211
|
-
try {
|
|
212
|
-
const parsed = JSON.parse(text);
|
|
213
|
-
// Only a shape that actually carries a verdict — anything else stays `unknown`, which is the
|
|
214
|
-
// honest answer for a result this function could not read.
|
|
215
|
-
if ('object' === typeof parsed && null !== parsed && field in parsed) {
|
|
216
|
-
return parsed;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
catch {
|
|
220
|
-
/* Not JSON; the next part may still be. */
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
return undefined;
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* The tool's own words when it refused, rather than the envelope carrying them.
|
|
227
|
-
*
|
|
228
|
-
* A refusal from these tools is the most useful text they produce — it names the cause and the next
|
|
229
|
-
* action — and printing the MCP result object around it buries that in JSON escaping. The reader is
|
|
230
|
-
* at a terminal; give them the sentence.
|
|
231
|
-
*/
|
|
232
|
-
export function refusalText(result) {
|
|
233
|
-
const r = result;
|
|
234
|
-
if (true !== r?.isError || !Array.isArray(r.content))
|
|
235
|
-
return undefined;
|
|
236
|
-
const text = r.content
|
|
237
|
-
.map((part) => part.text)
|
|
238
|
-
.filter((t) => 'string' === typeof t)
|
|
239
|
-
.join('\n');
|
|
240
|
-
if (0 === text.length)
|
|
241
|
-
return undefined;
|
|
242
|
-
// The tools answer with a JSON envelope whose `error` is the sentence; unwrap when it is one.
|
|
243
|
-
try {
|
|
244
|
-
const parsed = JSON.parse(text);
|
|
245
|
-
const inner = parsed?.error;
|
|
246
|
-
return 'string' === typeof inner ? inner : text;
|
|
247
|
-
}
|
|
248
|
-
catch {
|
|
249
|
-
return text;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
138
|
/**
|
|
253
139
|
* Navigate (optionally) and assert, against the daemon already on this port.
|
|
254
140
|
*
|
|
@@ -288,8 +174,9 @@ export async function runAdhocVerdict(options) {
|
|
|
288
174
|
}
|
|
289
175
|
if (url !== undefined && options.sessionId === undefined && options.sessions !== undefined) {
|
|
290
176
|
const opened = await leaseIfNoTab(caller, url, options.sessions, options.root);
|
|
291
|
-
if ('failed' in opened)
|
|
177
|
+
if ('failed' in opened) {
|
|
292
178
|
return { code: 1, lines: ['verified: unknown', ...opened.failed] };
|
|
179
|
+
}
|
|
293
180
|
leased = opened.leased;
|
|
294
181
|
alreadyAt = true === opened.alreadyAt;
|
|
295
182
|
}
|
|
@@ -301,8 +188,9 @@ export async function runAdhocVerdict(options) {
|
|
|
301
188
|
await caller.call(ReticleTool.NAVIGATE, { url, ...pin });
|
|
302
189
|
}
|
|
303
190
|
const waited = await waitForExpectation(caller, options.predicate, pin, options.timeoutMs);
|
|
304
|
-
if ('refused' in waited)
|
|
191
|
+
if ('refused' in waited) {
|
|
305
192
|
return { code: 1, lines: ['verified: unknown', waited.refused] };
|
|
193
|
+
}
|
|
306
194
|
const result = waited.result;
|
|
307
195
|
const refusal = refusalText(result);
|
|
308
196
|
if (refusal !== undefined) {
|
|
@@ -330,8 +218,9 @@ export async function runAdhocVerdict(options) {
|
|
|
330
218
|
};
|
|
331
219
|
}
|
|
332
220
|
finally {
|
|
333
|
-
if (leased !== undefined)
|
|
221
|
+
if (leased !== undefined) {
|
|
334
222
|
await releaseLease(caller, leased);
|
|
223
|
+
}
|
|
335
224
|
await caller.close().catch(() => undefined);
|
|
336
225
|
}
|
|
337
226
|
}
|
|
@@ -357,8 +246,9 @@ export async function exploreToEnd(caller, args, budgetMs, now = Date.now) {
|
|
|
357
246
|
for (;;) {
|
|
358
247
|
const report = verdictOf(result, 'status');
|
|
359
248
|
const runId = report?.['runId'];
|
|
360
|
-
if (DRIVE_RUNNING !== report?.['status'] || 'string' !== typeof runId || now() >= deadline)
|
|
249
|
+
if (DRIVE_RUNNING !== report?.['status'] || 'string' !== typeof runId || now() >= deadline) {
|
|
361
250
|
return result;
|
|
251
|
+
}
|
|
362
252
|
result = await ask({ runId });
|
|
363
253
|
}
|
|
364
254
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GateOutcome } from '@reticlehq/core/telemetry';
|
|
1
2
|
/**
|
|
2
3
|
* What `reticle gate` means by its exit code.
|
|
3
4
|
*
|
|
@@ -21,14 +22,17 @@ export declare const GateExit: {
|
|
|
21
22
|
/** The platform knows a flow that passed before and is broken now: `reticle runs regression`'s code. */
|
|
22
23
|
readonly REGRESSION: 3;
|
|
23
24
|
};
|
|
25
|
+
export type GateExit = (typeof GateExit)[keyof typeof GateExit];
|
|
26
|
+
/** The `gate_completed` outcome for each exit code. A gate that throws reports `error` instead. */
|
|
27
|
+
export declare const GATE_OUTCOME: Readonly<Record<GateExit, GateOutcome>>;
|
|
24
28
|
/**
|
|
25
29
|
* The gate's code once the platform has been asked about regressions: a known one fails the build
|
|
26
30
|
* with `reticle runs regression`'s code, whatever the local answer was, so the gate is the one
|
|
27
31
|
* command CI needs. `undefined` (not linked, or the platform did not answer) changes nothing.
|
|
28
32
|
*/
|
|
29
|
-
export declare function gateExitWith(local:
|
|
33
|
+
export declare function gateExitWith(local: GateExit, regressed: number | undefined,
|
|
30
34
|
/** The platform the project is linked to refused its credential: the gate fails closed. */
|
|
31
|
-
refused?: boolean):
|
|
35
|
+
refused?: boolean): GateExit;
|
|
32
36
|
/**
|
|
33
37
|
* Said when the linked platform refused the key. A CI pipeline whose key was revoked stayed green
|
|
34
38
|
* and silent: the gate lost the platform's regression report and the only trace was a log line.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GateOutcome } from '@reticlehq/core/telemetry';
|
|
1
2
|
/**
|
|
2
3
|
* What `reticle gate` means by its exit code.
|
|
3
4
|
*
|
|
@@ -21,6 +22,13 @@ export const GateExit = {
|
|
|
21
22
|
/** The platform knows a flow that passed before and is broken now: `reticle runs regression`'s code. */
|
|
22
23
|
REGRESSION: 3,
|
|
23
24
|
};
|
|
25
|
+
/** The `gate_completed` outcome for each exit code. A gate that throws reports `error` instead. */
|
|
26
|
+
export const GATE_OUTCOME = {
|
|
27
|
+
[GateExit.PASS]: GateOutcome.PASS,
|
|
28
|
+
[GateExit.FAIL]: GateOutcome.FAIL,
|
|
29
|
+
[GateExit.NOTHING_TO_CHECK]: GateOutcome.NOTHING_TO_CHECK,
|
|
30
|
+
[GateExit.REGRESSION]: GateOutcome.REGRESSION,
|
|
31
|
+
};
|
|
24
32
|
/**
|
|
25
33
|
* The gate's code once the platform has been asked about regressions: a known one fails the build
|
|
26
34
|
* with `reticle runs regression`'s code, whatever the local answer was, so the gate is the one
|
|
@@ -29,8 +37,9 @@ export const GateExit = {
|
|
|
29
37
|
export function gateExitWith(local, regressed,
|
|
30
38
|
/** The platform the project is linked to refused its credential: the gate fails closed. */
|
|
31
39
|
refused = false) {
|
|
32
|
-
if (regressed !== undefined && 0 < regressed)
|
|
40
|
+
if (regressed !== undefined && 0 < regressed) {
|
|
33
41
|
return GateExit.REGRESSION;
|
|
42
|
+
}
|
|
34
43
|
return refused && GateExit.PASS === local ? GateExit.FAIL : local;
|
|
35
44
|
}
|
|
36
45
|
/**
|
|
@@ -52,8 +61,9 @@ export const MSG_GATE_NO_FLOWS = 'Reticle gate: no saved flows here, so there wa
|
|
|
52
61
|
*/
|
|
53
62
|
export function msgGateRegression(broken) {
|
|
54
63
|
const names = broken.map((entry) => {
|
|
55
|
-
if ('string' === typeof entry)
|
|
64
|
+
if ('string' === typeof entry) {
|
|
56
65
|
return entry;
|
|
66
|
+
}
|
|
57
67
|
const record = 'object' === typeof entry && null !== entry ? entry : {};
|
|
58
68
|
const name = record['flowName'] ?? record['name'];
|
|
59
69
|
const was = record['previousStatus'];
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { LOOPBACK_HOST, MCP_SSE_PATH } from '@reticlehq/core';
|
|
2
|
+
const MCP_CONNECTION_HINT = 'If your agent has no reticle_* tools, connect over HTTP/SSE at';
|
|
3
|
+
/** The same connection hint for a running daemon in `status` and `doctor`. */
|
|
4
|
+
export function mcpConnectionHint(port) {
|
|
5
|
+
return `${MCP_CONNECTION_HINT} http://${LOOPBACK_HOST}:${String(port)}${MCP_SSE_PATH}`;
|
|
6
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One line at the end of `reticle gate`, `reticle verify` and `reticle affected` when they run in a
|
|
3
|
+
* CI runner or a container. It names the pull request check and the page that tells more about it.
|
|
4
|
+
*
|
|
5
|
+
* Rules: one line; never in an interactive terminal; never in a machine output mode; off with
|
|
6
|
+
* `RETICLE_NO_CI_HINT`. It goes to stderr. The stdout of `verify` carries the verdict lines that a
|
|
7
|
+
* pipeline reads, and stderr already carries the human notes of these commands.
|
|
8
|
+
*
|
|
9
|
+
* No network call. The latest version comes from the update manifest that the update check already
|
|
10
|
+
* caches on disk. When there is no cache, the line does not compare versions.
|
|
11
|
+
*
|
|
12
|
+
* The caller gives the automation hint (`currentAutomationHint`): `telemetry` already reaches this
|
|
13
|
+
* directory, so this directory does not reach back.
|
|
14
|
+
*/
|
|
15
|
+
import { AutomationHint } from '@reticlehq/core/telemetry';
|
|
16
|
+
/** Set to `1` to stop the line. */
|
|
17
|
+
export declare const CI_HINT_SILENCE_ENV = "RETICLE_NO_CI_HINT";
|
|
18
|
+
/** The page that tells about the pull request check. */
|
|
19
|
+
export declare const CI_HINT_URL = "https://reticle.sh/ci";
|
|
20
|
+
export interface CiHintInput {
|
|
21
|
+
env: NodeJS.ProcessEnv;
|
|
22
|
+
automation: AutomationHint | undefined;
|
|
23
|
+
/** A person watches the output in a terminal. */
|
|
24
|
+
interactive: boolean;
|
|
25
|
+
/** The command writes output for a program to read (JSON, an agent hook). */
|
|
26
|
+
machineOutput: boolean;
|
|
27
|
+
currentVersion: string;
|
|
28
|
+
/** The latest version from the cached update check, if there is one. */
|
|
29
|
+
latestVersion: string | undefined;
|
|
30
|
+
}
|
|
31
|
+
/** The line, or undefined when it must not print. Pure. */
|
|
32
|
+
export declare function ciHintLine(input: CiHintInput): string | undefined;
|
|
33
|
+
export interface CiHintPorts {
|
|
34
|
+
env: NodeJS.ProcessEnv;
|
|
35
|
+
interactive: () => boolean;
|
|
36
|
+
latestVersion: () => string | undefined;
|
|
37
|
+
write: (text: string) => void;
|
|
38
|
+
}
|
|
39
|
+
/** Write the line to stderr when it applies. Call it last, after the command's own output. */
|
|
40
|
+
export declare function writeCiHint(args: {
|
|
41
|
+
automation: AutomationHint | undefined;
|
|
42
|
+
machineOutput: boolean;
|
|
43
|
+
ports?: CiHintPorts;
|
|
44
|
+
}): void;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One line at the end of `reticle gate`, `reticle verify` and `reticle affected` when they run in a
|
|
3
|
+
* CI runner or a container. It names the pull request check and the page that tells more about it.
|
|
4
|
+
*
|
|
5
|
+
* Rules: one line; never in an interactive terminal; never in a machine output mode; off with
|
|
6
|
+
* `RETICLE_NO_CI_HINT`. It goes to stderr. The stdout of `verify` carries the verdict lines that a
|
|
7
|
+
* pipeline reads, and stderr already carries the human notes of these commands.
|
|
8
|
+
*
|
|
9
|
+
* No network call. The latest version comes from the update manifest that the update check already
|
|
10
|
+
* caches on disk. When there is no cache, the line does not compare versions.
|
|
11
|
+
*
|
|
12
|
+
* The caller gives the automation hint (`currentAutomationHint`): `telemetry` already reaches this
|
|
13
|
+
* directory, so this directory does not reach back.
|
|
14
|
+
*/
|
|
15
|
+
import { AutomationHint } from '@reticlehq/core/telemetry';
|
|
16
|
+
import { parseMajor } from '@reticlehq/init';
|
|
17
|
+
import { loadManifest } from '../update/update-checker.js';
|
|
18
|
+
import { SERVER_VERSION } from '../version/identity/server-version.js';
|
|
19
|
+
/** Set to `1` to stop the line. */
|
|
20
|
+
export const CI_HINT_SILENCE_ENV = 'RETICLE_NO_CI_HINT';
|
|
21
|
+
/** The page that tells about the pull request check. */
|
|
22
|
+
export const CI_HINT_URL = 'https://reticle.sh/ci';
|
|
23
|
+
/** The env values that do not turn the line off. */
|
|
24
|
+
const NOT_SILENCED = new Set(['', '0', 'false']);
|
|
25
|
+
/** The automation hints that get the line. A hosted workspace or an agent sandbox is a person. */
|
|
26
|
+
const CI_HINT_AUTOMATION = new Set([
|
|
27
|
+
AutomationHint.CI_RUNNER,
|
|
28
|
+
AutomationHint.CONTAINER,
|
|
29
|
+
]);
|
|
30
|
+
const CiHintCopy = {
|
|
31
|
+
CHECK: `Reticle: a pull request check shows each replay, the run history and a merge block. Read ${CI_HINT_URL}`,
|
|
32
|
+
BEHIND: (current, latest) => `Reticle: this engine (${current}) is a major version behind ${latest}. Update it, then read ${CI_HINT_URL}`,
|
|
33
|
+
};
|
|
34
|
+
/** The line, or undefined when it must not print. Pure. */
|
|
35
|
+
export function ciHintLine(input) {
|
|
36
|
+
if (!NOT_SILENCED.has(input.env[CI_HINT_SILENCE_ENV] ?? '')) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
if (input.interactive || input.machineOutput) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
if (input.automation === undefined || !CI_HINT_AUTOMATION.has(input.automation)) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
const current = parseMajor(input.currentVersion);
|
|
46
|
+
const latest = parseMajor(input.latestVersion);
|
|
47
|
+
if (current !== undefined && latest !== undefined && latest > current) {
|
|
48
|
+
return CiHintCopy.BEHIND(input.currentVersion, input.latestVersion ?? '');
|
|
49
|
+
}
|
|
50
|
+
return CiHintCopy.CHECK;
|
|
51
|
+
}
|
|
52
|
+
const realPorts = () => ({
|
|
53
|
+
env: process.env,
|
|
54
|
+
interactive: () => true === process.stdout.isTTY || true === process.stderr.isTTY,
|
|
55
|
+
latestVersion: () => loadManifest()?.latestVersion,
|
|
56
|
+
write: (text) => process.stderr.write(text),
|
|
57
|
+
});
|
|
58
|
+
/** Write the line to stderr when it applies. Call it last, after the command's own output. */
|
|
59
|
+
export function writeCiHint(args) {
|
|
60
|
+
const ports = args.ports ?? realPorts();
|
|
61
|
+
const line = ciHintLine({
|
|
62
|
+
env: ports.env,
|
|
63
|
+
automation: args.automation,
|
|
64
|
+
interactive: ports.interactive(),
|
|
65
|
+
machineOutput: args.machineOutput,
|
|
66
|
+
currentVersion: SERVER_VERSION,
|
|
67
|
+
latestVersion: ports.latestVersion(),
|
|
68
|
+
});
|
|
69
|
+
if (line !== undefined) {
|
|
70
|
+
ports.write(`${line}\n`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -1 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import type { StepReporter } from './setup-mcp-cli.js';
|
|
2
|
+
/**
|
|
3
|
+
* `reticle doctor`, and with `fix`, `reticle doctor --fix`. Without `fix` it changes nothing and
|
|
4
|
+
* ends with how many rows `--fix` can repair. With `fix` the exit code is 1 while any row fails.
|
|
5
|
+
*/
|
|
6
|
+
export declare function handleDoctor(port: number, fix?: boolean, reportStep?: StepReporter): Promise<void>;
|
|
@@ -11,7 +11,8 @@ import { daemonLine } from './doctor/doctor-daemon-line.js';
|
|
|
11
11
|
import { projectWiringLine } from './doctor/doctor-project-line.js';
|
|
12
12
|
import { hasProjectConnectedBefore } from '../../memory/recall/prior/connection-memory.js';
|
|
13
13
|
import { sessionsLine } from './doctor/doctor-sessions-line.js';
|
|
14
|
-
import { captureLookup, describeForeignHolder
|
|
14
|
+
import { captureLookup, describeForeignHolder } from './ports/port-holder.js';
|
|
15
|
+
import { identifyPortHolder } from '../daemon/port-state.js';
|
|
15
16
|
import { chromiumHint } from './doctor/browser/chromium-hint.js';
|
|
16
17
|
import { probeChromiumWithFallback } from '../../launch-chromium.js';
|
|
17
18
|
import { SERVER_VERSION } from '../version/identity/server-version.js';
|
|
@@ -32,6 +33,8 @@ import { describeUnsynced } from '../../memory/cloud/unsynced-roots.js';
|
|
|
32
33
|
import { machineUnsyncedRoots } from '../../memory/project/sync-status.js';
|
|
33
34
|
import { attachState, describeAttachState } from '../../surface/mcp/attach-memory.js';
|
|
34
35
|
import { agentLinkText } from './doctor/doctor-agent-link.js';
|
|
36
|
+
import { countNeeded, fixFooter, runDoctorFix } from './doctor/doctor-fix.js';
|
|
37
|
+
import { machineRepairs, mcpRegistrationRow, readLauncherLine, readMcpRegistration, } from './doctor-repairs.js';
|
|
35
38
|
import { findOccupiedSiblings, siblingListenerNote } from './ports/sibling-ports.js';
|
|
36
39
|
import { daemonsServingProjectElsewhere, resolveDaemonForProject, splitBrainNote, wrongDaemonNote, } from '../daemon/daemon-resolve.js';
|
|
37
40
|
import { isAlive } from '../daemon/daemon.js';
|
|
@@ -70,12 +73,44 @@ function asIdentity(payload) {
|
|
|
70
73
|
*/
|
|
71
74
|
function splitBrainLine(port, projectId) {
|
|
72
75
|
const home = reticleStateHome();
|
|
73
|
-
const elsewhere = splitBrainNote(port, daemonsServingProjectElsewhere(projectId, port, home, isAlive, (other) => hasProjectConnectedBefore(home, other, projectId)));
|
|
76
|
+
const elsewhere = splitBrainNote(port, daemonsServingProjectElsewhere(projectId, port, home, isAlive, (other) => hasProjectConnectedBefore(home, other, projectId)), { projectId, home });
|
|
74
77
|
return elsewhere ?? wrongDaemonNote(port, resolveDaemonForProject(projectId, home, isAlive));
|
|
75
78
|
}
|
|
76
|
-
|
|
79
|
+
const writeLine = (s) => {
|
|
80
|
+
process.stdout.write(`${s}\n`);
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* `reticle doctor`, and with `fix`, `reticle doctor --fix`. Without `fix` it changes nothing and
|
|
84
|
+
* ends with how many rows `--fix` can repair. With `fix` the exit code is 1 while any row fails.
|
|
85
|
+
*/
|
|
86
|
+
export async function handleDoctor(port, fix = false, reportStep = () => { }) {
|
|
87
|
+
const repairs = machineRepairs(port, reportStep);
|
|
88
|
+
if (fix) {
|
|
89
|
+
const green = await runDoctorFix({
|
|
90
|
+
doctor: (show) => doctorLines(port, show),
|
|
91
|
+
repairs,
|
|
92
|
+
print: writeLine,
|
|
93
|
+
});
|
|
94
|
+
if (!green) {
|
|
95
|
+
process.exitCode = 1;
|
|
96
|
+
}
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
await doctorLines(port, true);
|
|
100
|
+
const footer = fixFooter(await countNeeded(repairs));
|
|
101
|
+
if (footer !== undefined) {
|
|
102
|
+
writeLine('');
|
|
103
|
+
writeLine(footer);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** Every doctor row, in order. Each row is printed as it is found when `show` is true. */
|
|
107
|
+
async function doctorLines(port, show) {
|
|
108
|
+
const lines = [];
|
|
77
109
|
const line = (s) => {
|
|
78
|
-
|
|
110
|
+
lines.push(s);
|
|
111
|
+
if (show) {
|
|
112
|
+
writeLine(s);
|
|
113
|
+
}
|
|
79
114
|
};
|
|
80
115
|
line('reticle doctor');
|
|
81
116
|
line(doctorRow(DoctorRow.NODE, process.version));
|
|
@@ -84,6 +119,7 @@ export async function handleDoctor(port) {
|
|
|
84
119
|
let sessions;
|
|
85
120
|
let daemonStatus;
|
|
86
121
|
line(doctorRow(DoctorRow.CHROMIUM, chromiumHint(await probeChromiumWithFallback())));
|
|
122
|
+
line(mcpRegistrationRow(readMcpRegistration()));
|
|
87
123
|
// Ask the PORT, not just the pid file. "not running on :4400" has been printed about a port that
|
|
88
124
|
// was demonstrably occupied, which sends the reader to start a daemon that cannot bind. The three
|
|
89
125
|
// states are genuinely different problems with different fixes, so doctor names which one it is.
|
|
@@ -126,7 +162,7 @@ export async function handleDoctor(port) {
|
|
|
126
162
|
// pipeline that also kills the agent's own MCP proxy.
|
|
127
163
|
// `pid` is what our pid file recorded for this port. When it matches the process actually
|
|
128
164
|
// holding it, this is our OWN daemon wedged, not a stranger — and the fix is different.
|
|
129
|
-
line(doctorRow(DoctorRow.DAEMON, `✗ ${describeForeignHolder(port,
|
|
165
|
+
line(doctorRow(DoctorRow.DAEMON, `✗ ${describeForeignHolder(port, identifyPortHolder(port, captureLookup), pid)}`));
|
|
130
166
|
}
|
|
131
167
|
else {
|
|
132
168
|
line(doctorRow(DoctorRow.DAEMON, `✗ not running on :${port} — your agent runs \`reticle mcp\` (or \`reticle serve\`)`));
|
|
@@ -167,6 +203,10 @@ export async function handleDoctor(port) {
|
|
|
167
203
|
// would flip agent presence on a daemon with no agents attached.
|
|
168
204
|
const foreign = presence === PortPresence.FOREIGN;
|
|
169
205
|
line(doctorRow(DoctorRow.AGENT_LINK, agentLinkText({ split, attachAction, foreign })));
|
|
206
|
+
const launcher = readLauncherLine(process.cwd());
|
|
207
|
+
if (launcher !== undefined) {
|
|
208
|
+
line(doctorRow(DoctorRow.LAUNCHER, launcher));
|
|
209
|
+
}
|
|
170
210
|
// Remaining half of #261. The SDK dialling a port we are not on is invisible as a refused inbound,
|
|
171
211
|
// but a listener on a well-known Reticle port is visible. Report the observation; do not conclude
|
|
172
212
|
// it is the daemon this app wants — somebody else's daemon looks the same from here.
|
|
@@ -263,6 +303,7 @@ export async function handleDoctor(port) {
|
|
|
263
303
|
if (keychain !== undefined) {
|
|
264
304
|
line(doctorRow(DoctorRow.DESKTOP, `⚠ ${keychain}`));
|
|
265
305
|
}
|
|
306
|
+
return lines;
|
|
266
307
|
}
|
|
267
308
|
/**
|
|
268
309
|
* Two rows: does each agent hand its prompts to Reticle, and does the daemon send this
|