@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
|
@@ -55,8 +55,9 @@ const URL_THEN_LEASE = 'Once you have that URL, open it with reticle_lease {acti
|
|
|
55
55
|
* diagnosed the problem.
|
|
56
56
|
*/
|
|
57
57
|
function leaseAdvice(base, facts) {
|
|
58
|
-
if (true === facts.desktop)
|
|
58
|
+
if (true === facts.desktop) {
|
|
59
59
|
return DESKTOP_NO_BROWSER;
|
|
60
|
+
}
|
|
60
61
|
const caveat = leaseCaveat(facts.leaseBrowser);
|
|
61
62
|
return caveat === undefined ? base : `${base} ${caveat}`;
|
|
62
63
|
}
|
|
@@ -87,12 +88,14 @@ const TAB_GONE_WHAT = 'The tab was closed, navigated away, or hard-reloaded.';
|
|
|
87
88
|
* page down is no longer the same dead end as "the human closed the tab".
|
|
88
89
|
*/
|
|
89
90
|
function tabGoneWhat(url) {
|
|
90
|
-
if (undefined === url || '' === url)
|
|
91
|
+
if (undefined === url || '' === url) {
|
|
91
92
|
return TAB_GONE_WHAT;
|
|
93
|
+
}
|
|
92
94
|
const torn = pageTornDownWhileOn(url);
|
|
93
95
|
const first = torn.charAt(0);
|
|
94
|
-
if ('' === first)
|
|
96
|
+
if ('' === first) {
|
|
95
97
|
return TAB_GONE_WHAT;
|
|
98
|
+
}
|
|
96
99
|
return `${first.toUpperCase()}${torn.slice(1)}. ${TAB_GONE_WHAT}`;
|
|
97
100
|
}
|
|
98
101
|
/**
|
|
@@ -158,6 +161,12 @@ const DO_NOT_REINSTALL = 'Re-running the install is the wrong move here: it cann
|
|
|
158
161
|
* evidence that was never gathered.
|
|
159
162
|
*/
|
|
160
163
|
const SCANNED_PORTS = [...DEV_SERVER_PORTS].join(', ');
|
|
164
|
+
/**
|
|
165
|
+
* The project's own sources the scan adds to the well-known list (reticle#1367, reticle#1543).
|
|
166
|
+
*
|
|
167
|
+
* Named in the "nothing else" sentences so that "the scan is partial" says what it did check.
|
|
168
|
+
*/
|
|
169
|
+
const PROJECT_PORT_SOURCES = "the port in this project's dev script and `.env` files, and the ports of earlier sessions";
|
|
161
170
|
/**
|
|
162
171
|
* How to say "open the app" to an agent that may have no `reticle` binary.
|
|
163
172
|
*
|
|
@@ -178,15 +187,16 @@ const INIT_CMD = '`npx @reticlehq/server init`';
|
|
|
178
187
|
* against it, and it has to be read before the "nothing is listening" sentence rather than after —
|
|
179
188
|
* the reader acts on the first claim.
|
|
180
189
|
*/
|
|
181
|
-
function slowListenerClause(facts) {
|
|
190
|
+
function slowListenerClause(facts, after = '') {
|
|
182
191
|
const slow = facts.slowListeners ?? [];
|
|
183
|
-
if (0 === slow.length)
|
|
192
|
+
if (0 === slow.length) {
|
|
184
193
|
return '';
|
|
194
|
+
}
|
|
185
195
|
const ports = slow.join(', ');
|
|
186
196
|
const subject = 1 === slow.length ? `Port ${ports} ACCEPTED` : `Ports ${ports} ACCEPTED`;
|
|
187
197
|
return (`${subject} a connection but did not answer in time, which is what a server-rendered dev ` +
|
|
188
198
|
'server compiling its first route looks like — so something IS running there and you should ' +
|
|
189
|
-
|
|
199
|
+
`open it rather than start it.${after}`);
|
|
190
200
|
}
|
|
191
201
|
/**
|
|
192
202
|
* The commonest first-run state there is (#320).
|
|
@@ -216,6 +226,22 @@ function openTheApp(facts) {
|
|
|
216
226
|
function orOpenCommand(facts) {
|
|
217
227
|
return true === facts.desktop ? '' : ` (or run ${OPEN_CMD_BARE})`;
|
|
218
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* The start advice's lead when processes in this folder listen. Empty when none do.
|
|
231
|
+
*
|
|
232
|
+
* Names ports and no URL. It ends where the caller's "start it" begins, so an agent whose listeners
|
|
233
|
+
* are only its own tools still gets the app started.
|
|
234
|
+
*/
|
|
235
|
+
function folderListenerClause(facts) {
|
|
236
|
+
const ports = facts.folderListeners ?? [];
|
|
237
|
+
if (0 === ports.length) {
|
|
238
|
+
return '';
|
|
239
|
+
}
|
|
240
|
+
const named = ports.map((port) => `:${String(port)}`).join(', ');
|
|
241
|
+
return (`No port Reticle scans serves a page, but processes in this folder listen on ${named}. ` +
|
|
242
|
+
'Reticle cannot tell if one is this app, because agent tools listen here too. ' +
|
|
243
|
+
'If one of them IS this app, open its URL. If none is, ');
|
|
244
|
+
}
|
|
219
245
|
/**
|
|
220
246
|
* What a machine-wide port scan can and cannot say.
|
|
221
247
|
*
|
|
@@ -224,7 +250,14 @@ function orOpenCommand(facts) {
|
|
|
224
250
|
* is up and never dialled" is unsound: those ports can belong to anything, and the app's own port
|
|
225
251
|
* may not be in the scanned set at all.
|
|
226
252
|
*/
|
|
227
|
-
function unattributedListeners(
|
|
253
|
+
function unattributedListeners(facts) {
|
|
254
|
+
const { listening } = facts;
|
|
255
|
+
const folder = facts.folderListeners ?? [];
|
|
256
|
+
if (0 < folder.length && 0 === listening.length) {
|
|
257
|
+
const named = folder.map((port) => `:${String(port)}`).join(', ');
|
|
258
|
+
return (`No port the scan covers serves a page, but processes in this folder listen on ${named}. ` +
|
|
259
|
+
'Reticle cannot tell if one is this app, because agent tools listen here too.');
|
|
260
|
+
}
|
|
228
261
|
if (0 === listening.length) {
|
|
229
262
|
return (`No listener found that I can attribute to this project: the scan covers ${SCANNED_PORTS} ` +
|
|
230
263
|
'across the whole machine, so an app on any other port is invisible to it.');
|
|
@@ -242,8 +275,9 @@ function unattributedListeners(listening) {
|
|
|
242
275
|
*/
|
|
243
276
|
function portMismatchClause(facts) {
|
|
244
277
|
const configured = facts.projectPort;
|
|
245
|
-
if (configured === undefined || configured === facts.port)
|
|
278
|
+
if (configured === undefined || configured === facts.port) {
|
|
246
279
|
return '';
|
|
280
|
+
}
|
|
247
281
|
return (` They already disagree: \`.reticle.json\` says port ${String(configured)} and this daemon is` +
|
|
248
282
|
` on ${String(facts.port)}, so the SDK is dialling ${String(configured)} and nothing is there.` +
|
|
249
283
|
` Either restart the daemon on ${String(configured)}, or update \`.reticle.json\` to` +
|
|
@@ -258,8 +292,9 @@ function portMismatchClause(facts) {
|
|
|
258
292
|
*/
|
|
259
293
|
function siblingListenerClause(facts) {
|
|
260
294
|
const occupied = facts.siblingListeners ?? [];
|
|
261
|
-
if (0 === occupied.length)
|
|
295
|
+
if (0 === occupied.length) {
|
|
262
296
|
return '';
|
|
297
|
+
}
|
|
263
298
|
const mismatch = facts.projectPort;
|
|
264
299
|
const extra = mismatch !== undefined && mismatch !== facts.port
|
|
265
300
|
? occupied.filter((port) => port !== mismatch)
|
|
@@ -291,8 +326,9 @@ function rankedCauses(facts) {
|
|
|
291
326
|
*/
|
|
292
327
|
function configsElsewhereClause(facts) {
|
|
293
328
|
const configs = facts.configsElsewhere ?? [];
|
|
294
|
-
if (0 === configs.length)
|
|
329
|
+
if (0 === configs.length) {
|
|
295
330
|
return '';
|
|
331
|
+
}
|
|
296
332
|
const named = configs
|
|
297
333
|
.map((c) => (c.projectId === undefined ? c.directory : `${c.directory} ('${c.projectId}')`))
|
|
298
334
|
.join(', ');
|
|
@@ -303,10 +339,12 @@ function configsElsewhereClause(facts) {
|
|
|
303
339
|
/** Where we looked, when we found nothing. An absence nobody can check is not evidence. */
|
|
304
340
|
function searchedClause(facts) {
|
|
305
341
|
const searched = facts.searchedDirectories ?? [];
|
|
306
|
-
if (0 === searched.length)
|
|
342
|
+
if (0 === searched.length) {
|
|
307
343
|
return '';
|
|
308
|
-
|
|
344
|
+
}
|
|
345
|
+
if ((facts.configsElsewhere ?? []).length > 0) {
|
|
309
346
|
return '';
|
|
347
|
+
}
|
|
310
348
|
return ` I looked in: ${searched.join(', ')}. If your app is not in that list, that is the answer — this daemon is standing somewhere else.`;
|
|
311
349
|
}
|
|
312
350
|
/**
|
|
@@ -318,20 +356,24 @@ function searchedClause(facts) {
|
|
|
318
356
|
*/
|
|
319
357
|
function stallClause(facts) {
|
|
320
358
|
const { daemonUpMs, initialized, everConnected } = facts;
|
|
321
|
-
if (everConnected)
|
|
359
|
+
if (everConnected) {
|
|
322
360
|
return '';
|
|
323
|
-
|
|
361
|
+
}
|
|
362
|
+
if (!initialized) {
|
|
324
363
|
return '';
|
|
325
|
-
|
|
364
|
+
}
|
|
365
|
+
if (daemonUpMs === undefined || daemonUpMs < STALL_AFTER_MS) {
|
|
326
366
|
return '';
|
|
367
|
+
}
|
|
327
368
|
const minutes = Math.round(daemonUpMs / 60_000);
|
|
328
369
|
return (`This daemon has been running for ${String(minutes)} minutes and no app has connected. ` +
|
|
329
370
|
'The most likely cause is that the dev server was not restarted after adding the Reticle ' +
|
|
330
371
|
'plugin, so the running bundle carries no SDK. Restart the dev server first. ');
|
|
331
372
|
}
|
|
332
373
|
function alreadyListeningClause(listening) {
|
|
333
|
-
if (0 === listening.length)
|
|
374
|
+
if (0 === listening.length) {
|
|
334
375
|
return '';
|
|
376
|
+
}
|
|
335
377
|
if (1 === listening.length) {
|
|
336
378
|
const port = listening[0];
|
|
337
379
|
return (` Something is serving a page on :${String(port)}; it may not be this app — just open ` +
|
|
@@ -450,9 +492,9 @@ export function explainNoSession(facts) {
|
|
|
450
492
|
// wiring is unproven, printed by a daemon holding proof that it is.
|
|
451
493
|
if (true === facts.previouslyConnected) {
|
|
452
494
|
const listeners = 0 === listening.length
|
|
453
|
-
? `${unattributedListeners(
|
|
495
|
+
? `${unattributedListeners(facts)} If the dev server is not running, start it first ` +
|
|
454
496
|
'(the command is in `next_action`).'
|
|
455
|
-
: unattributedListeners(
|
|
497
|
+
: unattributedListeners(facts);
|
|
456
498
|
return reason(NoSessionReason.APP_NOT_REOPENED, `${RESTARTED_LEAD} ${openTheApp(facts)} ${leaseAdvice(SELF_SERVE, facts)} ${RETRY}`, `${DO_NOT_REINSTALL} ${listeners} ${rankedCauses(facts)}`);
|
|
457
499
|
}
|
|
458
500
|
// A config found elsewhere outranks every "you may have no SDK" branch below: those reason from
|
|
@@ -461,7 +503,7 @@ export function explainNoSession(facts) {
|
|
|
461
503
|
if (!initialized && (facts.configsElsewhere ?? []).length > 0) {
|
|
462
504
|
return reason(NoSessionReason.CONFIG_ELSEWHERE, 'no browser session connected, and this daemon has never seen one. ' +
|
|
463
505
|
`${configsElsewhereClause(facts)} ${openTheApp(facts)} ${leaseAdvice(SELF_SERVE, facts)} ${RETRY}`, 'This daemon was started somewhere that is not the project, which is the normal outcome when ' +
|
|
464
|
-
`an editor launches it from your home directory. ${unattributedListeners(
|
|
506
|
+
`an editor launches it from your home directory. ${unattributedListeners(facts)} ` +
|
|
465
507
|
`${rankedCauses(facts)}`);
|
|
466
508
|
}
|
|
467
509
|
if (0 === listening.length) {
|
|
@@ -481,28 +523,35 @@ export function explainNoSession(facts) {
|
|
|
481
523
|
// is expected rather than diagnostic.
|
|
482
524
|
if (!initialized) {
|
|
483
525
|
return reason(NoSessionReason.NO_LISTENER_NO_CONFIG, 'no browser session connected. Two things to weigh, and neither of them is proof. ' +
|
|
484
|
-
`(1) ${slowListenerClause(facts
|
|
485
|
-
|
|
526
|
+
`(1) ${slowListenerClause(facts, ' Setting that aside: ')}${folderListenerClause(facts) ||
|
|
527
|
+
'Nothing is listening on the ports Reticle scans, so the dev server may not be running: '}START IT YOURSELF, in the background, using the command ` +
|
|
486
528
|
'in `next_action`, and tell the human in one line that it is running. ' +
|
|
487
529
|
`(2) There is no \`.reticle.json\` in ${where}, which is the file ${INIT_CMD} writes, so ` +
|
|
488
530
|
`the app may carry no Reticle SDK. Check the app's OWN directory before re-running it. ` +
|
|
489
|
-
`${ZERO_INSTALL} ${RETRY}`, `The scan covers ${SCANNED_PORTS} and nothing else, so a server on any other port is ` +
|
|
531
|
+
`${ZERO_INSTALL} ${RETRY}`, `The scan covers ${SCANNED_PORTS}, plus ${PROJECT_PORT_SOURCES}, and nothing else, so a server on any other port is ` +
|
|
490
532
|
'invisible to it: if the app IS running, ask for its URL rather than assuming it is down, ' +
|
|
491
533
|
`and open it with ${OPEN_CMD}. The missing config is not proof either — in a monorepo the ` +
|
|
492
534
|
'daemon often runs at the root while the app lives in a subdirectory, and an app wired by ' +
|
|
493
535
|
'the Vite or Babel plugin carries the SDK without that file at all.' +
|
|
494
536
|
`${searchedClause(facts)}${siblingListenerClause(facts)} ${leaseAdvice(URL_THEN_LEASE, facts)}`);
|
|
495
537
|
}
|
|
538
|
+
// A wired project whose own port accepted a connection and answered nothing yet is compiling,
|
|
539
|
+
// not down. "Start it yourself" here starts a second dev server.
|
|
540
|
+
if ((facts.slowListeners ?? []).length > 0) {
|
|
541
|
+
return reason(NoSessionReason.NO_LISTENER, `${stallClause(facts)}no browser session connected, and this daemon has never seen one. ` +
|
|
542
|
+
`${slowListenerClause(facts)} Do not start a second dev server. ` +
|
|
543
|
+
`Wait for the first compile to finish, then open the app (the command is in \`next_action\`). ${RETRY}`, `${leaseAdvice(URL_THEN_LEASE, facts)}${siblingListenerClause(facts)}`);
|
|
544
|
+
}
|
|
496
545
|
return reason(NoSessionReason.NO_LISTENER, `${stallClause(facts)}no browser session connected, and this daemon has never seen one. ${openTheApp(facts)} ` +
|
|
497
|
-
|
|
498
|
-
|
|
546
|
+
`${folderListenerClause(facts) ||
|
|
547
|
+
'Nothing is listening on the ports Reticle scans either, and the usual reason is a dev server that is not running: '}start it yourself in the background with the command in ` +
|
|
499
548
|
'`next_action`, tell the human in one line that it is running, then open the app in a ' +
|
|
500
549
|
`browser. ${RETRY}`,
|
|
501
550
|
// The caveat is in the detail rather than omitted because the scan is NARROW: an empty result
|
|
502
551
|
// is not proof of absence. Reported twice, once against a server answering 200 on :7699 and
|
|
503
552
|
// once against one on :5000 under a custom hostname. The common defaults are in the scanned
|
|
504
553
|
// set, which narrows the gap and cannot close it — anything passed to `--port` is invisible.
|
|
505
|
-
`The scan covers ${SCANNED_PORTS} and nothing else, so it is not proof: a server on any other ` +
|
|
554
|
+
`The scan covers ${SCANNED_PORTS}, plus ${PROJECT_PORT_SOURCES}, and nothing else, so it is not proof: a server on any other ` +
|
|
506
555
|
'port is invisible to it. If the app IS running, ask the human for its URL rather than ' +
|
|
507
556
|
// Deliberately NOT offering reticle_lease here, and a test pins that: a lease opens a URL, and
|
|
508
557
|
// if nothing is listening there is nothing at any URL to open. Asking for the real one is the
|
|
@@ -519,11 +568,11 @@ export function explainNoSession(facts) {
|
|
|
519
568
|
'there and restart the dev server; if it has one, the app is wired and simply has no page ' +
|
|
520
569
|
`open — ${OPEN_CMD}. ${ZERO_INSTALL} ${RETRY}`, 'That absence is not proof: the same one is expected in a monorepo whose daemon runs at the ' +
|
|
521
570
|
'root while the app lives in a subdirectory, or in an app wired by the Vite or Babel ' +
|
|
522
|
-
`plugin. ${unattributedListeners(
|
|
571
|
+
`plugin. ${unattributedListeners(facts)}${searchedClause(facts)}${siblingListenerClause(facts)}`);
|
|
523
572
|
}
|
|
524
573
|
return reason(NoSessionReason.SDK_NOT_REACHING_DAEMON, `${stallClause(facts)}no browser session connected, and this daemon has never seen one for this project, which is ` +
|
|
525
574
|
`wired for Reticle. ${openTheApp(facts)} If the page IS open and still does not appear, the SDK ` +
|
|
526
|
-
`is not reaching this daemon (on ${String(port)}). ${leaseAdvice(SELF_SERVE, facts)} ${RETRY}`, `${unattributedListeners(
|
|
575
|
+
`is not reaching this daemon (on ${String(port)}). ${leaseAdvice(SELF_SERVE, facts)} ${RETRY}`, `${unattributedListeners(facts)} ${rankedCauses(facts)}`);
|
|
527
576
|
}
|
|
528
577
|
/**
|
|
529
578
|
* Pair a branch's verdict with its prose, so neither can be produced without the other.
|
|
@@ -30,6 +30,8 @@ interface NextActionFacts {
|
|
|
30
30
|
listening: readonly number[];
|
|
31
31
|
/** Scanned ports that serve a page from a process that cannot be tied to this project. */
|
|
32
32
|
otherListeners?: readonly number[];
|
|
33
|
+
/** Ports that processes in this folder listen on. See `NoSessionFacts.folderListeners`. */
|
|
34
|
+
folderListeners?: readonly number[];
|
|
33
35
|
dev: DevCommand | undefined;
|
|
34
36
|
/**
|
|
35
37
|
* File-existence predicate for the project root, pure for testing.
|
|
@@ -102,6 +104,11 @@ interface NextActionFacts {
|
|
|
102
104
|
* project's own runner (see `initCommandIn`). Absent means the generic npx spelling.
|
|
103
105
|
*/
|
|
104
106
|
init?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Several direct child folders are apps with a dev script, and this folder has no package.json.
|
|
109
|
+
* Absent or short means there is no choice to hand the agent. See `childDevApps`.
|
|
110
|
+
*/
|
|
111
|
+
childApps?: readonly string[];
|
|
105
112
|
}
|
|
106
113
|
/** The port a tombstone URL names, when it names one — anything unparseable names no port. */
|
|
107
114
|
export declare function portOfUrl(url: string): number | undefined;
|
|
@@ -123,6 +130,13 @@ export declare const INIT_COMMAND = "npx @reticlehq/server init";
|
|
|
123
130
|
* agent asks first. The lease changes nothing, so it needs no question.
|
|
124
131
|
*/
|
|
125
132
|
export declare function wiringConsent(init?: string): string;
|
|
133
|
+
/**
|
|
134
|
+
* The offer for the first session in an unwired web app: check it now with the lease, then ask
|
|
135
|
+
* before `init`. The one text for the plugin's SessionStart hook and the first tool call of each
|
|
136
|
+
* agent connection. The hook cannot import this, so it keeps a copy, and
|
|
137
|
+
* `plugin-init-nudge.test.ts` fails when the two are not the same.
|
|
138
|
+
*/
|
|
139
|
+
export declare function firstSessionOffer(init?: string): string;
|
|
126
140
|
/** The zero-install call, with the URL only when it can be named without guessing. */
|
|
127
141
|
export declare function zeroInstallLease(url: string | undefined): string;
|
|
128
142
|
export declare function nextActionFor(facts: NextActionFacts): NoSessionNextAction;
|
|
@@ -18,8 +18,9 @@ import { detectNonJsEcosystem, noPackageJsonMessage } from '@reticlehq/init';
|
|
|
18
18
|
export function portOfUrl(url) {
|
|
19
19
|
try {
|
|
20
20
|
const raw = new URL(url).port;
|
|
21
|
-
if ('' === raw)
|
|
21
|
+
if ('' === raw) {
|
|
22
22
|
return undefined;
|
|
23
|
+
}
|
|
23
24
|
const port = Number(raw);
|
|
24
25
|
return Number.isSafeInteger(port) && port > 0 ? port : undefined;
|
|
25
26
|
}
|
|
@@ -45,8 +46,9 @@ export function departedPortGone(facts) {
|
|
|
45
46
|
* for a url that does not parse, or one with no port to name (a desktop webview's opaque origin).
|
|
46
47
|
*/
|
|
47
48
|
function reopenableUrl(raw) {
|
|
48
|
-
if (raw === undefined)
|
|
49
|
+
if (raw === undefined) {
|
|
49
50
|
return undefined;
|
|
51
|
+
}
|
|
50
52
|
let url;
|
|
51
53
|
try {
|
|
52
54
|
url = new URL(raw);
|
|
@@ -54,10 +56,12 @@ function reopenableUrl(raw) {
|
|
|
54
56
|
catch {
|
|
55
57
|
return undefined;
|
|
56
58
|
}
|
|
57
|
-
if ('http:' !== url.protocol && 'https:' !== url.protocol)
|
|
59
|
+
if ('http:' !== url.protocol && 'https:' !== url.protocol) {
|
|
58
60
|
return undefined;
|
|
59
|
-
|
|
61
|
+
}
|
|
62
|
+
for (const param of Object.values(RETICLE_URL_PARAM)) {
|
|
60
63
|
url.searchParams.delete(param);
|
|
64
|
+
}
|
|
61
65
|
const port = '' === url.port ? ('https:' === url.protocol ? 443 : 80) : Number(url.port);
|
|
62
66
|
return { url: url.toString(), port };
|
|
63
67
|
}
|
|
@@ -78,6 +82,17 @@ export function wiringConsent(init = INIT_COMMAND) {
|
|
|
78
82
|
'build config and starts the dev server. Ask the user before you wire the app. If they ' +
|
|
79
83
|
`agree, run \`${init}\` in the app's folder. If they decline, do not ask again.`);
|
|
80
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* The offer for the first session in an unwired web app: check it now with the lease, then ask
|
|
87
|
+
* before `init`. The one text for the plugin's SessionStart hook and the first tool call of each
|
|
88
|
+
* agent connection. The hook cannot import this, so it keeps a copy, and
|
|
89
|
+
* `plugin-init-nudge.test.ts` fails when the two are not the same.
|
|
90
|
+
*/
|
|
91
|
+
export function firstSessionOffer(init = INIT_COMMAND) {
|
|
92
|
+
return (`This web app can be checked now with no install: \`${zeroInstallLease(undefined)}\` opens ` +
|
|
93
|
+
"the running app in Reticle's own browser and changes no file. To keep Reticle wired to this " +
|
|
94
|
+
`app: ${wiringConsent(init)}`);
|
|
95
|
+
}
|
|
81
96
|
const OPEN_COMMAND = `${CLI} open`;
|
|
82
97
|
const LOCALHOST = 'http://localhost';
|
|
83
98
|
/**
|
|
@@ -99,7 +114,15 @@ function neverWired(facts) {
|
|
|
99
114
|
* The start advice's first claim when no port is this project's. A scan that heard a page it could
|
|
100
115
|
* not tie to this project says so, because "nothing is listening" is then false.
|
|
101
116
|
*/
|
|
102
|
-
function notThisProject(others) {
|
|
117
|
+
function notThisProject(others, folder = []) {
|
|
118
|
+
// First: the folder is nearer to this app than a machine-wide scan. It is still no URL to hand
|
|
119
|
+
// over, because agent tools listen in this folder too (reticle#1543).
|
|
120
|
+
if (0 < folder.length) {
|
|
121
|
+
const ports = folder.map((port) => `:${String(port)}`).join(', ');
|
|
122
|
+
return (`processes in this folder listen on ${ports}, and Reticle cannot tell if one is this app, ` +
|
|
123
|
+
'because agent tools listen here too — if one of them IS this app, open it instead of ' +
|
|
124
|
+
'starting a second one, ');
|
|
125
|
+
}
|
|
103
126
|
if (others === undefined || 0 === others.length) {
|
|
104
127
|
return 'nothing is listening on the ports Reticle scans, so the app is probably not running — ';
|
|
105
128
|
}
|
|
@@ -243,6 +266,19 @@ export function nextActionFor(facts) {
|
|
|
243
266
|
'args: { action: "acquire", url, projectId } }, or restart the daemon from the app\'s own directory.',
|
|
244
267
|
};
|
|
245
268
|
}
|
|
269
|
+
// A wired project whose only port accepted a connection and answered nothing yet: a dev server
|
|
270
|
+
// compiling its first route. It is up, so a start command would start a second one.
|
|
271
|
+
const compiling = facts.slowListeners?.[0];
|
|
272
|
+
if (true === facts.initialized && 0 === facts.listening.length && compiling !== undefined) {
|
|
273
|
+
return {
|
|
274
|
+
action: NoSessionAction.OPEN_APP,
|
|
275
|
+
command: `${OPEN_COMMAND} ${LOCALHOST}:${String(compiling)}`,
|
|
276
|
+
port: compiling,
|
|
277
|
+
reason: `port ${String(compiling)} accepted a connection but did not answer in time, which is a dev ` +
|
|
278
|
+
'server compiling its first route. The app IS running. Do not start a second dev server. ' +
|
|
279
|
+
'Wait for the compile to finish, then open it.',
|
|
280
|
+
};
|
|
281
|
+
}
|
|
246
282
|
if (0 === facts.listening.length || departedPortIsGone) {
|
|
247
283
|
const dev = facts.dev;
|
|
248
284
|
// The start advice below follows a departed session whose port is gone. Name it, so the restart
|
|
@@ -251,10 +287,23 @@ export function nextActionFor(facts) {
|
|
|
251
287
|
const stoppedNote = stopped === undefined
|
|
252
288
|
? ''
|
|
253
289
|
: ` The session that was on ${redactUrl(stopped.url)} is gone and nothing listens there now.`;
|
|
254
|
-
const
|
|
290
|
+
const folder = facts.folderListeners ?? [];
|
|
291
|
+
const notRunning = departedPortIsGone && 0 === folder.length
|
|
255
292
|
? "nothing answers on the port this project's app was last on, so the app is probably not running — "
|
|
256
|
-
: notThisProject(facts.otherListeners);
|
|
293
|
+
: notThisProject(facts.otherListeners, folder);
|
|
257
294
|
if (dev === undefined) {
|
|
295
|
+
const childApps = facts.childApps ?? [];
|
|
296
|
+
if (1 < childApps.length) {
|
|
297
|
+
return {
|
|
298
|
+
action: NoSessionAction.START_DEV_SERVER,
|
|
299
|
+
reason: notRunning +
|
|
300
|
+
`but this folder has no package.json, and ${childApps.length} child folders are apps ` +
|
|
301
|
+
`with a dev script: ${childApps.join(', ')}. Reticle cannot tell which one you mean, so ` +
|
|
302
|
+
'there is no command to hand you. Pick one, then run Reticle from that folder or ask ' +
|
|
303
|
+
'the human which app to start.' +
|
|
304
|
+
stoppedNote,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
258
307
|
if (facts.exists !== undefined && !facts.exists('package.json')) {
|
|
259
308
|
const ecosystem = detectNonJsEcosystem(facts.exists);
|
|
260
309
|
if (ecosystem !== undefined) {
|
|
@@ -74,6 +74,12 @@ interface NoSessionWatchOptions {
|
|
|
74
74
|
* to it. Injected for tests; a test that injects `probe` and omits this observes no folder.
|
|
75
75
|
*/
|
|
76
76
|
listenerDirectory?: (port: number) => string | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Every TCP port on this machine with a listener (reticle#1543).
|
|
79
|
+
*
|
|
80
|
+
* Injected for tests; a test that injects `probe` and omits this observes no listener.
|
|
81
|
+
*/
|
|
82
|
+
listeningPorts?: () => readonly number[];
|
|
77
83
|
/**
|
|
78
84
|
* What the route the last session was on answers right now, as an HTTP status, or undefined
|
|
79
85
|
* when there is no answer to report.
|
|
@@ -13,11 +13,12 @@ import { probeRouteStatus } from './dev-server/route-status-probe.js';
|
|
|
13
13
|
import { probeDevServerStates } from './dev-server/dev-server-probe.js';
|
|
14
14
|
import { existsSync } from 'node:fs';
|
|
15
15
|
import { homedir } from 'node:os';
|
|
16
|
-
import { join, resolve } from 'node:path';
|
|
16
|
+
import { join, parse, resolve } from 'node:path';
|
|
17
17
|
import { callingClientDirectory } from '../../hooks/client-directory.js';
|
|
18
18
|
import { registeredElsewhere } from '../../memory/recall/registered-projects.js';
|
|
19
19
|
import { explainNoSession } from './no-session-diagnosis.js';
|
|
20
|
-
import { detectDevCommandInProject, initCommandIn } from './dev-server/dev-command.js';
|
|
20
|
+
import { childDevApps, detectDevCommandInProject, initCommandIn, } from './dev-server/dev-command.js';
|
|
21
|
+
import { envFilePorts } from './dev-server/project-ports.js';
|
|
21
22
|
import { nextActionFor, portOfUrl, renderNextAction } from './no-session-next-action.js';
|
|
22
23
|
import { DEV_SERVER_PORTS, readProjectFramework, readProjectId, readProjectIsDesktop, readProjectPort, } from '../../command/cli/ports/resolve/cli-port.js';
|
|
23
24
|
import { discoverProjectConfigs } from '../../command/cli/config/config-discovery.js';
|
|
@@ -27,10 +28,11 @@ import { daemonsServingProjectElsewhere, projectDaemonsElsewhere, projectlessNot
|
|
|
27
28
|
import { stallUptime } from './stall-clock.js';
|
|
28
29
|
import { probeDaemon } from '../../surface/mcp/mcp-proxy.js';
|
|
29
30
|
import { findOccupiedSiblings } from '../../command/cli/ports/sibling-ports.js';
|
|
31
|
+
import { captureLookup, findListeningPorts } from '../../command/cli/ports/port-holder.js';
|
|
30
32
|
import { isAuthRefusalReason } from '../bridge/auth-failure-reason.js';
|
|
31
33
|
import { devServersForProject } from '@reticlehq/core';
|
|
32
34
|
import { readDevServers } from '../../command/daemon/dev-servers.js';
|
|
33
|
-
import { servingDirectoryOf } from './serving-directory.js';
|
|
35
|
+
import { listenerFolders, servingDirectoryOf } from './serving-directory.js';
|
|
34
36
|
import { within } from './zero-install-first-call.js';
|
|
35
37
|
/** Slow enough to be free, fast enough that a dev server started 15s ago is already reflected. */
|
|
36
38
|
const REFRESH_MS = 15_000;
|
|
@@ -77,6 +79,16 @@ export function startNoSessionWatch(options) {
|
|
|
77
79
|
(options.probe === undefined
|
|
78
80
|
? (port) => servingDirectoryOf(`${LOCALHOST}:${String(port)}`)
|
|
79
81
|
: () => undefined);
|
|
82
|
+
const listeningPorts = options.listeningPorts ??
|
|
83
|
+
(options.probe === undefined
|
|
84
|
+
? () => findListeningPorts(captureLookup)
|
|
85
|
+
: () => []);
|
|
86
|
+
/**
|
|
87
|
+
* The folder of each listener outside `listening`, `slowListeners` and the Reticle daemons.
|
|
88
|
+
*
|
|
89
|
+
* Beside `listenerDirs` and never in `listening`: see `NoSessionFacts.folderListeners`.
|
|
90
|
+
*/
|
|
91
|
+
let unscannedFolders = new Map();
|
|
80
92
|
let siblingListeners = [];
|
|
81
93
|
/**
|
|
82
94
|
* What the last-known route answered, cached beside the port scan for the same reason the scan
|
|
@@ -163,7 +175,7 @@ export function startNoSessionWatch(options) {
|
|
|
163
175
|
if (projectId === undefined) {
|
|
164
176
|
return projectlessNote(options.port, projectDaemonsElsewhere(options.port, stateDir, isAlive));
|
|
165
177
|
}
|
|
166
|
-
return splitBrainNote(options.port, daemonsServingProjectElsewhere(projectId, options.port, stateDir, isAlive, (port) => hasProjectConnectedBefore(stateDir, port, projectId)));
|
|
178
|
+
return splitBrainNote(options.port, daemonsServingProjectElsewhere(projectId, options.port, stateDir, isAlive, (port) => hasProjectConnectedBefore(stateDir, port, projectId)), { projectId, home: stateDir });
|
|
167
179
|
};
|
|
168
180
|
// Every path that registers a session goes through SessionManager.add, so this is the one hook
|
|
169
181
|
// that makes the bit durable. Recorded per port + projectId so a shared 4400 cannot make one
|
|
@@ -208,6 +220,10 @@ export function startNoSessionWatch(options) {
|
|
|
208
220
|
if (pinned !== undefined) {
|
|
209
221
|
ports.add(pinned);
|
|
210
222
|
}
|
|
223
|
+
// A script that reads its port from `.env` pins nothing in `package.json` (reticle#1543).
|
|
224
|
+
for (const port of envFilePorts(directory)) {
|
|
225
|
+
ports.add(port);
|
|
226
|
+
}
|
|
211
227
|
const known = options.sessions.lastKnown?.();
|
|
212
228
|
const knownPort = known === undefined ? undefined : portOfUrl(known.url);
|
|
213
229
|
if (knownPort !== undefined) {
|
|
@@ -223,6 +239,19 @@ export function startNoSessionWatch(options) {
|
|
|
223
239
|
}
|
|
224
240
|
return [...ports];
|
|
225
241
|
};
|
|
242
|
+
/**
|
|
243
|
+
* The ports that processes in `dir` listen on, without the ones in `shown`.
|
|
244
|
+
*
|
|
245
|
+
* Nothing for the home folder or a filesystem root. A daemon an editor starts there holds every
|
|
246
|
+
* process on the machine inside its "folder", so the answer would prove nothing.
|
|
247
|
+
*/
|
|
248
|
+
const folderListeners = (dir, shown) => {
|
|
249
|
+
const folder = resolve(dir);
|
|
250
|
+
if (folder === homedir() || folder === parse(folder).root) {
|
|
251
|
+
return [];
|
|
252
|
+
}
|
|
253
|
+
return [...unscannedFolders.entries()].flatMap(([port, cwd]) => within(cwd, folder) && !shown.includes(port) ? [port] : []);
|
|
254
|
+
};
|
|
226
255
|
/**
|
|
227
256
|
* Is `port` demonstrably this project's app? Either its dev server announced it, or this
|
|
228
257
|
* project's own last session was on it. Anything else is a guess, and a guess that opens a
|
|
@@ -300,6 +329,8 @@ export function startNoSessionWatch(options) {
|
|
|
300
329
|
: options.probe === undefined
|
|
301
330
|
? await findOccupiedSiblings(options.port, probeDaemon)
|
|
302
331
|
: [];
|
|
332
|
+
const reported = new Set([options.port, ...siblingListeners, ...ports, ...slowListeners]);
|
|
333
|
+
unscannedFolders = listenerFolders(listeningPorts().filter((port) => !reported.has(port)), unscannedFolders, listenerDirectory);
|
|
303
334
|
// Asked once per departed URL, on the same background cadence as the port scan, and never
|
|
304
335
|
// on the hint's own path. A url already answered is not asked again; a new departure is.
|
|
305
336
|
const known = options.sessions.lastKnown?.();
|
|
@@ -447,6 +478,7 @@ export function startNoSessionWatch(options) {
|
|
|
447
478
|
: {}),
|
|
448
479
|
listening: heard,
|
|
449
480
|
slowListeners: slow,
|
|
481
|
+
folderListeners: folderListeners(dir, heard),
|
|
450
482
|
port: options.port,
|
|
451
483
|
directory: dir,
|
|
452
484
|
previouslyConnected,
|
|
@@ -473,6 +505,7 @@ export function startNoSessionWatch(options) {
|
|
|
473
505
|
listening: heard,
|
|
474
506
|
...(0 === others.length ? {} : { otherListeners: others }),
|
|
475
507
|
slowListeners: slow,
|
|
508
|
+
folderListeners: folderListeners(dir, heard),
|
|
476
509
|
...(known === undefined
|
|
477
510
|
? {}
|
|
478
511
|
: {
|
|
@@ -480,6 +513,7 @@ export function startNoSessionWatch(options) {
|
|
|
480
513
|
...(known.departedTo === undefined ? {} : { departedTo: known.departedTo }),
|
|
481
514
|
}),
|
|
482
515
|
dev: detectDevCommandInProject(dir),
|
|
516
|
+
childApps: childDevApps(dir),
|
|
483
517
|
init: initCommandIn(dir),
|
|
484
518
|
});
|
|
485
519
|
return { facts, next };
|
|
@@ -525,6 +559,7 @@ export function startNoSessionWatch(options) {
|
|
|
525
559
|
...(split === undefined ? {} : { splitBrain: split }),
|
|
526
560
|
listening: observedListening(),
|
|
527
561
|
slowListeners,
|
|
562
|
+
folderListeners: folderListeners(directory, observedListening()),
|
|
528
563
|
// The url the departed tab was on — the same tombstone the prose diagnosis quotes, so the
|
|
529
564
|
// command and the sentence beside it name the same page.
|
|
530
565
|
...(() => {
|
|
@@ -540,6 +575,7 @@ export function startNoSessionWatch(options) {
|
|
|
540
575
|
// Read when asked, like everything else here: a `package.json` can gain a dev script, and a
|
|
541
576
|
// daemon that cached "there is none" at boot would keep saying so for the rest of the day.
|
|
542
577
|
dev: detectDevCommandInProject(directory),
|
|
578
|
+
childApps: childDevApps(directory),
|
|
543
579
|
// This project's own runner and app folder, so the agent can wire it itself.
|
|
544
580
|
init: initCommandIn(directory),
|
|
545
581
|
});
|
|
@@ -568,6 +604,7 @@ export function startNoSessionWatch(options) {
|
|
|
568
604
|
...scope,
|
|
569
605
|
listening: observedListening(),
|
|
570
606
|
slowListeners,
|
|
607
|
+
folderListeners: folderListeners(directory, observedListening()),
|
|
571
608
|
port: options.port,
|
|
572
609
|
// The directory `initialized` was decided in. Named in the message because "there is no
|
|
573
610
|
// `.reticle.json`" is a claim about ONE directory, and a reader standing somewhere else
|
|
@@ -18,8 +18,14 @@
|
|
|
18
18
|
* answers rather than a set lookup at the call site.
|
|
19
19
|
*/
|
|
20
20
|
import { type CommandResult } from '@reticlehq/core';
|
|
21
|
-
/**
|
|
22
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Why nothing was sent, in a sentence, or undefined when the command should go.
|
|
23
|
+
*
|
|
24
|
+
* `behind` is the caller's sentence for a page SDK older than this daemon. A newer command
|
|
25
|
+
* (`render`, `match`) is then missing because of the version, and the list of commands alone
|
|
26
|
+
* does not say that.
|
|
27
|
+
*/
|
|
28
|
+
export declare function refusalForUndeclared(name: string, declared: readonly string[] | undefined, behind?: string): string | undefined;
|
|
23
29
|
/**
|
|
24
30
|
* The refusal as a finished result, or undefined when the command should be sent.
|
|
25
31
|
*
|
|
@@ -27,4 +33,4 @@ export declare function refusalForUndeclared(name: string, declared: readonly st
|
|
|
27
33
|
* cannot get the envelope subtly wrong -- an `ok: true` refusal would be read as a command that
|
|
28
34
|
* worked, which is the one shape this must never produce.
|
|
29
35
|
*/
|
|
30
|
-
export declare function refusedResult(name: string, declared: readonly string[] | undefined, id: string): CommandResult | undefined;
|
|
36
|
+
export declare function refusedResult(name: string, declared: readonly string[] | undefined, id: string, behind?: string): CommandResult | undefined;
|
|
@@ -18,16 +18,25 @@
|
|
|
18
18
|
* answers rather than a set lookup at the call site.
|
|
19
19
|
*/
|
|
20
20
|
import { MessageKind } from '@reticlehq/core';
|
|
21
|
-
/**
|
|
22
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Why nothing was sent, in a sentence, or undefined when the command should go.
|
|
23
|
+
*
|
|
24
|
+
* `behind` is the caller's sentence for a page SDK older than this daemon. A newer command
|
|
25
|
+
* (`render`, `match`) is then missing because of the version, and the list of commands alone
|
|
26
|
+
* does not say that.
|
|
27
|
+
*/
|
|
28
|
+
export function refusalForUndeclared(name, declared, behind) {
|
|
23
29
|
// Too old to say. Unknown, never "nothing".
|
|
24
|
-
if (declared === undefined)
|
|
30
|
+
if (declared === undefined) {
|
|
25
31
|
return undefined;
|
|
26
|
-
|
|
32
|
+
}
|
|
33
|
+
if (declared.includes(name)) {
|
|
27
34
|
return undefined;
|
|
35
|
+
}
|
|
28
36
|
return (`this page does not serve "${name}". It declared ${String(declared.length)} command(s) when ` +
|
|
29
37
|
`it connected, and this is not one of them: ${declared.join(', ')}. Nothing was sent, so ` +
|
|
30
|
-
'nothing happened -- this is a refusal, not a failure of the app.'
|
|
38
|
+
'nothing happened -- this is a refusal, not a failure of the app.' +
|
|
39
|
+
(behind === undefined ? '' : ` ${behind}`));
|
|
31
40
|
}
|
|
32
41
|
/**
|
|
33
42
|
* The refusal as a finished result, or undefined when the command should be sent.
|
|
@@ -36,8 +45,8 @@ export function refusalForUndeclared(name, declared) {
|
|
|
36
45
|
* cannot get the envelope subtly wrong -- an `ok: true` refusal would be read as a command that
|
|
37
46
|
* worked, which is the one shape this must never produce.
|
|
38
47
|
*/
|
|
39
|
-
export function refusedResult(name, declared, id) {
|
|
40
|
-
const error = refusalForUndeclared(name, declared);
|
|
48
|
+
export function refusedResult(name, declared, id, behind) {
|
|
49
|
+
const error = refusalForUndeclared(name, declared, behind);
|
|
41
50
|
return error === undefined
|
|
42
51
|
? undefined
|
|
43
52
|
: { kind: MessageKind.COMMAND_RESULT, id, ok: false, error };
|
|
@@ -49,7 +49,7 @@ export declare function probeMarkers(tabs: readonly ProbedTab[]): Promise<boolea
|
|
|
49
49
|
/**
|
|
50
50
|
* The `engineBlindSpots` field for a verdict result: what this engine could not observe in the
|
|
51
51
|
* session so far. Notes this verdict's own comparison first, so a `compare` clears the arithmetic
|
|
52
|
-
* spot on the result that ran it. `claims`: the inline intent,
|
|
52
|
+
* spot on the result that ran it. `claims`: the inline intent, or else the run's declared intents.
|
|
53
53
|
*/
|
|
54
54
|
export declare function engineBlindSpotsField(sessionId: string, predicate: Predicate | undefined, intent: unknown, declared: readonly {
|
|
55
55
|
statement: string;
|
|
@@ -162,12 +162,15 @@ const comparedSeen = new Set();
|
|
|
162
162
|
/**
|
|
163
163
|
* The `engineBlindSpots` field for a verdict result: what this engine could not observe in the
|
|
164
164
|
* session so far. Notes this verdict's own comparison first, so a `compare` clears the arithmetic
|
|
165
|
-
* spot on the result that ran it. `claims`: the inline intent,
|
|
165
|
+
* spot on the result that ran it. `claims`: the inline intent, or else the run's declared intents.
|
|
166
166
|
*/
|
|
167
167
|
export function engineBlindSpotsField(sessionId, predicate, intent, declared) {
|
|
168
168
|
if (computesComparison(predicate))
|
|
169
169
|
comparedSeen.add(sessionId);
|
|
170
|
-
|
|
170
|
+
// A call that names its own intent is judged on that intent alone. The run's open intents can be
|
|
171
|
+
// an earlier task's, and judging them reported that task's claim on this one (#1938).
|
|
172
|
+
const own = text(intent);
|
|
173
|
+
const claims = own === undefined ? declared.map((each) => each.statement) : [own];
|
|
171
174
|
return {
|
|
172
175
|
[ENGINE_BLIND_SPOTS_FIELD]: engineBlindSpots({
|
|
173
176
|
canvasSeen: canvasSeen.has(sessionId),
|