@jevitate/cli 0.1.0 → 0.2.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.js +40 -30
- package/dist/ai-cli.js.map +1 -1
- package/dist/author-journey-cli.d.ts +4 -0
- package/dist/author-journey-cli.js +109 -0
- package/dist/author-journey-cli.js.map +1 -0
- package/dist/bin.js +58077 -22454
- package/dist/bin.js.map +1 -1
- package/dist/browser-run-options.d.ts +58 -0
- package/dist/browser-run-options.js +106 -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/check-api.d.ts +5 -0
- package/dist/check-api.js +233 -0
- package/dist/check-api.js.map +1 -0
- package/dist/check-budget.d.ts +26 -0
- package/dist/check-budget.js +89 -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 +25 -0
- package/dist/check-execute.js +385 -0
- package/dist/check-execute.js.map +1 -0
- package/dist/check-plan.d.ts +113 -0
- package/dist/check-plan.js +448 -0
- package/dist/check-plan.js.map +1 -0
- package/dist/check-suite.d.ts +171 -0
- package/dist/check-suite.js +515 -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 +102 -0
- package/dist/cli-output.js +516 -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 +330 -0
- package/dist/cli-shared.js +492 -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 +502 -0
- package/dist/defect-evidence.js.map +1 -0
- package/dist/demo-aspect-api.d.ts +209 -0
- package/dist/demo-aspect-api.js +397 -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 +241 -0
- package/dist/demo-aspect-cli.js.map +1 -0
- package/dist/demo-capture.d.ts +108 -0
- package/dist/demo-capture.js +438 -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 +137 -0
- package/dist/explore-adversarial.js +218 -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 +963 -0
- package/dist/explore-cli.js.map +1 -0
- package/dist/explore-coverage.d.ts +158 -0
- package/dist/explore-coverage.js +240 -0
- package/dist/explore-coverage.js.map +1 -0
- package/dist/explore-feature.d.ts +127 -0
- package/dist/explore-feature.js +220 -0
- package/dist/explore-feature.js.map +1 -0
- package/dist/explore-goal.d.ts +253 -0
- package/dist/explore-goal.js +374 -0
- package/dist/explore-goal.js.map +1 -0
- package/dist/explore-shared.d.ts +152 -0
- package/dist/explore-shared.js +129 -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 +52 -0
- package/dist/fixture-auth.js +82 -0
- package/dist/fixture-auth.js.map +1 -0
- package/dist/fixture-cli.d.ts +70 -0
- package/dist/fixture-cli.js +178 -0
- package/dist/fixture-cli.js.map +1 -0
- package/dist/github-issue-filer.d.ts +62 -0
- package/dist/github-issue-filer.js +188 -0
- package/dist/github-issue-filer.js.map +1 -0
- package/dist/host-health-run.d.ts +24 -0
- package/dist/host-health-run.js +27 -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 +127 -0
- package/dist/init-cli.js.map +1 -0
- package/dist/init-keys.d.ts +19 -2
- package/dist/init-keys.js +15 -4
- 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 +256 -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 +179 -0
- package/dist/journey-annotate-cli.js.map +1 -0
- package/dist/journey-api.d.ts +79 -2
- package/dist/journey-api.js +136 -19
- package/dist/journey-api.js.map +1 -1
- package/dist/journey-cli.d.ts +4 -0
- package/dist/journey-cli.js +370 -0
- package/dist/journey-cli.js.map +1 -0
- package/dist/journey-demo-api.d.ts +112 -0
- package/dist/journey-demo-api.js +392 -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 +155 -0
- package/dist/journey-demo-cli.js.map +1 -0
- package/dist/kill-signal.d.ts +193 -0
- package/dist/kill-signal.js +284 -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 +237 -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 +147 -0
- package/dist/log-correlation.js +325 -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 +235 -0
- package/dist/log-sources.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 +84 -0
- package/dist/logs-retention.js.map +1 -0
- package/dist/mcp-api.d.ts +89 -1
- package/dist/mcp-api.js +472 -18
- package/dist/mcp-api.js.map +1 -1
- package/dist/mcp-args.d.ts +38 -0
- package/dist/mcp-args.js +131 -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 +125 -0
- package/dist/mcp-cli-tools.js +680 -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 +58 -2
- package/dist/mission-api.js.map +1 -1
- package/dist/mission-cli.d.ts +4 -0
- package/dist/mission-cli.js +247 -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 +225 -0
- package/dist/mission-fixtures.js +828 -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 +397 -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 +110 -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 +63 -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 +119 -1921
- package/dist/program.js.map +1 -1
- package/dist/project-dir.d.ts +96 -0
- package/dist/project-dir.js +220 -0
- package/dist/project-dir.js.map +1 -0
- package/dist/record-api.d.ts +10 -6
- package/dist/record-api.js +39 -28
- package/dist/record-api.js.map +1 -1
- package/dist/record-cli.d.ts +4 -0
- package/dist/record-cli.js +64 -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 +101 -0
- package/dist/regression-api.js +384 -5
- package/dist/regression-api.js.map +1 -1
- package/dist/regression-cli.d.ts +4 -0
- package/dist/regression-cli.js +232 -0
- package/dist/regression-cli.js.map +1 -0
- package/dist/report-api.d.ts +146 -0
- package/dist/report-api.js +430 -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/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-screenshots.d.ts +123 -0
- package/dist/run-screenshots.js +229 -0
- package/dist/run-screenshots.js.map +1 -0
- package/dist/runtime-env.d.ts +8 -0
- package/dist/runtime-env.js +22 -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 +34 -0
- package/dist/server-log-verify.js +115 -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 +58 -0
- package/dist/site-gate-cli.js.map +1 -0
- package/dist/source-api.js +18 -3
- 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 +289 -0
- package/dist/suite-explore-options.js +140 -0
- package/dist/suite-explore-options.js.map +1 -0
- package/dist/target-config.d.ts +109 -0
- package/dist/target-config.js +216 -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/ui-api.d.ts +3 -0
- package/dist/ui-api.js +7 -1
- package/dist/ui-api.js.map +1 -1
- package/dist/usability-capture.d.ts +43 -0
- package/dist/usability-capture.js +326 -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-cli.d.ts +4 -0
- package/dist/ux-cli.js +102 -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-review.d.ts +112 -0
- package/dist/ux-review.js +151 -0
- package/dist/ux-review.js.map +1 -0
- package/dist/ux-usability.d.ts +238 -0
- package/dist/ux-usability.js +494 -0
- package/dist/ux-usability.js.map +1 -0
- package/dist/verify-fix-api.d.ts +173 -0
- package/dist/verify-fix-api.js +454 -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 +110 -0
- package/dist/verify-fix-cli.js.map +1 -0
- package/package.json +19 -14
- package/skills/jevitate-ci-check/SKILL.md +77 -0
- package/skills/jevitate-demo/SKILL.md +61 -0
- package/skills/jevitate-explore/SKILL.md +88 -87
- package/skills/jevitate-getting-started/SKILL.md +88 -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-ux-review/SKILL.md +106 -16
- package/skills/jevitate-verify-fix/SKILL.md +76 -0
package/dist/init-cli.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { envCredentialStore, FEATURE_KEYS } from "@jevitate/ai-core";
|
|
2
|
+
import { loadLocalCredentials } from "./credentials-file.js";
|
|
3
|
+
import { ok, fail } from "./envelope.js";
|
|
4
|
+
import { initProjectDir } from "./project-dir.js";
|
|
5
|
+
import { realSecureIO } from "./ai-cli.js";
|
|
6
|
+
import { collectAllMissingKeys } from "./init-keys.js";
|
|
7
|
+
import { formatInitKeysHuman } from "./cli-output.js";
|
|
8
|
+
import { detectRuntimes, resolveInstallTargetPaths, installSkills } from "./init-skills.js";
|
|
9
|
+
import { registerMcp, resolveMcpTargetPaths } from "./init-mcp.js";
|
|
10
|
+
import { initNextSteps, environmentHint } from "./init-next-steps.js";
|
|
11
|
+
import { loadManifest } from "@jevitate/skills";
|
|
12
|
+
import { resolveDataDir } from "./data-dir.js";
|
|
13
|
+
import { emitJson, emitCommandResult } from "./cli-shared.js";
|
|
14
|
+
/** Registers `jevitate init` (API keys, skills/MCP wiring, the repo's .jevitate/). */
|
|
15
|
+
export function registerInitCommands(program, deps) {
|
|
16
|
+
program
|
|
17
|
+
.command("init")
|
|
18
|
+
.description("set up jevitate: collect API keys, install skills/MCP wiring, create the repo's .jevitate/")
|
|
19
|
+
.option("--json", "emit a JSON envelope")
|
|
20
|
+
.option("--skip-keys", "skip credential collection")
|
|
21
|
+
.option("--skip-skills", "skip skill installation")
|
|
22
|
+
.option("--skip-mcp", "skip registering the jevitate MCP server in detected harnesses")
|
|
23
|
+
.option("--targets <ids>", "comma-separated runtime ids to force-install to, overriding detection")
|
|
24
|
+
.option("--force", "overwrite a user-modified installed skill file/block or MCP config entry")
|
|
25
|
+
.option("--dry-run", "report planned skill-install/mcp-register actions without writing")
|
|
26
|
+
.option("--skip-project", "skip creating the repo's .jevitate/ (journeys, regressions, baselines, logs)")
|
|
27
|
+
.action(async function () {
|
|
28
|
+
const { json, skipKeys, skipSkills, skipMcp, skipProject, targets, force, dryRun } = this.opts();
|
|
29
|
+
try {
|
|
30
|
+
const data = { initialized: true };
|
|
31
|
+
// The repo's own .jevitate/ (0.2.0 layout): Journeys, regressions and baselines live with the
|
|
32
|
+
// app's code; logs stay local. Secrets and machine state stay in ~/.jevitate.
|
|
33
|
+
if (!skipProject)
|
|
34
|
+
data.project = initProjectDir(deps.init?.detection?.cwd?.() ?? process.cwd(), { ...(dryRun === true ? { dryRun: true } : {}) });
|
|
35
|
+
if (!skipKeys) {
|
|
36
|
+
// SECURITY: reuses the existing, already-guardrailed credential
|
|
37
|
+
// collection. The report holds only key NAMES (required/collected/missing),
|
|
38
|
+
// never a value — nothing here reads, echoes, logs, or returns a key.
|
|
39
|
+
const store = envCredentialStore(deps.ai?.env ?? process.env, deps.ai?.localConfig ?? loadLocalCredentials());
|
|
40
|
+
const io = deps.ai?.secureIO ?? realSecureIO();
|
|
41
|
+
// #230: never prompt a non-interactive stdin (no TTY — how coding agents and CI run
|
|
42
|
+
// `jevitate init`) — it would hang reading a 'line' event that never comes, or read EOF
|
|
43
|
+
// silently. Report what's still missing instead; the rest of init still completes.
|
|
44
|
+
const interactive = deps.init?.isInteractive?.() ?? process.stdin.isTTY === true;
|
|
45
|
+
data.keys = await collectAllMissingKeys(store, io, { interactive });
|
|
46
|
+
}
|
|
47
|
+
// Explicit `--targets` overrides detection entirely (the user takes
|
|
48
|
+
// full control); otherwise `detectRuntimes` decides, always including
|
|
49
|
+
// the always-on generic fallback. Shared by the skill install and the
|
|
50
|
+
// MCP registration so a single selection drives both.
|
|
51
|
+
const runtimes = targets
|
|
52
|
+
? targets.split(",").map((t) => t.trim()).filter((t) => t.length > 0)
|
|
53
|
+
: detectRuntimes(deps.init?.detection);
|
|
54
|
+
if (!skipSkills) {
|
|
55
|
+
const paths = resolveInstallTargetPaths(deps.init?.detection);
|
|
56
|
+
const statePath = deps.init?.statePath ?? resolveDataDir(["skills-install-state.json"]);
|
|
57
|
+
const skills = loadManifest();
|
|
58
|
+
data.skills = await installSkills(runtimes, skills, paths, statePath, { force, dryRun });
|
|
59
|
+
}
|
|
60
|
+
if (!skipMcp) {
|
|
61
|
+
// Register the `jevitate mcp` server for each detected/selected
|
|
62
|
+
// harness, with the SAME never-clobber safety as skills: a user's
|
|
63
|
+
// conflicting or unparseable config is never overwritten without
|
|
64
|
+
// --force; each declined target reports a printable instruction
|
|
65
|
+
// instead (honest, never corrupts a config). `generic` has no MCP
|
|
66
|
+
// convention and is skipped inside `registerMcp`.
|
|
67
|
+
const mcpPaths = resolveMcpTargetPaths(deps.init?.detection);
|
|
68
|
+
data.mcp = await registerMcp(runtimes, mcpPaths, { force, dryRun });
|
|
69
|
+
}
|
|
70
|
+
// #230: exit 0 even when keys are still missing (the non-interactive path above) —
|
|
71
|
+
// init's other work (project dir, skills, MCP registration) genuinely succeeded, and a
|
|
72
|
+
// missing key is expected/normal for a fresh non-interactive install (CI, a coding
|
|
73
|
+
// agent) that configures keys separately. The warning lives in `data.keys[*].missing`
|
|
74
|
+
// (both here and in the --json envelope) rather than in the exit code, so a script that
|
|
75
|
+
// only checks the exit code still sees init as having done its job; a caller that cares
|
|
76
|
+
// about keys reads the summary/envelope, same as `jevitate ai status`.
|
|
77
|
+
// The "try this next" block, tailored to what is set up now (keys, MCP, the repo's
|
|
78
|
+
// environments). Additive in --json (`data.nextSteps`); keys are checked by NAME only.
|
|
79
|
+
const keysReady = data.keys !== undefined
|
|
80
|
+
? Object.values(data.keys).every((r) => (r.missing ?? []).length === 0)
|
|
81
|
+
: (() => {
|
|
82
|
+
const store = envCredentialStore(deps.ai?.env ?? process.env, deps.ai?.localConfig ?? loadLocalCredentials());
|
|
83
|
+
return Object.keys(FEATURE_KEYS).every((f) => FEATURE_KEYS[f].every((k) => store.detect(k)));
|
|
84
|
+
})();
|
|
85
|
+
const projectDir = data.project?.dir ?? null;
|
|
86
|
+
data.nextSteps = initNextSteps({
|
|
87
|
+
keysReady,
|
|
88
|
+
...environmentHint(projectDir),
|
|
89
|
+
...(data.mcp !== undefined ? { mcp: data.mcp } : {}),
|
|
90
|
+
skills: data.skills !== undefined,
|
|
91
|
+
dryRun: dryRun === true,
|
|
92
|
+
});
|
|
93
|
+
const envelope = ok(data);
|
|
94
|
+
if (json) {
|
|
95
|
+
emitJson(program, envelope);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
const out = program.configureOutput().writeOut;
|
|
99
|
+
// #213: --dry-run writes nothing — say "would" so the summary matches the disk.
|
|
100
|
+
out?.(dryRun === true ? "jevitate: dry run — nothing was written\n" : "jevitate initialized\n");
|
|
101
|
+
// #210/#230: per feature, "ready — n/n configured", or (no TTY on stdin) "not
|
|
102
|
+
// configured — set X or run `jevitate ai setup <feature>`" — never a raw `collected:
|
|
103
|
+
// []` that reads as "missing" when every key was already set.
|
|
104
|
+
if (data.keys)
|
|
105
|
+
out?.(`${formatInitKeysHuman(data.keys)}\n`);
|
|
106
|
+
if (data.skills)
|
|
107
|
+
out?.(`skills: ${data.skills.length} target/skill pairs ${dryRun === true ? "would be processed" : "processed"}\n`);
|
|
108
|
+
if (data.mcp)
|
|
109
|
+
out?.(`mcp: ${data.mcp.length} harness config(s) ${dryRun === true ? "would be processed" : "processed"}\n`);
|
|
110
|
+
const project = data.project;
|
|
111
|
+
if (project !== undefined) {
|
|
112
|
+
out?.(project.dir === null
|
|
113
|
+
? `project: ${project.reason ?? "none"}\n`
|
|
114
|
+
: `project: ${project.dir} (${project.created.length} ${dryRun === true ? "would create" : "created"})\n`);
|
|
115
|
+
}
|
|
116
|
+
out?.(`next steps${data.project?.dir == null ? "" : " (app URLs: .jevitate/environments.json)"}:\n`);
|
|
117
|
+
for (const line of data.nextSteps)
|
|
118
|
+
out?.(` ${line}\n`);
|
|
119
|
+
process.exitCode = 0;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
emitCommandResult(program, fail("E_INIT", String(err instanceof Error ? err.message : err)), { json: json === true, command: "init" });
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=init-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-cli.js","sourceRoot":"","sources":["../src/init-cli.ts"],"names":[],"mappings":"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"}
|
package/dist/init-keys.d.ts
CHANGED
|
@@ -2,13 +2,30 @@ import { type CredentialStore, type SecureKeyIO, type Feature, type CredentialKe
|
|
|
2
2
|
export interface FeatureKeyReport {
|
|
3
3
|
required: CredentialKey[];
|
|
4
4
|
collected: CredentialKey[];
|
|
5
|
+
/**
|
|
6
|
+
* #230: only set on the non-interactive path — the required keys still absent after this
|
|
7
|
+
* command ran (nothing was prompted for, nothing persisted). Undefined/empty on the
|
|
8
|
+
* interactive path: `collectMissingKeys` either leaves every required key configured or
|
|
9
|
+
* throws (fail-closed), so there is nothing left to report as missing.
|
|
10
|
+
*/
|
|
11
|
+
missing?: CredentialKey[];
|
|
5
12
|
}
|
|
6
13
|
export type KeyCollectionReport = Record<Feature, FeatureKeyReport>;
|
|
14
|
+
export interface CollectAllMissingKeysOptions {
|
|
15
|
+
/**
|
|
16
|
+
* #230: false when stdin is not a TTY (no key env vars, piped/redirected input — how coding
|
|
17
|
+
* agents and CI run `jevitate init`). `SecureKeyIO.promptSecret` reads a 'line' event that a
|
|
18
|
+
* closed/non-interactive stdin never emits, so prompting there would hang until the process is
|
|
19
|
+
* killed, or (observed) read EOF and exit 0 with nothing collected and no summary. Default true
|
|
20
|
+
* (a real terminal): unchanged prompting behavior.
|
|
21
|
+
*/
|
|
22
|
+
interactive?: boolean;
|
|
23
|
+
}
|
|
7
24
|
/**
|
|
8
25
|
* Thin orchestration over the existing, already-guardrailed `collectMissingKeys`
|
|
9
26
|
* — collects every feature's missing keys in turn (never in parallel:
|
|
10
27
|
* `SecureKeyIO.promptSecret` is a single shared stdin, so concurrent prompts
|
|
11
28
|
* would interleave). Adds NO new key-handling logic: it never reads, echoes,
|
|
12
|
-
* logs, or returns a key value — only the key NAMES (required/collected).
|
|
29
|
+
* logs, or returns a key value — only the key NAMES (required/collected/missing).
|
|
13
30
|
*/
|
|
14
|
-
export declare function collectAllMissingKeys(store: CredentialStore, io: SecureKeyIO): Promise<KeyCollectionReport>;
|
|
31
|
+
export declare function collectAllMissingKeys(store: CredentialStore, io: SecureKeyIO, opts?: CollectAllMissingKeysOptions): Promise<KeyCollectionReport>;
|
package/dist/init-keys.js
CHANGED
|
@@ -5,13 +5,24 @@ const FEATURES = ["generation", "judgment"];
|
|
|
5
5
|
* — collects every feature's missing keys in turn (never in parallel:
|
|
6
6
|
* `SecureKeyIO.promptSecret` is a single shared stdin, so concurrent prompts
|
|
7
7
|
* would interleave). Adds NO new key-handling logic: it never reads, echoes,
|
|
8
|
-
* logs, or returns a key value — only the key NAMES (required/collected).
|
|
8
|
+
* logs, or returns a key value — only the key NAMES (required/collected/missing).
|
|
9
9
|
*/
|
|
10
|
-
export async function collectAllMissingKeys(store, io) {
|
|
10
|
+
export async function collectAllMissingKeys(store, io, opts = {}) {
|
|
11
11
|
const report = {};
|
|
12
|
+
const interactive = opts.interactive ?? true;
|
|
12
13
|
for (const feature of FEATURES) {
|
|
13
|
-
const
|
|
14
|
-
|
|
14
|
+
const required = [...FEATURE_KEYS[feature]];
|
|
15
|
+
if (interactive) {
|
|
16
|
+
const collected = await collectMissingKeys(feature, store, io);
|
|
17
|
+
report[feature] = { required, collected };
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
// Never prompt: report what's still missing instead of hanging on a closed stdin. `missing`
|
|
21
|
+
// is omitted (not an empty array) when nothing is missing, so a fully-configured non-TTY
|
|
22
|
+
// run reads identically to the interactive path's `{ required, collected: [] }`.
|
|
23
|
+
const missing = required.filter((k) => !store.detect(k));
|
|
24
|
+
report[feature] = { required, collected: [], ...(missing.length > 0 ? { missing } : {}) };
|
|
25
|
+
}
|
|
15
26
|
}
|
|
16
27
|
return report;
|
|
17
28
|
}
|
package/dist/init-keys.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-keys.js","sourceRoot":"","sources":["../src/init-keys.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,GAKb,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"init-keys.js","sourceRoot":"","sources":["../src/init-keys.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,GAKb,MAAM,mBAAmB,CAAC;AAe3B,MAAM,QAAQ,GAAc,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;AAavD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,KAAsB,EACtB,EAAe,EACf,OAAqC,EAAE;IAEvC,MAAM,MAAM,GAAG,EAAyB,CAAC;IACzC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC;IAC7C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;QAC5C,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAC/D,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;QAC5C,CAAC;aAAM,CAAC;YACN,4FAA4F;YAC5F,yFAAyF;YACzF,iFAAiF;YACjF,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YACzD,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;QAC5F,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { McpInstallReport } from "./init-mcp.js";
|
|
2
|
+
/** What `jevitate init` knows after setup that changes the "try this next" block. */
|
|
3
|
+
export interface InitNextStepsInput {
|
|
4
|
+
/** Both AI features (generation + judgment) have their keys configured. */
|
|
5
|
+
readonly keysReady: boolean;
|
|
6
|
+
/** The app URL to put in the commands, when the repo's environments file names a real one. */
|
|
7
|
+
readonly appUrl?: string;
|
|
8
|
+
/** A non-production environment name from `.jevitate/environments.json`, for `demo --env`. */
|
|
9
|
+
readonly env?: string;
|
|
10
|
+
/** The MCP registration report; undefined when `--skip-mcp`. */
|
|
11
|
+
readonly mcp?: readonly McpInstallReport[];
|
|
12
|
+
/** Whether skills were installed (false under `--skip-skills`). */
|
|
13
|
+
readonly skills: boolean;
|
|
14
|
+
readonly dryRun: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The ≤5 "try this next" lines `jevitate init` prints (and returns as `data.nextSteps`). Every
|
|
18
|
+
* command is a real one with real flags (skills-cli-drift.test.ts checks them against the CLI);
|
|
19
|
+
* placeholders are `<…>` so nothing reads as a value we guessed. Tailored, never silent:
|
|
20
|
+
* - keys ready → a goal run, an authored Journey and a demo (all need the model gateway);
|
|
21
|
+
* - keys missing → the key-free adversarial run (`--fake-ai`: misuse is planned in code, the
|
|
22
|
+
* findings are hard signals), a human-recorded flow, and how to add the keys;
|
|
23
|
+
* - the agent line says whether the MCP server was registered, declined (conflict), or skipped.
|
|
24
|
+
*/
|
|
25
|
+
export declare function initNextSteps(input: InitNextStepsInput): string[];
|
|
26
|
+
/**
|
|
27
|
+
* Reads `.jevitate/environments.json` for the next-steps block: the first non-production
|
|
28
|
+
* environment's name, and its `baseUrl` only when it is not the untouched scaffold's (so the block
|
|
29
|
+
* never presents the example `http://localhost:3000` as "your app"). Unreadable → nothing: the
|
|
30
|
+
* block keeps its `<app-url>`/`<env>` placeholders.
|
|
31
|
+
*/
|
|
32
|
+
export declare function environmentHint(projectDir: string | null): {
|
|
33
|
+
appUrl?: string;
|
|
34
|
+
env?: string;
|
|
35
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { ENVIRONMENTS_FILE, ENVIRONMENTS_SCAFFOLD } from "./project-dir.js";
|
|
4
|
+
const REGISTERED = new Set(["create", "update", "unchanged", "force-update"]);
|
|
5
|
+
/**
|
|
6
|
+
* The ≤5 "try this next" lines `jevitate init` prints (and returns as `data.nextSteps`). Every
|
|
7
|
+
* command is a real one with real flags (skills-cli-drift.test.ts checks them against the CLI);
|
|
8
|
+
* placeholders are `<…>` so nothing reads as a value we guessed. Tailored, never silent:
|
|
9
|
+
* - keys ready → a goal run, an authored Journey and a demo (all need the model gateway);
|
|
10
|
+
* - keys missing → the key-free adversarial run (`--fake-ai`: misuse is planned in code, the
|
|
11
|
+
* findings are hard signals), a human-recorded flow, and how to add the keys;
|
|
12
|
+
* - the agent line says whether the MCP server was registered, declined (conflict), or skipped.
|
|
13
|
+
*/
|
|
14
|
+
export function initNextSteps(input) {
|
|
15
|
+
const url = input.appUrl ?? "<app-url>";
|
|
16
|
+
const env = input.env ?? "<env>";
|
|
17
|
+
const lines = [];
|
|
18
|
+
if (input.keysReady) {
|
|
19
|
+
lines.push(`1. try it: jevitate explore --url ${url} --goal "<a task a user does>" --success "urlIncludes:<done-path>" --real`);
|
|
20
|
+
lines.push(`2. keep it: jevitate explore-author-journey --url ${url} --goal "<task>" --success "<check>" --id <id> --name "<name>" --real`);
|
|
21
|
+
lines.push(`3. demo it: jevitate demo "<aspect>" --env ${env} --success "<check>" --real`);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
lines.push(`1. try it: jevitate explore --strategy adversarial --url ${url} --fake-ai (no keys: finds 5xx, crashes, hangs)`);
|
|
25
|
+
lines.push(`2. record it: jevitate record --url ${url} (you click; Enter saves a replayable Recording)`);
|
|
26
|
+
lines.push("3. add keys: jevitate ai setup generation && jevitate ai setup judgment (goals, Journeys, demos)");
|
|
27
|
+
}
|
|
28
|
+
lines.push("4. gate CI: jevitate check --suite <suite.json> (JUnit + SARIF; exit 1 = a gating finding)");
|
|
29
|
+
const agent = agentLine(input);
|
|
30
|
+
if (agent !== undefined)
|
|
31
|
+
lines.push(agent);
|
|
32
|
+
return lines;
|
|
33
|
+
}
|
|
34
|
+
function agentLine(input) {
|
|
35
|
+
const would = input.dryRun ? "would be " : "";
|
|
36
|
+
if (input.mcp !== undefined && input.mcp.length > 0) {
|
|
37
|
+
const ok = input.mcp.filter((r) => REGISTERED.has(r.action)).map((r) => r.target);
|
|
38
|
+
const declined = input.mcp.filter((r) => !REGISTERED.has(r.action)).map((r) => r.target);
|
|
39
|
+
if (ok.length > 0) {
|
|
40
|
+
return `agents: MCP server ${would}registered for ${ok.join(", ")}${declined.length > 0 ? ` (not ${declined.join(", ")}: see above)` : ""} — restart the agent, then ask in plain words`;
|
|
41
|
+
}
|
|
42
|
+
return `agents: MCP server NOT registered (${declined.join(", ")}: existing config kept) — rerun with --force, or: jevitate mcp --print-config claude`;
|
|
43
|
+
}
|
|
44
|
+
if (input.skills) {
|
|
45
|
+
return "agents: skills installed (CLI) — for MCP tools too: jevitate mcp --print-config claude|cursor|codex|json";
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Reads `.jevitate/environments.json` for the next-steps block: the first non-production
|
|
51
|
+
* environment's name, and its `baseUrl` only when it is not the untouched scaffold's (so the block
|
|
52
|
+
* never presents the example `http://localhost:3000` as "your app"). Unreadable → nothing: the
|
|
53
|
+
* block keeps its `<app-url>`/`<env>` placeholders.
|
|
54
|
+
*/
|
|
55
|
+
export function environmentHint(projectDir) {
|
|
56
|
+
if (projectDir === null)
|
|
57
|
+
return {};
|
|
58
|
+
let parsed;
|
|
59
|
+
try {
|
|
60
|
+
parsed = JSON.parse(readFileSync(join(projectDir, ENVIRONMENTS_FILE), "utf8"));
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return {};
|
|
64
|
+
}
|
|
65
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
|
|
66
|
+
return {};
|
|
67
|
+
for (const [name, entry] of Object.entries(parsed)) {
|
|
68
|
+
if (name.startsWith("$") || entry === null || typeof entry !== "object")
|
|
69
|
+
continue;
|
|
70
|
+
const e = entry;
|
|
71
|
+
if (e.production === true)
|
|
72
|
+
continue;
|
|
73
|
+
const baseUrl = typeof e.baseUrl === "string" ? e.baseUrl : undefined;
|
|
74
|
+
const isScaffold = name === "local" && baseUrl === ENVIRONMENTS_SCAFFOLD.local.baseUrl;
|
|
75
|
+
return { env: name, ...(baseUrl !== undefined && !isScaffold ? { appUrl: baseUrl } : {}) };
|
|
76
|
+
}
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=init-next-steps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-next-steps.js","sourceRoot":"","sources":["../src/init-next-steps.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type InvariantSpec } from "@jevitate/recording";
|
|
2
|
+
/**
|
|
3
|
+
* `--invariants <file.json>` (repeatable, #86): loads the app team's declared-invariant files,
|
|
4
|
+
* validates each against the closed schema, merges them, and authorizes every probe against the
|
|
5
|
+
* run's allowlist — all BEFORE any browser opens. A bad file refuses the dispatch with a precise
|
|
6
|
+
* path (`a.json: invariants[2].require: unknown observable "balanse"`), never mid-run.
|
|
7
|
+
*/
|
|
8
|
+
export declare class InvariantsFileError extends Error {
|
|
9
|
+
readonly code: "E_EXPLORE_INVARIANTS";
|
|
10
|
+
/** #195: each path-precise problem on its own (`invariants[2].require: …`); the message joins them. */
|
|
11
|
+
readonly problems: readonly string[];
|
|
12
|
+
constructor(message: string, problems?: readonly string[]);
|
|
13
|
+
}
|
|
14
|
+
export interface LoadInvariantsOptions {
|
|
15
|
+
/**
|
|
16
|
+
* The run's authorized origins: every probe must resolve onto one. Omitted (with `baseUrl`) only by
|
|
17
|
+
* `jevitate invariants validate` without `--url` (#195): then every probe/`deniedAs` is REFUSED
|
|
18
|
+
* ("needs the mission's authorized origins") — nothing is ever assumed authorized.
|
|
19
|
+
*/
|
|
20
|
+
readonly allowlist?: readonly string[];
|
|
21
|
+
/** What relative probe paths resolve against (the run's start URL). */
|
|
22
|
+
readonly baseUrl?: string;
|
|
23
|
+
/** #147: the registered observer actors (every `--actor` but the primary) cross-actor checks may name. */
|
|
24
|
+
readonly observers?: readonly string[];
|
|
25
|
+
}
|
|
26
|
+
/** Loads, validates and merges invariant files. Returns undefined for no files. Throws `InvariantsFileError`. */
|
|
27
|
+
export declare function loadInvariantFiles(paths: readonly string[], opts: LoadInvariantsOptions): InvariantSpec | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Resolves every `authFrom.secret` ref (#135, `env:VAR`) a spec's probes use, from `env` — the ONE
|
|
30
|
+
* place this ever happens (the CLI dispatch), matching `--secret-field`'s own `env:VAR` resolution.
|
|
31
|
+
* Throws `InvariantsFileError` (naming the ref, never a value) for an unset/empty variable. Returns
|
|
32
|
+
* a map keyed by the ref itself (`"env:APP_TOKEN"` → its value) for `InvariantMonitorOptions.authTokens`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveInvariantAuthTokens(spec: InvariantSpec, env: Readonly<Record<string, string | undefined>>): Map<string, string>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { InvariantSpecError, invariantAuthSecretRefs, mergeInvariantSpecs, validateInvariantSpec, } from "@jevitate/recording";
|
|
3
|
+
/**
|
|
4
|
+
* `--invariants <file.json>` (repeatable, #86): loads the app team's declared-invariant files,
|
|
5
|
+
* validates each against the closed schema, merges them, and authorizes every probe against the
|
|
6
|
+
* run's allowlist — all BEFORE any browser opens. A bad file refuses the dispatch with a precise
|
|
7
|
+
* path (`a.json: invariants[2].require: unknown observable "balanse"`), never mid-run.
|
|
8
|
+
*/
|
|
9
|
+
export class InvariantsFileError extends Error {
|
|
10
|
+
code = "E_EXPLORE_INVARIANTS";
|
|
11
|
+
/** #195: each path-precise problem on its own (`invariants[2].require: …`); the message joins them. */
|
|
12
|
+
problems;
|
|
13
|
+
constructor(message, problems = [message]) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "InvariantsFileError";
|
|
16
|
+
this.problems = problems;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Loads, validates and merges invariant files. Returns undefined for no files. Throws `InvariantsFileError`. */
|
|
20
|
+
export function loadInvariantFiles(paths, opts) {
|
|
21
|
+
if (paths.length === 0)
|
|
22
|
+
return undefined;
|
|
23
|
+
const specs = [];
|
|
24
|
+
for (const path of paths) {
|
|
25
|
+
let raw;
|
|
26
|
+
try {
|
|
27
|
+
raw = JSON.parse(readFileSync(path, "utf8"));
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
throw new InvariantsFileError(`cannot read invariants file ${path}: ${e instanceof Error ? e.message.split("\n")[0] : String(e)}`);
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
specs.push(validateInvariantSpec(raw, opts));
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
if (e instanceof InvariantSpecError)
|
|
37
|
+
throw new InvariantsFileError(`${path}: ${e.problems.join("; ")}`, e.problems);
|
|
38
|
+
throw e;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
return mergeInvariantSpecs(specs);
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
if (e instanceof InvariantSpecError)
|
|
46
|
+
throw new InvariantsFileError(e.problems.join("; "), e.problems);
|
|
47
|
+
throw e;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolves every `authFrom.secret` ref (#135, `env:VAR`) a spec's probes use, from `env` — the ONE
|
|
52
|
+
* place this ever happens (the CLI dispatch), matching `--secret-field`'s own `env:VAR` resolution.
|
|
53
|
+
* Throws `InvariantsFileError` (naming the ref, never a value) for an unset/empty variable. Returns
|
|
54
|
+
* a map keyed by the ref itself (`"env:APP_TOKEN"` → its value) for `InvariantMonitorOptions.authTokens`.
|
|
55
|
+
*/
|
|
56
|
+
export function resolveInvariantAuthTokens(spec, env) {
|
|
57
|
+
const tokens = new Map();
|
|
58
|
+
for (const ref of invariantAuthSecretRefs(spec)) {
|
|
59
|
+
const name = ref.slice("env:".length);
|
|
60
|
+
const value = env[name];
|
|
61
|
+
if (value === undefined || value === "") {
|
|
62
|
+
throw new InvariantsFileError(`--invariants: authFrom.secret ${ref}: environment variable ${name} is not set`);
|
|
63
|
+
}
|
|
64
|
+
tokens.set(ref, value);
|
|
65
|
+
}
|
|
66
|
+
return tokens;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=invariants-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariants-file.js","sourceRoot":"","sources":["../src/invariants-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,GAEtB,MAAM,qBAAqB,CAAC;AAE7B;;;;;GAKG;AAEH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IACnC,IAAI,GAAG,sBAA+B,CAAC;IAChD,uGAAuG;IAC9F,QAAQ,CAAoB;IACrC,YAAY,OAAe,EAAE,WAA8B,CAAC,OAAO,CAAC;QAClE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAeD,iHAAiH;AACjH,MAAM,UAAU,kBAAkB,CAAC,KAAwB,EAAE,IAA2B;IACtF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,KAAK,GAAoB,EAAE,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,GAAY,CAAC;QACjB,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,mBAAmB,CAAC,+BAA+B,IAAI,KAAK,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACrI,CAAC;QACD,IAAI,CAAC;YACH,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,kBAAkB;gBAAE,MAAM,IAAI,mBAAmB,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;YACpH,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IACD,IAAI,CAAC;QACH,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,kBAAkB;YAAE,MAAM,IAAI,mBAAmB,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;QACtG,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CACxC,IAAmB,EACnB,GAAiD;IAEjD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,GAAG,IAAI,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACxC,MAAM,IAAI,mBAAmB,CAAC,iCAAiC,GAAG,0BAA0B,IAAI,aAAa,CAAC,CAAC;QACjH,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import { type LoadInvariantsOptions } from "./invariants-file.js";
|
|
3
|
+
/**
|
|
4
|
+
* `jevitate invariants validate <file…>` (#195): lints declared-invariant files WITHOUT a browser —
|
|
5
|
+
* the exact loader `explore --invariants` runs before any browser opens (`loadInvariantFiles`: the
|
|
6
|
+
* closed schema, expression/observable cross-references, probe and `deniedAs` origin authorization,
|
|
7
|
+
* the cross-file merge), so CI can gate committed invariant files. No second implementation.
|
|
8
|
+
*
|
|
9
|
+
* Probe/`deniedAs` origins are authorized only against what the caller names (`--url`, `--allow`);
|
|
10
|
+
* without `--url` a spec that makes network probes is refused, never assumed authorized.
|
|
11
|
+
*/
|
|
12
|
+
export interface InvariantsFileResult {
|
|
13
|
+
readonly file: string;
|
|
14
|
+
readonly valid: boolean;
|
|
15
|
+
/** The file's declared invariants (when it validated). */
|
|
16
|
+
readonly invariants?: number;
|
|
17
|
+
/** Path-precise problems (`invariants[2].require: unknown observable "balanse"`). */
|
|
18
|
+
readonly problems: string[];
|
|
19
|
+
}
|
|
20
|
+
export interface InvariantsValidation {
|
|
21
|
+
readonly valid: boolean;
|
|
22
|
+
readonly files: InvariantsFileResult[];
|
|
23
|
+
/** Problems merging the (individually valid) files: a repeated id, an observable declared twice differently. */
|
|
24
|
+
readonly merge: string[];
|
|
25
|
+
/** How to fix an origin-authorization refusal, when one occurred. */
|
|
26
|
+
readonly hint?: string;
|
|
27
|
+
}
|
|
28
|
+
/** Validates each file on its own (so every file's problems are reported), then their merge. */
|
|
29
|
+
export declare function validateInvariantFiles(files: readonly string[], opts: LoadInvariantsOptions): InvariantsValidation;
|
|
30
|
+
export declare function registerInvariantsCommands(program: Command): void;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { emitJsonOrRefusal } from "./cli-refusal.js";
|
|
3
|
+
import { ok, fail } from "./envelope.js";
|
|
4
|
+
import { resolveExploreAllowlist } from "./explore-api.js";
|
|
5
|
+
import { InvariantsFileError, loadInvariantFiles } from "./invariants-file.js";
|
|
6
|
+
import { EXIT_CODES } from "./exit-codes.js";
|
|
7
|
+
const ORIGIN_HINT = "pass --url <start-url> (and --allow <origin>, repeatable) to authorize probe and deniedAs origins, as `explore --invariants` does";
|
|
8
|
+
/** Validates each file on its own (so every file's problems are reported), then their merge. */
|
|
9
|
+
export function validateInvariantFiles(files, opts) {
|
|
10
|
+
const results = files.map((file) => {
|
|
11
|
+
try {
|
|
12
|
+
const spec = loadInvariantFiles([file], opts);
|
|
13
|
+
return { file, valid: true, invariants: spec?.invariants.length ?? 0, problems: [] };
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
if (!(e instanceof InvariantsFileError))
|
|
17
|
+
throw e;
|
|
18
|
+
return { file, valid: false, problems: [...e.problems] };
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
let merge = [];
|
|
22
|
+
if (files.length > 1 && results.every((r) => r.valid)) {
|
|
23
|
+
try {
|
|
24
|
+
loadInvariantFiles(files, opts);
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
if (!(e instanceof InvariantsFileError))
|
|
28
|
+
throw e;
|
|
29
|
+
merge = [...e.problems];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const valid = merge.length === 0 && results.every((r) => r.valid);
|
|
33
|
+
const needsOrigins = results.some((r) => r.problems.some((p) => p.includes("authorized origins to be checked against")));
|
|
34
|
+
return { valid, files: results, merge, ...(needsOrigins ? { hint: ORIGIN_HINT } : {}) };
|
|
35
|
+
}
|
|
36
|
+
/** The envelope (success, or a refusal with --json); a refusal without --json is a human stderr line (#218). */
|
|
37
|
+
function emit(program, envelope, exitCode) {
|
|
38
|
+
emitJsonOrRefusal(program, envelope, exitCode);
|
|
39
|
+
}
|
|
40
|
+
/** The first file that cannot be read at all, with why — unusable input, refused before validating (#218). */
|
|
41
|
+
function unreadableFile(files) {
|
|
42
|
+
for (const file of files) {
|
|
43
|
+
try {
|
|
44
|
+
readFileSync(file, "utf8");
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
return `cannot read invariants file ${file}: ${e instanceof Error ? e.message.split("\n")[0] : String(e)}`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
const collect = (v, prev) => [...prev, v];
|
|
53
|
+
export function registerInvariantsCommands(program) {
|
|
54
|
+
const invariants = program.command("invariants").description("declared-invariant files (`explore --invariants`)");
|
|
55
|
+
invariants
|
|
56
|
+
.command("validate <files...>")
|
|
57
|
+
.description("validate invariant files without a browser (the same pre-browser check `explore --invariants` runs); exit 1 when any is invalid, 64 when one cannot be read")
|
|
58
|
+
.option("--url <url>", "the run's start URL: relative probe/deniedAs paths resolve against it, and its origin is authorized")
|
|
59
|
+
.option("--allow <origin>", "authorized origin (repeatable; needs --url); REPLACES the URL's own origin, as `explore --allow`", collect, [])
|
|
60
|
+
.option("--observer <name>", "a registered observer actor a probe `as:` / `deniedAs.actor` may name (repeatable; `explore --actor` minus the primary)", collect, [])
|
|
61
|
+
.option("--json", "emit a JSON envelope")
|
|
62
|
+
.action(function (files) {
|
|
63
|
+
const o = this.opts();
|
|
64
|
+
if (o.url === undefined && o.allow.length > 0) {
|
|
65
|
+
emit(program, fail("E_INVARIANTS_ARGS", "--allow needs --url (relative probe paths resolve against it)"), EXIT_CODES.usage);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// #218: a file that cannot be read is unusable input (64, like every command), not an invalid one (1).
|
|
69
|
+
const unreadable = unreadableFile(files);
|
|
70
|
+
if (unreadable !== undefined) {
|
|
71
|
+
emit(program, fail("E_INVARIANTS_INPUT", unreadable), EXIT_CODES.usage);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// Without --url nothing is authorized: the loader refuses every probe/deniedAs origin itself.
|
|
75
|
+
const opts = o.url === undefined
|
|
76
|
+
? { observers: o.observer }
|
|
77
|
+
: { allowlist: resolveExploreAllowlist(o.url, o.allow), baseUrl: o.url, observers: o.observer };
|
|
78
|
+
const result = validateInvariantFiles(files, opts);
|
|
79
|
+
const exitCode = result.valid ? EXIT_CODES.ok : EXIT_CODES.defects;
|
|
80
|
+
if (o.json === true) {
|
|
81
|
+
emit(program, ok(result), exitCode);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const lines = [];
|
|
85
|
+
for (const f of result.files) {
|
|
86
|
+
if (f.valid)
|
|
87
|
+
lines.push(`valid ${f.file} (${f.invariants ?? 0} invariants)`);
|
|
88
|
+
else {
|
|
89
|
+
lines.push(`invalid ${f.file}`);
|
|
90
|
+
for (const p of f.problems)
|
|
91
|
+
lines.push(` ${p}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (result.merge.length > 0) {
|
|
95
|
+
lines.push("invalid merge of the files above");
|
|
96
|
+
for (const p of result.merge)
|
|
97
|
+
lines.push(` ${p}`);
|
|
98
|
+
}
|
|
99
|
+
if (result.hint !== undefined)
|
|
100
|
+
lines.push(`hint: ${result.hint}`);
|
|
101
|
+
program.configureOutput().writeOut?.(`${lines.join("\n")}\n`);
|
|
102
|
+
process.exitCode = exitCode;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=invariants-validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariants-validate.js","sourceRoot":"","sources":["../src/invariants-validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAqB,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAA8B,MAAM,sBAAsB,CAAC;AAC3G,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AA8B7C,MAAM,WAAW,GAAG,mIAAmI,CAAC;AAExJ,gGAAgG;AAChG,MAAM,UAAU,sBAAsB,CAAC,KAAwB,EAAE,IAA2B;IAC1F,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAwB,EAAE;QACvD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,kBAAkB,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;YAC9C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,CAAC,MAAM,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACvF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,CAAC,CAAC,YAAY,mBAAmB,CAAC;gBAAE,MAAM,CAAC,CAAC;YACjD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3D,CAAC;IACH,CAAC,CAAC,CAAC;IACH,IAAI,KAAK,GAAa,EAAE,CAAC;IACzB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACtD,IAAI,CAAC;YACH,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,CAAC,CAAC,YAAY,mBAAmB,CAAC;gBAAE,MAAM,CAAC,CAAC;YACjD,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAClE,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,0CAA0C,CAAC,CAAC,CAAC,CAAC;IACzH,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC1F,CAAC;AAED,gHAAgH;AAChH,SAAS,IAAI,CAAC,OAAgB,EAAE,QAA+B,EAAE,QAAgB;IAC/E,iBAAiB,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACjD,CAAC;AAED,8GAA8G;AAC9G,SAAS,cAAc,CAAC,KAAwB;IAC9C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,+BAA+B,IAAI,KAAK,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7G,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,IAAc,EAAY,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;AAEtE,MAAM,UAAU,0BAA0B,CAAC,OAAgB;IACzD,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,WAAW,CAAC,mDAAmD,CAAC,CAAC;IAClH,UAAU;SACP,OAAO,CAAC,qBAAqB,CAAC;SAC9B,WAAW,CAAC,6JAA6J,CAAC;SAC1K,MAAM,CAAC,aAAa,EAAE,qGAAqG,CAAC;SAC5H,MAAM,CAAC,kBAAkB,EAAE,kGAAkG,EAAE,OAAO,EAAE,EAAc,CAAC;SACvJ,MAAM,CAAC,mBAAmB,EAAE,yHAAyH,EAAE,OAAO,EAAE,EAAc,CAAC;SAC/K,MAAM,CAAC,QAAQ,EAAE,sBAAsB,CAAC;SACxC,MAAM,CAAC,UAAyB,KAAe;QAC9C,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAyE,CAAC;QAC7F,IAAI,CAAC,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,+DAA+D,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;YAC5H,OAAO;QACT,CAAC;QACD,uGAAuG;QACvG,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;YACxE,OAAO;QACT,CAAC;QACD,8FAA8F;QAC9F,MAAM,IAAI,GACR,CAAC,CAAC,GAAG,KAAK,SAAS;YACjB,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,QAAQ,EAAE;YAC3B,CAAC,CAAC,EAAE,SAAS,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;QACpG,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACnD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC;QACnE,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACpB,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;YACpC,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,CAAC,CAAC,KAAK;gBAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,UAAU,IAAI,CAAC,cAAc,CAAC,CAAC;iBAC3E,CAAC;gBACJ,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;gBACjC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ;oBAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;QACD,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;YAChD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK;gBAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACrD,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAClE,OAAO,CAAC,eAAe,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9D,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC9B,CAAC,CAAC,CAAC;AACP,CAAC"}
|