@jevitate/cli 0.1.0 → 0.3.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/README.md +23 -0
- package/dist/ai-cli.d.ts +31 -11
- package/dist/ai-cli.js +131 -88
- package/dist/ai-cli.js.map +1 -1
- package/dist/author-journey-cli.d.ts +4 -0
- package/dist/author-journey-cli.js +111 -0
- package/dist/author-journey-cli.js.map +1 -0
- package/dist/bin.js +60349 -16477
- package/dist/bin.js.map +1 -1
- package/dist/browser-run-options.d.ts +89 -0
- package/dist/browser-run-options.js +175 -0
- package/dist/browser-run-options.js.map +1 -0
- package/dist/build-info.generated.d.ts +2 -0
- package/dist/build-info.generated.js +10 -0
- package/dist/build-info.generated.js.map +1 -0
- package/dist/campaign-api.d.ts +151 -0
- package/dist/campaign-api.js +446 -0
- package/dist/campaign-api.js.map +1 -0
- package/dist/campaign-cli.d.ts +6 -0
- package/dist/campaign-cli.js +66 -0
- package/dist/campaign-cli.js.map +1 -0
- package/dist/check-api.d.ts +5 -0
- package/dist/check-api.js +234 -0
- package/dist/check-api.js.map +1 -0
- package/dist/check-budget.d.ts +26 -0
- package/dist/check-budget.js +90 -0
- package/dist/check-budget.js.map +1 -0
- package/dist/check-cli.d.ts +31 -0
- package/dist/check-cli.js +109 -0
- package/dist/check-cli.js.map +1 -0
- package/dist/check-execute.d.ts +29 -0
- package/dist/check-execute.js +420 -0
- package/dist/check-execute.js.map +1 -0
- package/dist/check-plan.d.ts +118 -0
- package/dist/check-plan.js +516 -0
- package/dist/check-plan.js.map +1 -0
- package/dist/check-suite.d.ts +184 -0
- package/dist/check-suite.js +540 -0
- package/dist/check-suite.js.map +1 -0
- package/dist/check-types.d.ts +181 -0
- package/dist/check-types.js +35 -0
- package/dist/check-types.js.map +1 -0
- package/dist/cli-args.d.ts +26 -0
- package/dist/cli-args.js +50 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli-output.d.ts +106 -0
- package/dist/cli-output.js +563 -0
- package/dist/cli-output.js.map +1 -0
- package/dist/cli-reference.d.ts +3 -0
- package/dist/cli-reference.js +81 -0
- package/dist/cli-reference.js.map +1 -0
- package/dist/cli-refusal.d.ts +12 -0
- package/dist/cli-refusal.js +52 -0
- package/dist/cli-refusal.js.map +1 -0
- package/dist/cli-shared.d.ts +340 -0
- package/dist/cli-shared.js +537 -0
- package/dist/cli-shared.js.map +1 -0
- package/dist/cli-surface.d.ts +33 -0
- package/dist/cli-surface.js +48 -0
- package/dist/cli-surface.js.map +1 -0
- package/dist/conversation-options.d.ts +15 -0
- package/dist/conversation-options.js +10 -0
- package/dist/conversation-options.js.map +1 -0
- package/dist/credentials-file.d.ts +15 -0
- package/dist/credentials-file.js +56 -0
- package/dist/credentials-file.js.map +1 -0
- package/dist/data-dir.d.ts +1 -1
- package/dist/data-dir.js +1 -1
- package/dist/defect-evidence.d.ts +141 -0
- package/dist/defect-evidence.js +505 -0
- package/dist/defect-evidence.js.map +1 -0
- package/dist/demo-aspect-api.d.ts +209 -0
- package/dist/demo-aspect-api.js +398 -0
- package/dist/demo-aspect-api.js.map +1 -0
- package/dist/demo-aspect-cli.d.ts +3 -0
- package/dist/demo-aspect-cli.js +243 -0
- package/dist/demo-aspect-cli.js.map +1 -0
- package/dist/demo-capture.d.ts +142 -0
- package/dist/demo-capture.js +537 -0
- package/dist/demo-capture.js.map +1 -0
- package/dist/engine.d.ts +35 -0
- package/dist/engine.js +25 -0
- package/dist/engine.js.map +1 -0
- package/dist/environments.d.ts +155 -0
- package/dist/environments.js +364 -0
- package/dist/environments.js.map +1 -0
- package/dist/exit-codes.d.ts +46 -0
- package/dist/exit-codes.js +91 -0
- package/dist/exit-codes.js.map +1 -0
- package/dist/explore-adversarial.d.ts +144 -0
- package/dist/explore-adversarial.js +227 -0
- package/dist/explore-adversarial.js.map +1 -0
- package/dist/explore-api.d.ts +7 -187
- package/dist/explore-api.js +7 -301
- package/dist/explore-api.js.map +1 -1
- package/dist/explore-author.d.ts +79 -0
- package/dist/explore-author.js +86 -0
- package/dist/explore-author.js.map +1 -0
- package/dist/explore-cli.d.ts +7 -0
- package/dist/explore-cli.js +1199 -0
- package/dist/explore-cli.js.map +1 -0
- package/dist/explore-coverage.d.ts +173 -0
- package/dist/explore-coverage.js +246 -0
- package/dist/explore-coverage.js.map +1 -0
- package/dist/explore-feature.d.ts +125 -0
- package/dist/explore-feature.js +218 -0
- package/dist/explore-feature.js.map +1 -0
- package/dist/explore-goal.d.ts +271 -0
- package/dist/explore-goal.js +417 -0
- package/dist/explore-goal.js.map +1 -0
- package/dist/explore-shared.d.ts +177 -0
- package/dist/explore-shared.js +149 -0
- package/dist/explore-shared.js.map +1 -0
- package/dist/explore-specs.d.ts +53 -0
- package/dist/explore-specs.js +333 -0
- package/dist/explore-specs.js.map +1 -0
- package/dist/findings-filing.d.ts +64 -0
- package/dist/findings-filing.js +108 -0
- package/dist/findings-filing.js.map +1 -0
- package/dist/fixture-auth.d.ts +63 -0
- package/dist/fixture-auth.js +95 -0
- package/dist/fixture-auth.js.map +1 -0
- package/dist/fixture-cli.d.ts +99 -0
- package/dist/fixture-cli.js +292 -0
- package/dist/fixture-cli.js.map +1 -0
- package/dist/github-issue-filer.d.ts +62 -0
- package/dist/github-issue-filer.js +189 -0
- package/dist/github-issue-filer.js.map +1 -0
- package/dist/host-health-run.d.ts +25 -0
- package/dist/host-health-run.js +33 -0
- package/dist/host-health-run.js.map +1 -0
- package/dist/http-5xx-outcome.d.ts +6 -0
- package/dist/http-5xx-outcome.js +39 -0
- package/dist/http-5xx-outcome.js.map +1 -0
- package/dist/inbox-cli.d.ts +7 -0
- package/dist/inbox-cli.js +197 -0
- package/dist/inbox-cli.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/init-cli.d.ts +4 -0
- package/dist/init-cli.js +156 -0
- package/dist/init-cli.js.map +1 -0
- package/dist/init-keys.d.ts +30 -2
- package/dist/init-keys.js +19 -5
- package/dist/init-keys.js.map +1 -1
- package/dist/init-next-steps.d.ts +35 -0
- package/dist/init-next-steps.js +79 -0
- package/dist/init-next-steps.js.map +1 -0
- package/dist/invariants-file.d.ts +34 -0
- package/dist/invariants-file.js +68 -0
- package/dist/invariants-file.js.map +1 -0
- package/dist/invariants-validate.d.ts +30 -0
- package/dist/invariants-validate.js +105 -0
- package/dist/invariants-validate.js.map +1 -0
- package/dist/journey-annotate-api.d.ts +76 -0
- package/dist/journey-annotate-api.js +269 -0
- package/dist/journey-annotate-api.js.map +1 -0
- package/dist/journey-annotate-cli.d.ts +9 -0
- package/dist/journey-annotate-cli.js +181 -0
- package/dist/journey-annotate-cli.js.map +1 -0
- package/dist/journey-api.d.ts +104 -2
- package/dist/journey-api.js +163 -20
- package/dist/journey-api.js.map +1 -1
- package/dist/journey-cli.d.ts +4 -0
- package/dist/journey-cli.js +411 -0
- package/dist/journey-cli.js.map +1 -0
- package/dist/journey-demo-api.d.ts +114 -0
- package/dist/journey-demo-api.js +405 -0
- package/dist/journey-demo-api.js.map +1 -0
- package/dist/journey-demo-cli.d.ts +10 -0
- package/dist/journey-demo-cli.js +158 -0
- package/dist/journey-demo-cli.js.map +1 -0
- package/dist/journey-prefix.d.ts +194 -0
- package/dist/journey-prefix.js +279 -0
- package/dist/journey-prefix.js.map +1 -0
- package/dist/key-report.d.ts +49 -0
- package/dist/key-report.js +101 -0
- package/dist/key-report.js.map +1 -0
- package/dist/kill-signal.d.ts +193 -0
- package/dist/kill-signal.js +283 -0
- package/dist/kill-signal.js.map +1 -0
- package/dist/launch-armed.d.ts +37 -0
- package/dist/launch-armed.js +31 -0
- package/dist/launch-armed.js.map +1 -0
- package/dist/ledger-api.d.ts +106 -0
- package/dist/ledger-api.js +239 -0
- package/dist/ledger-api.js.map +1 -0
- package/dist/ledger-cli.d.ts +18 -0
- package/dist/ledger-cli.js +107 -0
- package/dist/ledger-cli.js.map +1 -0
- package/dist/load-api.d.ts +29 -11
- package/dist/load-api.js +23 -15
- package/dist/load-api.js.map +1 -1
- package/dist/load-cli.d.ts +4 -0
- package/dist/load-cli.js +97 -0
- package/dist/load-cli.js.map +1 -0
- package/dist/log-correlation.d.ts +200 -0
- package/dist/log-correlation.js +394 -0
- package/dist/log-correlation.js.map +1 -0
- package/dist/log-lines.d.ts +131 -0
- package/dist/log-lines.js +389 -0
- package/dist/log-lines.js.map +1 -0
- package/dist/log-sources.d.ts +71 -0
- package/dist/log-sources.js +236 -0
- package/dist/log-sources.js.map +1 -0
- package/dist/log-trace.d.ts +80 -0
- package/dist/log-trace.js +210 -0
- package/dist/log-trace.js.map +1 -0
- package/dist/logs-cli.d.ts +3 -0
- package/dist/logs-cli.js +51 -0
- package/dist/logs-cli.js.map +1 -0
- package/dist/logs-retention.d.ts +28 -0
- package/dist/logs-retention.js +85 -0
- package/dist/logs-retention.js.map +1 -0
- package/dist/masked-input.d.ts +22 -0
- package/dist/masked-input.js +99 -0
- package/dist/masked-input.js.map +1 -0
- package/dist/mcp-api.d.ts +91 -1
- package/dist/mcp-api.js +514 -18
- package/dist/mcp-api.js.map +1 -1
- package/dist/mcp-args.d.ts +50 -0
- package/dist/mcp-args.js +164 -0
- package/dist/mcp-args.js.map +1 -0
- package/dist/mcp-cli-bridge.d.ts +34 -0
- package/dist/mcp-cli-bridge.js +62 -0
- package/dist/mcp-cli-bridge.js.map +1 -0
- package/dist/mcp-cli-runner.d.ts +29 -0
- package/dist/mcp-cli-runner.js +44 -0
- package/dist/mcp-cli-runner.js.map +1 -0
- package/dist/mcp-cli-tools.d.ts +129 -0
- package/dist/mcp-cli-tools.js +737 -0
- package/dist/mcp-cli-tools.js.map +1 -0
- package/dist/mcp-paths.d.ts +28 -0
- package/dist/mcp-paths.js +76 -0
- package/dist/mcp-paths.js.map +1 -0
- package/dist/mission-actors.d.ts +40 -0
- package/dist/mission-actors.js +72 -0
- package/dist/mission-actors.js.map +1 -0
- package/dist/mission-api.d.ts +35 -0
- package/dist/mission-api.js +60 -3
- package/dist/mission-api.js.map +1 -1
- package/dist/mission-cli.d.ts +4 -0
- package/dist/mission-cli.js +248 -0
- package/dist/mission-cli.js.map +1 -0
- package/dist/mission-exit.d.ts +22 -0
- package/dist/mission-exit.js +26 -0
- package/dist/mission-exit.js.map +1 -0
- package/dist/mission-fixtures.d.ts +234 -0
- package/dist/mission-fixtures.js +862 -0
- package/dist/mission-fixtures.js.map +1 -0
- package/dist/mission-journal.d.ts +60 -0
- package/dist/mission-journal.js +115 -0
- package/dist/mission-journal.js.map +1 -0
- package/dist/mission-queue-cli.d.ts +10 -0
- package/dist/mission-queue-cli.js +198 -0
- package/dist/mission-queue-cli.js.map +1 -0
- package/dist/mission-queue-runner.d.ts +126 -0
- package/dist/mission-queue-runner.js +406 -0
- package/dist/mission-queue-runner.js.map +1 -0
- package/dist/multi-run-cli.d.ts +37 -0
- package/dist/multi-run-cli.js +116 -0
- package/dist/multi-run-cli.js.map +1 -0
- package/dist/multi-run.d.ts +339 -0
- package/dist/multi-run.js +619 -0
- package/dist/multi-run.js.map +1 -0
- package/dist/openrouter-call.d.ts +22 -0
- package/dist/openrouter-call.js +64 -0
- package/dist/openrouter-call.js.map +1 -0
- package/dist/profile-cli.d.ts +4 -0
- package/dist/profile-cli.js +57 -0
- package/dist/profile-cli.js.map +1 -0
- package/dist/program.d.ts +3 -75
- package/dist/program.js +123 -1921
- package/dist/program.js.map +1 -1
- package/dist/project-dir.d.ts +96 -0
- package/dist/project-dir.js +221 -0
- package/dist/project-dir.js.map +1 -0
- package/dist/record-api.d.ts +13 -7
- package/dist/record-api.js +44 -30
- package/dist/record-api.js.map +1 -1
- package/dist/record-cli.d.ts +4 -0
- package/dist/record-cli.js +76 -0
- package/dist/record-cli.js.map +1 -0
- package/dist/recording-cli.d.ts +4 -0
- package/dist/recording-cli.js +248 -0
- package/dist/recording-cli.js.map +1 -0
- package/dist/regression-api.d.ts +107 -0
- package/dist/regression-api.js +387 -6
- package/dist/regression-api.js.map +1 -1
- package/dist/regression-cli.d.ts +4 -0
- package/dist/regression-cli.js +284 -0
- package/dist/regression-cli.js.map +1 -0
- package/dist/report-api.d.ts +146 -0
- package/dist/report-api.js +431 -0
- package/dist/report-api.js.map +1 -0
- package/dist/report-cli.d.ts +12 -0
- package/dist/report-cli.js +147 -0
- package/dist/report-cli.js.map +1 -0
- package/dist/resource-preflight.d.ts +87 -0
- package/dist/resource-preflight.js +160 -0
- package/dist/resource-preflight.js.map +1 -0
- package/dist/result-schema.d.ts +22 -0
- package/dist/result-schema.js +28 -0
- package/dist/result-schema.js.map +1 -0
- package/dist/run-index.d.ts +29 -0
- package/dist/run-index.js +70 -0
- package/dist/run-index.js.map +1 -0
- package/dist/run-key-preflight.d.ts +42 -0
- package/dist/run-key-preflight.js +82 -0
- package/dist/run-key-preflight.js.map +1 -0
- package/dist/run-screenshots.d.ts +123 -0
- package/dist/run-screenshots.js +235 -0
- package/dist/run-screenshots.js.map +1 -0
- package/dist/runtime-env.d.ts +8 -0
- package/dist/runtime-env.js +23 -0
- package/dist/runtime-env.js.map +1 -0
- package/dist/secret-args.d.ts +23 -0
- package/dist/secret-args.js +45 -0
- package/dist/secret-args.js.map +1 -0
- package/dist/serve-cli.d.ts +4 -0
- package/dist/serve-cli.js +95 -0
- package/dist/serve-cli.js.map +1 -0
- package/dist/server-log-verify.d.ts +36 -0
- package/dist/server-log-verify.js +120 -0
- package/dist/server-log-verify.js.map +1 -0
- package/dist/session-check.d.ts +14 -0
- package/dist/session-check.js +44 -0
- package/dist/session-check.js.map +1 -0
- package/dist/site-cli.d.ts +4 -0
- package/dist/site-cli.js +127 -0
- package/dist/site-cli.js.map +1 -0
- package/dist/site-gate-cli.d.ts +28 -0
- package/dist/site-gate-cli.js +59 -0
- package/dist/site-gate-cli.js.map +1 -0
- package/dist/source-api.js +20 -4
- package/dist/source-api.js.map +1 -1
- package/dist/source-cli.d.ts +4 -0
- package/dist/source-cli.js +284 -0
- package/dist/source-cli.js.map +1 -0
- package/dist/source-run-api.d.ts +27 -1
- package/dist/source-run-api.js +22 -11
- package/dist/source-run-api.js.map +1 -1
- package/dist/storage-state-snapshot.d.ts +50 -0
- package/dist/storage-state-snapshot.js +87 -0
- package/dist/storage-state-snapshot.js.map +1 -0
- package/dist/suite-explore-options.d.ts +321 -0
- package/dist/suite-explore-options.js +162 -0
- package/dist/suite-explore-options.js.map +1 -0
- package/dist/target-config.d.ts +115 -0
- package/dist/target-config.js +225 -0
- package/dist/target-config.js.map +1 -0
- package/dist/transcript-file.d.ts +12 -0
- package/dist/transcript-file.js +23 -0
- package/dist/transcript-file.js.map +1 -0
- package/dist/type-fixture-file.d.ts +9 -0
- package/dist/type-fixture-file.js +48 -0
- package/dist/type-fixture-file.js.map +1 -0
- package/dist/ui-api.d.ts +3 -0
- package/dist/ui-api.js +11 -4
- package/dist/ui-api.js.map +1 -1
- package/dist/usability-capture.d.ts +43 -0
- package/dist/usability-capture.js +327 -0
- package/dist/usability-capture.js.map +1 -0
- package/dist/usage-config.d.ts +36 -0
- package/dist/usage-config.js +114 -0
- package/dist/usage-config.js.map +1 -0
- package/dist/ux-api.d.ts +3 -75
- package/dist/ux-api.js +3 -220
- package/dist/ux-api.js.map +1 -1
- package/dist/ux-claim-probe.d.ts +45 -0
- package/dist/ux-claim-probe.js +386 -0
- package/dist/ux-claim-probe.js.map +1 -0
- package/dist/ux-cli.d.ts +4 -0
- package/dist/ux-cli.js +109 -0
- package/dist/ux-cli.js.map +1 -0
- package/dist/ux-config.d.ts +29 -0
- package/dist/ux-config.js +103 -0
- package/dist/ux-config.js.map +1 -0
- package/dist/ux-evidence.d.ts +54 -0
- package/dist/ux-evidence.js +197 -0
- package/dist/ux-evidence.js.map +1 -0
- package/dist/ux-product.d.ts +14 -0
- package/dist/ux-product.js +39 -0
- package/dist/ux-product.js.map +1 -0
- package/dist/ux-review.d.ts +116 -0
- package/dist/ux-review.js +171 -0
- package/dist/ux-review.js.map +1 -0
- package/dist/ux-usability.d.ts +263 -0
- package/dist/ux-usability.js +580 -0
- package/dist/ux-usability.js.map +1 -0
- package/dist/verify-fix-api.d.ts +194 -0
- package/dist/verify-fix-api.js +506 -0
- package/dist/verify-fix-api.js.map +1 -0
- package/dist/verify-fix-cli.d.ts +4 -0
- package/dist/verify-fix-cli.js +115 -0
- package/dist/verify-fix-cli.js.map +1 -0
- package/package.json +23 -18
- package/skills/jevitate-ci-check/SKILL.md +77 -0
- package/skills/jevitate-demo/SKILL.md +61 -0
- package/skills/jevitate-explore/SKILL.md +96 -87
- package/skills/jevitate-getting-started/SKILL.md +89 -0
- package/skills/jevitate-load-test/SKILL.md +11 -2
- package/skills/jevitate-mission-scope/SKILL.md +19 -11
- package/skills/jevitate-record/SKILL.md +23 -5
- package/skills/jevitate-run-journey/SKILL.md +61 -17
- package/skills/jevitate-sources/SKILL.md +57 -14
- package/skills/jevitate-test-campaign/SKILL.md +203 -0
- package/skills/jevitate-ux-review/SKILL.md +106 -16
- package/skills/jevitate-verify-fix/SKILL.md +76 -0
|
@@ -0,0 +1,737 @@
|
|
|
1
|
+
import { argErrorBody, McpArgError, optRecordVideo, optScreenshots, optViewport } from "./mcp-args.js";
|
|
2
|
+
import { confineMcpPath } from "./mcp-paths.js";
|
|
3
|
+
// ── Why a flag is not an MCP argument ──────────────────────────────────────────────────────────
|
|
4
|
+
export const OMIT = {
|
|
5
|
+
json: "always set: the tool returns the command's JSON envelope",
|
|
6
|
+
hooks: "operator shell hooks run commands on this machine: never model-chosen (--allow-shell-hooks is never set over MCP; an environment's hooks refuse as on the CLI without it)",
|
|
7
|
+
browserBin: "which browser binary, channel and Chromium switches launch is the operator's setting (the server's own launch), never an MCP argument",
|
|
8
|
+
storeDir: "store and results locations are the server's (the `jevitate mcp` defaults / --dir): an MCP argument never picks which directory is read or written as a store",
|
|
9
|
+
envSecret: "binds an environment variable (or a literal secret) the run types or redacts: a request never chooses which of the operator's variables is read — secret fields come from targets.json (secretFields/personas)",
|
|
10
|
+
logCmd: "server-log sources can run commands and read arbitrary files: operator-declared only (targets.json logSources/allowLogCmd)",
|
|
11
|
+
hangWrites: "re-sending a paid/destructive write is the operator's call (targets.json safety.hangReplayWrites)",
|
|
12
|
+
filingRepo: "where findings are filed (a GitHub repo, under the operator's identity) is the operator's filing config (~/.jevitate/filing.json)",
|
|
13
|
+
watch: "a watch loop never returns: MCP drains once (call again to drain more)",
|
|
14
|
+
branchParams: "#293: a branch-point finding replays through its Journey prefix with the params its result recorded (non-secret ones); a secret param is re-supplied by the operator on the CLI, never sent as an MCP argument",
|
|
15
|
+
tou: "accepting a third-party source's Terms of Use is a person's decision (like approve_action): MCP can add, pull and run a source, never accept for them",
|
|
16
|
+
hostLoad: "#205: starting a browser run on a STARVED host (overriding E_HOST_STARVED) can take the machine other people's work runs on down with it: the operator's call, never a request's",
|
|
17
|
+
};
|
|
18
|
+
const HOOK_FLAGS = { "--before": OMIT.hooks, "--after": OMIT.hooks, "--allow-shell-hooks": OMIT.hooks, "--hook-timeout-ms": OMIT.hooks };
|
|
19
|
+
const BROWSER_FLAGS = { "--browser-executable": OMIT.browserBin, "--browser-channel": OMIT.browserBin, "--browser-arg": OMIT.browserBin, "--ignore-host-load": OMIT.hostLoad };
|
|
20
|
+
const JSON_FLAG = { "--json": OMIT.json };
|
|
21
|
+
// ── Param helpers ─────────────────────────────────────────────────────────────────────────────
|
|
22
|
+
const s = (flag, extra = {}) => ({ kind: "string", flag, ...extra });
|
|
23
|
+
const n = (flag, extra = {}) => ({ kind: "integer", flag, ...extra });
|
|
24
|
+
const num = (flag) => ({ kind: "number", flag });
|
|
25
|
+
const b = (flag) => ({ kind: "boolean", flag });
|
|
26
|
+
const many = (flag) => ({ kind: "string[]", flag });
|
|
27
|
+
const path = (flag, extra = {}) => ({ kind: "path", flag, ...extra });
|
|
28
|
+
const session = (flag) => ({ kind: "session", flag });
|
|
29
|
+
const pos = (kind = "string", extra = {}) => ({ kind, positional: true, required: true, ...extra });
|
|
30
|
+
const EMULATION = { viewport: { kind: "viewport", flag: "--viewport" }, device: s("--device") };
|
|
31
|
+
/** #256: unpacked browser extensions to load — confined like every path argument (a directory with manifest.json). */
|
|
32
|
+
const EXTENSION = {
|
|
33
|
+
extension: { kind: "path[]", flag: "--extension" },
|
|
34
|
+
// #205: every browser-launching command also takes the run's resource limits (machine-wide browser
|
|
35
|
+
// cap, browser memory ceiling in MiB) — spread with EXTENSION, which every such command already has.
|
|
36
|
+
maxBrowsers: n("--max-browsers"),
|
|
37
|
+
maxBrowserMemory: n("--max-browser-memory"),
|
|
38
|
+
};
|
|
39
|
+
const DEMO_SHOW = { headed: b("--headed"), slowMo: n("--slow-mo") };
|
|
40
|
+
const ENVIRONMENT = { env: s("--env"), baseUrl: s("--base-url") };
|
|
41
|
+
const AI = { real: b("--real"), fakeAi: b("--fake-ai") };
|
|
42
|
+
/** #243: `name=<storageState>` identities a fixture step authenticates as — each path confined as a session. */
|
|
43
|
+
const FIXTURE_IDENTITY = { kind: "named-sessions", flag: "--fixture-identity" };
|
|
44
|
+
// ── The tools ─────────────────────────────────────────────────────────────────────────────────
|
|
45
|
+
export const CLI_TOOL_SPECS = [
|
|
46
|
+
{
|
|
47
|
+
name: "list_journeys",
|
|
48
|
+
description: "`jevitate journey list`: every Journey in the store (promoted and not) — id, name, promoted, params. find_capabilities is the promoted-only search.",
|
|
49
|
+
command: { path: "journey list", params: {}, omitted: { "--dir": OMIT.storeDir, ...JSON_FLAG } },
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "promote_journey",
|
|
53
|
+
description: "`jevitate journey promote <id>`: promote a local Journey so it becomes discoverable (find_capabilities) and runnable (run_journey).",
|
|
54
|
+
command: { path: "journey promote", params: { id: pos() }, omitted: { "--dir": OMIT.storeDir, ...JSON_FLAG } },
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "journey_anchors",
|
|
58
|
+
description: "`jevitate journey anchors <id>` (#293): a Journey's named anchors — states worth exploring from, each with the step it follows and its suggested adversarial probes. Branch a mission off one with run_exploration fromJourney + atStep.",
|
|
59
|
+
command: { path: "journey anchors", params: { id: pos() }, omitted: { "--dir": OMIT.storeDir, ...JSON_FLAG } },
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "annotate_journey",
|
|
63
|
+
description: "`jevitate journey annotate <id>` (#246): replay the Journey and DRAFT each step's objective/expected result (and a missing goal/success criteria) into a reviewable draft — the Journey itself is never written. " +
|
|
64
|
+
"With approve: true, applies the reviewed draft (shows the diff; refused with E_JOURNEY_ANNOTATIONS_STALE if the Journey changed since the draft) — the same proposal/approval semantics as the CLI. Drafting needs real or fakeAi.",
|
|
65
|
+
command: {
|
|
66
|
+
path: "journey annotate",
|
|
67
|
+
params: { ...EXTENSION, id: pos(), approve: b("--approve"), params: { kind: "params", flag: "--param" }, storageState: session("--storage-state"), fixtures: path("--fixtures"), fixtureIdentity: FIXTURE_IDENTITY, screenshots: { kind: "screenshots", flag: "--screenshots" }, actionDeltas: b("--action-deltas"), ...ENVIRONMENT, ...EMULATION, ...AI },
|
|
68
|
+
omitted: { "--dir": OMIT.storeDir, ...HOOK_FLAGS, ...BROWSER_FLAGS, ...JSON_FLAG },
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "demo_journey",
|
|
73
|
+
description: "`jevitate journey demo <id>` (#248): replay a Journey as a narrated demo — a WebM video with .vtt subtitles (video: a .webm path) and/or a Markdown step-by-step guide with screenshots (guide: a .md path). A Journey that no longer replays fails (exit 1). Paths inside the project or ~/.jevitate.",
|
|
74
|
+
command: {
|
|
75
|
+
path: "journey demo",
|
|
76
|
+
params: {
|
|
77
|
+
id: pos(),
|
|
78
|
+
...EXTENSION,
|
|
79
|
+
video: path("--video"),
|
|
80
|
+
guide: path("--guide"),
|
|
81
|
+
pace: n("--pace"),
|
|
82
|
+
params: { kind: "params", flag: "--param" },
|
|
83
|
+
storageState: session("--storage-state"),
|
|
84
|
+
fixtures: path("--fixtures"),
|
|
85
|
+
fixtureIdentity: FIXTURE_IDENTITY,
|
|
86
|
+
screenshots: { kind: "screenshots", flag: "--screenshots" },
|
|
87
|
+
actionDeltas: b("--action-deltas"),
|
|
88
|
+
...ENVIRONMENT,
|
|
89
|
+
...EMULATION,
|
|
90
|
+
...DEMO_SHOW,
|
|
91
|
+
},
|
|
92
|
+
omitted: { "--dir": OMIT.storeDir, ...HOOK_FLAGS, ...BROWSER_FLAGS, ...JSON_FLAG },
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "publish_journey",
|
|
97
|
+
description: "`jevitate journey publish <id> --to <source>`: publish a promoted Journey into a registered source on a new publish/<id> branch (a PR when gh is available). Secret references only; declared origins must cover its steps.",
|
|
98
|
+
command: {
|
|
99
|
+
path: "journey publish",
|
|
100
|
+
params: { id: pos(), to: s("--to", { required: true }), declareOrigin: many("--declare-origin"), as: s("--as") },
|
|
101
|
+
omitted: { "--dir": OMIT.storeDir, ...JSON_FLAG },
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: "create_demo",
|
|
106
|
+
description: "`jevitate demo \"<aspect>\"` / `demo create` (#249): explore a NAMED, non-production environment (env, required) toward the aspect, checked by success (required), minimize the path (verified by replay), annotate it and render a DRAFT demo (video, .vtt, guide). Nothing is promoted until approve_demo. Needs real or fakeAi.",
|
|
107
|
+
command: {
|
|
108
|
+
path: "demo create",
|
|
109
|
+
params: { ...EXTENSION,
|
|
110
|
+
aspect: pos(),
|
|
111
|
+
env: s("--env"),
|
|
112
|
+
success: s("--success"),
|
|
113
|
+
persona: s("--persona"),
|
|
114
|
+
id: s("--id"),
|
|
115
|
+
start: s("--start"),
|
|
116
|
+
maxActions: n("--max-actions"),
|
|
117
|
+
maxDecisions: n("--max-decisions"),
|
|
118
|
+
out: path("--out"),
|
|
119
|
+
pace: n("--pace"),
|
|
120
|
+
storageState: session("--storage-state"),
|
|
121
|
+
fixtures: path("--fixtures"),
|
|
122
|
+
fixtureIdentity: FIXTURE_IDENTITY,
|
|
123
|
+
...EMULATION,
|
|
124
|
+
...DEMO_SHOW,
|
|
125
|
+
...AI,
|
|
126
|
+
},
|
|
127
|
+
omitted: { "--dir": OMIT.storeDir, ...HOOK_FLAGS, ...BROWSER_FLAGS, ...JSON_FLAG },
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: "approve_demo",
|
|
132
|
+
description: "`jevitate demo approve <id>` (#249): approve a DRAFT demo — renders the final demo (no DRAFT marks) on the environment it was made on, then applies its annotations and promotes the Journey. A replay that no longer works promotes nothing (exit 1).",
|
|
133
|
+
command: {
|
|
134
|
+
path: "demo approve",
|
|
135
|
+
params: { ...EXTENSION, id: pos(), out: path("--out"), pace: n("--pace"), storageState: session("--storage-state"), fixtures: path("--fixtures"), fixtureIdentity: FIXTURE_IDENTITY, ...EMULATION, ...DEMO_SHOW },
|
|
136
|
+
omitted: { "--dir": OMIT.storeDir, ...HOOK_FLAGS, ...BROWSER_FLAGS, ...JSON_FLAG },
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: "run_exploration",
|
|
141
|
+
description: "`jevitate explore` run DIRECTLY (every strategy: goal (default) | coverage | exploratory | adversarial | usability, or feature): drives a real browser on url (which must be on an allow origin) within its budget, and returns the typed result (read later with get_mission_result by its result id). " +
|
|
142
|
+
"For a PROMOTED target prefer queue_exploration (queue + poll). Model-driven strategies need real or fakeAi. Media: recordVideo, screenshots, evidenceVideo. Sessions: storageState, persona/actor entries 'name=<storageState path>'.",
|
|
143
|
+
command: {
|
|
144
|
+
path: "explore",
|
|
145
|
+
params: { ...EXTENSION,
|
|
146
|
+
url: s("--url"),
|
|
147
|
+
// #293 journey-anchored exploration: replay a promoted Journey to a step/anchor, then the mission.
|
|
148
|
+
fromJourney: s("--from-journey"),
|
|
149
|
+
atStep: s("--at-step"),
|
|
150
|
+
params: { kind: "params", flag: "--param" },
|
|
151
|
+
...ENVIRONMENT,
|
|
152
|
+
allow: many("--allow"),
|
|
153
|
+
strategy: s("--strategy", { enum: ["goal", "coverage", "exploratory", "adversarial", "usability"] }),
|
|
154
|
+
goal: s("--goal"),
|
|
155
|
+
success: many("--success"),
|
|
156
|
+
successWhen: s("--success-when", { enum: ["final", "held"] }),
|
|
157
|
+
allowVacuousChecks: b("--allow-vacuous-checks"),
|
|
158
|
+
actionDeltas: b("--action-deltas"),
|
|
159
|
+
feature: s("--feature"),
|
|
160
|
+
route: many("--route"),
|
|
161
|
+
scope: s("--scope", { enum: ["app"] }),
|
|
162
|
+
maxActions: n("--max-actions"),
|
|
163
|
+
maxDecisions: n("--max-decisions"),
|
|
164
|
+
stallTimeout: n("--stall-timeout"),
|
|
165
|
+
invariants: { kind: "path[]", flag: "--invariants" },
|
|
166
|
+
storageState: session("--storage-state"),
|
|
167
|
+
saveStorageState: session("--save-storage-state"),
|
|
168
|
+
persona: { kind: "named-sessions", flag: "--persona" },
|
|
169
|
+
personas: path("--personas"),
|
|
170
|
+
actor: { kind: "named-sessions", flag: "--actor" },
|
|
171
|
+
fixtures: path("--fixtures"),
|
|
172
|
+
fixtureIdentity: FIXTURE_IDENTITY,
|
|
173
|
+
fixture: path("--fixture"),
|
|
174
|
+
typeFixture: { kind: "bound-paths", flag: "--type-fixture" },
|
|
175
|
+
appClass: s("--app-class"),
|
|
176
|
+
show: s("--show"),
|
|
177
|
+
minConfidence: num("--min-confidence"),
|
|
178
|
+
maxFindingsPerPage: n("--max-findings-per-page"),
|
|
179
|
+
product: path("--product"),
|
|
180
|
+
polish: b("--polish"),
|
|
181
|
+
probeGuards: b("--probe-guards"),
|
|
182
|
+
repeat: n("--repeat"),
|
|
183
|
+
minAgreement: n("--min-agreement"),
|
|
184
|
+
allowDestructive: b("--allow-destructive"),
|
|
185
|
+
allowWrites: b("--allow-writes"),
|
|
186
|
+
allowWrite: many("--allow-write"),
|
|
187
|
+
deny: many("--deny"),
|
|
188
|
+
paid: many("--paid"),
|
|
189
|
+
readRpc: many("--read-rpc"),
|
|
190
|
+
settleIgnore: many("--settle-ignore"),
|
|
191
|
+
ignoreNoProgress: many("--ignore-no-progress"),
|
|
192
|
+
ignoreOverflow: many("--ignore-overflow"),
|
|
193
|
+
checkOverflow: b("--check-overflow"),
|
|
194
|
+
apiPrefix: many("--api-prefix"),
|
|
195
|
+
longPollMs: n("--long-poll-ms"),
|
|
196
|
+
jobWaitMs: n("--job-wait-ms"),
|
|
197
|
+
replyWaitMs: n("--reply-wait-ms"),
|
|
198
|
+
replyCeilingMs: n("--reply-ceiling-ms"),
|
|
199
|
+
replyMaxChars: n("--reply-max-chars"),
|
|
200
|
+
hangReplays: n("--hang-replays"),
|
|
201
|
+
minControlCoverage: num("--min-control-coverage"),
|
|
202
|
+
requireFormSubmit: b("--no-require-form-submit"),
|
|
203
|
+
fileIssues: b("--file-issues"),
|
|
204
|
+
out: path("--out"),
|
|
205
|
+
recordVideo: { kind: "optional-path", flag: "--record-video" },
|
|
206
|
+
screenshots: { kind: "screenshots", flag: "--screenshots" },
|
|
207
|
+
evidenceVideo: b("--evidence-video"),
|
|
208
|
+
overlay: b("--no-overlay"),
|
|
209
|
+
...EMULATION,
|
|
210
|
+
...DEMO_SHOW,
|
|
211
|
+
...AI,
|
|
212
|
+
},
|
|
213
|
+
omitted: {
|
|
214
|
+
...HOOK_FLAGS,
|
|
215
|
+
...BROWSER_FLAGS,
|
|
216
|
+
...JSON_FLAG,
|
|
217
|
+
"--secret": OMIT.envSecret,
|
|
218
|
+
"--secret-field": OMIT.envSecret,
|
|
219
|
+
"--totp": OMIT.envSecret,
|
|
220
|
+
"--allow-log-cmd": OMIT.logCmd,
|
|
221
|
+
"--log-source": OMIT.logCmd,
|
|
222
|
+
"--log-defect": OMIT.logCmd,
|
|
223
|
+
"--log-ignore": OMIT.logCmd,
|
|
224
|
+
"--log-scope": OMIT.logCmd,
|
|
225
|
+
"--log-correlation-header": OMIT.logCmd,
|
|
226
|
+
"--log-id-pattern": OMIT.logCmd,
|
|
227
|
+
"--log-quiet-ok": OMIT.logCmd,
|
|
228
|
+
"--server-log-drain-ms": OMIT.logCmd,
|
|
229
|
+
"--hang-replay-writes": OMIT.hangWrites,
|
|
230
|
+
"--issue-repo": OMIT.filingRepo,
|
|
231
|
+
"--jevitate-repo": OMIT.filingRepo,
|
|
232
|
+
"--journeys-dir": OMIT.storeDir,
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
name: "run_campaign",
|
|
238
|
+
description: "`jevitate campaign run <spec>` (#293): a bounded campaign of journey-anchored missions — replay each job's promoted Journey (discovery), run its anchored missions in order with the spec's fixtures restore between runs, and return ONE deduped report (each defect with the Journey steps it branched from). An invalid spec is refused listing every problem. Needs real or fakeAi.",
|
|
239
|
+
command: {
|
|
240
|
+
path: "campaign run",
|
|
241
|
+
params: { spec: pos("path"), out: path("--out"), ...AI },
|
|
242
|
+
omitted: { "--journeys-dir": OMIT.storeDir, "--allow-shell-hooks": OMIT.hooks, ...JSON_FLAG },
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
name: "author_journey",
|
|
247
|
+
description: "`jevitate explore-author-journey`: explore url toward goal (checked by success) several takes, and author an UNPROMOTED Journey from the verified path (promote_journey makes it runnable). Needs real or fakeAi.",
|
|
248
|
+
command: {
|
|
249
|
+
path: "explore-author-journey",
|
|
250
|
+
params: { ...EXTENSION,
|
|
251
|
+
url: s("--url"),
|
|
252
|
+
goal: s("--goal"),
|
|
253
|
+
success: s("--success"),
|
|
254
|
+
allow: many("--allow"),
|
|
255
|
+
id: s("--id"),
|
|
256
|
+
name: s("--name"),
|
|
257
|
+
takes: n("--takes"),
|
|
258
|
+
maxActions: n("--max-actions"),
|
|
259
|
+
maxDecisions: n("--max-decisions"),
|
|
260
|
+
storageState: session("--storage-state"),
|
|
261
|
+
...AI,
|
|
262
|
+
},
|
|
263
|
+
omitted: { "--journeys-dir": OMIT.storeDir, ...BROWSER_FLAGS, ...JSON_FLAG },
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
name: "run_check",
|
|
268
|
+
description: "`jevitate check --suite <file>`: the CI regression gate — a suite of Journeys, invariants, goals and missions within a budget; writes JUnit + SARIF + JSON under out. Exit 1 = a gating finding.",
|
|
269
|
+
command: {
|
|
270
|
+
path: "check",
|
|
271
|
+
params: { ...EXTENSION,
|
|
272
|
+
suite: path("--suite", { required: true }),
|
|
273
|
+
out: path("--out"),
|
|
274
|
+
jsonOut: path("--json-out"),
|
|
275
|
+
junit: path("--junit"),
|
|
276
|
+
sarif: path("--sarif"),
|
|
277
|
+
baseline: s("--baseline"),
|
|
278
|
+
changedRoutes: many("--changed-routes"),
|
|
279
|
+
targetBuild: s("--target-build"),
|
|
280
|
+
...AI,
|
|
281
|
+
},
|
|
282
|
+
omitted: { "--baseline-dir": OMIT.storeDir, ...BROWSER_FLAGS, ...JSON_FLAG },
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
name: "get_report",
|
|
287
|
+
description: "`jevitate report`: one deduped defect list for a target across every mode and run (+ an optional diff section against a baseline run, tag or `last`).",
|
|
288
|
+
command: {
|
|
289
|
+
path: "report",
|
|
290
|
+
params: { target: s("--target"), since: s("--since"), baseline: s("--baseline"), out: path("--out") },
|
|
291
|
+
omitted: { "--dir": OMIT.storeDir, ...JSON_FLAG },
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
name: "diff_runs",
|
|
296
|
+
description: "`jevitate diff <runA> <runB>`: classify findings new / resolved / still-present / flaky / not-rerun between two runs (runA = baseline).",
|
|
297
|
+
command: { path: "diff", params: { runA: pos(), runB: pos() }, omitted: { "--dir": OMIT.storeDir, ...JSON_FLAG } },
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
name: "baselines",
|
|
301
|
+
description: "`jevitate baseline list | show <name> | tag <name> <runs…>`: named baselines for report/check/diff.",
|
|
302
|
+
actions: {
|
|
303
|
+
list: { path: "baseline list", params: {}, omitted: JSON_FLAG },
|
|
304
|
+
show: { path: "baseline show", params: { name: pos() }, omitted: JSON_FLAG },
|
|
305
|
+
tag: { path: "baseline tag", params: { name: pos(), runs: pos("string[]") }, omitted: { "--dir": OMIT.storeDir, ...JSON_FLAG } },
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
name: "ledger",
|
|
310
|
+
description: "`jevitate ledger add <result> <fingerprint> | list | verify [fingerprints…]`: the repro ledger verify_fix falls back to, kept by fingerprint. verify replays entries (replays, storageState).",
|
|
311
|
+
actions: {
|
|
312
|
+
add: { path: "ledger add", params: { result: pos("path"), fingerprint: pos(), ticket: s("--ticket") }, omitted: { "--dir": OMIT.storeDir, "--secret": OMIT.envSecret, ...JSON_FLAG } },
|
|
313
|
+
list: { path: "ledger list", params: {}, omitted: { "--dir": OMIT.storeDir, ...JSON_FLAG } },
|
|
314
|
+
verify: {
|
|
315
|
+
path: "ledger verify",
|
|
316
|
+
params: { ...EXTENSION, fingerprints: { kind: "string[]", positional: true }, ticket: s("--ticket"), replays: n("--replays"), storageState: session("--storage-state") },
|
|
317
|
+
omitted: { "--dir": OMIT.storeDir, "--allow-log-cmd": OMIT.logCmd, ...BROWSER_FLAGS, ...JSON_FLAG },
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
name: "run_load_test",
|
|
323
|
+
description: "`jevitate load run <journeyId>`: replay a Journey concurrently (concurrency × iterations) against an authorized origin and report latency/errors.",
|
|
324
|
+
command: {
|
|
325
|
+
path: "load run",
|
|
326
|
+
params: {
|
|
327
|
+
journeyId: pos(),
|
|
328
|
+
...EXTENSION,
|
|
329
|
+
authorizedOrigin: many("--authorized-origin"),
|
|
330
|
+
concurrency: n("--concurrency"),
|
|
331
|
+
iterations: n("--iterations"),
|
|
332
|
+
seed: n("--seed"),
|
|
333
|
+
params: { kind: "params", flag: "--param" },
|
|
334
|
+
storageState: session("--storage-state"),
|
|
335
|
+
...ENVIRONMENT,
|
|
336
|
+
...EMULATION,
|
|
337
|
+
},
|
|
338
|
+
omitted: { "--dir": OMIT.storeDir, ...BROWSER_FLAGS, ...JSON_FLAG },
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: "prune_logs",
|
|
343
|
+
description: "`jevitate logs prune`: prune run output under .jevitate/logs by the retention policy (dryRun: report only).",
|
|
344
|
+
command: { path: "logs prune", params: { dryRun: b("--dry-run") }, omitted: { "--dir": OMIT.storeDir, ...JSON_FLAG } },
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
name: "run_queued_missions",
|
|
348
|
+
description: "`jevitate mission run --once`: drain the missions queue_exploration queued (each through its strategy's runner; results where get_mission_result reads them), then return the drain report. Model-driven missions need real or fakeAi (others stay queued, reported as skipped).",
|
|
349
|
+
command: {
|
|
350
|
+
path: "mission run",
|
|
351
|
+
params: { ...EXTENSION, ...AI },
|
|
352
|
+
omitted: {
|
|
353
|
+
"--once": "the default: MCP drains what is queued once and returns",
|
|
354
|
+
"--watch": OMIT.watch,
|
|
355
|
+
"--interval": OMIT.watch,
|
|
356
|
+
"--dir": OMIT.storeDir,
|
|
357
|
+
"--targets-dir": OMIT.storeDir,
|
|
358
|
+
"--out": OMIT.storeDir,
|
|
359
|
+
...BROWSER_FLAGS,
|
|
360
|
+
...JSON_FLAG,
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
name: "mission_targets",
|
|
366
|
+
description: "`jevitate mission target add | list | update | promote`: the targets queue_exploration may enqueue against (only PROMOTED ones). add/update may set the target's session (storageState / saveStorageState paths); which environment variables a target's secret fields read is the operator's (`--secret-field` on the CLI, or targets.json), never an MCP argument.",
|
|
367
|
+
actions: {
|
|
368
|
+
add: {
|
|
369
|
+
path: "mission target add",
|
|
370
|
+
params: {
|
|
371
|
+
id: pos(),
|
|
372
|
+
name: s("--name"),
|
|
373
|
+
description: s("--description"),
|
|
374
|
+
authorizedOrigin: s("--authorized-origin"),
|
|
375
|
+
apiOrigin: many("--api-origin"),
|
|
376
|
+
baseUrl: s("--base-url"),
|
|
377
|
+
storageState: session("--storage-state"),
|
|
378
|
+
saveStorageState: { kind: "optional-session", flag: "--save-storage-state" },
|
|
379
|
+
},
|
|
380
|
+
omitted: { "--dir": OMIT.storeDir, "--secret-field": OMIT.envSecret, ...JSON_FLAG },
|
|
381
|
+
},
|
|
382
|
+
list: { path: "mission target list", params: {}, omitted: { "--dir": OMIT.storeDir, ...JSON_FLAG } },
|
|
383
|
+
update: {
|
|
384
|
+
path: "mission target update",
|
|
385
|
+
params: { id: pos(), storageState: session("--storage-state"), saveStorageState: { kind: "optional-session", flag: "--save-storage-state" }, clearAuth: b("--clear-auth") },
|
|
386
|
+
omitted: { "--dir": OMIT.storeDir, "--secret-field": OMIT.envSecret, ...JSON_FLAG },
|
|
387
|
+
},
|
|
388
|
+
promote: { path: "mission target promote", params: { id: pos() }, omitted: { "--dir": OMIT.storeDir, ...JSON_FLAG } },
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
name: "profiles",
|
|
393
|
+
description: "`jevitate profile create <name> | status <name>`: isolated credential/data profiles.",
|
|
394
|
+
actions: {
|
|
395
|
+
create: { path: "profile create", params: { name: pos() }, omitted: JSON_FLAG },
|
|
396
|
+
status: { path: "profile status", params: { name: pos() }, omitted: JSON_FLAG },
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
name: "recordings",
|
|
401
|
+
description: "`jevitate recording diff | fit | postdoc | promote`: compare takes, fit a Recording, post-document takes, promote a literal to a variable.",
|
|
402
|
+
actions: {
|
|
403
|
+
diff: { path: "recording diff", params: { takeA: pos("path"), takeB: pos("path"), more: { kind: "path[]", positional: true } }, omitted: JSON_FLAG },
|
|
404
|
+
fit: { path: "recording fit", params: { file: pos("path") }, omitted: JSON_FLAG },
|
|
405
|
+
postdoc: { path: "recording postdoc", params: { take: pos("path"), more: { kind: "path[]", positional: true }, decisions: path("--decisions"), out: path("--out") }, omitted: JSON_FLAG },
|
|
406
|
+
// No --json flag: it prints the promoted Recording as JSON (refusals are envelopes).
|
|
407
|
+
promote: {
|
|
408
|
+
path: "recording promote",
|
|
409
|
+
params: { file: pos("path"), page: n("--page", { required: true }), step: n("--step", { required: true }), var: s("--var", { required: true }) },
|
|
410
|
+
omitted: {},
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
name: "regressions",
|
|
416
|
+
description: "`jevitate regression capture | run`: capture a finding as a committed regression (from a Recording/result, verified by attempts) and replay one by id (exit 1 = it regressed).",
|
|
417
|
+
actions: {
|
|
418
|
+
capture: {
|
|
419
|
+
path: "regression capture",
|
|
420
|
+
params: { ...EXTENSION,
|
|
421
|
+
from: path("--from", { required: true }),
|
|
422
|
+
id: s("--id", { required: true }),
|
|
423
|
+
result: path("--result"),
|
|
424
|
+
fingerprint: s("--fingerprint"),
|
|
425
|
+
summary: s("--summary"),
|
|
426
|
+
attempts: n("--attempts"),
|
|
427
|
+
force: b("--force"),
|
|
428
|
+
storageState: session("--storage-state"),
|
|
429
|
+
fixtures: path("--fixtures"),
|
|
430
|
+
fixtureIdentity: FIXTURE_IDENTITY,
|
|
431
|
+
...EMULATION,
|
|
432
|
+
...DEMO_SHOW,
|
|
433
|
+
},
|
|
434
|
+
omitted: { "--dir": OMIT.storeDir, "--param": OMIT.branchParams, ...HOOK_FLAGS, ...BROWSER_FLAGS, ...JSON_FLAG },
|
|
435
|
+
},
|
|
436
|
+
run: {
|
|
437
|
+
path: "regression run",
|
|
438
|
+
params: { ...EXTENSION, id: pos(), attempts: n("--attempts"), storageState: session("--storage-state"), ...ENVIRONMENT, ...EMULATION, ...DEMO_SHOW },
|
|
439
|
+
omitted: { "--dir": OMIT.storeDir, "--param": OMIT.branchParams, ...BROWSER_FLAGS, ...JSON_FLAG },
|
|
440
|
+
},
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
name: "site_policy",
|
|
445
|
+
description: "`jevitate site policy get | set` and `site simulate`: per-origin pacing, throttles, budgets and quiet hours (run_journey honours them).",
|
|
446
|
+
actions: {
|
|
447
|
+
get: { path: "site policy get", params: { site: pos(), account: s("--account") }, omitted: { "--db": OMIT.storeDir, ...JSON_FLAG } },
|
|
448
|
+
set: { path: "site policy set", params: { site: pos(), file: path("--file", { required: true }), account: s("--account") }, omitted: { "--db": OMIT.storeDir, ...JSON_FLAG } },
|
|
449
|
+
simulate: { path: "site simulate", params: { site: pos(), script: path("--script", { required: true }), seed: n("--seed"), account: s("--account") }, omitted: { "--db": OMIT.storeDir, ...JSON_FLAG } },
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
name: "sources",
|
|
454
|
+
description: "`jevitate source add | list | pull | update | remove | run`: distributed Journey sources (git). A source's Terms of Use and per-Journey trust are a person's decisions (`source add --accept-tou`, `source trust` on the CLI); run refuses an untrusted Journey.",
|
|
455
|
+
actions: {
|
|
456
|
+
add: { path: "source add", params: { name: pos(), gitUrl: pos() }, omitted: { "--accept-tou": OMIT.tou, ...JSON_FLAG } },
|
|
457
|
+
list: { path: "source list", params: {}, omitted: JSON_FLAG },
|
|
458
|
+
pull: { path: "source pull", params: { name: pos() }, omitted: JSON_FLAG },
|
|
459
|
+
update: { path: "source update", params: { name: pos() }, omitted: JSON_FLAG },
|
|
460
|
+
remove: { path: "source remove", params: { name: pos() }, omitted: JSON_FLAG },
|
|
461
|
+
run: {
|
|
462
|
+
path: "source run",
|
|
463
|
+
params: { ...EXTENSION, name: pos(), journeyId: pos(), params: { kind: "params", flag: "--param" }, storageState: session("--storage-state"), ...EMULATION },
|
|
464
|
+
omitted: { ...BROWSER_FLAGS, ...JSON_FLAG },
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
name: "ux_review",
|
|
470
|
+
description: "`jevitate ux <recording>`: offline UX review of a saved Recording — ranked, cited usability findings (appClass required). Needs real or fakeAi.",
|
|
471
|
+
command: {
|
|
472
|
+
path: "ux",
|
|
473
|
+
params: {
|
|
474
|
+
recording: pos("path"),
|
|
475
|
+
appClass: s("--app-class"),
|
|
476
|
+
job: s("--job"),
|
|
477
|
+
persona: s("--persona"),
|
|
478
|
+
evidence: path("--evidence"),
|
|
479
|
+
result: path("--result"),
|
|
480
|
+
out: path("--out"),
|
|
481
|
+
show: s("--show"),
|
|
482
|
+
minConfidence: num("--min-confidence"),
|
|
483
|
+
maxFindingsPerPage: n("--max-findings-per-page"),
|
|
484
|
+
product: path("--product"),
|
|
485
|
+
polish: b("--polish"),
|
|
486
|
+
...AI,
|
|
487
|
+
},
|
|
488
|
+
omitted: JSON_FLAG,
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
name: "validate_invariants",
|
|
493
|
+
description: "`jevitate invariants validate <files…>`: validate app-declared invariant files (optionally against a url / allow origins / observer actors) without running anything.",
|
|
494
|
+
command: {
|
|
495
|
+
path: "invariants validate",
|
|
496
|
+
params: { files: pos("path[]"), url: s("--url"), allow: many("--allow"), observer: many("--observer") },
|
|
497
|
+
omitted: JSON_FLAG,
|
|
498
|
+
},
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
name: "get_ai_status",
|
|
502
|
+
description: "`jevitate ai status`: which model-gateway credentials each AI feature uses, where each comes from (env or the stored file) and whether its provider accepts it (a live auth check; `verify: false` skips it) — names, sources and verdicts only, never a key value.",
|
|
503
|
+
command: { path: "ai status", params: { verify: b("--no-verify") }, omitted: JSON_FLAG },
|
|
504
|
+
},
|
|
505
|
+
];
|
|
506
|
+
// ── Schema + argv ─────────────────────────────────────────────────────────────────────────────
|
|
507
|
+
function paramSchema(p) {
|
|
508
|
+
switch (p.kind) {
|
|
509
|
+
case "string":
|
|
510
|
+
return p.enum === undefined ? { type: "string" } : { type: "string", enum: [...p.enum] };
|
|
511
|
+
case "integer":
|
|
512
|
+
return { type: "integer", minimum: 0 };
|
|
513
|
+
case "number":
|
|
514
|
+
return { type: "number" };
|
|
515
|
+
case "boolean":
|
|
516
|
+
return { type: "boolean" };
|
|
517
|
+
case "string[]":
|
|
518
|
+
case "path[]":
|
|
519
|
+
case "named-sessions":
|
|
520
|
+
case "bound-paths":
|
|
521
|
+
return { type: "array", items: { type: "string" } };
|
|
522
|
+
case "params":
|
|
523
|
+
return { type: "object", additionalProperties: { type: "string" } };
|
|
524
|
+
case "path":
|
|
525
|
+
case "session":
|
|
526
|
+
return { type: "string" };
|
|
527
|
+
case "optional-path":
|
|
528
|
+
case "optional-session":
|
|
529
|
+
case "screenshots":
|
|
530
|
+
return { type: ["boolean", "string"] };
|
|
531
|
+
case "viewport":
|
|
532
|
+
return { type: "object", properties: { width: { type: "integer" }, height: { type: "integer" } }, required: ["width", "height"] };
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
/** The MCP inputSchema for a CLI-backed tool (a family adds the `action` discriminator). */
|
|
536
|
+
export function cliToolInputSchema(spec) {
|
|
537
|
+
const commands = spec.command !== undefined ? [spec.command] : Object.values(spec.actions ?? {});
|
|
538
|
+
const properties = {};
|
|
539
|
+
for (const c of commands)
|
|
540
|
+
for (const [name, p] of Object.entries(c.params))
|
|
541
|
+
properties[name] = paramSchema(p);
|
|
542
|
+
if (spec.actions !== undefined)
|
|
543
|
+
properties.action = { type: "string", enum: Object.keys(spec.actions) };
|
|
544
|
+
const required = spec.actions !== undefined
|
|
545
|
+
? ["action"]
|
|
546
|
+
: Object.entries(spec.command.params)
|
|
547
|
+
.filter(([, p]) => p.required === true)
|
|
548
|
+
.map(([k]) => k);
|
|
549
|
+
return { type: "object", properties, ...(required.length === 0 ? {} : { required }), additionalProperties: false };
|
|
550
|
+
}
|
|
551
|
+
/** The command an invocation selects (validating `action` for a family). */
|
|
552
|
+
export function commandFor(spec, args) {
|
|
553
|
+
if (spec.command !== undefined)
|
|
554
|
+
return spec.command;
|
|
555
|
+
const actions = spec.actions ?? {};
|
|
556
|
+
const action = args.action;
|
|
557
|
+
if (typeof action !== "string" || actions[action] === undefined)
|
|
558
|
+
throw new McpArgError(`'action' must be one of ${Object.keys(actions).join(" | ")}`);
|
|
559
|
+
return actions[action];
|
|
560
|
+
}
|
|
561
|
+
const asText = (v, key) => {
|
|
562
|
+
if (typeof v !== "string" || v.length === 0)
|
|
563
|
+
throw new McpArgError(`'${key}' must be a non-empty string`);
|
|
564
|
+
if (v.includes("\0"))
|
|
565
|
+
throw new McpArgError(`'${key}' must not contain a NUL byte`);
|
|
566
|
+
return v;
|
|
567
|
+
};
|
|
568
|
+
const asStrings = (v, key) => {
|
|
569
|
+
if (!Array.isArray(v))
|
|
570
|
+
throw new McpArgError(`'${key}' must be an array of strings`);
|
|
571
|
+
return v.map((x, i) => asText(x, `${key}[${i}]`));
|
|
572
|
+
};
|
|
573
|
+
/** The values one argument contributes (before flag formatting). */
|
|
574
|
+
function values(name, p, v, roots) {
|
|
575
|
+
switch (p.kind) {
|
|
576
|
+
case "string": {
|
|
577
|
+
const t = asText(v, name);
|
|
578
|
+
if (p.enum !== undefined && !p.enum.includes(t))
|
|
579
|
+
throw new McpArgError(`'${name}' must be one of ${p.enum.join(" | ")}`);
|
|
580
|
+
return [t];
|
|
581
|
+
}
|
|
582
|
+
case "integer":
|
|
583
|
+
if (typeof v !== "number" || !Number.isInteger(v) || v < 0)
|
|
584
|
+
throw new McpArgError(`'${name}' must be a non-negative integer`);
|
|
585
|
+
return [String(v)];
|
|
586
|
+
case "number":
|
|
587
|
+
if (typeof v !== "number" || !Number.isFinite(v))
|
|
588
|
+
throw new McpArgError(`'${name}' must be a number`);
|
|
589
|
+
return [String(v)];
|
|
590
|
+
case "boolean":
|
|
591
|
+
if (typeof v !== "boolean")
|
|
592
|
+
throw new McpArgError(`'${name}' must be a boolean`);
|
|
593
|
+
return v;
|
|
594
|
+
case "string[]":
|
|
595
|
+
return asStrings(v, name);
|
|
596
|
+
case "path":
|
|
597
|
+
return [confineMcpPath(v, name, roots)];
|
|
598
|
+
case "session":
|
|
599
|
+
return [confineMcpPath(v, name, roots, { session: true })];
|
|
600
|
+
case "path[]":
|
|
601
|
+
return asStrings(v, name).map((x, i) => confineMcpPath(x, `${name}[${i}]`, roots));
|
|
602
|
+
case "named-sessions":
|
|
603
|
+
return asStrings(v, name).map((x, i) => {
|
|
604
|
+
const eq = x.indexOf("=");
|
|
605
|
+
if (eq <= 0)
|
|
606
|
+
throw new McpArgError(`'${name}[${i}]' must be 'name=<storageState path>'`);
|
|
607
|
+
return `${x.slice(0, eq)}=${confineMcpPath(x.slice(eq + 1), `${name}[${i}]`, roots, { session: true })}`;
|
|
608
|
+
});
|
|
609
|
+
case "bound-paths":
|
|
610
|
+
return asStrings(v, name).map((x, i) => {
|
|
611
|
+
const eq = x.lastIndexOf("=");
|
|
612
|
+
if (eq <= 0)
|
|
613
|
+
throw new McpArgError(`'${name}[${i}]' must be '<descriptor>=<file path>'`);
|
|
614
|
+
return `${x.slice(0, eq)}=${confineMcpPath(x.slice(eq + 1), `${name}[${i}]`, roots)}`;
|
|
615
|
+
});
|
|
616
|
+
case "params": {
|
|
617
|
+
if (v === null || typeof v !== "object" || Array.isArray(v))
|
|
618
|
+
throw new McpArgError(`'${name}' must be an object of string values`);
|
|
619
|
+
return Object.entries(v).map(([k, x]) => {
|
|
620
|
+
if (k.length === 0 || k.includes("="))
|
|
621
|
+
throw new McpArgError(`'${name}' keys must be non-empty and contain no '='`);
|
|
622
|
+
return `${k}=${asText(x, `${name}.${k}`)}`;
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
case "optional-path": {
|
|
626
|
+
const r = optRecordVideo({ [name]: v }, roots, name);
|
|
627
|
+
return typeof r === "string" ? [r] : r === true;
|
|
628
|
+
}
|
|
629
|
+
case "optional-session":
|
|
630
|
+
if (v === false)
|
|
631
|
+
return false;
|
|
632
|
+
if (v === true)
|
|
633
|
+
return true;
|
|
634
|
+
return [confineMcpPath(v, name, roots, { session: true })];
|
|
635
|
+
case "screenshots": {
|
|
636
|
+
const r = optScreenshots({ [name]: v }, roots, name);
|
|
637
|
+
return typeof r === "string" ? [r] : r === true;
|
|
638
|
+
}
|
|
639
|
+
case "viewport":
|
|
640
|
+
return [optViewport({ [name]: v }, name)];
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* The argv for one invocation: `<path…> --flag=value… --json -- <positionals…>`. Options use the
|
|
645
|
+
* `=` form and positionals follow `--`, so no value can ever be read as a flag.
|
|
646
|
+
*/
|
|
647
|
+
export function buildCliArgv(spec, args, roots) {
|
|
648
|
+
const command = commandFor(spec, args);
|
|
649
|
+
const known = new Set([...Object.keys(command.params), ...(spec.actions === undefined ? [] : ["action"])]);
|
|
650
|
+
const unknown = Object.keys(args).filter((k) => !known.has(k));
|
|
651
|
+
if (unknown.length > 0) {
|
|
652
|
+
throw new McpArgError(`unknown argument(s) for ${spec.name}${spec.actions === undefined ? "" : ` ${String(args.action)}`}: ${unknown.join(", ")} (allowed: ${[...known].join(", ") || "none"})`);
|
|
653
|
+
}
|
|
654
|
+
const flags = [];
|
|
655
|
+
const positionals = [];
|
|
656
|
+
for (const [name, p] of Object.entries(command.params)) {
|
|
657
|
+
const v = args[name];
|
|
658
|
+
if (v === undefined) {
|
|
659
|
+
if (p.required === true)
|
|
660
|
+
throw new McpArgError(`'${name}' is required`);
|
|
661
|
+
continue;
|
|
662
|
+
}
|
|
663
|
+
const out = values(name, p, v, roots);
|
|
664
|
+
if (p.positional === true) {
|
|
665
|
+
if (typeof out === "boolean")
|
|
666
|
+
throw new McpArgError(`'${name}' must be a value`);
|
|
667
|
+
positionals.push(...out);
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
670
|
+
const flag = p.flag;
|
|
671
|
+
if (typeof out === "boolean") {
|
|
672
|
+
// `--no-x` flags are exposed as `x: false`; everything else as `x: true`.
|
|
673
|
+
const negated = flag.startsWith("--no-");
|
|
674
|
+
if (out === !negated)
|
|
675
|
+
flags.push(flag);
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
for (const value of out)
|
|
679
|
+
flags.push(`${flag}=${value}`);
|
|
680
|
+
}
|
|
681
|
+
// `--json` whenever the command has it (every one but `recording promote`, which prints JSON anyway).
|
|
682
|
+
return [...command.path.split(" "), ...flags, ...(command.omitted["--json"] === undefined ? [] : ["--json"]), "--", ...positionals];
|
|
683
|
+
}
|
|
684
|
+
/** The last `{v, ok}` envelope line the command printed. */
|
|
685
|
+
function lastEnvelope(stdout) {
|
|
686
|
+
const lines = stdout.split("\n").map((l) => l.trim()).filter((l) => l.startsWith("{"));
|
|
687
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
688
|
+
try {
|
|
689
|
+
const o = JSON.parse(lines[i]);
|
|
690
|
+
if (typeof o.ok === "boolean" && "v" in o)
|
|
691
|
+
return o;
|
|
692
|
+
}
|
|
693
|
+
catch {
|
|
694
|
+
// not an envelope line
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
return undefined;
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Runs one CLI-backed tool call: argv from the typed arguments, the CLI in process, its envelope back.
|
|
701
|
+
* `redact` strips credential values from the output text (belt-and-braces over the CLI's own redaction).
|
|
702
|
+
*/
|
|
703
|
+
export async function runCliTool(spec, args, deps) {
|
|
704
|
+
let argv;
|
|
705
|
+
try {
|
|
706
|
+
argv = buildCliArgv(spec, args, deps.roots);
|
|
707
|
+
}
|
|
708
|
+
catch (err) {
|
|
709
|
+
const body = argErrorBody(err);
|
|
710
|
+
if (body === undefined)
|
|
711
|
+
throw err;
|
|
712
|
+
return { isError: true, body };
|
|
713
|
+
}
|
|
714
|
+
if (deps.runCli === undefined) {
|
|
715
|
+
return { isError: true, body: { error: "not_configured", message: `${spec.name} runs \`jevitate ${commandFor(spec, args).path}\` in process, which this server was not given` } };
|
|
716
|
+
}
|
|
717
|
+
const { stdout: raw, exitCode } = await deps.runCli(argv);
|
|
718
|
+
const stdout = deps.redact(raw);
|
|
719
|
+
let envelope = lastEnvelope(stdout);
|
|
720
|
+
if (envelope === undefined && exitCode === 0) {
|
|
721
|
+
// A command without --json (`recording promote`) prints its result as plain JSON.
|
|
722
|
+
try {
|
|
723
|
+
envelope = { ok: true, data: JSON.parse(stdout) };
|
|
724
|
+
}
|
|
725
|
+
catch {
|
|
726
|
+
envelope = undefined;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
if (envelope === undefined)
|
|
730
|
+
return { isError: true, body: { error: "internal", message: "the command printed no JSON envelope", exitCode } };
|
|
731
|
+
if (!envelope.ok) {
|
|
732
|
+
return { isError: true, body: { error: exitCode === 64 ? "invalid_args" : "refused", code: envelope.error?.code ?? "E_UNKNOWN", message: envelope.error?.message ?? "refused", exitCode } };
|
|
733
|
+
}
|
|
734
|
+
// 0/1/3/4 are answers; 2 (proved nothing) is never a pass.
|
|
735
|
+
return { isError: exitCode === 2 || exitCode >= 64, body: { exitCode, data: envelope.data ?? null } };
|
|
736
|
+
}
|
|
737
|
+
//# sourceMappingURL=mcp-cli-tools.js.map
|