@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
|
@@ -9,6 +9,7 @@ import { type ChangedFiles } from '../../language/flows/change/git-changed.js';
|
|
|
9
9
|
import { type ProjectId } from '@reticlehq/core';
|
|
10
10
|
import { type FileSystemPort } from '../../memory/project/fs/fs-port.js';
|
|
11
11
|
import { type NamedFlow } from '../../language/flows/change/flow-sources.js';
|
|
12
|
+
import { type GateCompleted } from '@reticlehq/core/telemetry';
|
|
12
13
|
/** Load the {name, steps} of every saved flow for the active project. */
|
|
13
14
|
/** Explicit files plus, when --since is given, the git-changed files since that ref. */
|
|
14
15
|
/**
|
|
@@ -30,4 +31,9 @@ export declare function handleGate(files: string[], since: string | undefined,
|
|
|
30
31
|
/** Hook mode: prose for a human, and silence when there was simply nothing to check. */
|
|
31
32
|
hook?: boolean,
|
|
32
33
|
/** Accept today's coverage levels as the best before judging, for a drop that was intended. */
|
|
33
|
-
acceptCoverage?: boolean
|
|
34
|
+
acceptCoverage?: boolean,
|
|
35
|
+
/**
|
|
36
|
+
* Called once with how the gate ended, on every path. `cli.ts` passes the `gate_completed`
|
|
37
|
+
* sender: telemetry already reaches this directory, so this directory does not reach back.
|
|
38
|
+
*/
|
|
39
|
+
reportGateCompleted?: (gate: GateCompleted) => void): Promise<void>;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* opens first. These five functions form one cohesive group: they all read the flow store and report on
|
|
6
6
|
* verification state, and none of them touch daemon lifecycle, which is what the rest of cli.ts does.
|
|
7
7
|
*/
|
|
8
|
-
import { GateExit, MSG_GATE_NO_FLOWS, msgGateRegression, msgGateRefused, gateExitWith, } from './answers/gate-exit.js';
|
|
8
|
+
import { GATE_OUTCOME, GateExit, MSG_GATE_NO_FLOWS, msgGateRegression, msgGateRefused, gateExitWith, } from './answers/gate-exit.js';
|
|
9
9
|
import { knownRegression } from './known-regression.js';
|
|
10
10
|
import { gateHookMessage, GATE_SKIP_ENV } from './answers/gate-hook-message.js';
|
|
11
11
|
import { readProjectId } from './ports/resolve/cli-port.js';
|
|
@@ -13,6 +13,7 @@ import { changedFilesSince } from '../../language/flows/change/git-changed.js';
|
|
|
13
13
|
import { isAbsolute, join, sep } from 'node:path';
|
|
14
14
|
import { ReticleDir } from '@reticlehq/core';
|
|
15
15
|
import { FlowStore } from '../../language/flows/flows.js';
|
|
16
|
+
import { namedFlowsIn } from '../../language/flows/flow-store-for-session.js';
|
|
16
17
|
import { RunStore } from '../../judgement/runs/artifact/run-store.js';
|
|
17
18
|
import { createNodeFileSystem } from '../../memory/project/fs/fs-port.js';
|
|
18
19
|
import { affectedSavedFlows, toFlowSources, } from '../../language/flows/change/flow-sources.js';
|
|
@@ -25,6 +26,7 @@ import { detectDowngrades } from '../../judgement/outcome/assertion-integrity.js
|
|
|
25
26
|
import { computeCoverage, flowCoverageReport } from '../../language/flows/suite/coverage.js';
|
|
26
27
|
import { readFileSync, statSync } from 'node:fs';
|
|
27
28
|
import { log } from '../../log.js';
|
|
29
|
+
import { GateOutcome } from '@reticlehq/core/telemetry';
|
|
28
30
|
/** Load the {name, steps} of every saved flow for the active project. */
|
|
29
31
|
/** Explicit files plus, when --since is given, the git-changed files since that ref. */
|
|
30
32
|
/**
|
|
@@ -34,8 +36,9 @@ import { log } from '../../log.js';
|
|
|
34
36
|
*/
|
|
35
37
|
export async function resolveChangedFiles(files, since, cwd) {
|
|
36
38
|
// No ref means no question was asked of git, which is not a failure to answer one.
|
|
37
|
-
if (since === undefined)
|
|
39
|
+
if (since === undefined) {
|
|
38
40
|
return { files, failed: false };
|
|
41
|
+
}
|
|
39
42
|
const changed = await changedFilesSince(since, cwd);
|
|
40
43
|
return {
|
|
41
44
|
files: [...new Set([...files, ...changed.files])],
|
|
@@ -52,14 +55,7 @@ export async function resolveChangedFiles(files, since, cwd) {
|
|
|
52
55
|
* confident negative about somebody else's project, which is worse than an error.
|
|
53
56
|
*/
|
|
54
57
|
export async function loadNamedFlows(fs, reticleRoot, projectId) {
|
|
55
|
-
|
|
56
|
-
const flows = [];
|
|
57
|
-
for (const name of await store.list(projectId)) {
|
|
58
|
-
const loaded = await store.load(name, projectId);
|
|
59
|
-
if (loaded.ok)
|
|
60
|
-
flows.push({ name: loaded.value.name, steps: loaded.value.steps });
|
|
61
|
-
}
|
|
62
|
-
return flows;
|
|
58
|
+
return await namedFlowsIn(new FlowStore(fs, reticleRoot, { now: () => Date.now() }), projectId);
|
|
63
59
|
}
|
|
64
60
|
/**
|
|
65
61
|
* `reticle gate <file...>` — exit non-zero unless passing artifacts cover the flows affected by the
|
|
@@ -81,8 +77,9 @@ function atChangedPath(cwd, file, read) {
|
|
|
81
77
|
return undefined;
|
|
82
78
|
}
|
|
83
79
|
};
|
|
84
|
-
if (isAbsolute(file))
|
|
80
|
+
if (isAbsolute(file)) {
|
|
85
81
|
return attempt(file);
|
|
82
|
+
}
|
|
86
83
|
const parts = file.split('/');
|
|
87
84
|
const cwdParts = cwd.split(sep);
|
|
88
85
|
for (let i = 0; i < parts.length; i += 1) {
|
|
@@ -91,8 +88,9 @@ function atChangedPath(cwd, file, read) {
|
|
|
91
88
|
continue;
|
|
92
89
|
}
|
|
93
90
|
const found = attempt(join(cwd, ...parts.slice(i)));
|
|
94
|
-
if (found !== undefined)
|
|
91
|
+
if (found !== undefined) {
|
|
95
92
|
return found;
|
|
93
|
+
}
|
|
96
94
|
}
|
|
97
95
|
return undefined;
|
|
98
96
|
}
|
|
@@ -122,8 +120,9 @@ async function currentPassing(fs, root, flows, affected, changed) {
|
|
|
122
120
|
const own = 0 === sources.length ? changed : changed.filter((f) => sourceMatchesChange(f, sources));
|
|
123
121
|
const stale = affected.includes(name) &&
|
|
124
122
|
own.some((f) => !((changedFileModifiedAt(cwd, f) ?? Infinity) < at));
|
|
125
|
-
if (!stale)
|
|
123
|
+
if (!stale) {
|
|
126
124
|
passing.push(name);
|
|
125
|
+
}
|
|
127
126
|
}
|
|
128
127
|
return passing;
|
|
129
128
|
}
|
|
@@ -131,7 +130,12 @@ export async function handleGate(files, since,
|
|
|
131
130
|
/** Hook mode: prose for a human, and silence when there was simply nothing to check. */
|
|
132
131
|
hook = false,
|
|
133
132
|
/** Accept today's coverage levels as the best before judging, for a drop that was intended. */
|
|
134
|
-
acceptCoverage = false
|
|
133
|
+
acceptCoverage = false,
|
|
134
|
+
/**
|
|
135
|
+
* Called once with how the gate ended, on every path. `cli.ts` passes the `gate_completed`
|
|
136
|
+
* sender: telemetry already reaches this directory, so this directory does not reach back.
|
|
137
|
+
*/
|
|
138
|
+
reportGateCompleted = () => undefined) {
|
|
135
139
|
try {
|
|
136
140
|
const fs = createNodeFileSystem();
|
|
137
141
|
const reticleRoot = join(process.cwd(), ReticleDir.ROOT);
|
|
@@ -207,13 +211,17 @@ acceptCoverage = false) {
|
|
|
207
211
|
// once the exit code is: it said "pass": true over an exit of 1 or 3.
|
|
208
212
|
const known = await knownRegression(reticleRoot);
|
|
209
213
|
const regressed = known.broken;
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
214
|
+
let local = GateExit.FAIL;
|
|
215
|
+
if (pass) {
|
|
216
|
+
local = GateExit.PASS;
|
|
217
|
+
}
|
|
218
|
+
else if (result.pass && flowCoverage.outcome !== undefined) {
|
|
219
|
+
local = GateExit.NOTHING_TO_CHECK;
|
|
220
|
+
}
|
|
215
221
|
// Fails closed in CI, not in an agent's stop hook, where it would block over a key, not a change.
|
|
216
222
|
const code = gateExitWith(local, regressed?.length, !hook && known.refused !== undefined);
|
|
223
|
+
// What the gate judged, sent before a hook's skip can turn the exit code into a pass.
|
|
224
|
+
reportGateCompleted({ outcome: GATE_OUTCOME[code], flowsChecked: affected.length });
|
|
217
225
|
log('reticle_gate', {
|
|
218
226
|
pass: GateExit.PASS === code,
|
|
219
227
|
uncovered: result.uncovered,
|
|
@@ -237,14 +245,18 @@ acceptCoverage = false) {
|
|
|
237
245
|
// A regression the platform already knows fails the build here too, with `reticle runs
|
|
238
246
|
// regression`'s code, so the gate is the one command CI needs. Best-effort: unlinked or offline
|
|
239
247
|
// changes nothing.
|
|
240
|
-
if (regressed !== undefined && 0 < regressed.length)
|
|
248
|
+
if (regressed !== undefined && 0 < regressed.length) {
|
|
241
249
|
log('reticle_gate_regression', { broken: regressed });
|
|
242
|
-
|
|
250
|
+
}
|
|
251
|
+
if (known.refused !== undefined) {
|
|
243
252
|
process.stderr.write(`${msgGateRefused(known.refused)}\n`);
|
|
244
|
-
|
|
253
|
+
}
|
|
254
|
+
if (GateExit.NOTHING_TO_CHECK === code && !hook) {
|
|
245
255
|
process.stderr.write(`${MSG_GATE_NO_FLOWS}\n`);
|
|
246
|
-
|
|
256
|
+
}
|
|
257
|
+
if (GateExit.REGRESSION === code && !hook && regressed !== undefined) {
|
|
247
258
|
process.stderr.write(`${msgGateRegression(regressed)}\n`);
|
|
259
|
+
}
|
|
248
260
|
if (GateExit.PASS !== code) {
|
|
249
261
|
process.exitCode = code;
|
|
250
262
|
if (hook) {
|
|
@@ -267,13 +279,16 @@ acceptCoverage = false) {
|
|
|
267
279
|
unexecuted: result.unexecuted,
|
|
268
280
|
regressed: regressed?.length ?? 0,
|
|
269
281
|
});
|
|
270
|
-
if (message !== undefined)
|
|
282
|
+
if (message !== undefined) {
|
|
271
283
|
process.stderr.write(`${message}\n`);
|
|
284
|
+
}
|
|
272
285
|
}
|
|
273
286
|
}
|
|
274
287
|
}
|
|
275
288
|
catch (error) {
|
|
276
289
|
log('reticle_gate_failed', { error: error instanceof Error ? error.message : String(error) });
|
|
290
|
+
// No flow count: the gate broke before it judged, so a count would describe nothing.
|
|
291
|
+
reportGateCompleted({ outcome: GateOutcome.ERROR });
|
|
277
292
|
process.exitCode = GateExit.FAIL;
|
|
278
293
|
}
|
|
279
294
|
}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* written, or belongs to a daemon from another checkout. `kill` asks the PORT, which is the thing the
|
|
18
18
|
* user actually wants freed, and falls back to the pid file only where the lookup cannot run.
|
|
19
19
|
*/
|
|
20
|
+
import { PortPresence } from '../daemon/binding/port-presence.js';
|
|
20
21
|
import { type PortHolder } from './ports/port-holder.js';
|
|
21
22
|
/** What the plan says to do with the port. */
|
|
22
23
|
export declare const KillAction: {
|
|
@@ -62,6 +63,26 @@ export declare function planKill(input: {
|
|
|
62
63
|
* wrong token, or no answer: the caller then sends the signal as before.
|
|
63
64
|
*/
|
|
64
65
|
export declare function requestShutdown(port: number, token?: string | undefined): Promise<boolean>;
|
|
66
|
+
/**
|
|
67
|
+
* How long the second look waits for `/status`. The usual probe gives up after 1 second, and on a
|
|
68
|
+
* busy machine a healthy daemon took longer than that. A daemon that answers slowly is busy, not
|
|
69
|
+
* stuck, and other agents can use it.
|
|
70
|
+
*/
|
|
71
|
+
export declare const WEDGED_STATUS_TIMEOUT_MS = 10000;
|
|
72
|
+
/**
|
|
73
|
+
* Stop a Reticle daemon that holds `port` and does not answer. True when it stopped one (#1937).
|
|
74
|
+
*
|
|
75
|
+
* The MCP proxy used to move to another port when it found one. The app's SDK dials the old port,
|
|
76
|
+
* so the new daemon got no page. Stopping the stuck daemon keeps the port the app dials. The holder
|
|
77
|
+
* must have a Reticle daemon's command line, so a stranger and the proxy itself are never signalled.
|
|
78
|
+
*/
|
|
79
|
+
export declare function stopWedgedDaemon(port: number, deps?: {
|
|
80
|
+
/** `statusTimeoutMs`: how long to wait for `/status`. Absent: the usual short probe. */
|
|
81
|
+
presence: (statusTimeoutMs?: number) => Promise<PortPresence>;
|
|
82
|
+
holder: () => PortHolder | null;
|
|
83
|
+
kill: () => Promise<boolean>;
|
|
84
|
+
wait: (ms: number) => Promise<void>;
|
|
85
|
+
}): Promise<boolean>;
|
|
65
86
|
/** `reticle kill` — free the port. Resolves to whether the port is now free. */
|
|
66
87
|
export declare function runKill(port: number, force: boolean): Promise<boolean>;
|
|
67
88
|
export {};
|
|
@@ -22,7 +22,8 @@ import { isAlive, readPid, removePid } from '../daemon/daemon.js';
|
|
|
22
22
|
import { probeDaemon } from '../../surface/mcp/mcp-proxy.js';
|
|
23
23
|
import { log } from '../../log.js';
|
|
24
24
|
import { fetchStatus } from '../daemon/binding/daemon-status-probe.js';
|
|
25
|
-
import { captureLookup
|
|
25
|
+
import { captureLookup } from './ports/port-holder.js';
|
|
26
|
+
import { identifyPortHolder } from '../daemon/port-state.js';
|
|
26
27
|
import * as http from 'node:http';
|
|
27
28
|
import { LOOPBACK_HOST, SHUTDOWN_PATH } from '@reticlehq/core';
|
|
28
29
|
import { storedPairingToken } from '../../portal/bridge/pairing-token.js';
|
|
@@ -50,7 +51,8 @@ export function planKill(input) {
|
|
|
50
51
|
return { action: KillAction.NOTHING, forced: false, identifiedListener: false };
|
|
51
52
|
return { action: KillAction.KILL, pid: recordedPid, forced: false, identifiedListener: false };
|
|
52
53
|
}
|
|
53
|
-
|
|
54
|
+
// `reticleDaemon`: its command line says so, though it answers nothing and no pid file names it.
|
|
55
|
+
const ours = answersStatus || listener.pid === recordedPid || true === listener.reticleDaemon;
|
|
54
56
|
if (ours || force) {
|
|
55
57
|
return {
|
|
56
58
|
action: KillAction.KILL,
|
|
@@ -67,7 +69,7 @@ export function planKill(input) {
|
|
|
67
69
|
holder: listener,
|
|
68
70
|
reason: `pid ${String(listener.pid)} ("${listener.command}") is listening, and it is not a Reticle ` +
|
|
69
71
|
`daemon — it never answered /status and it is not the pid Reticle recorded. Killing it would ` +
|
|
70
|
-
`be killing someone else's process. If that is what you meant, \`reticle restart ${FORCE_FLAG}\` ` +
|
|
72
|
+
`be killing someone else's process. If that is what you meant, \`reticle serve --restart ${FORCE_FLAG}\` ` +
|
|
71
73
|
`stops it and starts Reticle there (\`stop ${FORCE_FLAG}\` never does); or start Reticle on ` +
|
|
72
74
|
`another port.`,
|
|
73
75
|
};
|
|
@@ -156,12 +158,53 @@ async function terminate(pid, asked = false) {
|
|
|
156
158
|
*/
|
|
157
159
|
const PROXY_SPARED_NOTE = 'only the listener was signalled. Any `reticle mcp` proxy on this port holds a client connection, ' +
|
|
158
160
|
'not the port, and was left alone — it goes dormant and starts a fresh daemon on the next tool call.';
|
|
161
|
+
/**
|
|
162
|
+
* How long a daemon that holds the port gets to answer before it counts as stuck. A daemon that has
|
|
163
|
+
* just bound answers in far less, so a second look after this does not stop one that is starting.
|
|
164
|
+
*/
|
|
165
|
+
const WEDGED_GRACE_MS = 2_000;
|
|
166
|
+
/**
|
|
167
|
+
* How long the second look waits for `/status`. The usual probe gives up after 1 second, and on a
|
|
168
|
+
* busy machine a healthy daemon took longer than that. A daemon that answers slowly is busy, not
|
|
169
|
+
* stuck, and other agents can use it.
|
|
170
|
+
*/
|
|
171
|
+
export const WEDGED_STATUS_TIMEOUT_MS = 10_000;
|
|
172
|
+
/**
|
|
173
|
+
* Stop a Reticle daemon that holds `port` and does not answer. True when it stopped one (#1937).
|
|
174
|
+
*
|
|
175
|
+
* The MCP proxy used to move to another port when it found one. The app's SDK dials the old port,
|
|
176
|
+
* so the new daemon got no page. Stopping the stuck daemon keeps the port the app dials. The holder
|
|
177
|
+
* must have a Reticle daemon's command line, so a stranger and the proxy itself are never signalled.
|
|
178
|
+
*/
|
|
179
|
+
export async function stopWedgedDaemon(port, deps = {
|
|
180
|
+
presence: (statusTimeoutMs) => probePresence(port, {
|
|
181
|
+
tcpOpen: probeDaemon,
|
|
182
|
+
status: (p) => fetchStatus(p, LOOPBACK_HOST, false, statusTimeoutMs),
|
|
183
|
+
}),
|
|
184
|
+
holder: () => identifyPortHolder(port, captureLookup),
|
|
185
|
+
kill: () => runKill(port, false),
|
|
186
|
+
wait: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
187
|
+
}) {
|
|
188
|
+
if (PortPresence.FOREIGN !== (await deps.presence())) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
const holder = deps.holder();
|
|
192
|
+
if (true !== holder?.reticleDaemon) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
await deps.wait(WEDGED_GRACE_MS);
|
|
196
|
+
if (PortPresence.FOREIGN !== (await deps.presence(WEDGED_STATUS_TIMEOUT_MS))) {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
log('reticle_wedged_daemon_stopping', { port, pid: holder.pid });
|
|
200
|
+
return deps.kill();
|
|
201
|
+
}
|
|
159
202
|
/** `reticle kill` — free the port. Resolves to whether the port is now free. */
|
|
160
203
|
export async function runKill(port, force) {
|
|
161
204
|
const presence = await probePresence(port, { tcpOpen: probeDaemon, status: fetchStatus });
|
|
162
205
|
const recorded = readPid(port);
|
|
163
206
|
const plan = planKill({
|
|
164
|
-
listener:
|
|
207
|
+
listener: identifyPortHolder(port, captureLookup),
|
|
165
208
|
recordedPid: null !== recorded && isAlive(recorded) ? recorded : null,
|
|
166
209
|
answersStatus: presence === PortPresence.DAEMON,
|
|
167
210
|
force,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `reticle compare <reference-url> <candidate-url> [--base <url>] [--state <file>] [--json] [--report <file>]`. The
|
|
3
|
+
* command has one recipe. `--state` names the app's stored data to read, and `--port` names the
|
|
4
|
+
* daemon, as on every command that uses one.
|
|
5
|
+
*
|
|
6
|
+
* Split out of `cli-parse.ts` when that file came near the 1000-line cap.
|
|
7
|
+
*/
|
|
8
|
+
import { type ParseError } from './cli-parse-grammar.js';
|
|
9
|
+
export declare const COMPARE_COMMAND = "compare";
|
|
10
|
+
export type CompareArgs = {
|
|
11
|
+
kind: 'ok';
|
|
12
|
+
reference: string;
|
|
13
|
+
candidate: string;
|
|
14
|
+
base?: string;
|
|
15
|
+
/** The path of the state sources file. */
|
|
16
|
+
state?: string;
|
|
17
|
+
/** Where to write the HTML report. */
|
|
18
|
+
report?: string;
|
|
19
|
+
json: boolean;
|
|
20
|
+
port: number;
|
|
21
|
+
} | ParseError;
|
|
22
|
+
export declare function parseCompareArgs(args: readonly string[], defaultPort: number): CompareArgs;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `reticle compare <reference-url> <candidate-url> [--base <url>] [--state <file>] [--json] [--report <file>]`. The
|
|
3
|
+
* command has one recipe. `--state` names the app's stored data to read, and `--port` names the
|
|
4
|
+
* daemon, as on every command that uses one.
|
|
5
|
+
*
|
|
6
|
+
* Split out of `cli-parse.ts` when that file came near the 1000-line cap.
|
|
7
|
+
*/
|
|
8
|
+
import { JSON_FLAG, PORT_FLAG, missingOperand, missingValue, notANumber, unknownArgument, } from './cli-parse-grammar.js';
|
|
9
|
+
export const COMPARE_COMMAND = 'compare';
|
|
10
|
+
/** `compare --base <url>`: the build before the change. */
|
|
11
|
+
const BASE_FLAG = '--base';
|
|
12
|
+
/** `compare --state <file.json>`: the declared state sources to read after each sequence. */
|
|
13
|
+
const STATE_FLAG = '--state';
|
|
14
|
+
/** `compare --report <file>`: also write the result as one HTML page. */
|
|
15
|
+
const REPORT_FLAG = '--report';
|
|
16
|
+
/** `compare` takes exactly a reference url and a candidate url. */
|
|
17
|
+
const COMPARE_URLS = 2;
|
|
18
|
+
export function parseCompareArgs(args, defaultPort) {
|
|
19
|
+
const urls = [];
|
|
20
|
+
let base;
|
|
21
|
+
let state;
|
|
22
|
+
let report;
|
|
23
|
+
let json = false;
|
|
24
|
+
let port = defaultPort;
|
|
25
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
26
|
+
const arg = args[i] ?? '';
|
|
27
|
+
if (JSON_FLAG === arg) {
|
|
28
|
+
json = true;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (BASE_FLAG === arg || STATE_FLAG === arg || REPORT_FLAG === arg || PORT_FLAG === arg) {
|
|
32
|
+
const value = args[i + 1];
|
|
33
|
+
if (value === undefined || value.startsWith('--')) {
|
|
34
|
+
return missingValue(arg);
|
|
35
|
+
}
|
|
36
|
+
i += 1;
|
|
37
|
+
if (BASE_FLAG === arg) {
|
|
38
|
+
base = value;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (STATE_FLAG === arg) {
|
|
42
|
+
state = value;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (REPORT_FLAG === arg) {
|
|
46
|
+
report = value;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const n = Number(value);
|
|
50
|
+
if (!Number.isInteger(n)) {
|
|
51
|
+
return notANumber(arg, value);
|
|
52
|
+
}
|
|
53
|
+
port = n;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (arg.startsWith('--') || COMPARE_URLS === urls.length) {
|
|
57
|
+
return unknownArgument(arg);
|
|
58
|
+
}
|
|
59
|
+
urls.push(arg);
|
|
60
|
+
}
|
|
61
|
+
const [reference, candidate] = urls;
|
|
62
|
+
if (reference === undefined || candidate === undefined) {
|
|
63
|
+
return missingOperand(COMPARE_COMMAND, 'a reference url and a candidate url');
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
kind: 'ok',
|
|
67
|
+
reference,
|
|
68
|
+
candidate,
|
|
69
|
+
...(base === undefined ? {} : { base }),
|
|
70
|
+
...(state === undefined ? {} : { state }),
|
|
71
|
+
...(report === undefined ? {} : { report }),
|
|
72
|
+
json,
|
|
73
|
+
port,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `reticle grade <snapshot|judge|tables|suggest> [flags]`: grade a finished run of an app from
|
|
3
|
+
* snapshots of its stored data. The rules are in `@/features/grade/`.
|
|
4
|
+
*/
|
|
5
|
+
import { type ParseError } from './cli-parse-grammar.js';
|
|
6
|
+
export declare const GRADE_COMMAND = "grade";
|
|
7
|
+
export declare const GradeStep: {
|
|
8
|
+
readonly SNAPSHOT: "snapshot";
|
|
9
|
+
readonly JUDGE: "judge";
|
|
10
|
+
readonly TABLES: "tables";
|
|
11
|
+
readonly SUGGEST: "suggest";
|
|
12
|
+
};
|
|
13
|
+
export type GradeStep = (typeof GradeStep)[keyof typeof GradeStep];
|
|
14
|
+
/** Each flag that takes a value, and the field it fills. */
|
|
15
|
+
declare const VALUE_FLAGS: {
|
|
16
|
+
readonly '--state': "state";
|
|
17
|
+
readonly '--out': "out";
|
|
18
|
+
readonly '--url': "url";
|
|
19
|
+
readonly '--reference': "reference";
|
|
20
|
+
readonly '--again': "again";
|
|
21
|
+
readonly '--candidate': "candidate";
|
|
22
|
+
readonly '--expect': "expect";
|
|
23
|
+
readonly '--answer': "answer";
|
|
24
|
+
readonly '--list': "list";
|
|
25
|
+
readonly '--rows': "rows";
|
|
26
|
+
readonly '--container': "container";
|
|
27
|
+
readonly '--skip': "skip";
|
|
28
|
+
};
|
|
29
|
+
type GradeField = (typeof VALUE_FLAGS)[keyof typeof VALUE_FLAGS];
|
|
30
|
+
export type GradeArgs = ({
|
|
31
|
+
kind: 'ok';
|
|
32
|
+
step: GradeStep;
|
|
33
|
+
json: boolean;
|
|
34
|
+
} & Partial<Record<GradeField, string>>) | ParseError;
|
|
35
|
+
export declare function parseGradeArgs(args: readonly string[]): GradeArgs;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `reticle grade <snapshot|judge|tables|suggest> [flags]`: grade a finished run of an app from
|
|
3
|
+
* snapshots of its stored data. The rules are in `@/features/grade/`.
|
|
4
|
+
*/
|
|
5
|
+
import { JSON_FLAG, missingOperand, missingValue, unknownArgument, } from './cli-parse-grammar.js';
|
|
6
|
+
export const GRADE_COMMAND = 'grade';
|
|
7
|
+
export const GradeStep = {
|
|
8
|
+
SNAPSHOT: 'snapshot',
|
|
9
|
+
JUDGE: 'judge',
|
|
10
|
+
TABLES: 'tables',
|
|
11
|
+
SUGGEST: 'suggest',
|
|
12
|
+
};
|
|
13
|
+
/** Each flag that takes a value, and the field it fills. */
|
|
14
|
+
const VALUE_FLAGS = {
|
|
15
|
+
'--state': 'state',
|
|
16
|
+
'--out': 'out',
|
|
17
|
+
'--url': 'url',
|
|
18
|
+
'--reference': 'reference',
|
|
19
|
+
'--again': 'again',
|
|
20
|
+
'--candidate': 'candidate',
|
|
21
|
+
'--expect': 'expect',
|
|
22
|
+
'--answer': 'answer',
|
|
23
|
+
'--list': 'list',
|
|
24
|
+
'--rows': 'rows',
|
|
25
|
+
'--container': 'container',
|
|
26
|
+
'--skip': 'skip',
|
|
27
|
+
};
|
|
28
|
+
/** The flags each step needs, and the flags it also takes. */
|
|
29
|
+
const STEP_FLAGS = {
|
|
30
|
+
[GradeStep.SNAPSHOT]: { needs: ['state', 'out'], takes: ['url'] },
|
|
31
|
+
[GradeStep.JUDGE]: {
|
|
32
|
+
needs: ['reference', 'again', 'candidate'],
|
|
33
|
+
takes: ['expect', 'answer'],
|
|
34
|
+
},
|
|
35
|
+
[GradeStep.TABLES]: { needs: ['list', 'rows', 'out'], takes: ['container', 'skip'] },
|
|
36
|
+
[GradeStep.SUGGEST]: { needs: ['state', 'reference', 'again', 'out'], takes: [] },
|
|
37
|
+
};
|
|
38
|
+
const isStep = (word) => Object.values(GradeStep).some((step) => step === word);
|
|
39
|
+
const isValueFlag = (arg) => arg in VALUE_FLAGS;
|
|
40
|
+
const flagOf = (field) => Object.keys(VALUE_FLAGS).find((f) => VALUE_FLAGS[f] === field) ??
|
|
41
|
+
field;
|
|
42
|
+
export function parseGradeArgs(args) {
|
|
43
|
+
const [step, ...rest] = args;
|
|
44
|
+
if (!isStep(step)) {
|
|
45
|
+
// A known flag before the step is a missing step, not an unknown flag.
|
|
46
|
+
return step === undefined || isValueFlag(step) || JSON_FLAG === step
|
|
47
|
+
? missingOperand(GRADE_COMMAND, `a step first: ${Object.values(GradeStep).join(', ')}`)
|
|
48
|
+
: unknownArgument(step);
|
|
49
|
+
}
|
|
50
|
+
const allowed = new Set([...STEP_FLAGS[step].needs, ...STEP_FLAGS[step].takes]);
|
|
51
|
+
const values = {};
|
|
52
|
+
let json = false;
|
|
53
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
54
|
+
const arg = rest[i] ?? '';
|
|
55
|
+
if (JSON_FLAG === arg && GradeStep.JUDGE === step) {
|
|
56
|
+
json = true;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (!isValueFlag(arg) || !allowed.has(VALUE_FLAGS[arg])) {
|
|
60
|
+
return unknownArgument(arg);
|
|
61
|
+
}
|
|
62
|
+
const value = rest[i + 1];
|
|
63
|
+
// An answer may start with "--"; every other value may not.
|
|
64
|
+
if (value === undefined || ('--answer' !== arg && value.startsWith('--'))) {
|
|
65
|
+
return missingValue(arg);
|
|
66
|
+
}
|
|
67
|
+
values[VALUE_FLAGS[arg]] = value;
|
|
68
|
+
i += 1;
|
|
69
|
+
}
|
|
70
|
+
const missing = STEP_FLAGS[step].needs.filter((field) => values[field] === undefined);
|
|
71
|
+
if (missing.length > 0) {
|
|
72
|
+
return missingOperand(`${GRADE_COMMAND} ${step}`, missing.map(flagOf).join(', '));
|
|
73
|
+
}
|
|
74
|
+
return { kind: 'ok', step, json, ...values };
|
|
75
|
+
}
|
|
@@ -26,6 +26,8 @@ export declare const missingOperand: (command: string, what: string) => ParseErr
|
|
|
26
26
|
/** Show the browser. Shared by every command that can drive one. */
|
|
27
27
|
export declare const HEADED_FLAG = "--headed";
|
|
28
28
|
export declare const PORT_FLAG = "--port";
|
|
29
|
+
/** Print one JSON object. */
|
|
30
|
+
export declare const JSON_FLAG = "--json";
|
|
29
31
|
export declare const VERIFY_COMMAND = "verify";
|
|
30
32
|
/**
|
|
31
33
|
* The predicate flag, shared for the same reason the rest of this file is: two places have to name
|
|
@@ -36,6 +36,8 @@ export const missingOperand = (command, what) => ({
|
|
|
36
36
|
/** Show the browser. Shared by every command that can drive one. */
|
|
37
37
|
export const HEADED_FLAG = '--headed';
|
|
38
38
|
export const PORT_FLAG = '--port';
|
|
39
|
+
/** Print one JSON object. */
|
|
40
|
+
export const JSON_FLAG = '--json';
|
|
39
41
|
export const VERIFY_COMMAND = 'verify';
|
|
40
42
|
/**
|
|
41
43
|
* The predicate flag, shared for the same reason the rest of this file is: two places have to name
|
|
@@ -49,37 +51,22 @@ export const EXPECT_FLAG = '--expect';
|
|
|
49
51
|
* that the dispatcher and the telemetry vocabulary read one list instead of two.
|
|
50
52
|
*/
|
|
51
53
|
export const CLOUD_COMMANDS = [
|
|
52
|
-
'login',
|
|
53
54
|
'connect',
|
|
54
55
|
'try',
|
|
55
56
|
'logout',
|
|
56
|
-
'whoami',
|
|
57
|
-
'link',
|
|
58
|
-
'project',
|
|
59
57
|
'config',
|
|
60
|
-
'issues',
|
|
61
|
-
'memory',
|
|
62
|
-
'push',
|
|
63
58
|
'sync',
|
|
64
59
|
'runs',
|
|
65
|
-
'regression',
|
|
66
|
-
'share',
|
|
67
60
|
];
|
|
68
61
|
/**
|
|
69
62
|
* Old command names that still run, for one release, under the name that replaced them. Each one
|
|
70
63
|
* prints a single line saying so, then does what it always did.
|
|
71
64
|
*/
|
|
72
65
|
export const RENAMED_COMMANDS = new Map([
|
|
73
|
-
['
|
|
74
|
-
['
|
|
75
|
-
['
|
|
76
|
-
['
|
|
77
|
-
['whoami', 'status'],
|
|
78
|
-
['push', 'sync'],
|
|
79
|
-
['regression', 'runs regression'],
|
|
80
|
-
['share', 'runs share <runId>'],
|
|
81
|
-
['issues', 'runs issues'],
|
|
82
|
-
['memory', 'runs memory'],
|
|
66
|
+
['affected', 'gate --list'],
|
|
67
|
+
['license', 'status'],
|
|
68
|
+
['rollback', 'update --rollback'],
|
|
69
|
+
['restart', 'serve --restart'],
|
|
83
70
|
]);
|
|
84
71
|
const HELP_FLAGS = new Set(['--help', '-h']);
|
|
85
72
|
/**
|
|
@@ -98,13 +85,24 @@ export function renamedCommandFor(argv) {
|
|
|
98
85
|
*/
|
|
99
86
|
export const REMOVED_COMMANDS = new Map([
|
|
100
87
|
['hunt', 'it has no replacement'],
|
|
101
|
-
['watch', 'use `reticle
|
|
88
|
+
['watch', 'use `reticle gate --list` after you save, or `reticle gate` before you commit'],
|
|
102
89
|
['capsules', 'it has no replacement; saved capsules stay in .reticle/capsules'],
|
|
103
90
|
['tutorial', "use `reticle init` in your app's folder, or `reticle try <url>`"],
|
|
104
91
|
[
|
|
105
92
|
'identify',
|
|
106
93
|
'it has no replacement; delete ~/.reticle/identity.json to forget a saved identity, and use `reticle feedback` to reach us',
|
|
107
94
|
],
|
|
95
|
+
// Renamed one release earlier, and kept for that one release.
|
|
96
|
+
['kill', 'use `reticle stop --force`'],
|
|
97
|
+
['login', 'use `reticle connect`'],
|
|
98
|
+
['link', 'use `reticle connect`'],
|
|
99
|
+
['project', 'use `reticle connect --project <name|id>`'],
|
|
100
|
+
['whoami', 'use `reticle status`'],
|
|
101
|
+
['push', 'use `reticle sync`'],
|
|
102
|
+
['regression', 'use `reticle runs regression`'],
|
|
103
|
+
['share', 'use `reticle runs share <runId>`'],
|
|
104
|
+
['issues', 'use `reticle runs issues`'],
|
|
105
|
+
['memory', 'use `reticle runs memory`'],
|
|
108
106
|
]);
|
|
109
107
|
export const removedNote = (command, instead) => `\`reticle ${command}\` was removed in this version; ${instead}`;
|
|
110
108
|
const DIM = '\u001b[2m';
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/** A missing step 1 control on a freshly loaded start page fails the flow (#2061). */
|
|
2
|
+
export declare const REQUIRE_START_CONTROL_FLAG = "--require-start-control";
|
|
3
|
+
/** Keep judging after a step whose consequence failed, so every step gets a verdict (the score). */
|
|
4
|
+
export declare const SWEEP_FLAG = "--sweep";
|
|
5
|
+
/** Compare the url with this reference build, and report each difference in what users see. */
|
|
6
|
+
export declare const AGAINST_FLAG = "--against";
|
|
1
7
|
export type VerifySuffix = {
|
|
2
8
|
kind: 'ok';
|
|
3
9
|
url: string;
|
|
@@ -14,6 +20,10 @@ export type VerifySuffix = {
|
|
|
14
20
|
select?: string[];
|
|
15
21
|
resultsJson?: string;
|
|
16
22
|
confirmDangerous?: boolean;
|
|
23
|
+
requireStartControl?: boolean;
|
|
24
|
+
sweep?: boolean;
|
|
25
|
+
/** The reference build's url, when the url is to be compared with it. */
|
|
26
|
+
against?: string;
|
|
17
27
|
} | {
|
|
18
28
|
kind: 'error';
|
|
19
29
|
message: string;
|