@reticlehq/server 3.9.0 → 3.10.1
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/SKILL.md +13 -12
- 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 -187
- 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/cli-doctor.js +1 -1
- package/dist/command/cli/cli-flow-commands.js +2 -9
- package/dist/command/cli/cli-kill.js +1 -1
- 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 +17 -15
- package/dist/command/cli/cli-parse.js +44 -27
- 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 +58 -29
- package/dist/command/cli/cli-verify.d.ts +11 -2
- package/dist/command/cli/cli-verify.js +27 -8
- 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/doctor-daemon-line.js +6 -3
- package/dist/command/cli/doctor-repairs.js +1 -1
- 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/lifecycle/daemon-lifecycle.d.ts +1 -1
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +1 -1
- package/dist/command/cli/ports/port-holder.d.ts +9 -0
- package/dist/command/cli/ports/port-holder.js +27 -3
- package/dist/command/cli/status/status-lines.d.ts +1 -0
- package/dist/command/cli/status/status-lines.js +22 -0
- package/dist/command/cli/status-fields.d.ts +5 -1
- package/dist/command/cli/status-fields.js +7 -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 +46 -41
- 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 +12 -1
- package/dist/command/daemon/daemon.js +35 -4
- package/dist/command/daemon/lifetime/death-cause.js +21 -2
- package/dist/command/daemon/lifetime/heartbeat.js +7 -2
- package/dist/command/daemon/lifetime/startup-failure.d.ts +29 -0
- package/dist/command/daemon/lifetime/startup-failure.js +62 -0
- 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-runtime.js +43 -2
- 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 +6 -3
- package/dist/command/update/updater.js +6 -0
- package/dist/command/version/version-skew.js +1 -1
- 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/visual/visual-tools.js +66 -19
- package/dist/index.js +7 -4
- 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/runner-port.d.ts +2 -0
- package/dist/judgement/runs/runner-port.js +23 -5
- 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 +44 -0
- 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 +19 -3
- package/dist/language/flows/recording/tape/recordings.js +71 -5
- package/dist/language/flows/replay.d.ts +19 -5
- package/dist/language/flows/replay.js +99 -7
- 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/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/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/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 +28 -9
- 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 +22 -20
- package/dist/portal/input/real-input.js +41 -31
- package/dist/portal/input/viewport-tools.d.ts +8 -0
- package/dist/portal/input/viewport-tools.js +75 -18
- package/dist/portal/pool/browser-pool.d.ts +11 -29
- package/dist/portal/pool/browser-pool.js +35 -17
- package/dist/portal/pool/context-permissions.d.ts +17 -3
- package/dist/portal/pool/context-permissions.js +36 -5
- 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 +44 -17
- package/dist/portal/pool/lease-page-error.js +147 -5
- package/dist/portal/pool/page-error-journal.d.ts +7 -1
- package/dist/portal/pool/page-error-journal.js +27 -0
- package/dist/portal/pool/playwright-launcher.js +51 -8
- package/dist/portal/pool/pool-contract.d.ts +27 -1
- package/dist/portal/pool/pool-lease.d.ts +36 -1
- package/dist/portal/pool/zero-install.d.ts +8 -0
- package/dist/portal/pool/zero-install.js +23 -1
- package/dist/portal/session/dev-server/dev-command.d.ts +7 -6
- package/dist/portal/session/dev-server/dev-command.js +61 -15
- 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 +67 -25
- package/dist/portal/session/no-session-next-action.d.ts +2 -0
- package/dist/portal/session/no-session-next-action.js +12 -3
- package/dist/portal/session/no-session-watch.d.ts +6 -0
- package/dist/portal/session/no-session-watch.js +38 -3
- 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 +174 -63
- package/dist/start-wiring.d.ts +2 -1
- package/dist/start-wiring.js +2 -1
- package/dist/surface/mcp/mcp.js +3 -2
- 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 +1 -1
- 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/after-match.d.ts +4 -1
- package/dist/surface/tools/act/after-match.js +8 -1
- 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 +15 -1
- package/dist/surface/tools/act/resolve-target.js +24 -1
- package/dist/surface/tools/act/sequence-grade.d.ts +12 -0
- package/dist/surface/tools/act/sequence-grade.js +37 -26
- 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 +78 -50
- package/dist/surface/tools/act-tools.d.ts +1 -13
- package/dist/surface/tools/act-tools.js +74 -86
- 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 +16 -37
- package/dist/surface/tools/browser-tools.js +12 -6
- 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 +9 -2
- package/dist/surface/tools/error-recovery.d.ts +12 -1
- package/dist/surface/tools/error-recovery.js +91 -21
- package/dist/surface/tools/explore-tools.js +1 -1
- package/dist/surface/tools/invoke-tool.js +3 -2
- 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 +35 -1
- package/dist/surface/tools/lease-hint.js +42 -0
- package/dist/surface/tools/lease-readiness.d.ts +26 -0
- package/dist/surface/tools/lease-readiness.js +79 -0
- package/dist/surface/tools/lease-seed.d.ts +14 -1
- package/dist/surface/tools/lease-seed.js +35 -3
- package/dist/surface/tools/lease-tools.d.ts +3 -41
- package/dist/surface/tools/lease-tools.js +62 -110
- 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/session-ports.d.ts +14 -0
- package/dist/surface/tools/session-ports.js +53 -0
- package/dist/surface/tools/tool-kit.d.ts +6 -0
- package/dist/surface/tools/tool-kit.js +2 -3
- package/dist/surface/tools/tool-surface.js +0 -1
- package/dist/surface/tools/tools.js +28 -5
- 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 +1 -0
- package/dist/telemetry/tool-refused.d.ts +6 -3
- package/dist/telemetry/tool-refused.js +8 -3
- package/docs/actions.mdx +3 -3
- package/docs/agent-cheatsheet.md +1 -1
- 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 +1 -1
- package/docs/cli/grade.mdx +97 -0
- package/docs/cli/init.mdx +2 -2
- package/docs/cli/license.mdx +9 -7
- package/docs/cli/restart.mdx +7 -5
- package/docs/cli/rollback.mdx +5 -5
- 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 +33 -23
- package/docs/deploy-checks.md +1 -1
- package/docs/desktop.mdx +1 -1
- package/docs/enterprise.md +2 -2
- package/docs/environment.mdx +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 +1 -1
- package/docs/license-activation.mdx +3 -3
- package/docs/packages/tauri.mdx +1 -1
- package/docs/packages.mdx +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 +2 -2
- package/docs/tools/navigate.mdx +1 -1
- package/docs/tools/verify.mdx +4 -1
- package/docs/troubleshooting.mdx +30 -1
- package/docs/usage.md +17 -14
- package/package.json +11 -14
- package/dist/features/exhaust/exhaust-run.d.ts +0 -33
- package/dist/features/exhaust/exhaust-run.js +0 -82
|
@@ -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;
|
|
@@ -38,6 +38,18 @@ const SELECT_FLAG = '--select';
|
|
|
38
38
|
const RESULTS_JSON_FLAG = '--results-json';
|
|
39
39
|
/** Acknowledge, for this run only, the steps the replay guard holds as destructive ("Place order"). */
|
|
40
40
|
const CONFIRM_DANGEROUS_FLAG = '--confirm-dangerous';
|
|
41
|
+
/** A missing step 1 control on a freshly loaded start page fails the flow (#2061). */
|
|
42
|
+
export const REQUIRE_START_CONTROL_FLAG = '--require-start-control';
|
|
43
|
+
/** Keep judging after a step whose consequence failed, so every step gets a verdict (the score). */
|
|
44
|
+
export const SWEEP_FLAG = '--sweep';
|
|
45
|
+
/** Compare the url with this reference build, and report each difference in what users see. */
|
|
46
|
+
export const AGAINST_FLAG = '--against';
|
|
47
|
+
/**
|
|
48
|
+
* `--against` compares two builds with the same actions. A predicate asks another question, and a
|
|
49
|
+
* model drive does not repeat its actions, so neither can join it.
|
|
50
|
+
*/
|
|
51
|
+
const MSG_AGAINST_ALONE = `${AGAINST_FLAG} compares two builds with the same actions. It cannot be combined with ` +
|
|
52
|
+
`${EXPECT_FLAG}, ${EXPECT_FILE_FLAG}, ${EXPLORE_FLAG} or ${PERSONA_FLAG}. Run them as two commands.`;
|
|
41
53
|
/**
|
|
42
54
|
* Parse `verify <url> [--port N] [--headed] [--timeout N] [--storage-state <file>]
|
|
43
55
|
* [--session-id <id>]`. The first non-flag token is the preview URL. `defaultPort` is already
|
|
@@ -96,54 +108,65 @@ export function parseVerifySuffix(args, defaultPort) {
|
|
|
96
108
|
const select = [];
|
|
97
109
|
let resultsJson;
|
|
98
110
|
let confirmDangerous = false;
|
|
111
|
+
let requireStartControl = false;
|
|
112
|
+
let sweep = false;
|
|
113
|
+
let against;
|
|
99
114
|
let port = defaultPort;
|
|
100
115
|
let i = 0;
|
|
101
116
|
while (i < args.length) {
|
|
102
117
|
const arg = args[i];
|
|
103
|
-
if (arg === undefined)
|
|
118
|
+
if (arg === undefined) {
|
|
104
119
|
break;
|
|
120
|
+
}
|
|
105
121
|
if (arg === HEADED_FLAG) {
|
|
106
122
|
headless = false;
|
|
107
123
|
}
|
|
108
124
|
else if (arg === PORT_FLAG) {
|
|
109
125
|
i++;
|
|
110
126
|
const n = args[i];
|
|
111
|
-
if (n === undefined)
|
|
127
|
+
if (n === undefined) {
|
|
112
128
|
return missingValue(PORT_FLAG);
|
|
129
|
+
}
|
|
113
130
|
const parsed = parseInt(n, 10);
|
|
114
|
-
if (isNaN(parsed))
|
|
131
|
+
if (isNaN(parsed)) {
|
|
115
132
|
return notANumber(PORT_FLAG, n);
|
|
133
|
+
}
|
|
116
134
|
port = parsed;
|
|
117
135
|
}
|
|
118
136
|
else if (arg === TIMEOUT_FLAG) {
|
|
119
137
|
i++;
|
|
120
138
|
const n = args[i];
|
|
121
|
-
if (n === undefined)
|
|
139
|
+
if (n === undefined) {
|
|
122
140
|
return missingValue(TIMEOUT_FLAG);
|
|
141
|
+
}
|
|
123
142
|
const parsed = parseInt(n, 10);
|
|
124
|
-
if (isNaN(parsed))
|
|
143
|
+
if (isNaN(parsed)) {
|
|
125
144
|
return notANumber(TIMEOUT_FLAG, n);
|
|
145
|
+
}
|
|
126
146
|
timeoutMs = parsed;
|
|
127
147
|
}
|
|
128
148
|
else if (arg === STORAGE_STATE_FLAG) {
|
|
129
149
|
i++;
|
|
130
150
|
const v = args[i];
|
|
131
|
-
if (v === undefined)
|
|
151
|
+
if (v === undefined) {
|
|
132
152
|
return missingValue(STORAGE_STATE_FLAG);
|
|
153
|
+
}
|
|
133
154
|
storageState = v;
|
|
134
155
|
}
|
|
135
156
|
else if (arg === SESSION_ID_FLAG) {
|
|
136
157
|
i++;
|
|
137
158
|
const v = args[i];
|
|
138
|
-
if (v === undefined)
|
|
159
|
+
if (v === undefined) {
|
|
139
160
|
return missingValue(SESSION_ID_FLAG);
|
|
161
|
+
}
|
|
140
162
|
sessionId = v;
|
|
141
163
|
}
|
|
142
164
|
else if (arg === SELECT_FLAG) {
|
|
143
165
|
i++;
|
|
144
166
|
const v = args[i];
|
|
145
|
-
if (v === undefined)
|
|
167
|
+
if (v === undefined) {
|
|
146
168
|
return missingValue(SELECT_FLAG);
|
|
169
|
+
}
|
|
147
170
|
// Repeatable rather than comma-split: a label is free-form, and a comma inside one would
|
|
148
171
|
// silently become two selections that match nothing.
|
|
149
172
|
select.push(v);
|
|
@@ -151,21 +174,37 @@ export function parseVerifySuffix(args, defaultPort) {
|
|
|
151
174
|
else if (arg === RESULTS_JSON_FLAG) {
|
|
152
175
|
i++;
|
|
153
176
|
const v = args[i];
|
|
154
|
-
if (v === undefined)
|
|
177
|
+
if (v === undefined) {
|
|
155
178
|
return missingValue(RESULTS_JSON_FLAG);
|
|
179
|
+
}
|
|
156
180
|
resultsJson = v;
|
|
157
181
|
}
|
|
182
|
+
else if (arg === AGAINST_FLAG) {
|
|
183
|
+
i++;
|
|
184
|
+
const v = args[i];
|
|
185
|
+
if (v === undefined) {
|
|
186
|
+
return missingValue(AGAINST_FLAG);
|
|
187
|
+
}
|
|
188
|
+
against = v;
|
|
189
|
+
}
|
|
158
190
|
else if (arg === EXPLORE_FLAG) {
|
|
159
191
|
explore = true;
|
|
160
192
|
}
|
|
161
193
|
else if (arg === CONFIRM_DANGEROUS_FLAG) {
|
|
162
194
|
confirmDangerous = true;
|
|
163
195
|
}
|
|
196
|
+
else if (arg === REQUIRE_START_CONTROL_FLAG) {
|
|
197
|
+
requireStartControl = true;
|
|
198
|
+
}
|
|
199
|
+
else if (arg === SWEEP_FLAG) {
|
|
200
|
+
sweep = true;
|
|
201
|
+
}
|
|
164
202
|
else if (arg === PERSONA_FLAG) {
|
|
165
203
|
i++;
|
|
166
204
|
const v = args[i];
|
|
167
|
-
if (v === undefined)
|
|
205
|
+
if (v === undefined) {
|
|
168
206
|
return missingValue(PERSONA_FLAG);
|
|
207
|
+
}
|
|
169
208
|
// A persona is what to explore AS, so naming one is asking for the drive. Requiring both
|
|
170
209
|
// flags would only give a user a way to say something they cannot mean.
|
|
171
210
|
persona = v;
|
|
@@ -174,18 +213,21 @@ export function parseVerifySuffix(args, defaultPort) {
|
|
|
174
213
|
else if (arg === EXPECT_FLAG) {
|
|
175
214
|
i++;
|
|
176
215
|
const v = args[i];
|
|
177
|
-
if (v === undefined)
|
|
216
|
+
if (v === undefined) {
|
|
178
217
|
return missingValue(EXPECT_FLAG);
|
|
218
|
+
}
|
|
179
219
|
const read = parseExpect(v);
|
|
180
|
-
if ('error' === read.kind)
|
|
220
|
+
if ('error' === read.kind) {
|
|
181
221
|
return read;
|
|
222
|
+
}
|
|
182
223
|
expect = read.value;
|
|
183
224
|
}
|
|
184
225
|
else if (arg === EXPECT_FILE_FLAG) {
|
|
185
226
|
i++;
|
|
186
227
|
const v = args[i];
|
|
187
|
-
if (v === undefined)
|
|
228
|
+
if (v === undefined) {
|
|
188
229
|
return missingValue(EXPECT_FILE_FLAG);
|
|
230
|
+
}
|
|
189
231
|
expectFile = v;
|
|
190
232
|
}
|
|
191
233
|
else if (arg.startsWith('--')) {
|
|
@@ -199,8 +241,9 @@ export function parseVerifySuffix(args, defaultPort) {
|
|
|
199
241
|
}
|
|
200
242
|
i++;
|
|
201
243
|
}
|
|
202
|
-
if (url === undefined)
|
|
244
|
+
if (url === undefined) {
|
|
203
245
|
return missingOperand(VERIFY_COMMAND, 'a url');
|
|
246
|
+
}
|
|
204
247
|
// Two ways to say the same thing, and no way to say two different things. Preferring one
|
|
205
248
|
// silently is how a run asserts something the person did not write.
|
|
206
249
|
if (expect !== undefined && expectFile !== undefined) {
|
|
@@ -209,6 +252,9 @@ export function parseVerifySuffix(args, defaultPort) {
|
|
|
209
252
|
message: `${EXPECT_FLAG} and ${EXPECT_FILE_FLAG} both name the predicate; pass one`,
|
|
210
253
|
};
|
|
211
254
|
}
|
|
255
|
+
if (against !== undefined && (expect !== undefined || expectFile !== undefined || explore)) {
|
|
256
|
+
return { kind: 'error', message: MSG_AGAINST_ALONE };
|
|
257
|
+
}
|
|
212
258
|
// Refused here, where nothing has been bound and no browser exists yet, because the damage this
|
|
213
259
|
// pair does is a verdict taken against the wrong user. A predicate from a file is the same
|
|
214
260
|
// predicate, so it is refused the same way.
|
|
@@ -230,5 +276,8 @@ export function parseVerifySuffix(args, defaultPort) {
|
|
|
230
276
|
...(select.length > 0 ? { select } : {}),
|
|
231
277
|
...(resultsJson !== undefined ? { resultsJson } : {}),
|
|
232
278
|
...(confirmDangerous ? { confirmDangerous } : {}),
|
|
279
|
+
...(requireStartControl ? { requireStartControl } : {}),
|
|
280
|
+
...(sweep ? { sweep } : {}),
|
|
281
|
+
...(against !== undefined ? { against } : {}),
|
|
233
282
|
};
|
|
234
283
|
}
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
* and re-exports this surface.
|
|
5
5
|
*/
|
|
6
6
|
import { type ParsedFeedback } from './cli-parse-feedback.js';
|
|
7
|
+
import { type VerifySuffix } from './cli-parse-verify.js';
|
|
8
|
+
import { type CompareArgs } from './cli-parse-compare.js';
|
|
9
|
+
import { type GradeArgs } from './cli-parse-grade.js';
|
|
7
10
|
import { DAEMON_INNER_COMMAND } from '../daemon/daemon-argv.js';
|
|
8
11
|
import { HEADED_FLAG, PORT_FLAG } from './cli-parse-grammar.js';
|
|
9
12
|
export { DAEMON_INNER_COMMAND, HEADED_FLAG, PORT_FLAG };
|
|
@@ -138,22 +141,21 @@ export type CliResult = {
|
|
|
138
141
|
port: number;
|
|
139
142
|
driveUrl: string;
|
|
140
143
|
headless: boolean;
|
|
141
|
-
} | {
|
|
144
|
+
} | ({
|
|
142
145
|
kind: 'verify';
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
} | {
|
|
146
|
+
} & Omit<Extract<VerifySuffix, {
|
|
147
|
+
kind: 'ok';
|
|
148
|
+
}>, 'kind'>) | ({
|
|
149
|
+
kind: 'compare';
|
|
150
|
+
} & Omit<Extract<CompareArgs, {
|
|
151
|
+
kind: 'ok';
|
|
152
|
+
}>, 'kind'>) | ({
|
|
153
|
+
kind: 'grade';
|
|
154
|
+
} & {
|
|
155
|
+
args: Extract<GradeArgs, {
|
|
156
|
+
kind: 'ok';
|
|
157
|
+
}>;
|
|
158
|
+
}) | {
|
|
157
159
|
kind: 'affected';
|
|
158
160
|
files: string[];
|
|
159
161
|
since?: string;
|
|
@@ -6,8 +6,10 @@
|
|
|
6
6
|
import { parseFeedbackArgs } from './cli-parse-feedback.js';
|
|
7
7
|
import { HEADLESS_FLAG, parseServeFlags } from './cli-parse-serve.js';
|
|
8
8
|
import { parseVerifySuffix } from './cli-parse-verify.js';
|
|
9
|
+
import { COMPARE_COMMAND, parseCompareArgs } from './cli-parse-compare.js';
|
|
10
|
+
import { GRADE_COMMAND, parseGradeArgs } from './cli-parse-grade.js';
|
|
9
11
|
import { DAEMON_INNER_COMMAND } from '../daemon/daemon-argv.js';
|
|
10
|
-
import { HEADED_FLAG, PORT_FLAG, VERIFY_COMMAND, missingOperand, missingValue, notANumber, retiredFlag, unknownArgument, CLOUD_COMMANDS, REMOVED_COMMANDS, removedNote, } from './cli-parse-grammar.js';
|
|
12
|
+
import { HEADED_FLAG, JSON_FLAG, PORT_FLAG, VERIFY_COMMAND, missingOperand, missingValue, notANumber, retiredFlag, unknownArgument, CLOUD_COMMANDS, REMOVED_COMMANDS, removedNote, } from './cli-parse-grammar.js';
|
|
11
13
|
// Re-exported because the daemon's own argv builder reaches for these through this module, which is
|
|
12
14
|
// where the grammar has always lived as far as every caller is concerned.
|
|
13
15
|
export { DAEMON_INNER_COMMAND, HEADED_FLAG, PORT_FLAG };
|
|
@@ -21,13 +23,18 @@ export { CLI_USAGE };
|
|
|
21
23
|
const INIT_COMMAND = 'init';
|
|
22
24
|
const SERVE_COMMAND = 'serve';
|
|
23
25
|
const STOP_COMMAND = 'stop';
|
|
24
|
-
|
|
26
|
+
/** Kept for one release as `serve --restart`. */
|
|
25
27
|
const RESTART_COMMAND = 'restart';
|
|
28
|
+
/** `serve --restart`: stop the daemon, then start it and wait until it listens. */
|
|
29
|
+
const RESTART_FLAG = '--restart';
|
|
26
30
|
const STATUS_COMMAND = 'status';
|
|
27
31
|
const OPEN_COMMAND = 'open';
|
|
28
32
|
const DRIVE_COMMAND = 'drive';
|
|
33
|
+
/** Kept for one release as `gate --list`. */
|
|
29
34
|
const AFFECTED_COMMAND = 'affected';
|
|
30
35
|
const GATE_COMMAND = 'gate';
|
|
36
|
+
/** `gate --list`: name the saved flows the changes touch, and check nothing. */
|
|
37
|
+
const LIST_FLAG = '--list';
|
|
31
38
|
/** Hook mode: prose a human can read, and silence when there was simply nothing to check. */
|
|
32
39
|
const HOOK_FLAG = '--hook';
|
|
33
40
|
const ACCEPT_COVERAGE_FLAG = '--accept-coverage';
|
|
@@ -37,7 +44,9 @@ const REPORT_COMMAND = 'report';
|
|
|
37
44
|
const CONTEXT_COMMAND = 'context';
|
|
38
45
|
const SESSION_FLAG = '--session';
|
|
39
46
|
const UPDATE_COMMAND = 'update';
|
|
47
|
+
/** Kept for one release as `update --rollback`. */
|
|
40
48
|
const ROLLBACK_COMMAND = 'rollback';
|
|
49
|
+
const ROLLBACK_FLAG = '--rollback';
|
|
41
50
|
const MCP_COMMAND = 'mcp';
|
|
42
51
|
const LICENSE_COMMAND = 'license';
|
|
43
52
|
const VERSION_COMMAND = 'version';
|
|
@@ -80,12 +89,13 @@ export const LOCAL_COMMANDS = [
|
|
|
80
89
|
INIT_COMMAND,
|
|
81
90
|
SERVE_COMMAND,
|
|
82
91
|
STOP_COMMAND,
|
|
83
|
-
KILL_COMMAND,
|
|
84
92
|
RESTART_COMMAND,
|
|
85
93
|
STATUS_COMMAND,
|
|
86
94
|
OPEN_COMMAND,
|
|
87
95
|
DRIVE_COMMAND,
|
|
88
96
|
VERIFY_COMMAND,
|
|
97
|
+
COMPARE_COMMAND,
|
|
98
|
+
GRADE_COMMAND,
|
|
89
99
|
AFFECTED_COMMAND,
|
|
90
100
|
GATE_COMMAND,
|
|
91
101
|
REPORT_COMMAND,
|
|
@@ -179,7 +189,6 @@ const NO_PROMPT_CAPTURE_FLAG = '--no-prompt-capture';
|
|
|
179
189
|
* and reading one object is one turn where interpreting a report is several. The three opt-outs are
|
|
180
190
|
* what a machine without a browser, or a caller already running their app, actually needs.
|
|
181
191
|
*/
|
|
182
|
-
const JSON_FLAG = '--json';
|
|
183
192
|
const NO_DRIVE_FLAG = '--no-drive';
|
|
184
193
|
const NO_OPEN_FLAG = '--no-open';
|
|
185
194
|
/** `reticle open <url> --navigate`: move a tab already on the origin to the url (#1140). */
|
|
@@ -550,6 +559,16 @@ export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
|
550
559
|
};
|
|
551
560
|
}
|
|
552
561
|
case SERVE_COMMAND: {
|
|
562
|
+
if (rest.includes(RESTART_FLAG)) {
|
|
563
|
+
return {
|
|
564
|
+
kind: 'restart',
|
|
565
|
+
port: parsePortFlag(rest, defaultPort),
|
|
566
|
+
force: rest.includes(FORCE_FLAG),
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
if (rest.includes(FORCE_FLAG)) {
|
|
570
|
+
return { kind: 'error', message: `${FORCE_FLAG} works only with ${RESTART_FLAG}` };
|
|
571
|
+
}
|
|
553
572
|
const r = parseServeFlags(rest, defaultPort, defaultHeadless);
|
|
554
573
|
if ('error' === r.kind) {
|
|
555
574
|
return r;
|
|
@@ -567,17 +586,13 @@ export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
|
567
586
|
case STOP_COMMAND: {
|
|
568
587
|
const port = parsePortFlag(rest, defaultPort);
|
|
569
588
|
// `stop --force` is what `kill` was: free the port by its listener, which must still be a
|
|
570
|
-
// Reticle daemon. Overriding that refusal stays on `
|
|
589
|
+
// Reticle daemon. Overriding that refusal stays on `serve --restart --force`.
|
|
571
590
|
if (rest.includes(FORCE_FLAG)) {
|
|
572
591
|
return { kind: 'kill', port, force: false };
|
|
573
592
|
}
|
|
574
593
|
const quiet = rest.includes(QUIET_FLAG);
|
|
575
594
|
return { kind: 'stop', port, quiet };
|
|
576
595
|
}
|
|
577
|
-
case KILL_COMMAND: {
|
|
578
|
-
const port = parsePortFlag(rest, defaultPort);
|
|
579
|
-
return { kind: 'kill', port, force: rest.includes(FORCE_FLAG) };
|
|
580
|
-
}
|
|
581
596
|
case RESTART_COMMAND: {
|
|
582
597
|
const port = parsePortFlag(rest, defaultPort);
|
|
583
598
|
return { kind: 'restart', port, force: rest.includes(FORCE_FLAG) };
|
|
@@ -682,22 +697,21 @@ export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
|
682
697
|
if ('error' === r.kind) {
|
|
683
698
|
return r;
|
|
684
699
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
};
|
|
700
|
+
// Every parsed field, so a flag the suffix parser reads cannot be lost here.
|
|
701
|
+
const { kind: _ok, ...fields } = r;
|
|
702
|
+
return { kind: 'verify', ...fields };
|
|
703
|
+
}
|
|
704
|
+
case COMPARE_COMMAND: {
|
|
705
|
+
const r = parseCompareArgs(rest, defaultPort);
|
|
706
|
+
if ('error' === r.kind) {
|
|
707
|
+
return r;
|
|
708
|
+
}
|
|
709
|
+
const { kind: _ok, ...fields } = r;
|
|
710
|
+
return { kind: 'compare', ...fields };
|
|
711
|
+
}
|
|
712
|
+
case GRADE_COMMAND: {
|
|
713
|
+
const r = parseGradeArgs(rest);
|
|
714
|
+
return 'error' === r.kind ? r : { kind: 'grade', args: r };
|
|
701
715
|
}
|
|
702
716
|
case AFFECTED_COMMAND: {
|
|
703
717
|
const t = parseTargetArgs(rest);
|
|
@@ -708,8 +722,11 @@ export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
|
708
722
|
// Flags are stripped before target parsing, which would reject them as unknown.
|
|
709
723
|
const hook = rest.includes(HOOK_FLAG);
|
|
710
724
|
const acceptCoverage = rest.includes(ACCEPT_COVERAGE_FLAG);
|
|
711
|
-
const t = parseTargetArgs(rest.filter((a) => a !== HOOK_FLAG && a !== ACCEPT_COVERAGE_FLAG));
|
|
725
|
+
const t = parseTargetArgs(rest.filter((a) => a !== HOOK_FLAG && a !== ACCEPT_COVERAGE_FLAG && a !== LIST_FLAG));
|
|
712
726
|
const since = t.since ?? implicitSince(t.files);
|
|
727
|
+
if (rest.includes(LIST_FLAG)) {
|
|
728
|
+
return { kind: 'affected', files: t.files, ...(since === undefined ? {} : { since }) };
|
|
729
|
+
}
|
|
713
730
|
return {
|
|
714
731
|
kind: 'gate',
|
|
715
732
|
files: t.files,
|
|
@@ -737,7 +754,7 @@ export function parseCliArgs(argv, defaultPort, defaultHeadless = false) {
|
|
|
737
754
|
return { kind: 'context', ...(session === undefined ? {} : { session }) };
|
|
738
755
|
}
|
|
739
756
|
case UPDATE_COMMAND:
|
|
740
|
-
return { kind: 'update' };
|
|
757
|
+
return rest.includes(ROLLBACK_FLAG) ? { kind: 'rollback' } : { kind: 'update' };
|
|
741
758
|
case ROLLBACK_COMMAND:
|
|
742
759
|
return { kind: 'rollback' };
|
|
743
760
|
case MCP_COMMAND: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/** `reticle update` — install the latest server version, sync the app's SDK, and restart. */
|
|
2
2
|
export declare function handleUpdate(cwd?: string): Promise<void>;
|
|
3
|
-
/** `reticle rollback` — restore the previous server version and restart. */
|
|
3
|
+
/** `reticle update --rollback` — restore the previous server version and restart. */
|
|
4
4
|
export declare function handleRollback(): Promise<void>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The self-update command pair — `reticle update` and `reticle rollback`.
|
|
2
|
+
* The self-update command pair — `reticle update` and `reticle update --rollback`.
|
|
3
3
|
*
|
|
4
4
|
* Split out of cli.ts, which sits at the 600-line cap: these two are one cohesive unit (swap the
|
|
5
5
|
* installed version, restart) and the file they came from is the CLI's dispatch table, which grows
|
|
@@ -91,6 +91,29 @@ function syncProjectSdk(target, cwd) {
|
|
|
91
91
|
}
|
|
92
92
|
say(MSG_SDK_SYNCED(target));
|
|
93
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Bring this project's agent rules up with the version.
|
|
96
|
+
*
|
|
97
|
+
* The managed block has always been updatable — marker-delimited, idempotent by comparing content —
|
|
98
|
+
* and nothing called it after the first install. `mergeMarkedInstruction` is reachable from
|
|
99
|
+
* `buildPlan` alone, so a project set up on an older release kept that release's instructions
|
|
100
|
+
* forever and every improvement to them reached new projects only.
|
|
101
|
+
*
|
|
102
|
+
* That is backwards: the people who most need better instructions are the ones already installed
|
|
103
|
+
* and not getting value, and this is the moment they are touching the install anyway. Only files
|
|
104
|
+
* that ALREADY carry the block are touched, and only inside the markers.
|
|
105
|
+
*/
|
|
106
|
+
function refreshProjectRules(cwd, version) {
|
|
107
|
+
const refreshed = refreshAgentRules(cwd, {
|
|
108
|
+
read: (path) => (existsSync(path) ? readFileSync(path, 'utf8') : null),
|
|
109
|
+
write: (path, content) => {
|
|
110
|
+
writeFileSync(path, content, 'utf8');
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
if (0 !== refreshed.updated.length) {
|
|
114
|
+
log('reticle_rules_refreshed', { files: refreshed.updated, to: version });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
94
117
|
/** `reticle update` — install the latest server version, sync the app's SDK, and restart. */
|
|
95
118
|
export async function handleUpdate(cwd = process.cwd()) {
|
|
96
119
|
try {
|
|
@@ -103,6 +126,9 @@ export async function handleUpdate(cwd = process.cwd()) {
|
|
|
103
126
|
// is on the latest release while the app keeps the SDK `init` pinned months ago, and this
|
|
104
127
|
// branch used to return before the sync — so the one command that should fix that pair
|
|
105
128
|
// answered "already on the latest version" and left the old overlay in the page.
|
|
129
|
+
// The same holds for the agent rules: a project on the latest CLI kept the block that its
|
|
130
|
+
// first `init` wrote, because this branch returned before the refresh (#1948).
|
|
131
|
+
refreshProjectRules(cwd, SERVER_VERSION);
|
|
106
132
|
const installed = installedSdkVersion(cwd, readTextFile);
|
|
107
133
|
if (installed === undefined)
|
|
108
134
|
say(MSG_NO_SDK_HERE);
|
|
@@ -118,24 +144,7 @@ export async function handleUpdate(cwd = process.cwd()) {
|
|
|
118
144
|
return;
|
|
119
145
|
}
|
|
120
146
|
log('reticle_update', { ok: true, from: SERVER_VERSION, to: target });
|
|
121
|
-
|
|
122
|
-
//
|
|
123
|
-
// The managed block has always been updatable — marker-delimited, idempotent by comparing
|
|
124
|
-
// content — and nothing called it after the first install. `mergeMarkedInstruction` is reachable
|
|
125
|
-
// from `buildPlan` alone, so a project set up on an older release kept that release's
|
|
126
|
-
// instructions forever and every improvement to them reached new projects only.
|
|
127
|
-
//
|
|
128
|
-
// That is backwards: the people who most need better instructions are the ones already
|
|
129
|
-
// installed and not getting value, and this is the moment they are touching the install anyway.
|
|
130
|
-
// Only files that ALREADY carry the block are touched, and only inside the markers.
|
|
131
|
-
const refreshed = refreshAgentRules(cwd, {
|
|
132
|
-
read: (path) => (existsSync(path) ? readFileSync(path, 'utf8') : null),
|
|
133
|
-
write: (path, content) => {
|
|
134
|
-
writeFileSync(path, content, 'utf8');
|
|
135
|
-
},
|
|
136
|
-
});
|
|
137
|
-
if (0 !== refreshed.updated.length)
|
|
138
|
-
log('reticle_rules_refreshed', { files: refreshed.updated, to: target });
|
|
147
|
+
refreshProjectRules(cwd, target);
|
|
139
148
|
// The app's SDK FIRST, then the CLI. `reticle update` used to swap only the CLI, so the command
|
|
140
149
|
// whose job is keeping an install current was itself a way to produce a version-skewed pair —
|
|
141
150
|
// and the skew message told people to run it to fix an outdated SDK, which it could not do.
|
|
@@ -157,7 +166,7 @@ export async function handleUpdate(cwd = process.cwd()) {
|
|
|
157
166
|
process.exitCode = 1;
|
|
158
167
|
}
|
|
159
168
|
}
|
|
160
|
-
/** `reticle rollback` — restore the previous server version and restart. */
|
|
169
|
+
/** `reticle update --rollback` — restore the previous server version and restart. */
|
|
161
170
|
export async function handleRollback() {
|
|
162
171
|
try {
|
|
163
172
|
await rollback(); // calls process.exit
|