@penvhq/cli 0.3.1 → 0.3.2

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/doctor.ts","../src/project.ts","../src/registry.ts","../src/schema.ts","../src/ui.ts","../src/commands/push.ts","../src/commands/validate.ts","../src/commands/encrypt.ts","../src/commands/set.ts","../src/commands/fill.ts","../src/commands/generate.ts","../src/commands/get.ts","../src/commands/import.ts","../src/detect.ts","../src/commands/init.ts","../src/commands/key.ts","../src/keychain.ts","../src/commands/list.ts","../src/commands/mv.ts","../src/commands/pull.ts","../src/commands/remove.ts","../src/commands/rotate.ts","../src/commands/watch.ts"],"sourcesContent":["/**\n * penv's command line.\n *\n * The wiring here is deliberately thin: every command's real work is a plain\n * exported function that takes a `cwd` and returns a result, and citty only\n * parses arguments, calls it, and prints what it returned. That is what lets the\n * tests call the commands rather than spawn them.\n */\n\nimport { setKeychain } from \"@penvhq/core\";\nimport { runMain as cittyRunMain, defineCommand } from \"citty\";\nimport { doctorCommand } from \"./commands/doctor.js\";\nimport { decryptCommand, encryptCommand } from \"./commands/encrypt.js\";\nimport { fillCommand } from \"./commands/fill.js\";\nimport { generateCommand } from \"./commands/generate.js\";\nimport { getCommand } from \"./commands/get.js\";\nimport { importCommand } from \"./commands/import.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { keyCommand } from \"./commands/key.js\";\nimport { listCommand } from \"./commands/list.js\";\nimport { mvCommand } from \"./commands/mv.js\";\nimport { pullCommand } from \"./commands/pull.js\";\nimport { pushCommand } from \"./commands/push.js\";\nimport { removeCommand } from \"./commands/remove.js\";\nimport { rotateCommand } from \"./commands/rotate.js\";\nimport { setCommand } from \"./commands/set.js\";\nimport { validateCommand } from \"./commands/validate.js\";\nimport { watchCommand } from \"./commands/watch.js\";\nimport { defaultKeychain } from \"./keychain.js\";\n\nexport const main = defineCommand({\n meta: {\n name: \"penv\",\n description: \"Configuration that shares a data model with your production secret manager\",\n },\n subCommands: {\n init: initCommand,\n import: importCommand,\n generate: generateCommand,\n get: getCommand,\n set: setCommand,\n fill: fillCommand,\n mv: mvCommand,\n pull: pullCommand,\n push: pushCommand,\n rotate: rotateCommand,\n remove: removeCommand,\n list: listCommand,\n encrypt: encryptCommand,\n decrypt: decryptCommand,\n key: keyCommand,\n validate: validateCommand,\n doctor: doctorCommand,\n watch: watchCommand,\n },\n});\n\nexport function runMain(): Promise<void> {\n // The CLI is where the keychain is read and written; core stays native-free and\n // the runtime never registers a binding. Idempotent, and the binding is lazy —\n // the native module loads only if a keychain key is actually touched.\n setKeychain(defaultKeychain);\n return cittyRunMain(main);\n}\n\nexport type {\n DoctorCheck,\n DoctorFinding,\n DoctorReport,\n DoctorSeverity,\n} from \"./commands/doctor.js\";\nexport { renderDoctor, runDoctor } from \"./commands/doctor.js\";\nexport type { ResealResult } from \"./commands/encrypt.js\";\nexport { runDecrypt, runEncrypt } from \"./commands/encrypt.js\";\nexport type { FillOptions, FillPrompt, FillResult } from \"./commands/fill.js\";\nexport { renderFill, runFill } from \"./commands/fill.js\";\nexport type { GenerateResult } from \"./commands/generate.js\";\nexport { generateDotenv, runGenerate } from \"./commands/generate.js\";\nexport type { GetExplanation } from \"./commands/get.js\";\nexport { runExplain, runGet } from \"./commands/get.js\";\nexport type { ImportReport } from \"./commands/import.js\";\nexport { importDotenv } from \"./commands/import.js\";\nexport type { InitResult, InitStep } from \"./commands/init.js\";\nexport { insertEnvAlias, runInit } from \"./commands/init.js\";\nexport type { ListResult } from \"./commands/list.js\";\nexport { runList } from \"./commands/list.js\";\nexport type { MoveResult } from \"./commands/mv.js\";\nexport { renderMove, runMove } from \"./commands/mv.js\";\nexport type { PullOptions, PullResult } from \"./commands/pull.js\";\nexport { renderPull, runPull } from \"./commands/pull.js\";\nexport type { PushOptions, PushResult } from \"./commands/push.js\";\nexport { LAST_PUSHED_KEY, renderPush, runPush } from \"./commands/push.js\";\nexport type { RemoveResult } from \"./commands/remove.js\";\nexport { runRemove } from \"./commands/remove.js\";\nexport type { RotateOptions, RotatePhase, RotateResult } from \"./commands/rotate.js\";\nexport { renderRotate, runRotate } from \"./commands/rotate.js\";\nexport type { SetResult } from \"./commands/set.js\";\nexport { runSet } from \"./commands/set.js\";\nexport type { ValidateIssue, ValidateResult } from \"./commands/validate.js\";\nexport { runValidate } from \"./commands/validate.js\";\nexport type { WatchHandle, WatchOptions } from \"./commands/watch.js\";\nexport { renderWatch, runWatch } from \"./commands/watch.js\";\n","/**\n * `penv doctor` — one report of everything that has drifted.\n *\n * Each check earns its place by catching something no other command can:\n *\n * - **missing** — meta marks a parameter required for this environment and it\n * resolves to nothing. Requiredness per environment is meta policy, not a\n * second schema (invariant 1).\n * - **declared** — the schema declares a parameter the tree has no value for.\n * The other half of the same distance `unused` measures, and a different\n * question from `missing`: this one is asked of the schema and answered for\n * every declared key, including one with no file anywhere — which no\n * tree-driven check can see, because a parameter with no file has no meta\n * either. It reports, and never writes: see `../schema.ts`.\n * - **weak** — the schema declares a minimum length the value does not meet.\n * - **unused** — a value file exists that the schema has no key for.\n * - **unscoped-fallback** — a real environment resolving via the unscoped\n * default. Invariant 13: fallback is never silent.\n * - **plaintext-secret** — meta declares the parameter a secret and the winning\n * value file carries no `.enc` marker. Invariant 14: encryption is\n * policy-driven, so the filename is checked *against* the policy and is never\n * the authority on what is secret.\n * - **public-secret** — meta declares the parameter a secret and its generated\n * variable carries a prefix the framework inlines into the client bundle.\n * - **rotation-overdue** — meta declares a rotation policy and more than its\n * interval has elapsed since the last completed rotation. A clock no other\n * check keeps: `missing` sees an absent value, never a stale present one.\n * - **rotation-stuck** — a `dual-valid` grace window opened and never closed. The\n * overdue clock's opposite: not a rotation that never ran, but one that started\n * and stalled with two credentials live at once.\n * - **provider-value-drift** — the local tree and the environment's readable\n * source-of-truth provider hold different opaque values for the same address.\n * The one drift the write-only sink can never report, because a provider can be\n * read back and a sink cannot.\n *\n * Warnings are reported; failures are reported and exit non-zero.\n */\n\nimport type {\n Meta,\n PenvConfig,\n Provider,\n Resolution,\n Scope,\n SecretScope,\n Sink,\n SinkConfig,\n SinkSecret,\n ValueFile,\n} from \"@penvhq/core\";\nimport {\n accessPath,\n assertNever,\n effectiveMeta,\n formatValueFile,\n isPublicVariable,\n isRequired,\n isSecret,\n isStuck,\n openValue,\n resolveAll,\n rotationOf,\n tryParseDuration,\n variableName,\n} from \"@penvhq/core\";\nimport { createGithubSink } from \"@penvhq/sink-github\";\nimport { defineCommand } from \"citty\";\nimport type { z } from \"zod\";\nimport type { Project } from \"../project.js\";\nimport { keySourceFor, openProject, sourceProviderFor, targetEnvironment } from \"../project.js\";\nimport { LOCAL_TREE_TYPE } from \"../registry.js\";\nimport type { DriftReport } from \"../schema.js\";\nimport { computeDrift, lookup, minLengthOf } from \"../schema.js\";\nimport { CHECK, formatRows, guard, type Row, UNKNOWN, WARN, write } from \"../ui.js\";\nimport { LAST_PUSHED_KEY } from \"./push.js\";\nimport { loadSchema } from \"./validate.js\";\n\n/**\n * A check reports one of four verdicts. `unknown` — a check that ran but could\n * not reach a verdict — is never rendered as a pass: \"I looked and found nothing\n * wrong\" and \"I could not look\" are opposite situations with opposite remedies,\n * and a write-only sink makes most of what doctor can say the second kind.\n */\nexport type DoctorSeverity = \"pass\" | \"warning\" | \"failure\" | \"unknown\";\n\nexport type DoctorCheck =\n | \"schema\"\n | \"missing\"\n | \"declared\"\n | \"weak\"\n | \"unused\"\n | \"unscoped-fallback\"\n | \"plaintext-secret\"\n | \"public-secret\"\n | \"encryption\"\n | \"rotation-overdue\"\n | \"rotation-stuck\"\n | \"provider-value-drift\"\n | \"provider\"\n | \"sink-unreachable\"\n | \"sink-name-drift\"\n | \"sink-manual-edit\"\n | \"sink-value-drift\";\n\nexport interface DoctorFinding {\n readonly check: DoctorCheck;\n readonly severity: DoctorSeverity;\n readonly label: string;\n readonly subject?: string;\n readonly detail?: string;\n /** A line the reader can act on — the `penv set` to paste, where there is one. */\n readonly remedy?: string;\n}\n\nexport interface DoctorReport {\n readonly environment: string;\n readonly findings: readonly DoctorFinding[];\n /** False when any finding is a failure. Warnings and unknowns do not fail the run. */\n readonly ok: boolean;\n}\n\nexport interface DoctorOptions {\n readonly cwd: string;\n readonly environment?: string;\n /** Injected in tests: the sink to check against. Defaults to the one the config declares. */\n readonly sink?: Sink;\n /**\n * Injected in tests: the source-of-truth provider to compare the local tree\n * against. Defaults to the one the config declares (`sourceProviderFor`).\n * Mirrors `sink`, for the same reason — the drift checks stay driveable without\n * a live backend.\n */\n readonly source?: Provider;\n /** Injected in tests: the wall-clock reading the rotation clocks are read against. Defaults to now. */\n readonly now?: string;\n /** Injected in tests: how long a `dual-valid` window may stay open before it reads as stuck. Defaults to 24h. */\n readonly stuckThresholdMs?: number;\n}\n\n/**\n * How long a `dual-valid` grace window may stay open before `rotation-stuck`\n * flags it. A day is generous for the overlap most rotations need — long enough\n * that a healthy rotation completing within a deploy or two never trips it, short\n * enough that a window left open for a week is caught while it still matters.\n */\nconst STUCK_THRESHOLD_MS = 86_400_000;\n\ninterface Subject {\n readonly resolution: Resolution;\n readonly meta: Meta | undefined;\n}\n\n/**\n * A check the schema failure above made impossible: `unknown`, not `warning`.\n * penv did not look, so it cannot claim there is nothing to find — and it cannot\n * claim a problem either. The verdict is \"I could not tell\".\n */\nfunction skipped(check: DoctorCheck, label: string): DoctorFinding {\n return {\n check,\n severity: \"unknown\",\n label,\n subject: \"not checked\",\n detail: \"the schema did not load, so this check could not run\",\n };\n}\n\nexport async function runDoctor(options: DoctorOptions): Promise<DoctorReport> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const findings: DoctorFinding[] = [];\n // The wall clock, read once and passed down — never read inside a check — so the\n // rotation boundaries the roadmap names are testable without mocking time, the\n // same discipline `rotation.ts` and `push.ts` keep.\n const now = new Date(options.now ?? new Date().toISOString());\n const stuckThresholdMs = options.stuckThresholdMs ?? STUCK_THRESHOLD_MS;\n\n const { schema, issues } = await loadSchema(project, environment);\n if (schema !== undefined) {\n findings.push({ check: \"schema\", severity: \"pass\", label: \"Schema valid\" });\n } else {\n for (const issue of issues) {\n findings.push({\n check: \"schema\",\n severity: \"failure\",\n label: \"Schema\",\n subject: issue.subject,\n detail: issue.message,\n });\n }\n }\n\n const resolutions = await resolveAll(\n environment,\n project.provider,\n keySourceFor(project, environment),\n );\n const subjects: Subject[] = await Promise.all(\n resolutions.map(async (resolution) => ({\n resolution,\n meta: await project.provider.readMeta(resolution.ref),\n })),\n );\n\n const missing = missingFindings(subjects, environment);\n findings.push(...missing);\n // A check that could not run says so. Printing nothing where a check belongs\n // reads as \"nothing found\", which is the one thing a report must never imply.\n if (schema === undefined) {\n findings.push(\n skipped(\"declared\", \"Schema coverage\"),\n skipped(\"weak\", \"Secret strength\"),\n skipped(\"unused\", \"Value coverage\"),\n );\n } else {\n const drift = computeDrift({\n schema,\n resolutions: subjects.map(({ resolution }) => resolution),\n config: project.config,\n environment,\n });\n findings.push(...declaredFindings(drift, missing, environment));\n findings.push(...weakFindings(subjects, schema));\n findings.push(...unusedFindings(drift));\n }\n findings.push(...fallbackFindings(subjects, environment));\n findings.push(...plaintextSecretFindings(subjects, environment));\n findings.push(...publicSecretFindings(subjects, environment, project.config));\n findings.push(...encryptionFindings(subjects, environment));\n // The rotation clocks read the environment's SOURCE provider, not `subjects`,\n // whose meta is the local tree's. `penv rotate` writes `rotatingSince` /\n // `state` / `lastRotated` to the source of truth (a `dual-valid` rotation\n // REQUIRES a retaining backend, so its rotating-state meta is never in the\n // local tree at all) — reading `subjects` here saw stale local meta and never\n // fired for a backend-backed environment.\n const rotation = await rotationSubjects(project, environment, subjects, options.source);\n if (rotation.kind === \"unreachable\") {\n findings.push(rotation.finding);\n } else {\n findings.push(...overdueFindings(rotation.subjects, environment, now));\n findings.push(...stuckFindings(rotation.subjects, environment, now, stuckThresholdMs));\n }\n findings.push(...(await providerDriftFindings(project, environment, options.source)));\n findings.push(...(await sinkFindings(project, environment, options.sink)));\n\n findings.push({\n check: \"provider\",\n severity: \"pass\",\n label: \"Provider\",\n subject: project.config.providers[environment]?.type ?? project.provider.type,\n });\n\n return {\n environment,\n findings,\n ok: !findings.some((finding) => finding.severity === \"failure\"),\n };\n}\n\nfunction missingFindings(subjects: readonly Subject[], environment: string): DoctorFinding[] {\n const required = subjects.filter(({ meta }) => isRequired(meta, environment));\n const findings: DoctorFinding[] = required\n .filter(({ resolution }) => resolution.winner === undefined)\n .map(({ resolution }) => ({\n check: \"missing\",\n severity: \"failure\",\n label: \"Missing parameter\",\n subject: resolution.parameter,\n detail: `required for ${environment}, absent`,\n remedy: `penv set ${[...resolution.ref.namespace, resolution.ref.name].join(\"/\")} --env ${environment}`,\n }));\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"missing\",\n severity: \"pass\",\n label: \"Required parameters\",\n subject:\n required.length === 0\n ? `none required for ${environment}`\n : `${required.length} required for ${environment}, all present`,\n },\n ];\n}\n\n/**\n * Schema → tree: declared, with no value for this environment.\n *\n * A warning, not a failure. The schema decides whether an absent value is fatal\n * and `penv validate` is where that verdict is reached; saying it twice, in two\n * voices, would make this report the second authority the design does not have.\n *\n * Parameters the `missing` check already named are dropped rather than repeated:\n * that line is the same absence with meta's stronger verdict on it, and it now\n * carries the same paste line. One absence, one line.\n */\nfunction declaredFindings(\n drift: DriftReport,\n missing: readonly DoctorFinding[],\n environment: string,\n): DoctorFinding[] {\n const reported = new Set(missing.filter((f) => f.severity !== \"pass\").map((f) => f.subject));\n\n const findings: DoctorFinding[] = drift.declared\n .filter((item) => !reported.has(item.subject))\n .map((item) => ({\n check: \"declared\",\n severity: \"warning\",\n label: \"Declared, no value\",\n subject: item.subject,\n detail: item.detail,\n remedy: item.remedy,\n }));\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"declared\",\n severity: \"pass\",\n label: \"Schema coverage\",\n subject: `every parameter .penv/env.ts requires has a value for ${environment}`,\n },\n ];\n}\n\nfunction weakFindings(subjects: readonly Subject[], schema: z.ZodType): DoctorFinding[] {\n const findings: DoctorFinding[] = [];\n let checked = 0;\n\n for (const { resolution } of subjects) {\n const value = resolution.value;\n // A decrypted secret has a value here, so it is length-checked like any\n // other — an encrypted secret used to be invisible to this check, which made\n // \"the schema declares a minimum\" a promise that quietly excluded exactly the\n // values a minimum is for. Absence is two other checks' business: an\n // undecryptable winner is the encryption check's, and nothing at all is the\n // missing check's.\n if (value === undefined) {\n continue;\n }\n const field = lookup(schema, accessPath(resolution.ref));\n if (field.kind !== \"found\") {\n continue;\n }\n const minimum = minLengthOf(field.node);\n if (minimum === undefined) {\n continue;\n }\n checked += 1;\n if (value.length >= minimum) {\n continue;\n }\n findings.push({\n check: \"weak\",\n severity: \"failure\",\n label: \"Weak secret\",\n subject: resolution.parameter,\n detail: `${value.length} chars, schema requires ≥${minimum}`,\n });\n }\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"weak\",\n severity: \"pass\",\n label: \"Secret strength\",\n subject:\n checked === 0\n ? \"no schema field declares a minimum length\"\n : checked === 1\n ? \"1 value meets the schema minimum\"\n : `${checked} values meet the schema minimum`,\n },\n ];\n}\n\n/** Tree → schema: a value the application has no declared way to read. */\nfunction unusedFindings(drift: DriftReport): DoctorFinding[] {\n const findings: DoctorFinding[] = drift.undeclared.map((item) => ({\n check: \"unused\",\n severity: \"warning\",\n label: \"Unused parameter\",\n subject: item.variable,\n detail: \"present, not in schema\",\n }));\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"unused\",\n severity: \"pass\",\n label: \"Value coverage\",\n subject: \"every value file has a schema key\",\n },\n ];\n}\n\nfunction fallbackFindings(subjects: readonly Subject[], environment: string): DoctorFinding[] {\n const findings: DoctorFinding[] = subjects\n .filter(({ resolution }) => resolution.viaUnscopedFallback)\n .map(({ resolution }) => ({\n check: \"unscoped-fallback\",\n severity: \"warning\",\n label: \"Unscoped fallback in use\",\n subject: resolution.parameter,\n detail: `${environment} resolving to default`,\n }));\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"unscoped-fallback\",\n severity: \"pass\",\n label: \"Scoped resolution\",\n subject: `no parameter falls back to the unscoped default for ${environment}`,\n },\n ];\n}\n\nfunction plaintextSecretFindings(\n subjects: readonly Subject[],\n environment: string,\n): DoctorFinding[] {\n const secrets = subjects.filter(({ meta }) => isSecret(meta, environment));\n const findings: DoctorFinding[] = [];\n\n for (const { resolution } of secrets) {\n const winner = resolution.winner;\n // Nothing resolves: that is the missing check's business, not this one's.\n if (winner === undefined || winner.file.encrypted) {\n continue;\n }\n findings.push({\n check: \"plaintext-secret\",\n severity: \"failure\",\n label: \"Plaintext secret\",\n subject: winner.location,\n detail: \"value file is not encrypted\",\n });\n }\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"plaintext-secret\",\n severity: \"pass\",\n label: \"Encryption policy\",\n subject:\n secrets.length === 0\n ? `no parameter is declared secret for ${environment}`\n : `every secret resolving for ${environment} is encrypted`,\n },\n ];\n}\n\n/**\n * The third face of the same policy: is it sealed, can it be opened, and is it\n * public. A secret whose generated variable starts with a framework's public\n * prefix is inlined into the client bundle — `NEXT_PUBLIC_STRIPE_SECRET` reaches\n * every browser that loads the page, permanently, in a bundle nobody can recall.\n *\n * Nothing else in the stack can see this. To the framework the prefix *is* the\n * intent: Next inlines `NEXT_PUBLIC_*` by definition and has no notion that the\n * value is secret. The application's own env module knows the name and not the\n * policy. penv holds both — meta says secret, the name transform says public —\n * so this contradiction is only visible from here.\n *\n * Read of the *generated* variable rather than the parameter name, because a\n * `names` override is what decides the string the framework sees, and it is the\n * one place the prefix can appear with nothing in the tree hinting at it.\n * Absence of a value is deliberately not a reprieve: the name is already wrong,\n * and the next `penv set` is what ships it.\n */\nfunction publicSecretFindings(\n subjects: readonly Subject[],\n environment: string,\n config: PenvConfig,\n): DoctorFinding[] {\n const prefixes = config.publicPrefixes ?? [];\n // Nothing declared, nothing checkable: a prefix penv was never told about is\n // one it cannot recognise. This is the \"I cannot tell\" answer, and it is not\n // the same as a clean report — saying \"no secret is exposed\" here would be a\n // promise made by a check that never looked at anything.\n if (prefixes.length === 0) {\n return [\n {\n check: \"public-secret\",\n severity: \"unknown\",\n label: \"Browser exposure\",\n subject: \"not checked — penv.config.ts declares no `publicPrefixes`\",\n detail: \"penv cannot tell which variables a framework inlines into the browser\",\n },\n ];\n }\n\n const secrets = subjects.filter(({ meta }) => isSecret(meta, environment));\n const findings: DoctorFinding[] = [];\n\n for (const { resolution } of secrets) {\n const variable = variableName(resolution.ref, config);\n if (!isPublicVariable(variable, config)) {\n continue;\n }\n // Which prefix matched is for the message alone; core stays the authority on\n // whether the variable is public at all.\n const prefix = prefixes.find((candidate) => variable.startsWith(candidate));\n findings.push({\n check: \"public-secret\",\n severity: \"failure\",\n label: \"Secret exposed to the browser\",\n subject: variable,\n detail:\n prefix === undefined\n ? \"meta declares this a secret, and its public prefix makes it public\"\n : `meta declares this a secret, and the \\`${prefix}\\` prefix makes it public`,\n remedy:\n \"rename the parameter so it carries no public prefix, or drop `secret` from its meta if it is not one\",\n });\n }\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"public-secret\",\n severity: \"pass\",\n label: \"Browser exposure\",\n subject: `no secret is exposed to the browser for ${environment}`,\n },\n ];\n}\n\n/**\n * The other half of the encryption policy: `plaintext-secret` catches a secret\n * that should be sealed and is not; this catches a sealed value penv cannot open.\n *\n * A failure, not a warning. An unopenable value is indistinguishable from an\n * absent one to everything downstream — the app gets nothing either way — and\n * the whole point of the `undecryptable` field is that penv can tell the\n * difference even when the application cannot.\n */\nfunction encryptionFindings(subjects: readonly Subject[], environment: string): DoctorFinding[] {\n const sealed = subjects.filter(({ resolution }) => resolution.winner?.file.encrypted === true);\n const findings: DoctorFinding[] = [];\n\n for (const { resolution } of sealed) {\n const failure = resolution.undecryptable;\n if (failure === undefined) {\n continue;\n }\n findings.push({\n check: \"encryption\",\n severity: \"failure\",\n label: \"Undecryptable value\",\n subject: resolution.winner?.location ?? resolution.parameter,\n detail: failure.detail,\n });\n }\n\n if (findings.length > 0) {\n return findings;\n }\n // Two different quiets, reported differently. \"Nothing is encrypted here\" and\n // \"everything encrypted here opens\" are both passes, and a reader who cannot\n // tell them apart cannot tell whether the check ran.\n return [\n {\n check: \"encryption\",\n severity: \"pass\",\n label: \"Encryption\",\n subject:\n sealed.length === 0\n ? `no encrypted value resolves for ${environment}`\n : `every encrypted value resolving for ${environment} decrypts`,\n },\n ];\n}\n\n/**\n * A sink report is mostly `unknown` by construction, and honest about it. Three\n * tiers, rendered differently (RFC \"A sink is a destination, not a provider\"):\n *\n * - **names** are exact, because listing them is the one read the destination\n * allows: declared-but-never-pushed, and present-in-the-destination-but-\n * undeclared — the `declared`/`unused` pair pointed at a sink.\n * - **manual edits** are detectable indirectly: GitHub's `updated_at` newer than\n * penv's own last-push time (kept per environment in committed meta) means the\n * secret was touched outside penv. A warning, never a failure — it detects that\n * something was touched, not that the copies differ.\n * - **values** are `unknown`, permanently, because they cannot be read back.\n *\n * The whole report is `unknown` when the destination cannot be reached — the\n * fourth verdict earning its keep against a write-only store.\n */\n/** Slack between penv's local push time and the destination's server `updated_at` before a difference reads as a hand-edit. */\nconst EDIT_SKEW_MS = 120_000;\n\nfunction buildSink(declared: SinkConfig, override: Sink | undefined): Sink | undefined {\n if (override !== undefined) {\n return override;\n }\n if (declared.type === \"github\") {\n return createGithubSink(declared.repo === undefined ? {} : { repo: declared.repo });\n }\n return undefined;\n}\n\nfunction errorDetail(error: unknown): string {\n if (error instanceof Error) {\n return error.message.split(\"\\n\")[0] ?? error.message;\n }\n return String(error);\n}\n\nfunction scopeLabel(scope: SecretScope): string {\n return scope.kind === \"repository\"\n ? \"repository secrets\"\n : `environment secrets for ${scope.environment}`;\n}\n\ninterface Expected {\n readonly ref: Resolution[\"ref\"];\n readonly variable: string;\n readonly scope: SecretScope;\n}\n\nasync function sinkFindings(\n project: Project,\n environment: string,\n override: Sink | undefined,\n): Promise<DoctorFinding[]> {\n const declared = project.config.sinks?.[environment];\n if (declared === undefined) {\n return [];\n }\n\n const sink = buildSink(declared, override);\n if (sink === undefined) {\n return [\n {\n check: \"sink-unreachable\",\n severity: \"unknown\",\n label: \"Sink\",\n subject: `sink type \\`${declared.type}\\` is not one penv knows`,\n detail: \"penv cannot check a sink it cannot build\",\n },\n ];\n }\n\n try {\n await sink.verify();\n } catch (error) {\n return [\n {\n check: \"sink-unreachable\",\n severity: \"unknown\",\n label: \"Sink\",\n subject: `could not reach the ${declared.type} sink for ${environment}`,\n detail: errorDetail(error),\n },\n ];\n }\n\n let repoSecrets: SinkSecret[];\n let envSecrets: SinkSecret[];\n try {\n repoSecrets = await sink.list({ kind: \"repository\" });\n envSecrets = await sink.list({ kind: \"environment\", environment });\n } catch (error) {\n return [\n {\n check: \"sink-unreachable\",\n severity: \"unknown\",\n label: \"Sink\",\n subject: `could not list secrets in the ${declared.type} sink for ${environment}`,\n detail: errorDetail(error),\n },\n ];\n }\n\n // The push view: what a push would place, `.local` dropped, so doctor compares\n // the same set a push would send.\n const resolutions = await resolveAll(\n environment,\n project.provider,\n keySourceFor(project, environment),\n true,\n );\n const expected: Expected[] = [];\n for (const resolution of resolutions) {\n const winner = resolution.winner;\n if (winner === undefined) {\n continue;\n }\n expected.push({\n ref: resolution.ref,\n variable: variableName(resolution.ref, project.config),\n scope:\n winner.file.scope.kind === \"unscoped\"\n ? { kind: \"repository\" }\n : { kind: \"environment\", environment },\n });\n }\n\n // GitHub secret names are case-insensitive, and the pre-flight already refused\n // any case collision, so comparing by uppercase is exact and safe.\n const upper = (name: string): string => name.toUpperCase();\n const repoByName = new Map(repoSecrets.map((secret) => [upper(secret.name), secret]));\n const envByName = new Map(envSecrets.map((secret) => [upper(secret.name), secret]));\n const destOf = (scope: SecretScope): Map<string, SinkSecret> =>\n scope.kind === \"repository\" ? repoByName : envByName;\n\n const nameDrift: DoctorFinding[] = [];\n const expectedEnv = new Set<string>();\n // Every variable this environment maps, at any scope. A repository secret is\n // shared across all environments, so it is \"declared\" as long as *some*\n // parameter produces its name — even one this environment resolves to an\n // environment-scoped override. Judging a repository secret against only this\n // environment's unscoped winners would flag another environment's default.\n const allVariables = new Set<string>();\n for (const item of expected) {\n const key = upper(item.variable);\n allVariables.add(key);\n if (item.scope.kind === \"environment\") {\n expectedEnv.add(key);\n }\n if (!destOf(item.scope).has(key)) {\n nameDrift.push({\n check: \"sink-name-drift\",\n severity: \"warning\",\n label: \"Declared, not pushed\",\n subject: item.variable,\n detail: `resolves for ${environment} but is absent from the ${scopeLabel(item.scope)}`,\n remedy: `penv push --env ${environment}`,\n });\n }\n }\n for (const secret of repoSecrets) {\n if (!allVariables.has(upper(secret.name))) {\n nameDrift.push({\n check: \"sink-name-drift\",\n severity: \"warning\",\n label: \"In destination, not declared\",\n subject: secret.name,\n detail: `a repository secret with no parameter penv pushes for ${environment}`,\n });\n }\n }\n for (const secret of envSecrets) {\n if (!expectedEnv.has(upper(secret.name))) {\n nameDrift.push({\n check: \"sink-name-drift\",\n severity: \"warning\",\n label: \"In destination, not declared\",\n subject: secret.name,\n detail: `an environment secret with no parameter resolving for ${environment}`,\n });\n }\n }\n\n const manualEdits: DoctorFinding[] = [];\n for (const item of expected) {\n const secret = destOf(item.scope).get(upper(item.variable));\n if (secret === undefined) {\n continue;\n }\n const pushed = effectiveMeta(await project.provider.readMeta(item.ref), environment)[\n LAST_PUSHED_KEY\n ];\n if (typeof pushed !== \"string\") {\n continue;\n }\n const destTime = Date.parse(secret.updatedAt);\n const pushTime = Date.parse(pushed);\n // The tolerance absorbs the skew between penv's local clock and GitHub's\n // server clock (and GitHub's whole-second truncation of `updated_at`), so a\n // clean push does not read as an edit. A genuine UI edit lands minutes to\n // days later, well outside it — this is a sensitive detector, not a proof.\n if (Number.isNaN(destTime) || Number.isNaN(pushTime) || destTime <= pushTime + EDIT_SKEW_MS) {\n continue;\n }\n manualEdits.push({\n check: \"sink-manual-edit\",\n severity: \"warning\",\n label: \"Edited outside penv\",\n subject: item.variable,\n detail: `changed in the destination at ${secret.updatedAt}, after penv last pushed it`,\n });\n }\n\n const findings: DoctorFinding[] = [];\n findings.push(\n ...(nameDrift.length > 0\n ? nameDrift\n : [\n {\n check: \"sink-name-drift\" as const,\n severity: \"pass\" as const,\n label: \"Sink names\",\n subject: `every parameter resolving for ${environment} is present, and nothing undeclared is`,\n },\n ]),\n );\n findings.push(\n ...(manualEdits.length > 0\n ? manualEdits\n : [\n {\n check: \"sink-manual-edit\" as const,\n severity: \"pass\" as const,\n label: \"Sink hand-edits\",\n subject: `no secret has changed outside penv since its last push for ${environment}`,\n },\n ]),\n );\n findings.push({\n check: \"sink-value-drift\",\n severity: \"unknown\",\n label: \"Sink values\",\n subject: \"cannot be read back from a write-only destination\",\n detail: \"value drift between the tree and the destination is unknowable by design\",\n });\n return findings;\n}\n\n/** A rough, human-facing span — the largest whole unit that fits. Never precise, and never claims to be. */\nfunction humanizeMs(ms: number): string {\n const abs = Math.max(0, ms);\n const day = 86_400_000;\n const hour = 3_600_000;\n const minute = 60_000;\n const round = (value: number, unit: string): string => {\n const n = Math.round(value);\n return `${n} ${unit}${n === 1 ? \"\" : \"s\"}`;\n };\n if (abs >= day) return round(abs / day, \"day\");\n if (abs >= hour) return round(abs / hour, \"hour\");\n if (abs >= minute) return round(abs / minute, \"minute\");\n return round(abs / 1000, \"second\");\n}\n\n/** The `<namespace>/<name>` path a `penv rotate` remedy pastes. */\nfunction refPathOf(ref: Resolution[\"ref\"]): string {\n return [...ref.namespace, ref.name].join(\"/\");\n}\n\n/**\n * The rotation clocks read the environment's source of truth, so this reads each\n * parameter's meta from the SOURCE provider rather than the local tree.\n *\n * `penv rotate` writes rotation state (`rotatingSince` / `state` / `lastRotated`)\n * to `sourceProviderFor(environment)` — a backend for a vault/mock env — and a\n * `dual-valid` rotation cannot run without one, so a backend-backed env's\n * rotating-state meta is NEVER in the local `.penv` tree. Reading `subjects`\n * (whose meta is the local tree's) left the overdue/stuck checks reading stale\n * local meta that never fired.\n *\n * When the source IS the local tree — the env declares no backend, or declares\n * `filesystem` — the two coincide, so the metas already read for `subjects` are\n * reused rather than round-tripping the identical files a second time. A backend\n * is read once, wrapped in try/catch: an unreachable source yields a single\n * `unknown` rotation finding, mirroring `sinkFindings`' tiering, because \"the\n * clock says overdue\" and \"penv could not read the clock\" are opposite verdicts.\n */\ntype RotationSubjects =\n | { readonly kind: \"read\"; readonly subjects: readonly Subject[] }\n | { readonly kind: \"unreachable\"; readonly finding: DoctorFinding };\n\nasync function rotationSubjects(\n project: Project,\n environment: string,\n local: readonly Subject[],\n override: Provider | undefined,\n): Promise<RotationSubjects> {\n const providerConfig = project.config.providers[environment];\n // No override and a local-tree source: the meta is the same meta `subjects`\n // already hold, so reuse it and make no extra round-trips.\n if (\n override === undefined &&\n (providerConfig === undefined || providerConfig.type === LOCAL_TREE_TYPE)\n ) {\n return { kind: \"read\", subjects: local };\n }\n\n const source = override ?? (await sourceProviderFor(project, environment));\n try {\n const subjects: Subject[] = await Promise.all(\n local.map(async ({ resolution }) => ({\n resolution,\n meta: await source.readMeta(resolution.ref),\n })),\n );\n return { kind: \"read\", subjects };\n } catch (error) {\n return {\n kind: \"unreachable\",\n finding: {\n check: \"rotation-overdue\",\n severity: \"unknown\",\n label: \"Rotation\",\n subject: `could not reach the ${providerConfig?.type ?? source.type} source of truth for ${environment}`,\n detail: errorDetail(error),\n },\n };\n }\n}\n\n/**\n * A staleness clock no other check keeps: `missing` reports a value that is\n * absent, and this reports one that is present and too old. The two are opposite\n * failures — a value nobody set, and a value nobody has changed in longer than\n * its own policy allows — and only meta's `rotationPolicy` plus `lastRotated`\n * make the second visible at all.\n *\n * The policy is parsed ONCE, here, inside `tryParseDuration`. The old code called\n * `isOverdue` (which parses via the throwing `parseDuration`) in this unguarded\n * loop, then parsed a SECOND time for the `overdueBy` text — so a single policy\n * `parseDuration` rejects (`1h30m`, `3 months`) threw straight out and aborted\n * the entire doctor run through `guard()`, blinding every other check on one bad\n * meta field. Now an unparseable policy is a warning on that one parameter and\n * the sweep continues, and the single parsed interval feeds both the overdue\n * decision and the message. A parameter with no policy, or one that has never\n * rotated, is not on a clock and is silently not overdue.\n */\nfunction overdueFindings(\n subjects: readonly Subject[],\n environment: string,\n now: Date,\n): DoctorFinding[] {\n const findings: DoctorFinding[] = [];\n for (const { resolution, meta } of subjects) {\n const { policy, lastRotated } = rotationOf(meta, environment);\n // Not on a clock: no interval declared, or never rotated. Not late.\n if (policy === undefined || lastRotated === null) {\n continue;\n }\n // Parse once, non-throwing. A policy penv cannot read used to throw here and\n // abort the whole run; now it is this parameter's own warning and nothing\n // else is lost.\n const interval = tryParseDuration(policy);\n if (interval === undefined) {\n findings.push({\n check: \"rotation-overdue\",\n severity: \"warning\",\n label: \"Rotation policy invalid\",\n subject: resolution.parameter,\n detail: `rotationPolicy \\`${policy}\\` is not a duration penv can parse (e.g. \\`90d\\`, \\`24h\\`)`,\n });\n continue;\n }\n const last = Date.parse(lastRotated);\n if (Number.isNaN(last)) {\n continue;\n }\n // The same boundary `isOverdue` keeps: exactly at the interval is not yet\n // overdue, strictly past it is. Reusing `interval` is what kills the second\n // parse the old `overdueBy` line made.\n const overdueBy = now.getTime() - last - interval;\n if (overdueBy <= 0) {\n continue;\n }\n findings.push({\n check: \"rotation-overdue\",\n severity: \"warning\",\n label: \"Rotation overdue\",\n subject: resolution.parameter,\n detail: `overdue by ~${humanizeMs(overdueBy)}, policy ${policy}`,\n remedy: `penv rotate ${refPathOf(resolution.ref)} --env ${environment}`,\n });\n }\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"rotation-overdue\",\n severity: \"pass\",\n label: \"Rotation freshness\",\n subject: `no parameter is past its rotation policy for ${environment}`,\n },\n ];\n}\n\n/**\n * The overdue clock's opposite: not a rotation that never ran, but one that\n * started and stalled. A `dual-valid` window is meant to open, let readers move\n * over, and close; a `rotatingSince` older than the threshold is a window that\n * opened and never did.\n *\n * Gated to `dual-valid` entirely — `isStuck` refuses every other mechanism, and\n * that refusal is the point. An `atomic-cutover` parameter overlaps only at the\n * infra layer and holds no penv-layer grace window, so a long-lived\n * `rotatingSince` on one is not stuck and must never be flagged; this check keeps\n * that promise by asking `isStuck` and never re-deriving the mechanism itself.\n */\nfunction stuckFindings(\n subjects: readonly Subject[],\n environment: string,\n now: Date,\n stuckThresholdMs: number,\n): DoctorFinding[] {\n const findings: DoctorFinding[] = [];\n for (const { resolution, meta } of subjects) {\n if (!isStuck(meta, environment, now, stuckThresholdMs)) {\n continue;\n }\n const { rotatingSince } = rotationOf(meta, environment);\n // isStuck was true, so the window is open with a parseable clock; the guard is\n // for the types, not a reachable path.\n if (rotatingSince === null) {\n continue;\n }\n const openFor = now.getTime() - Date.parse(rotatingSince);\n findings.push({\n check: \"rotation-stuck\",\n severity: \"warning\",\n label: \"Rotation stuck\",\n subject: resolution.parameter,\n detail: `dual-valid window open ~${humanizeMs(openFor)}, past the ${humanizeMs(stuckThresholdMs)} grace window`,\n remedy: `penv rotate ${refPathOf(resolution.ref)} --complete --env ${environment}`,\n });\n }\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"rotation-stuck\",\n severity: \"pass\",\n label: \"Rotation progress\",\n subject: `no dual-valid rotation has stayed open past its grace window for ${environment}`,\n },\n ];\n}\n\n/** One value file the drift check has read, kept with its raw stored string so a sealed local value can still be opened. */\ninterface DriftEntry {\n readonly file: ValueFile;\n readonly stored: string;\n}\n\n/**\n * The LOGICAL identity of a value file — namespace, name, and scope — with the\n * `.enc` marker deliberately dropped.\n *\n * `formatValueFile` encodes `encrypted`, so keying by it split an encrypted-local\n * value from its plaintext-source twin: the same logical parameter at the same\n * scope read as two one-sided addresses, a perpetual false drift the byte compare\n * never got to run. Encryption is a property of the local envelope, not of the\n * address, so it must not be part of the key two stores are matched on. Mirrors\n * the mock provider's `valueKey`, minus exactly that `encrypted` field.\n */\nfunction driftKey(file: ValueFile): string {\n return [file.namespace.join(\"/\"), file.name, scopeKey(file.scope)].join(\" \");\n}\n\nfunction scopeKey(scope: Scope): string {\n switch (scope.kind) {\n case \"unscoped\":\n return \"unscoped\";\n case \"environment\":\n return `environment:${scope.environment}`;\n case \"local\":\n return \"local\";\n case \"environment-local\":\n return `environment-local:${scope.environment}`;\n default:\n return assertNever(scope, \"scope\");\n }\n}\n\n/**\n * The value files that have a source-of-truth twin to drift against: the pushable\n * set for this environment — the unscoped default and this environment's own\n * scope, and nothing else.\n *\n * The old check compared the ENTIRE local tree (`project.provider.list()` is\n * every environment's files) against one env's source, so `doctor --env\n * production` flooded \"Only in the local tree\" for every development/staging\n * value. Both `.local` scopes are personal and never reach a backend; every other\n * environment's scoped file is that environment's business, not this one's. The\n * same filter is applied to both sides.\n */\nfunction relevantToEnvironment(file: ValueFile, environment: string): boolean {\n const scope = file.scope;\n if (scope.kind === \"unscoped\") return true;\n if (scope.kind === \"environment\") return scope.environment === environment;\n // Both `.local` scopes, and every other environment's scope: not pushed here.\n return false;\n}\n\n/**\n * Reads a provider's value files relevant to this environment into a logical\n * address → entry map, the raw stored strings kept unopened.\n *\n * Values are read in `list` order and mapped afterwards, so a same-address\n * collision (a plaintext and a sealed file at one scope) resolves the same way on\n * every machine rather than by Promise race. An address that `list` names but\n * `read` returns absent — a concurrent prune — is dropped, nothing to compare.\n */\nasync function readRelevant(\n provider: Provider,\n environment: string,\n): Promise<Map<string, DriftEntry>> {\n const files = (await provider.list()).filter((file) => relevantToEnvironment(file, environment));\n const stored = await Promise.all(files.map((file) => provider.read(file)));\n const entries = new Map<string, DriftEntry>();\n for (const [index, file] of files.entries()) {\n const value = stored[index];\n if (value !== undefined) {\n entries.set(driftKey(file), { file, stored: value });\n }\n }\n return entries;\n}\n\n/**\n * The one drift the sink can never report. `sink-value-drift` is permanently\n * `unknown` because a write-only destination cannot be read back; a provider is\n * the system of record precisely because it can, so here penv actually looks —\n * comparing PLAINTEXT, value by value.\n *\n * Custody model: the source of truth holds verbatim plaintext (the way `pull` and\n * `rotate` move it there), while the local tree may hold the value sealed. So a\n * sealed local value is opened before the compare — an encrypted-local vs\n * plaintext-source pair carrying the same secret is IN SYNC, not drift. A sealed\n * value that cannot be opened (the key is gone) is `unknown` for that parameter,\n * never a false disagreement: penv could not read one side, so it cannot say the\n * two agree or differ.\n *\n * When the environment keeps its values in the local tree there is no second\n * system of record, so this is a plain `pass` — \"not applicable\", never\n * `unknown`: penv could look and there was one copy by design. An unreachable\n * source *is* `unknown`, mirroring `sinkFindings`' try/catch tiering: a differing\n * value and an unreachable store are opposite verdicts with opposite remedies.\n */\nasync function providerDriftFindings(\n project: Project,\n environment: string,\n override: Provider | undefined,\n): Promise<DoctorFinding[]> {\n const providerConfig = project.config.providers[environment];\n if (providerConfig === undefined || providerConfig.type === LOCAL_TREE_TYPE) {\n return [\n {\n check: \"provider-value-drift\",\n severity: \"pass\",\n label: \"Provider values\",\n subject: `${environment} keeps its values in the local .penv tree, so there is no other source of truth to compare against`,\n },\n ];\n }\n\n const source = override ?? (await sourceProviderFor(project, environment));\n\n let local: Map<string, DriftEntry>;\n let remote: Map<string, DriftEntry>;\n try {\n local = await readRelevant(project.provider, environment);\n remote = await readRelevant(source, environment);\n } catch (error) {\n return [\n {\n check: \"provider-value-drift\",\n severity: \"unknown\",\n label: \"Provider values\",\n subject: `could not reach the ${providerConfig.type} provider for ${environment}`,\n detail: errorDetail(error),\n },\n ];\n }\n\n const keys = keySourceFor(project, environment);\n const findings: DoctorFinding[] = [];\n // Sorted so the report is identical on every machine, the same rule `refsFrom` keeps.\n const addresses = [...new Set([...local.keys(), ...remote.keys()])].sort();\n for (const address of addresses) {\n const here = local.get(address);\n const there = remote.get(address);\n if (here !== undefined && there !== undefined) {\n // Open the local value if it is sealed; the source is verbatim plaintext.\n // `openValue` returns a plaintext file unchanged, so this is unconditional.\n const opened = openValue(here.file, here.stored, keys);\n if (opened.kind !== \"plaintext\") {\n // A sealed value penv cannot open: the key is gone. Not drift — penv\n // could not read this side, so it cannot claim the two stores agree or\n // differ. The opposite of a false failure.\n findings.push({\n check: \"provider-value-drift\",\n severity: \"unknown\",\n label: \"Provider value unreadable\",\n subject: formatValueFile(here.file),\n detail: `the local value is sealed and did not open, so it cannot be compared against the ${providerConfig.type} source of truth`,\n });\n continue;\n }\n // A plaintext comparison. Drift in the system of record is serious: the\n // tree and the backend claim different truths for one address, and\n // something deploys the wrong one.\n if (opened.value !== there.stored) {\n findings.push({\n check: \"provider-value-drift\",\n severity: \"failure\",\n label: \"Provider value drift\",\n subject: formatValueFile(here.file),\n detail: `the local tree and the ${providerConfig.type} source of truth hold different values`,\n });\n }\n continue;\n }\n const present = here ?? there;\n // `present` is defined: the address is in the union, so at least one side has it.\n if (present === undefined) {\n continue;\n }\n findings.push({\n check: \"provider-value-drift\",\n severity: \"warning\",\n label: here !== undefined ? \"Only in the local tree\" : \"Only in the source\",\n subject: formatValueFile(present.file),\n detail:\n here !== undefined\n ? `present locally, absent from the ${providerConfig.type} source of truth`\n : `present in the ${providerConfig.type} source of truth, absent from the local tree`,\n });\n }\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"provider-value-drift\",\n severity: \"pass\",\n label: \"Provider values\",\n subject: `every value matches the ${providerConfig.type} source of truth for ${environment}`,\n },\n ];\n}\n\nexport function renderDoctor(report: DoctorReport): string[] {\n const rows: Row[] = report.findings.map((finding) => ({\n glyph: finding.severity === \"pass\" ? CHECK : finding.severity === \"unknown\" ? UNKNOWN : WARN,\n label: finding.label,\n ...(finding.subject === undefined ? {} : { subject: finding.subject }),\n ...(finding.detail === undefined ? {} : { detail: finding.detail }),\n }));\n\n const lines = formatRows(rows);\n // Below the table rather than beside it: these are lines to paste, and a line\n // to paste has to survive being selected without a report's columns coming\n // with it. Deduped, because two parameters can share a remedy.\n const remedies = [\n ...new Set(\n report.findings\n .filter((finding) => finding.severity !== \"pass\")\n .map((finding) => finding.remedy)\n .filter((remedy): remedy is string => remedy !== undefined),\n ),\n ];\n for (const remedy of remedies) {\n lines.push(` ${remedy}`);\n }\n return lines;\n}\n\nexport const doctorCommand = defineCommand({\n meta: {\n name: \"doctor\",\n description: \"Report missing, weak, unused, fallback, plaintext-secret, and sink-drift issues\",\n },\n args: {\n env: { type: \"string\", description: \"The environment to report on\" },\n },\n run({ args }) {\n return guard(async () => {\n const report = await runDoctor({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n });\n write(renderDoctor(report));\n if (!report.ok) {\n process.exitCode = 1;\n }\n });\n },\n});\n","/**\n * Opening a penv project from a working directory, and the pieces every command\n * needs once it is open: the config, the environment to act on, the provider\n * rooted at `.penv/`, and the parameter a CLI key names.\n */\n\nimport { dirname, resolve } from \"node:path\";\nimport type {\n DecryptFailure,\n KeySource,\n ParameterRef,\n PenvConfig,\n Provider,\n ResolutionCandidate,\n} from \"@penvhq/core\";\nimport {\n candidatesFor,\n formatValueFile,\n isCanonicalSegment,\n isReservedToken,\n loadConfig,\n openValue,\n PenvError,\n parameterId,\n ReservedTokenError,\n refFromAccessPath,\n resolveEnvironment,\n resolveKeySource,\n} from \"@penvhq/core\";\nimport { FilesystemProvider } from \"@penvhq/provider-filesystem\";\nimport {\n assertProvidersRegistered,\n createProvider,\n createSourceProvider,\n LOCAL_TREE_TYPE,\n} from \"./registry.js\";\n\nexport const PENV_DIR = \".penv\";\n\nexport interface Project {\n /** The directory holding `penv.config.ts`. */\n readonly root: string;\n readonly configFile: string;\n readonly config: PenvConfig;\n readonly penvDir: string;\n /**\n * The project's provider, as the contract — never the concrete\n * implementation. Shared commands speak the async interface and nothing more;\n * the sync twins a command genuinely needs are reached through `localTree`,\n * which is the one place the filesystem-only surface is named.\n */\n readonly provider: Provider;\n}\n\nexport function openProject(cwd: string): Project {\n const { config, file } = loadConfig(cwd);\n const root = dirname(file);\n const penvDir = resolve(root, PENV_DIR);\n // Refuse a config naming a provider this build cannot construct here, at open\n // time, rather than as a crash from whichever command first reached it. Plugin\n // types are resolved against the project (`root`), where the user installed them.\n assertProvidersRegistered(config, root);\n return {\n root,\n configFile: file,\n config,\n penvDir,\n provider: createProvider(LOCAL_TREE_TYPE, { root: penvDir, config }),\n };\n}\n\n/**\n * The project's provider as the concrete filesystem tree, for the sync reads and\n * writes a synchronous command cannot get from the async contract.\n *\n * `import`, `generate`, and `push` are synchronous — they are the adoption path\n * and the leaving guarantee — and they act on the local `.penv` tree, which is\n * always the filesystem provider (`penv pull` materialises it; the runtime reads\n * it). This narrows to that provider and names the reliance, so the type of\n * `Project.provider` stays the contract everywhere else. The refusal is a\n * belt-and-braces guard: `openProject` builds the tree as filesystem, so a\n * project in hand always narrows.\n */\nexport function localTree(project: Project): FilesystemProvider {\n if (!(project.provider instanceof FilesystemProvider)) {\n throw new PenvError(\n \"PROVIDER_NOT_LOCAL\",\n `This command reads the local .penv tree synchronously, which the \\`${project.provider.type}\\` provider is not`,\n \"Run this against a filesystem-backed project, or use a command that speaks the async provider contract.\",\n );\n }\n return project.provider;\n}\n\n/**\n * The environment's DECLARED source-of-truth provider — the backend that holds\n * the truth, as opposed to `Project.provider`, which is always the local\n * filesystem tree every command edits.\n *\n * `pull` and cross-provider `doctor` read here: they compare or copy against what\n * the config says the environment's values live in. An environment with no\n * `providers` entry has no separate source of truth, so this falls back to the\n * local tree — the two coincide, and there is nothing to pull from elsewhere.\n * `openProject` is untouched: the working copy stays filesystem regardless.\n */\nexport async function sourceProviderFor(project: Project, environment: string): Promise<Provider> {\n const providerConfig = project.config.providers[environment];\n if (providerConfig === undefined) {\n return createProvider(LOCAL_TREE_TYPE, { root: project.penvDir, config: project.config });\n }\n // A declared backend may be a plugin (`penv-cloud`, a third-party provider), so\n // this goes through the async, plugin-aware path rather than the built-in-only\n // `createProvider`. The local tree above is always a built-in and stays sync.\n return createSourceProvider(providerConfig.type, {\n root: project.penvDir,\n config: project.config,\n providerConfig,\n environment,\n });\n}\n\n/** The environment to act on: `--env`, then `PENV_ENV`, then `NODE_ENV`. */\nexport function targetEnvironment(project: Project, explicit?: string): string {\n return resolveEnvironment(project.config, explicit);\n}\n\n/** A namespace separator on the command line, either spelling. */\nconst KEY_SEPARATOR = /[./\\\\]/;\n\n/**\n * The reserved set for a caller that has no config to hand: the static tokens\n * and nothing else. Environments are a config whitelist (invariant 10), so a\n * caller without a config cannot know which environment names are reserved.\n */\nconst NO_ENVIRONMENTS: PenvConfig = { environments: [], providers: {} };\n\n/**\n * The parameter a CLI key names — `redis/password` and `redis.password` are one.\n *\n * `config` is optional because the reserved set is config-driven: given one,\n * a declared environment name is refused here too; without one, only the static\n * tokens are. Pass the open project's config whenever there is one — this is the\n * early, better-worded half of a check the filename grammar makes again when the\n * file is read, never the only half.\n */\nexport function refFromKey(key: string, config?: PenvConfig): ParameterRef {\n const segments = key.split(KEY_SEPARATOR).filter((segment) => segment.length > 0);\n const name = segments[segments.length - 1];\n if (name === undefined) {\n throw new PenvError(\n \"PARAMETER_KEY\",\n `\\`${key}\\` names no parameter`,\n \"A key is `<namespace>/<name>` or `<namespace>.<name>`, e.g. `redis/password`.\",\n );\n }\n if (isReservedToken(name, config ?? NO_ENVIRONMENTS)) {\n throw new ReservedTokenError(\"parameter\", name, key);\n }\n return { namespace: segments.slice(0, -1), name };\n}\n\n/**\n * Refuses a key that no canonical value file can back — the guard for the *write*\n * path only, `set` and the destination of `mv`.\n *\n * It lives apart from {@link refFromKey} deliberately. Read, remove and the\n * source of a rename address a file that already exists by its literal name, and\n * the filename grammar admits a non-canonical name (`dbHost`, `database_url`)\n * that the transform will never *produce* but a hand-written file or an older\n * penv may already have on disk. Guarding those paths would leave such a tree\n * repairable only by deleting the file by hand — the very lockout this function\n * is here to avoid. So only creation is refused: a `set` or a rename *into* a\n * name the schema cannot read is a file that would sit inert, and refusing it\n * early names the file that actually backs the key instead of writing a dead one.\n */\nexport function assertWritableKey(key: string): void {\n const segments = key.split(KEY_SEPARATOR).filter((s) => s.length > 0);\n if (segments.length === 0 || segments.every((s) => isCanonicalSegment(s))) {\n return;\n }\n const ref = refFromAccessPath(segments);\n if (ref !== undefined) {\n const suggestion = [...ref.namespace, ref.name].join(\"/\");\n throw new PenvError(\n \"PARAMETER_KEY_CASING\",\n `\\`${key}\\` is not a canonical parameter name`,\n `Parameter files are lower-case and hyphenated. Did you mean \\`${suggestion}\\`? That is the file that backs the \\`${key}\\` key in your schema.`,\n );\n }\n throw new PenvError(\n \"PARAMETER_KEY_UNREACHABLE\",\n `No value file can be named that reaches \\`${key}\\``,\n \"Parameter files are lower-case and hyphenated, and this key maps to no such file — a run of capitals like `apiURL` cannot be reached (use `api-url`, which the schema reads as `apiUrl`). Run `penv validate` or `penv fill` to see the names penv expects.\",\n );\n}\n\n/**\n * The key source for one environment, chosen by core.\n *\n * The CLI does not decide where keys live — it asks. Two choosers would be two\n * answers to one question, and the runtime is the other caller: a CLI that\n * sealed under a key the runtime could not find would make `penv set` and `load`\n * disagree about the same file.\n */\nexport function keySourceFor(project: Project, environment: string): KeySource {\n return resolveKeySource(project.config, environment);\n}\n\n/**\n * One parameter resolved against the filesystem, without reading it twice.\n *\n * The winner is a `ResolutionCandidate` rather than a bare `ValueFile` so this\n * satisfies core's `ResolvedValue`: the sync walk and the async one then hand the\n * same shape to the same `requireValue`, and there is one place that decides\n * what an unreadable value is.\n */\nexport interface SyncResolution {\n readonly ref: ParameterRef;\n readonly parameter: string;\n /** `undefined` when nothing is present, or when the winner did not open. */\n readonly value: string | undefined;\n readonly winner: ResolutionCandidate | undefined;\n /** Set only when the winner is `.enc` and did not decrypt. Mirrors `Resolution`. */\n readonly undecryptable?: DecryptFailure;\n}\n\n/**\n * The synchronous half of the cascade.\n *\n * `import` and `generate` are synchronous — they are the adoption path, and the\n * v0.1 gate exercises them as plain calls — while the provider contract is\n * async because a network-backed provider cannot be anything else. This walks\n * the filesystem provider's *additional* sync reads, exactly as the runtime\n * loader does for the same reason. It does not restate the precedence rule:\n * `candidatesFor` owns the order, and this only walks the list it returns.\n */\nexport function resolveSync(\n provider: FilesystemProvider,\n ref: ParameterRef,\n environment: string,\n keys: KeySource,\n skipPersonal?: boolean,\n): SyncResolution {\n for (const file of candidatesFor(ref, environment, skipPersonal)) {\n const read = provider.readSync(file);\n if (read === undefined) {\n continue;\n }\n // Unconditional, including for a plaintext file, which comes back verbatim:\n // a branch on `file.encrypted` here would be a second place deciding what\n // encryption means, and this walker is already the second walker.\n const opened = openValue(file, read, keys);\n return {\n ref,\n parameter: parameterId(ref),\n value: opened.kind === \"plaintext\" ? opened.value : undefined,\n ...(opened.kind === \"failed\" ? { undecryptable: opened.failure } : {}),\n winner: { file, location: formatValueFile(file), present: true },\n };\n }\n return { ref, parameter: parameterId(ref), value: undefined, winner: undefined };\n}\n\nexport function resolveAllSync(\n provider: FilesystemProvider,\n environment: string,\n keys: KeySource,\n skipPersonal?: boolean,\n): SyncResolution[] {\n return refsFrom(provider.listSync()).map((ref) =>\n resolveSync(provider, ref, environment, keys, skipPersonal),\n );\n}\n\n/**\n * The parameters a provider holds, scopes collapsed and ordered identically\n * everywhere.\n */\nexport function refsFrom(files: readonly ParameterRef[]): ParameterRef[] {\n const refs = new Map<string, ParameterRef>();\n for (const file of files) {\n const ref: ParameterRef = { namespace: file.namespace, name: file.name };\n const id = parameterId(ref);\n if (!refs.has(id)) {\n refs.set(id, ref);\n }\n }\n // Code-unit order, not locale order: a report must be identical on every machine.\n return [...refs.values()].sort((a, b) => {\n const left = parameterId(a);\n const right = parameterId(b);\n return left < right ? -1 : left > right ? 1 : 0;\n });\n}\n","/**\n * The provider registry: the one place the CLI turns a `providers.*.type` into a\n * concrete provider.\n *\n * It lives in the CLI, not in `@penvhq/core` and not in `@penvhq/runtime`. Core owns\n * the `Provider` *contract* and must not know which implementations exist —\n * knowing would make the interface answerable to its callers. The runtime never\n * selects a provider at all: it reads the local `.penv` tree whatever an\n * environment declares (see `runtime/src/resolve.ts`), so a registry there would\n * be the ability to dial a network provider at boot, which the design forbids.\n *\n * So the registry is exactly the portability seam. A built-in provider is one\n * entry in {@link REGISTRY}. A provider that cannot live in this repo — a private\n * or third-party backend — is resolved by convention instead: a `type` with no\n * built-in entry is loaded from the package `@penvhq/provider-<type>` (or the\n * `module` the config names), exactly as ESLint resolves `eslint-plugin-<name>`.\n * Either way, nothing else in the CLI names an implementation.\n */\n\nimport { createRequire } from \"node:module\";\nimport { dirname, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type { PenvConfig, Provider, ProviderConfig } from \"@penvhq/core\";\nimport { PenvError } from \"@penvhq/core\";\nimport { createFilesystemProvider } from \"@penvhq/provider-filesystem\";\nimport { createKubernetesProvider } from \"@penvhq/provider-kubernetes\";\nimport { createMockProvider } from \"@penvhq/provider-mock\";\nimport { createSsmProvider } from \"@penvhq/provider-ssm\";\nimport { createVaultProvider } from \"@penvhq/provider-vault\";\n\n/** What a factory needs to build a provider rooted at one project's `.penv`. */\nexport interface ProviderContext {\n /** The `.penv/` directory, absolute. */\n readonly root: string;\n /**\n * Required because a provider parses environment segments, and a segment is an\n * environment only if the config declares it — never inferred from the store.\n */\n readonly config: PenvConfig;\n /**\n * The one environment's own `providers.*` entry, when building its declared\n * source of truth. Carries provider-side settings — a Vault base `path`, say —\n * that the config authored, never inferred. The local-tree factory ignores it:\n * the filesystem tree is `.penv/` whatever an environment declares.\n */\n readonly providerConfig?: ProviderConfig;\n /**\n * The environment this provider is the source of truth *for*, when that is what\n * is being built. Unused by the filesystem tree, which is one store across\n * every environment.\n */\n readonly environment?: string;\n}\n\n/** Turns a project's `.penv` context into a provider of one `type`. */\nexport type ProviderFactory = (context: ProviderContext) => Provider;\n\n/** The factory shape a convention-loaded provider package exports. May be async. */\ntype PluginProviderFactory = (context: ProviderContext) => Provider | Promise<Provider>;\n\n/** The symbol a provider plugin package exports — the entry point this seam calls. */\nconst PLUGIN_FACTORY_EXPORT = \"penvProviderFactory\";\n\n/**\n * The local `.penv` tree is always served by the filesystem provider: it is the\n * working copy `penv pull` materialises and every command edits, whatever backend\n * an environment's source of truth lives in. Naming it here keeps the one string\n * literal that means \"the tree on disk\" out of `openProject`.\n */\nexport const LOCAL_TREE_TYPE = \"filesystem\";\n\nconst REGISTRY = new Map<string, ProviderFactory>([\n [LOCAL_TREE_TYPE, ({ root, config }) => createFilesystemProvider({ root, config })],\n [\"vault\", ({ providerConfig }) => createVaultProvider({ path: providerConfig?.path ?? \"penv\" })],\n [\"ssm\", ({ providerConfig }) => createSsmProvider({ path: providerConfig?.path ?? \"penv\" })],\n [\n \"kubernetes\",\n ({ providerConfig }) => createKubernetesProvider(kubernetesOptions(providerConfig)),\n ],\n [\"mock\", ({ root }) => createMockProvider({ storePath: resolve(root, \".penv-mock.json\") })],\n]);\n\n/** The contract methods a loaded plugin must carry before penv will trust it. */\nconst CONTRACT_METHODS = [\n \"read\",\n \"write\",\n \"list\",\n \"remove\",\n \"readMeta\",\n \"writeMeta\",\n \"removeMeta\",\n] as const;\n\n/**\n * Loaded plugin modules, memoized by resolved path, so a command touching several\n * environments backed by one package imports it once.\n */\nconst pluginModuleCache = new Map<string, Promise<Record<string, unknown>>>();\n\n/** Whether a `providers.*.type` names a provider penv builds in. */\nexport function isProviderRegistered(type: string): boolean {\n return REGISTRY.has(type);\n}\n\n/**\n * Builds a *built-in* provider of `type`, refusing an unregistered one loudly.\n * This is the synchronous path `openProject` uses for the local filesystem tree,\n * which is always a built-in — so it stays sync and never dials a plugin. A\n * declared source of truth that may be a plugin is built through\n * {@link createSourceProvider} instead.\n */\nexport function createProvider(type: string, context: ProviderContext): Provider {\n const factory = REGISTRY.get(type);\n if (factory === undefined) {\n throw unknownProvider(type);\n }\n return factory(context);\n}\n\n/**\n * Builds a provider of `type`, resolving a non-built-in `type` as a plugin. A\n * built-in comes from the static map (synchronously); anything else is imported\n * from `@penvhq/provider-<type>`, or the config's `module`, and validated against\n * the contract before it is trusted. The import is async, which is why this is —\n * a network or plugin provider cannot be constructed on a synchronous path.\n */\nexport async function createSourceProvider(\n type: string,\n context: ProviderContext,\n): Promise<Provider> {\n if (REGISTRY.has(type)) {\n return createProvider(type, context);\n }\n return loadPluginProvider(type, context);\n}\n\nasync function loadPluginProvider(type: string, context: ProviderContext): Promise<Provider> {\n const fromDir = resolutionBase(context);\n const specifier = pluginSpecifier(context.providerConfig, type);\n\n const resolved = resolvePlugin(specifier, fromDir);\n if (resolved === undefined) {\n throw unknownProvider(type, context.environment, specifier);\n }\n\n let mod: Record<string, unknown>;\n try {\n mod = await importPlugin(resolved);\n } catch {\n throw new PenvError(\n \"PROVIDER_PLUGIN_LOAD\",\n `The provider package \\`${specifier}\\` for type \\`${type}\\` failed to load`,\n \"It resolved but threw while importing. Check it builds and its dependencies are installed.\",\n );\n }\n\n const factory = mod[PLUGIN_FACTORY_EXPORT];\n if (typeof factory !== \"function\") {\n throw new PenvError(\n \"PROVIDER_PLUGIN_INVALID\",\n `\\`${specifier}\\` does not export \\`${PLUGIN_FACTORY_EXPORT}\\``,\n `A penv provider package must export \\`${PLUGIN_FACTORY_EXPORT}(context) => Provider\\`.`,\n );\n }\n\n const provider = await (factory as PluginProviderFactory)(context);\n assertSatisfiesContract(provider, specifier);\n return provider;\n}\n\n/**\n * Refuses at open time every environment whose `providers.*.type` names a backend\n * this project cannot construct — the whole config in one pass, so a user with two\n * unknown providers hears about both, and never as a crash from the later command\n * that would have been the first to reach one.\n *\n * A built-in type passes on the map; a plugin type passes only if its package\n * resolves from the project — a *synchronous* existence check that runs no plugin\n * code, so the open-time guarantee holds without `openProject` turning async. The\n * plugin's module is imported and its contract checked later, when the\n * environment's source is actually built.\n */\nexport function assertProvidersRegistered(config: PenvConfig, projectRoot: string): void {\n for (const [environment, provider] of Object.entries(config.providers)) {\n if (isProviderRegistered(provider.type)) {\n continue;\n }\n const specifier = pluginSpecifier(provider, provider.type);\n if (resolvePlugin(specifier, projectRoot) === undefined) {\n throw unknownProvider(provider.type, environment, specifier);\n }\n }\n}\n\n/** The package a non-built-in `type` loads from: the config's `module`, or the convention. */\nfunction pluginSpecifier(providerConfig: ProviderConfig | undefined, type: string): string {\n return providerConfig?.module ?? `@penvhq/provider-${type}`;\n}\n\n/** The project the user installed the plugin into — where resolution must start. */\nfunction resolutionBase(context: ProviderContext): string {\n // `context.root` is the `.penv/` directory; its parent is the project root,\n // where `penv.config.ts` and the project's `node_modules` live.\n return dirname(context.root);\n}\n\n/**\n * Resolves a plugin specifier from the project, synchronously and without running\n * it. Returns the absolute module path, or `undefined` when the package is not\n * installed. `createRequire` is anchored at the project (not the CLI's own\n * install), so a globally-installed penv still finds a plugin the project depends\n * on.\n */\nfunction resolvePlugin(specifier: string, fromDir: string): string | undefined {\n try {\n const require = createRequire(resolve(fromDir, \"noop.js\"));\n return require.resolve(specifier);\n } catch {\n return undefined;\n }\n}\n\n/** Imports the resolved module by path, memoized, working from both the ESM and CJS builds. */\nfunction importPlugin(resolvedPath: string): Promise<Record<string, unknown>> {\n const cached = pluginModuleCache.get(resolvedPath);\n if (cached !== undefined) {\n return cached;\n }\n const loading = import(pathToFileURL(resolvedPath).href) as Promise<Record<string, unknown>>;\n pluginModuleCache.set(resolvedPath, loading);\n return loading;\n}\n\n/** Fails loudly if a loaded plugin is missing a contract method — at load, not mid-write. */\nfunction assertSatisfiesContract(provider: Provider, specifier: string): void {\n for (const method of CONTRACT_METHODS) {\n if (typeof (provider as unknown as Record<string, unknown>)[method] !== \"function\") {\n throw new PenvError(\n \"PROVIDER_PLUGIN_INVALID\",\n `The provider from \\`${specifier}\\` is missing \\`${method}()\\``,\n \"It must satisfy the @penvhq/core Provider contract that the filesystem provider defines.\",\n );\n }\n }\n}\n\n/**\n * The Kubernetes provider's `providers.*.path` is `<namespace>/<secretName>`, or\n * just `<secretName>` to use the current `kubectl` context's namespace. Splitting\n * it here is what lets a Secret in a non-`default` namespace be reached from config\n * — `ProviderConfig` has no namespace field of its own.\n */\nfunction kubernetesOptions(providerConfig: ProviderConfig | undefined): {\n namespace?: string;\n secretName: string;\n} {\n const path = providerConfig?.path ?? \"penv\";\n const slash = path.indexOf(\"/\");\n if (slash === -1) return { secretName: path };\n const namespace = path.slice(0, slash);\n const secretName = path.slice(slash + 1) || \"penv\";\n return namespace === \"\" ? { secretName } : { namespace, secretName };\n}\n\nfunction unknownProvider(type: string, environment?: string, specifier?: string): PenvError {\n const known = [...REGISTRY.keys()].map((name) => `\\`${name}\\``).join(\", \");\n const where = environment === undefined ? \"\" : ` for environment ${environment}`;\n const remedy =\n specifier === undefined\n ? `This build registers ${known}. Name a registered provider, or install the build that carries \\`${type}\\`.`\n : `Install its package with \\`npm i ${specifier}\\`, or name a built-in provider: ${known}.`;\n return new PenvError(\n \"UNKNOWN_PROVIDER\",\n `The provider type \\`${type}\\`${where} in penv.config.ts is not one this penv build carries`,\n remedy,\n );\n}\n","/**\n * Reading the user's schema, and the distance between it and the parameter tree.\n *\n * `.penv/env.ts` declares what must exist and the tree holds what does. The gap\n * between them is the signal `penv validate` exists to raise; this module makes\n * it legible without closing it. Nothing here writes or deletes a value file —\n * a declaration has no value, so materialising one could only invent it, and an\n * invented value is the silent-value-reaching-runtime failure penv exists to\n * delete. `penv set` stays the only writer.\n *\n * The introspection below lives here, not in `doctor`, because `doctor` and\n * `watch` both report drift and two readers of the same schema would be two\n * answers to one question.\n *\n * Every helper answers \"I cannot tell\" rather than guessing. A report is only\n * worth reading if every line in it is true, so a field this module cannot\n * understand produces no line at all.\n */\n\nimport type { ParameterRef, PenvConfig, Resolution } from \"@penvhq/core\";\nimport {\n accessPath,\n isReservedToken,\n parameterId,\n refFromAccessPath,\n variableName,\n} from \"@penvhq/core\";\nimport type { z } from \"zod\";\n\nfunction defOf(node: unknown): Record<string, unknown> | undefined {\n if (typeof node !== \"object\" || node === null) {\n return undefined;\n }\n const def = (node as { def?: unknown }).def;\n return typeof def === \"object\" && def !== null ? (def as Record<string, unknown>) : undefined;\n}\n\nexport function typeOf(node: unknown): string | undefined {\n const type = defOf(node)?.type;\n return typeof type === \"string\" ? type : undefined;\n}\n\n/** Peels `.optional()`, `.default()`, `.nullable()` — wrappers, not shapes. */\nexport function unwrap(node: unknown): unknown {\n let current = node;\n for (let depth = 0; depth < 8; depth += 1) {\n const inner = defOf(current)?.innerType;\n if (inner === undefined) {\n return current;\n }\n current = inner;\n }\n return current;\n}\n\nexport function shapeOf(node: unknown): Record<string, unknown> | undefined {\n if (typeOf(node) !== \"object\") {\n return undefined;\n }\n const shape = (node as { shape?: unknown }).shape;\n return typeof shape === \"object\" && shape !== null\n ? (shape as Record<string, unknown>)\n : undefined;\n}\n\nexport type Lookup =\n | { readonly kind: \"found\"; readonly node: unknown }\n | { readonly kind: \"absent\" }\n /** The schema is not introspectable this far down. Every check skips it. */\n | { readonly kind: \"unknown\" };\n\nexport function lookup(root: z.ZodType, path: readonly string[]): Lookup {\n let node: unknown = unwrap(root);\n for (const key of path) {\n const shape = shapeOf(node);\n if (shape === undefined) {\n return { kind: \"unknown\" };\n }\n if (!Object.hasOwn(shape, key)) {\n return { kind: \"absent\" };\n }\n node = unwrap(shape[key]);\n }\n return { kind: \"found\", node };\n}\n\n/** The declared minimum length, when the field is a string that declares one. */\nexport function minLengthOf(node: unknown): number | undefined {\n if (typeOf(node) !== \"string\") {\n return undefined;\n }\n const min = (node as { minLength?: unknown }).minLength;\n return typeof min === \"number\" ? min : undefined;\n}\n\n/**\n * Wrappers that make an absent key legal: the schema itself says this parameter\n * need not have a value, so its absence is a declaration, not drift.\n */\nconst ABSENCE_PERMITTED = new Set([\"optional\", \"default\", \"catch\", \"prefault\"]);\n\n/**\n * Wrappers that still demand the key be present. `z.string().nullable()` accepts\n * `null`, which no value file can produce — a missing file is `undefined`, and\n * `undefined` is what the schema rejects. So a nullable field with no value is\n * drift exactly as a bare one is.\n */\nconst ABSENCE_REFUSED = new Set([\"nullable\", \"nonoptional\", \"readonly\"]);\n\n/**\n * Whether the schema permits this field to have no value at all.\n * `undefined` when a wrapper is not recognised — see the module note.\n */\nfunction permitsAbsence(node: unknown): boolean | undefined {\n let current = node;\n for (let depth = 0; depth < 8; depth += 1) {\n const type = typeOf(current);\n if (type !== undefined && ABSENCE_PERMITTED.has(type)) {\n return true;\n }\n const inner = defOf(current)?.innerType;\n if (inner === undefined) {\n // A plain type, wrapped in nothing that excuses absence.\n return type === undefined ? undefined : false;\n }\n if (type === undefined || !ABSENCE_REFUSED.has(type)) {\n // A wrapper this module has never heard of. It may or may not excuse\n // absence, and guessing either way puts an untrue line in the report.\n return undefined;\n }\n current = inner;\n }\n return undefined;\n}\n\n/** One schema key that takes a value: the leaf of a path through the object shapes. */\ninterface Leaf {\n readonly path: readonly string[];\n /** False only when this key, and every namespace above it, must be present. */\n readonly absencePermitted: boolean | undefined;\n}\n\n/**\n * Every leaf the schema declares. An object is a namespace and is descended\n * into; anything else is a value. A branch whose shape cannot be read is left\n * alone rather than reported as a leaf — an unreadable object is not a string.\n *\n * Absence permission is inherited, because it is inherited in fact: under\n * `z.object({ ... }).optional()` the whole namespace may be absent, so every\n * value beneath it may be too, and a leaf judged on its own wrapper would be\n * reported as drift while the schema is perfectly happy without it.\n */\nfunction leaves(\n node: unknown,\n path: readonly string[],\n inherited: boolean | undefined,\n out: Leaf[],\n): void {\n // `undefined` — a wrapper this module does not understand — is inherited as\n // \"cannot tell\" rather than collapsing to false, so an unreadable namespace\n // never makes its children look required.\n const own = permitsAbsence(node);\n const absencePermitted = inherited === true || own === true ? true : combine(inherited, own);\n\n const shape = shapeOf(unwrap(node));\n if (shape === undefined) {\n if (path.length > 0) {\n out.push({ path, absencePermitted });\n }\n return;\n }\n for (const key of Object.keys(shape)) {\n leaves(shape[key], [...path, key], absencePermitted, out);\n }\n}\n\n/** False only when both answers are a definite false; unknown is contagious. */\nfunction combine(left: boolean | undefined, right: boolean | undefined): boolean | undefined {\n return left === undefined || right === undefined ? undefined : false;\n}\n\nexport function declaredLeaves(schema: z.ZodType): Leaf[] {\n const out: Leaf[] = [];\n leaves(schema, [], false, out);\n return out;\n}\n\n/** A parameter `.penv/env.ts` declares that the tree has no value for. */\nexport interface DeclaredDrift {\n /** The parameter id, or the dotted schema path when no filename could reach it. */\n readonly subject: string;\n /** Absent when no filename reaches this key, which is drift `penv set` cannot close. */\n readonly ref?: ParameterRef;\n /** The line to paste: the `penv set` that closes this, or the rename that must precede it. */\n readonly remedy: string;\n readonly detail: string;\n}\n\n/** A parameter the tree holds a value for that `.penv/env.ts` does not declare. */\nexport interface UndeclaredDrift {\n readonly ref: ParameterRef;\n /** The generated variable, which is the name the application would have read. */\n readonly variable: string;\n}\n\n/**\n * The distance between `.penv/env.ts` and the tree, in both directions. Named\n * `declared`/`undeclared` for the side that has it, not for a verdict: neither\n * direction is by itself an error, and only `validate` decides that.\n */\nexport interface DriftReport {\n readonly declared: readonly DeclaredDrift[];\n readonly undeclared: readonly UndeclaredDrift[];\n}\n\nexport const EMPTY_DRIFT: DriftReport = { declared: [], undeclared: [] };\n\nexport interface DriftInput {\n readonly schema: z.ZodType;\n /** Every parameter the tree holds, resolved for `environment`. */\n readonly resolutions: readonly Resolution[];\n readonly config: PenvConfig;\n readonly environment: string;\n}\n\n/**\n * A parameter has a value for this environment when *some* file wins, not when\n * penv can read it: an `.enc` winner is a value that exists, and reporting it as\n * missing would send the user to `penv set` to overwrite a secret they have.\n */\nfunction hasValue(resolution: Resolution): boolean {\n return resolution.winner !== undefined;\n}\n\nexport function computeDrift(input: DriftInput): DriftReport {\n const { schema, resolutions, config, environment } = input;\n\n const valued = new Set(resolutions.filter(hasValue).map((resolution) => resolution.parameter));\n\n const declared: DeclaredDrift[] = [];\n for (const leaf of declaredLeaves(schema)) {\n if (leaf.absencePermitted !== false) {\n continue;\n }\n const path = leaf.path.join(\".\");\n const ref = refFromAccessPath(leaf.path);\n // Declared, and permanently unreachable — two ways, one consequence. Either\n // the key is outside the name transform's image (`apiURL`), or it spells a\n // reserved token, which the filename grammar refuses as a parameter name\n // (invariant 11). No value file resolves to this key either way, so the\n // remedy is a rename: a `penv set` line here would be a command that errors.\n if (ref === undefined || isReservedToken(ref.name, config)) {\n declared.push({\n subject: path,\n remedy:\n `Rename the \\`${path}\\` key in .penv/env.ts — a parameter name is lower-case, ` +\n `hyphenated, and never a reserved token, so no value file reaches this key.`,\n detail: \"declared, no filename reaches it\",\n });\n continue;\n }\n if (valued.has(parameterId(ref))) {\n continue;\n }\n declared.push({\n subject: parameterId(ref),\n ref,\n remedy: `penv set ${[...ref.namespace, ref.name].join(\"/\")} --env ${environment}`,\n detail: `declared in .penv/env.ts, no value for ${environment}`,\n });\n }\n\n const undeclared: UndeclaredDrift[] = [];\n for (const resolution of resolutions) {\n if (lookup(schema, accessPath(resolution.ref)).kind !== \"absent\") {\n continue;\n }\n undeclared.push({\n ref: resolution.ref,\n variable: variableName(resolution.ref, config),\n });\n }\n\n return { declared, undeclared };\n}\n","/**\n * The CLI's output voice.\n *\n * Reports are tables: a glyph, a label, and the parameter the line is about.\n * Columns are sized to the widest cell in one block so that a report reads down\n * the page as well as across it, and every command that reports uses this module\n * rather than assembling its own spacing.\n */\n\nimport { PenvError } from \"@penvhq/core\";\n\nexport const CHECK = \"✓\";\nexport const WARN = \"⚠\";\n/** \"I could not look\" — a check that ran but could not reach a verdict. Never a pass. */\nexport const UNKNOWN = \"?\";\n\n/** One reported line. `detail` is the last column and is never padded. */\nexport interface Row {\n readonly glyph: string;\n readonly label: string;\n readonly subject?: string;\n readonly detail?: string;\n}\n\n/** A step in a scaffolding run: what penv did, and an aligned aside. */\nexport interface Step {\n readonly glyph: string;\n readonly text: string;\n readonly note?: string;\n}\n\n/** Where a step's aside starts, measured from the glyph. */\nconst NOTE_COLUMN = 29;\n\nfunction widest(values: readonly string[]): number {\n return values.reduce((max, value) => Math.max(max, value.length), 0);\n}\n\nexport function formatRows(rows: readonly Row[]): string[] {\n const labelWidth = widest(rows.map((row) => row.label)) + 2;\n // Only rows that carry a detail need their subject padded; a row whose subject\n // is its last column must not widen the table for every other row.\n const detailed = rows.filter((row) => row.detail !== undefined);\n const subjectWidth = widest(detailed.map((row) => row.subject ?? \"\")) + 1;\n\n return rows.map((row) => {\n const head = `${row.glyph} ${row.label.padEnd(labelWidth)}`;\n if (row.detail === undefined) {\n return `${head}${row.subject ?? \"\"}`.trimEnd();\n }\n return `${head}${(row.subject ?? \"\").padEnd(subjectWidth)}${row.detail}`.trimEnd();\n });\n}\n\n/**\n * Free-form aligned columns, for output that is a table rather than a report.\n * Every column but the last is padded to its widest cell.\n */\nexport function columns(rows: readonly (readonly string[])[], gap = 2): string[] {\n const count = rows.reduce((max, row) => Math.max(max, row.length), 0);\n const widths: number[] = [];\n for (let column = 0; column < count; column += 1) {\n widths.push(widest(rows.map((row) => row[column] ?? \"\")) + gap);\n }\n return rows.map((row) =>\n row\n .map((cell, index) => (index === row.length - 1 ? cell : cell.padEnd(widths[index] ?? 0)))\n .join(\"\")\n .trimEnd(),\n );\n}\n\nexport function formatSteps(steps: readonly Step[]): string[] {\n return steps.map((step) => {\n if (step.note === undefined) {\n return `${step.glyph} ${step.text}`;\n }\n // A text wider than the column gets a single space instead of alignment.\n // `padEnd` returns the string untouched when it is already too long, so the\n // aside ran straight into the last word — legible right up until the day a\n // step had something long to say, which is the day it mattered.\n const text = step.text.length >= NOTE_COLUMN ? `${step.text} ` : step.text.padEnd(NOTE_COLUMN);\n return `${step.glyph} ${text}${step.note}`;\n });\n}\n\nexport function write(lines: readonly string[]): void {\n for (const line of lines) {\n process.stdout.write(`${line}\\n`);\n }\n}\n\n/**\n * A `PenvError` already names the parameter, the environment, and the remedy, so\n * it is printed as written. Anything else is a bug in penv and keeps its stack.\n */\nexport function reportError(error: unknown): void {\n if (error instanceof PenvError) {\n process.stderr.write(`${error.message}\\n`);\n } else if (error instanceof Error) {\n process.stderr.write(`${error.stack ?? error.message}\\n`);\n } else {\n process.stderr.write(`${String(error)}\\n`);\n }\n process.exitCode = 1;\n}\n\n/** Turns a thrown error into a printed one and a non-zero exit code. */\nexport async function guard(run: () => Promise<void>): Promise<void> {\n try {\n await run();\n } catch (error) {\n reportError(error);\n }\n}\n","/**\n * `penv push` — resolve an environment's values and ship them to its sink.\n *\n * This is `penv generate` pointed at CI. It resolves the tree exactly as a\n * deploy would read it — **both `.local` scopes skipped**, because a developer's\n * personal override is not CI's business — judges every generated name against\n * the destination's grammar *before* the first PUT, and only then pushes. The\n * push is all or nothing: a name refused mid-run would leave CI in a state\n * neither the tree nor the destination describes.\n *\n * The mapping is the RFC's: an environment-scoped value becomes a GitHub\n * environment secret of the same name, the unscoped default becomes a repository\n * secret, and GitHub resolves the two in penv's own order — environment over\n * repository — so the cascade is reproduced by the destination's native\n * mechanism rather than flattened at the boundary.\n */\n\nimport type { Meta, MetaBlock, ParameterRef, PenvConfig, SecretScope, Sink } from \"@penvhq/core\";\nimport { checkNameCollisions, PenvError, requireValue, variableName } from \"@penvhq/core\";\nimport type { FilesystemProvider } from \"@penvhq/provider-filesystem\";\nimport { checkGithubNames, createGithubSink } from \"@penvhq/sink-github\";\nimport { defineCommand } from \"citty\";\nimport type { Project, SyncResolution } from \"../project.js\";\nimport {\n keySourceFor,\n localTree,\n openProject,\n PENV_DIR,\n refsFrom,\n resolveAllSync,\n targetEnvironment,\n} from \"../project.js\";\nimport { CHECK, formatRows, guard, WARN, write } from \"../ui.js\";\n\n/** The per-environment meta field recording penv's last push, compared against the destination's `updatedAt`. */\nexport const LAST_PUSHED_KEY = \"lastPushedAt\";\n\nexport interface PushOptions {\n readonly cwd: string;\n readonly environment?: string;\n /** Permits sealed values to be decrypted locally and pushed as plaintext for the destination to re-seal. */\n readonly allowDecrypt?: boolean;\n /** Injected in tests: the sink to push to. Defaults to the one the config declares. */\n readonly sink?: Sink;\n /** Injected in tests: the wall-clock reading recorded in meta. Defaults to now. */\n readonly now?: string;\n}\n\nexport interface PushResult {\n readonly environment: string;\n /** The `owner/repo` targeted, when the config named one. */\n readonly repo: string | undefined;\n readonly pushed: number;\n readonly repositorySecrets: number;\n readonly environmentSecrets: number;\n /** How many were sealed and crossed as plaintext for the destination to re-seal. */\n readonly decrypted: number;\n}\n\n/** One value ready to send, with the destination scope it lands in. */\ninterface Outbound {\n readonly ref: ParameterRef;\n readonly variable: string;\n readonly value: string;\n readonly scope: SecretScope;\n readonly encrypted: boolean;\n}\n\n/** The sink the config declares for this environment, or the injected one. */\nfunction sinkFor(\n project: Project,\n environment: string,\n override: Sink | undefined,\n): { sink: Sink; repo: string | undefined } {\n const declared = project.config.sinks?.[environment];\n if (declared === undefined) {\n throw new PenvError(\n \"NO_SINK\",\n `Environment ${environment} declares no sink in penv.config.ts, so penv has nowhere to push`,\n `Add a \\`sinks\\` entry, e.g. \\`sinks: { ${environment}: { type: \"github\" } }\\`, then run \\`penv push --env ${environment}\\` again.`,\n );\n }\n const repo = declared.repo;\n if (override !== undefined) {\n return { sink: override, repo };\n }\n if (declared.type === \"github\") {\n return { sink: createGithubSink(repo === undefined ? {} : { repo }), repo };\n }\n throw new PenvError(\n \"UNKNOWN_SINK\",\n `Environment ${environment} declares sink type \\`${declared.type}\\`, which penv does not know`,\n 'The only sink in this release is `github`. Set `type: \"github\"`.',\n );\n}\n\n/**\n * Every value to send, resolved up front so the encrypted/allow-decrypt refusal\n * also happens before anything is pushed. A `.local` scope is already gone (the\n * push resolution dropped it), so a winner is only ever environment-scoped or the\n * unscoped default — the destination scope is that binary.\n */\nfunction plan(\n resolutions: readonly SyncResolution[],\n config: PenvConfig,\n environment: string,\n allowDecrypt: boolean,\n): Outbound[] {\n const outbound: Outbound[] = [];\n for (const resolution of resolutions) {\n const winner = resolution.winner;\n if (winner === undefined) {\n continue;\n }\n let encrypted = false;\n if (winner.file.encrypted) {\n if (!allowDecrypt) {\n throw new PenvError(\n \"ENCRYPTED_VALUE_REFUSED\",\n `Parameter ${resolution.parameter} for environment ${environment} resolves to the encrypted value file ${PENV_DIR}/${winner.location}, and a push sends plaintext for GitHub to re-seal`,\n \"Re-run with `--allow-decrypt` to decrypt it locally and push it, or push an environment \" +\n \"whose values are plaintext. penv's encryption stops at the sink; the destination seals it \" +\n \"under its own key.\",\n );\n }\n // Throws naming the reason if a sealed winner cannot be opened — never\n // silently dropping the secret CI needs.\n requireValue(resolution, environment);\n encrypted = true;\n }\n if (resolution.value === undefined) {\n continue;\n }\n const scope: SecretScope =\n winner.file.scope.kind === \"unscoped\"\n ? { kind: \"repository\" }\n : { kind: \"environment\", environment };\n outbound.push({\n ref: resolution.ref,\n variable: variableName(resolution.ref, config),\n value: resolution.value,\n scope,\n encrypted,\n });\n }\n return outbound;\n}\n\n/** Records what penv did, per environment, in the committed meta — never a value read back. */\nfunction withLastPushed(meta: Meta | undefined, environment: string, iso: string): Meta {\n const base: Meta = meta ?? {};\n const environments: Record<string, MetaBlock> = { ...(base.environments ?? {}) };\n environments[environment] = { ...(environments[environment] ?? {}), [LAST_PUSHED_KEY]: iso };\n return { ...base, environments };\n}\n\nfunction recordPush(\n tree: FilesystemProvider,\n ref: ParameterRef,\n environment: string,\n iso: string,\n): void {\n const meta = withLastPushed(tree.readMetaSync(ref), environment, iso);\n tree.writeMetaSync(ref, meta);\n}\n\nexport async function runPush(options: PushOptions): Promise<PushResult> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const { sink, repo } = sinkFor(project, environment, options.sink);\n\n const tree = localTree(project);\n const keys = keySourceFor(project, environment);\n // The push resolution: both `.local` scopes dropped. CI receives what CI would read.\n const resolutions = resolveAllSync(tree, environment, keys, true);\n const refs = refsFrom(resolutions.map((resolution) => resolution.ref));\n\n // Every name judged before a single PUT. Exact-string collisions are core's;\n // GitHub's reserved prefix, leading digit, charset, and case-insensitive\n // collisions are the sink's. Both refuse the whole push, never half of it.\n const collision = checkNameCollisions(refs, project.config)[0];\n if (collision !== undefined) {\n throw collision;\n }\n const nameError = checkGithubNames(refs, project.config)[0];\n if (nameError !== undefined) {\n throw nameError;\n }\n\n const outbound = plan(resolutions, project.config, environment, options.allowDecrypt === true);\n\n // Reachable and writable, or penv stops here having placed nothing.\n await sink.verify();\n\n let repositorySecrets = 0;\n let environmentSecrets = 0;\n for (const item of outbound) {\n await sink.push(item.variable, item.value, item.scope);\n if (item.scope.kind === \"repository\") {\n repositorySecrets += 1;\n } else {\n environmentSecrets += 1;\n }\n // Stamped AFTER the push, per item — not once before the loop. The destination\n // stamps each secret's `updated_at` when its own PUT lands, and one `gh`\n // process runs per parameter, so a single pre-loop time would sit seconds\n // behind the destination's and make `doctor`'s hand-edit check fire on a clean\n // push. A tolerance in `doctor` still absorbs the residual clock skew.\n recordPush(tree, item.ref, environment, options.now ?? new Date().toISOString());\n }\n\n return {\n environment,\n repo,\n pushed: outbound.length,\n repositorySecrets,\n environmentSecrets,\n decrypted: outbound.filter((item) => item.encrypted).length,\n };\n}\n\nexport function renderPush(result: PushResult): string[] {\n if (result.pushed === 0) {\n return formatRows([\n {\n glyph: CHECK,\n label: \"Nothing to push\",\n subject: `no values resolve for environment ${result.environment}`,\n },\n ]);\n }\n\n const target = `GitHub Actions for environment ${result.environment}${\n result.repo === undefined ? \"\" : ` (${result.repo})`\n }`;\n const rows = [\n {\n glyph: CHECK,\n label: \"Pushed\",\n subject: `${result.pushed} ${result.pushed === 1 ? \"secret\" : \"secrets\"}`,\n detail: `to ${target}`,\n },\n {\n glyph: CHECK,\n label: \"Scopes\",\n subject: `${result.environmentSecrets} environment, ${result.repositorySecrets} repository`,\n detail:\n \"environment secrets override repository secrets, as penv's env scope overrides the default\",\n },\n ];\n if (result.decrypted > 0) {\n rows.push({\n glyph: WARN,\n label: \"Decrypted\",\n subject: `${result.decrypted} ${result.decrypted === 1 ? \"secret\" : \"secrets\"}`,\n detail: \"sent as plaintext for GitHub to re-seal under its own key\",\n });\n }\n return formatRows(rows);\n}\n\nexport const pushCommand = defineCommand({\n meta: {\n name: \"push\",\n description: \"Push an environment's resolved values to its sink (GitHub Actions Secrets)\",\n },\n args: {\n env: { type: \"string\", description: \"The environment to push\" },\n \"allow-decrypt\": {\n type: \"boolean\",\n description: \"Decrypt sealed values locally and push them as plaintext for GitHub to re-seal\",\n },\n },\n run({ args }) {\n return guard(async () => {\n const result = await runPush({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n ...(args[\"allow-decrypt\"] === undefined ? {} : { allowDecrypt: args[\"allow-decrypt\"] }),\n });\n write(renderPush(result));\n });\n },\n});\n","/**\n * `penv validate` — build the target environment's configuration and check it\n * against the one schema.\n *\n * Three failures land here rather than anywhere else, and all three are errors:\n * a reserved token in a name (invariant 11), two parameters mapping to one\n * generated variable (invariant 12 — never last-write-wins), and a config object\n * the schema rejects. A passing run means the schema is internally consistent;\n * it does not mean the schema is correct. That is your review, especially after\n * an inferred import.\n */\n\nimport { resolve as resolvePath } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type { ParameterRef, ValueFile } from \"@penvhq/core\";\nimport {\n accessPath,\n checkNameCollisions,\n jitiFor,\n NameCollisionError,\n PenvError,\n ReservedTokenError,\n resolveAll,\n schemaFileOf,\n validateConfig,\n} from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport type { z } from \"zod\";\nimport type { Project } from \"../project.js\";\nimport { keySourceFor, openProject, refsFrom, targetEnvironment } from \"../project.js\";\nimport type { DriftReport } from \"../schema.js\";\nimport { computeDrift, EMPTY_DRIFT } from \"../schema.js\";\nimport { CHECK, formatRows, guard, type Row, WARN, write } from \"../ui.js\";\n\nexport type ValidateIssueKind = \"config\" | \"reserved\" | \"collision\" | \"schema\" | \"undecryptable\";\n\nexport interface ValidateIssue {\n readonly kind: ValidateIssueKind;\n /** What the line is about: a parameter, a variable, a token, or a file. */\n readonly subject: string;\n readonly message: string;\n readonly remedy?: string;\n}\n\nexport interface ValidateResult {\n readonly ok: boolean;\n readonly environment: string;\n readonly parameters: number;\n readonly issues: readonly ValidateIssue[];\n /**\n * The distance between the schema and the tree, carried for the callers\n * that report it (`watch`). Never folded into `ok` and never rendered by\n * `renderValidate`: drift is a report, and CI's verdict must not move because\n * a parameter the schema tolerates is absent. Empty when the schema did not\n * load, since there is nothing to measure against.\n */\n readonly drift: DriftReport;\n}\n\nexport interface ValidateOptions {\n readonly cwd: string;\n readonly environment?: string;\n}\n\nconst SCHEMA_EXPORT = \"schema\";\n\nconst LABELS: Readonly<Record<ValidateIssueKind, string>> = {\n config: \"Config\",\n reserved: \"Reserved token\",\n collision: \"Name collision\",\n schema: \"Invalid parameter\",\n undecryptable: \"Undecryptable value\",\n};\n\nfunction firstLine(text: string): string {\n return text.split(\"\\n\")[0] ?? text;\n}\n\nfunction issueFrom(error: PenvError, fallbackSubject: string): ValidateIssue {\n const base = {\n message: firstLine(error.message),\n ...(error.remedy === undefined ? {} : { remedy: error.remedy }),\n };\n if (error instanceof ReservedTokenError) {\n return { kind: \"reserved\", subject: error.token, ...base };\n }\n if (error instanceof NameCollisionError) {\n return { kind: \"collision\", subject: error.variable, ...base };\n }\n return { kind: \"config\", subject: fallbackSubject, ...base };\n}\n\n/**\n * Places a value at its access path. Values are placed exactly as the provider\n * holds them: coercion is the schema's job, so a value file's contents stay a\n * string here.\n */\nfunction place(root: Record<string, unknown>, path: readonly string[], value: string): void {\n const leaf = path[path.length - 1];\n if (leaf === undefined) {\n return;\n }\n let node = root;\n for (const key of path.slice(0, -1)) {\n const existing = node[key];\n if (typeof existing === \"object\" && existing !== null) {\n node = existing as Record<string, unknown>;\n continue;\n }\n const child: Record<string, unknown> = {};\n node[key] = child;\n node = child;\n }\n node[leaf] = value;\n}\n\nfunction isZodType(value: unknown): value is z.ZodType {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"safeParse\" in value &&\n typeof (value as { safeParse: unknown }).safeParse === \"function\"\n );\n}\n\nexport interface SchemaLoad {\n /** Absent when the module could not be evaluated. `issues` says why. */\n readonly schema?: z.ZodType;\n readonly issues: readonly ValidateIssue[];\n}\n\n/**\n * A penv error raised inside the user's own schema module, identified by its\n * `code` rather than by `instanceof`.\n *\n * The error is thrown by *their* copy of penv, which is a different module realm\n * from this one, so `instanceof` is false across the boundary. `code` is the\n * stable, machine-readable discriminator, and this is exactly what it is for.\n */\nfunction validationIssuesOf(\n cause: unknown,\n schemaPath: string,\n): readonly ValidateIssue[] | undefined {\n if (typeof cause !== \"object\" || cause === null) {\n return undefined;\n }\n const error = cause as { code?: unknown; issues?: unknown };\n if (error.code !== \"VALIDATION_FAILED\" || !Array.isArray(error.issues)) {\n return undefined;\n }\n return error.issues.map((issue: unknown) => {\n const { parameter, message } = issue as { parameter?: unknown; message?: unknown };\n return {\n kind: \"schema\" as const,\n subject: typeof parameter === \"string\" && parameter !== \"\" ? parameter : schemaPath,\n message: typeof message === \"string\" ? message : String(issue),\n remedy: `Fix the value, or adjust the schema in ${schemaPath} if the shape is wrong.`,\n };\n });\n}\n\n/**\n * Serialises the `PENV_ENV` pin in {@link loadSchema}.\n *\n * The environment reaches the user's module through a process global, because\n * that is the only channel their scaffolded `load(schema)` reads. A global\n * pinned across an `await` is not re-entrant: two overlapping loads interleave,\n * the second captures the first's value as `previous`, and restoring it on the\n * way out leaves the global pinned to an environment nobody asked for — every\n * later cycle then silently validates the wrong one. The window is real because\n * `runValidate` is exported and nothing stops a caller validating two\n * environments at once; `watch` is safe only by accident of its single-flight.\n *\n * A queue rather than a fix to the channel: the global *is* the contract with\n * the user's module, so the pin cannot go away. Only one load may hold it.\n */\nlet schemaLoads: Promise<unknown> = Promise.resolve();\n\nfunction exclusively<T>(work: () => Promise<T>): Promise<T> {\n const result = schemaLoads.then(work, work);\n // Never let a rejection break the chain for the next caller.\n schemaLoads = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n}\n\n/**\n * The one schema, read from wherever `schemaFile` puts it.\n *\n * Only the `schema` export is read, never `env` — a command whose job is to\n * *report* on configuration must not be stopped by it. That is the whole reason\n * the docs tell type-only consumers to import `schema`: a type-only import is\n * erased and never evaluates the module at all.\n *\n * A *runtime* read cannot have that guarantee. Evaluating the module runs its\n * top level, so a scaffolded `export const env = load(schema)` loads eagerly\n * here too, and if that load throws, the schema is unreachable — ESM produces no\n * namespace for a module that threw. Two things make that honest rather than\n * silent: `PENV_ENV` is pinned so the eager load targets the environment being\n * reported on, and a load that fails validation is unwrapped back into the\n * per-parameter issues it was built from, so the report still names parameters\n * instead of blaming the file.\n *\n * The pin is a process global, so only one load may hold it at a time — see\n * {@link exclusively}. Loads queue rather than overlap.\n */\nexport function loadSchema(project: Project, environment: string): Promise<SchemaLoad> {\n // Resolved against the project root, not `.penv/`: `schemaFile` is relative to\n // penv.config.ts, so a schema at `src/env.ts` is looked for where it is.\n const schemaPath = schemaFileOf(project.config);\n const file = pathToFileURL(resolvePath(project.root, schemaPath)).href;\n return exclusively(() => loadSchemaExclusively(file, schemaPath, environment));\n}\n\n/** {@link loadSchema}'s body, run only while it holds the `PENV_ENV` pin. */\nasync function loadSchemaExclusively(\n file: string,\n schemaPath: string,\n environment: string,\n): Promise<SchemaLoad> {\n // Resolved from the user's own file: `zod` and `penv` are their dependencies,\n // not the CLI's. Shared with config loading (jitiFor) so both evaluate user modules\n // identically — including resolving `server-only` to its no-throw variant so a\n // server-guarded `.penv/env.ts` still yields its `schema` export.\n const jiti = jitiFor(file);\n\n const previous = process.env.PENV_ENV;\n process.env.PENV_ENV = environment;\n let loaded: unknown;\n try {\n loaded = await jiti.import(file);\n } catch (cause) {\n const issues = validationIssuesOf(cause, schemaPath);\n if (issues !== undefined) {\n return { issues };\n }\n const detail = cause instanceof Error ? firstLine(cause.message) : String(cause);\n return {\n issues: [\n {\n kind: \"config\",\n subject: schemaPath,\n message: `${schemaPath} could not be loaded: ${detail}`,\n remedy: `Fix the error above. penv reads the \\`${SCHEMA_EXPORT}\\` export of ${schemaPath}, which is yours to edit.`,\n },\n ],\n };\n } finally {\n if (previous === undefined) {\n delete process.env.PENV_ENV;\n } else {\n process.env.PENV_ENV = previous;\n }\n }\n\n const exported =\n typeof loaded === \"object\" && loaded !== null\n ? (loaded as Record<string, unknown>)[SCHEMA_EXPORT]\n : undefined;\n\n if (!isZodType(exported)) {\n return {\n issues: [\n {\n kind: \"config\",\n subject: schemaPath,\n message: `${schemaPath} exports no \\`${SCHEMA_EXPORT}\\``,\n remedy: `Export the shape as \\`export const ${SCHEMA_EXPORT} = z.object({ ... })\\`. One schema drives both validation and types.`,\n },\n ],\n };\n }\n return { schema: exported, issues: [] };\n}\n\nexport async function runValidate(options: ValidateOptions): Promise<ValidateResult> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const schemaPath = schemaFileOf(project.config);\n const issues: ValidateIssue[] = [];\n\n // Invariant 11: a reserved token in a filename is an error, never a silent\n // misparse — so listing the tree is itself a check.\n let files: ValueFile[];\n try {\n files = await project.provider.list();\n } catch (error) {\n if (!(error instanceof PenvError)) {\n throw error;\n }\n return {\n ok: false,\n environment,\n parameters: 0,\n issues: [issueFrom(error, schemaPath)],\n drift: EMPTY_DRIFT,\n };\n }\n\n const refs: ParameterRef[] = refsFrom(files);\n\n // The config decides what an environment is, so a broken config is not a\n // smaller problem than a broken value — it is the problem that makes value\n // files unreadable. `validateConfig` collects every one of them, and until it\n // was called from here it collected them for nobody: a config declaring an\n // environment with no provider, or a name no filename can hold, passed\n // `penv validate` with a ✓.\n for (const error of validateConfig(project.config)) {\n issues.push(issueFrom(error, \"penv.config.ts\"));\n }\n\n // Invariant 12: two parameters mapping to one generated variable would lose a\n // value on `penv generate`. It fails here rather than there.\n for (const collision of checkNameCollisions(refs, project.config)) {\n issues.push(issueFrom(collision, collision.variable));\n }\n\n const { schema, issues: schemaIssues } = await loadSchema(project, environment);\n issues.push(...schemaIssues);\n\n let drift: DriftReport = EMPTY_DRIFT;\n\n if (schema !== undefined) {\n const resolutions = await resolveAll(\n environment,\n project.provider,\n keySourceFor(project, environment),\n );\n const object: Record<string, unknown> = {};\n // The access paths whose value exists and could not be read. Nothing is\n // placed at them, so the schema will call each one absent — see below.\n const undecryptable = new Set<string>();\n for (const resolution of resolutions) {\n if (resolution.undecryptable !== undefined) {\n undecryptable.add(accessPath(resolution.ref).join(\".\"));\n issues.push({\n kind: \"undecryptable\",\n subject: resolution.parameter,\n message: `${resolution.winner?.location ?? \"the winning value file\"} could not be decrypted: ${resolution.undecryptable.detail}`,\n remedy:\n \"Make the key available, or re-seal the value under a key you hold with `penv encrypt`. \" +\n \"The value is there — penv cannot read it.\",\n });\n continue;\n }\n if (resolution.value !== undefined) {\n place(object, accessPath(resolution.ref), resolution.value);\n }\n }\n // Measured from the same resolutions the verdict below is reached on, so the\n // report can never describe a tree the verdict did not read.\n drift = computeDrift({ schema, resolutions, config: project.config, environment });\n\n const result = schema.safeParse(object);\n if (!result.success) {\n for (const problem of result.error.issues) {\n const path = problem.path.join(\".\");\n // One absence, one line. The schema is right that nothing is there, but\n // \"expected string, received undefined\" is the wrong answer to why: the\n // value exists and penv could not read it, which is already reported\n // above with the remedy that fixes it. Printing both puts the true line\n // and the misleading one next to each other and lets the reader pick.\n if (undecryptable.has(path)) {\n continue;\n }\n issues.push({\n kind: \"schema\",\n subject: path || schemaPath,\n message: problem.message,\n remedy: `Fix the value, or adjust the schema in ${schemaPath} if the shape is wrong.`,\n });\n }\n }\n }\n\n return { ok: issues.length === 0, environment, parameters: refs.length, issues, drift };\n}\n\nexport function renderValidate(result: ValidateResult): string[] {\n if (result.ok) {\n return formatRows([\n {\n glyph: CHECK,\n label: \"Schema valid\",\n subject: `${result.parameters} parameters for environment ${result.environment}`,\n },\n ]);\n }\n\n const rows: Row[] = result.issues.map((issue) => ({\n glyph: WARN,\n label: LABELS[issue.kind],\n subject: issue.subject,\n detail: issue.message,\n }));\n\n const lines = formatRows(rows);\n const remedies = [...new Set(result.issues.map((issue) => issue.remedy))];\n for (const remedy of remedies) {\n if (remedy !== undefined) {\n lines.push(` ${remedy}`);\n }\n }\n return lines;\n}\n\nexport const validateCommand = defineCommand({\n meta: {\n name: \"validate\",\n description: \"Validate configuration against the schema; non-zero on failure\",\n },\n args: {\n env: { type: \"string\", description: \"The environment to validate\" },\n },\n run({ args }) {\n return guard(async () => {\n const result = await runValidate({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n });\n write(renderValidate(result));\n if (!result.ok) {\n process.exitCode = 1;\n }\n });\n },\n});\n","/**\n * `penv encrypt <key>` and `penv decrypt <key>` — change whether one value file\n * is sealed, without changing what it says.\n *\n * These act on one parameter at one scope, because a scope is the address the\n * provider actually has: `db-password.production` and `db-password` are two\n * files, and a command that \"encrypted the parameter\" would have to guess which.\n *\n * They exist for two moments the policy cannot handle by itself. The first is\n * adoption: `secret: true` added to a parameter that already has values leaves\n * every existing file plaintext, and `penv set` only seals what it writes. The\n * second is re-sealing after a move — a ciphertext is bound to the address it\n * lives at, so a value file that is renamed or re-scoped must be sealed again for\n * its new address.\n *\n * Neither invents a key. `penv encrypt` with no key refuses, because a key penv\n * chose is a key nobody can reproduce — the same reason `penv set` is the only\n * thing that writes a value, and never a value it made up.\n */\n\nimport type { ValueFile } from \"@penvhq/core\";\nimport {\n formatValueFile,\n isSecret,\n openValue,\n PenvError,\n parameterId,\n sealValue,\n} from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport type { Project } from \"../project.js\";\nimport { keySourceFor, openProject, PENV_DIR, refFromKey, targetEnvironment } from \"../project.js\";\nimport { CHECK, formatRows, guard, write } from \"../ui.js\";\nimport type { ScopeOptions } from \"./set.js\";\nimport { targetScope } from \"./set.js\";\n\nexport interface ResealOptions extends ScopeOptions {\n readonly cwd: string;\n readonly key: string;\n}\n\nexport interface ResealResult {\n readonly parameter: string;\n /** The file that now holds the value. */\n readonly location: string;\n /** The file that no longer exists, because its twin replaced it. */\n readonly removed: string;\n}\n\n/** The two files one value can live in at a scope. Exactly one of them exists. */\nfunction twins(project: Project, key: string, options: ScopeOptions): [ValueFile, ValueFile] {\n const ref = refFromKey(key, project.config);\n const scope = targetScope(project, options, key);\n return [\n { namespace: ref.namespace, name: ref.name, scope, encrypted: false },\n { namespace: ref.namespace, name: ref.name, scope, encrypted: true },\n ];\n}\n\n/**\n * The environment this scope's policy and key are read from.\n *\n * Unlike `set`, this refuses rather than falling back to the base block: both\n * commands here need a *key*, and a key is declared per environment. A scope that\n * names none has no key penv can choose, and choosing the ambient environment's\n * would seal a file every other environment reads under a key only one of them\n * has.\n */\nfunction environmentFor(project: Project, options: ScopeOptions, verb: string): string {\n if (options.environment === undefined) {\n throw new PenvError(\n \"SECRET_SCOPE_AMBIGUOUS\",\n `\\`penv ${verb}\\` names no environment, and keys are declared per environment`,\n \"Pass `--env <environment>`. penv cannot tell which environment's key applies to a file \" +\n \"that names none, and will not pick one for you.\",\n );\n }\n return targetEnvironment(project, options.environment);\n}\n\nasync function readOne(project: Project, file: ValueFile): Promise<string | undefined> {\n return project.provider.read(file);\n}\n\nexport async function runEncrypt(options: ResealOptions): Promise<ResealResult> {\n const project = openProject(options.cwd);\n const environment = environmentFor(project, options, \"encrypt\");\n const [plain, sealed] = twins(project, options.key, options);\n const parameter = parameterId(plain);\n\n const value = await readOne(project, plain);\n if (value === undefined) {\n const already = await readOne(project, sealed);\n throw new PenvError(\n \"PARAMETER_ABSENT\",\n already === undefined\n ? `Parameter ${parameter} has no value file at ${PENV_DIR}/${formatValueFile(plain)}`\n : `Parameter ${parameter} is already encrypted at ${PENV_DIR}/${formatValueFile(sealed)}`,\n already === undefined\n ? `Write it first with \\`penv set ${options.key} --env ${environment}\\`, which seals it ` +\n \"automatically when the parameter's meta declares it a secret.\"\n : \"Nothing to do.\",\n );\n }\n\n const text = sealValue(sealed, value, keySourceFor(project, environment), parameter, environment);\n\n // Written before the plaintext is removed. The reverse order has a window in\n // which the value exists nowhere, and the value is the thing being protected.\n await project.provider.write(sealed, text);\n await project.provider.remove(plain);\n\n return {\n parameter,\n location: formatValueFile(sealed),\n removed: formatValueFile(plain),\n };\n}\n\nexport async function runDecrypt(options: ResealOptions): Promise<ResealResult> {\n const project = openProject(options.cwd);\n const environment = environmentFor(project, options, \"decrypt\");\n const [plain, sealed] = twins(project, options.key, options);\n const parameter = parameterId(plain);\n\n // penv does not ship a command whose purpose is to fail its own check. A\n // secret written in plaintext is a `doctor` failure by policy (invariant 14),\n // and decrypting one on request would manufacture exactly that.\n if (isSecret(await project.provider.readMeta(plain), environment)) {\n throw new PenvError(\n \"SECRET_DECRYPT_REFUSED\",\n `Parameter ${parameter} is declared a secret for environment ${environment}, so penv will not write it in plaintext`,\n \"A secret with a plaintext value file is a `penv doctor` failure. Drop `secret` from the \" +\n \"parameter's meta if it is not one, or run `penv generate --allow-decrypt` if you need \" +\n \"the plaintext value in a `.env` artifact.\",\n );\n }\n\n const stored = await readOne(project, sealed);\n if (stored === undefined) {\n throw new PenvError(\n \"PARAMETER_ABSENT\",\n `Parameter ${parameter} has no encrypted value file at ${PENV_DIR}/${formatValueFile(sealed)}`,\n `Nothing to decrypt. \\`penv get ${options.key} --env ${environment} --explain\\` shows every file penv looked at.`,\n );\n }\n\n const opened = openValue(sealed, stored, keySourceFor(project, environment));\n if (opened.kind === \"failed\") {\n throw new UndecryptableAt(\n parameter,\n environment,\n formatValueFile(sealed),\n opened.failure.detail,\n );\n }\n\n await project.provider.write(plain, opened.value);\n await project.provider.remove(sealed);\n\n return {\n parameter,\n location: formatValueFile(plain),\n removed: formatValueFile(sealed),\n };\n}\n\n/** The one thing `decrypt` can fail at that `requireValue` does not cover: a named file. */\nclass UndecryptableAt extends PenvError {\n constructor(parameter: string, environment: string, location: string, detail: string) {\n super(\n \"VALUE_UNDECRYPTABLE\",\n `Parameter ${parameter} for environment ${environment} is sealed at ${PENV_DIR}/${location}, and penv could not open it: ${detail}`,\n \"Make the key available and run the command again. penv will not replace a value it \" +\n \"cannot read.\",\n );\n }\n}\n\nexport function renderReseal(result: ResealResult, verb: \"Encrypted\" | \"Decrypted\"): string[] {\n return formatRows([\n {\n glyph: CHECK,\n label: verb,\n subject: `${PENV_DIR}/${result.location}`,\n detail: `${PENV_DIR}/${result.removed} removed`,\n },\n ]);\n}\n\nconst SCOPE_ARGS = {\n key: { type: \"positional\", required: true, description: \"The parameter, e.g. redis/password\" },\n env: { type: \"string\", description: \"The environment whose value file to act on\" },\n local: {\n type: \"boolean\",\n description: \"Act on the personal override rather than the shared file\",\n },\n} as const;\n\nfunction scopeOptions(args: {\n env?: string | undefined;\n local?: boolean | undefined;\n}): ScopeOptions {\n return {\n ...(args.env === undefined ? {} : { environment: args.env }),\n ...(args.local === undefined ? {} : { local: args.local }),\n };\n}\n\nexport const encryptCommand = defineCommand({\n meta: { name: \"encrypt\", description: \"Encrypt one parameter's value file at one scope\" },\n args: SCOPE_ARGS,\n run({ args }) {\n return guard(async () => {\n const result = await runEncrypt({ cwd: process.cwd(), key: args.key, ...scopeOptions(args) });\n write(renderReseal(result, \"Encrypted\"));\n });\n },\n});\n\nexport const decryptCommand = defineCommand({\n meta: { name: \"decrypt\", description: \"Decrypt one parameter's value file at one scope\" },\n args: SCOPE_ARGS,\n run({ args }) {\n return guard(async () => {\n const result = await runDecrypt({ cwd: process.cwd(), key: args.key, ...scopeOptions(args) });\n write(renderReseal(result, \"Decrypted\"));\n });\n },\n});\n","/**\n * `penv set <key> [value]` — write one value file.\n *\n * The scope is chosen, never inferred: `--env <name>` writes `<name>.<env>`,\n * `--local` writes the personal override — for one environment when combined\n * with `--env`, for every environment on its own — and the default is the\n * unscoped one every environment falls back to. Writing to `--env production`\n * when you meant the default is a different file, so penv never picks for you.\n */\n\nimport type { ParameterRef, Provider, Scope, ValueFile } from \"@penvhq/core\";\nimport { formatValueFile, isSecret, PenvError, parameterId, sealValue } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport type { Project } from \"../project.js\";\nimport {\n assertWritableKey,\n keySourceFor,\n openProject,\n PENV_DIR,\n refFromKey,\n targetEnvironment,\n} from \"../project.js\";\nimport { CHECK, formatRows, guard, write } from \"../ui.js\";\n\nexport interface ScopeOptions {\n /** The environment scope. Combined with `local`, the environment-scoped override. */\n readonly environment?: string;\n readonly local?: boolean;\n}\n\nexport interface SetOptions extends ScopeOptions {\n readonly cwd: string;\n readonly key: string;\n readonly value: string;\n}\n\nexport interface SetResult {\n readonly parameter: string;\n /** The value file written, relative to `.penv/`. */\n readonly location: string;\n /** Whether meta's policy sealed it. Reported, so the marker is never a surprise. */\n readonly encrypted: boolean;\n}\n\n/**\n * The scope the flags name — one flag combination per cascade level, all four.\n *\n * `--local --env <e>` is the environment-scoped personal override, mirroring\n * `.env.<e>.local`: the flags compose, because the cascade has a level where\n * both are true. Refusing the combination is what used to leave that level\n * unaddressable from the CLI.\n *\n * `environment` must already be the name {@link targetScope} validated, never\n * the raw flag — the string here becomes a filename segment verbatim.\n */\nexport function scopeFrom(options: ScopeOptions): Scope {\n if (options.local === true) {\n if (options.environment !== undefined) {\n return { kind: \"environment-local\", environment: options.environment };\n }\n return { kind: \"local\" };\n }\n if (options.environment !== undefined) {\n return { kind: \"environment\", environment: options.environment };\n }\n return { kind: \"unscoped\" };\n}\n\n/**\n * The scope a writer may act on: the environment as `targetEnvironment`\n * *returned* it, never as the flag carried it.\n *\n * `resolveEnvironment` trims before it checks the whitelist, so the validated\n * name and the raw flag are two different strings and only the returned one has\n * been checked against `config.environments`. Passing the raw one to\n * `formatValueFile` is what let `--env \"production \"` write `api-key.production `\n * — a file the filename grammar refuses to read (invariant 10), so every later\n * `list`/`get`/`generate`/`validate`/`remove` throws and the tree is repairable\n * only by deleting the file by hand. Validation is what makes a string safe to\n * put in a filename, so the validated value is the only one that may reach one.\n *\n * A blank `--env` is refused rather than resolved: `resolveEnvironment` answers\n * it from `PENV_ENV`/`NODE_ENV`, and a writer scoping a file to an environment\n * the user never named is the same wrong file by a quieter route (invariants 10\n * and 13).\n */\nexport function targetScope(project: Project, options: ScopeOptions, key: string): Scope {\n const environment = options.environment;\n if (environment === undefined) {\n return scopeFrom(options);\n }\n if (environment.trim().length === 0) {\n throw new PenvError(\n \"ENVIRONMENT_FLAG_EMPTY\",\n `\\`--env\\` for parameter ${key} names no environment`,\n `Pass a declared environment — ${project.config.environments.map((e) => `\\`${e}\\``).join(\", \")} — ` +\n \"e.g. `--env production`, or drop `--env` to write the scope that has no environment.\",\n );\n }\n return scopeFrom({ ...options, environment: targetEnvironment(project, environment) });\n}\n\n/**\n * The environment whose policy governs the file being written.\n *\n * `undefined` for a scope that carries no environment, which asks meta for its\n * base block — the honest authority for a file every environment reads. Asking\n * `production`'s block about the unscoped default would apply one environment's\n * policy to a file the others fall back to.\n */\nfunction policyEnvironment(project: Project, options: ScopeOptions): string | undefined {\n return options.environment === undefined\n ? undefined\n : targetEnvironment(project, options.environment);\n}\n\n/**\n * Seals a secret, or refuses for a reason it can name.\n *\n * A key source is declared per environment, so a scope that names no environment\n * has no key penv can choose. It refuses rather than reaching for the ambient\n * environment's key: that key would seal a file every *other* environment also\n * reads, and each of them would then fail to open it — a scope-widening leak\n * dressed as a convenience. `penv set redis/password --env production` is one\n * more word and is unambiguous.\n */\nfunction sealFor(\n project: Project,\n file: ValueFile,\n value: string,\n parameter: string,\n environment: string | undefined,\n): string {\n if (environment === undefined) {\n throw new PenvError(\n \"SECRET_SCOPE_AMBIGUOUS\",\n `Parameter ${parameter} is a secret, and ${PENV_DIR}/${formatValueFile(file)} names no environment`,\n \"Keys are declared per environment in the `keys` block of penv.config.ts, so penv cannot \" +\n \"tell which key should seal a file that every environment reads. Write it at an \" +\n \"environment scope — add `--env <environment>` — or drop `secret` from the parameter's meta.\",\n );\n }\n return sealValue(file, value, keySourceFor(project, environment), parameter, environment);\n}\n\n/** What {@link sealAwareWrite} was told to write, and to which store. */\nexport interface SealAwareWriteOptions {\n readonly project: Project;\n /**\n * The store the value lands in, and the meta whose policy governs it is read\n * *from*. `set` passes the local tree; `rotate` passes it only when the\n * environment's source of truth IS the local tree, so the seal-and-twin rule\n * applies exactly where penv's envelope is penv's concern.\n */\n readonly provider: Provider;\n readonly ref: ParameterRef;\n readonly scope: Scope;\n readonly value: string;\n /** The environment whose meta block decides the policy, or `undefined` for the base block. */\n readonly environment: string | undefined;\n}\n\n/** What {@link sealAwareWrite} did: the marker meta chose, and the file it wrote. */\nexport interface SealAwareWriteResult {\n /** Whether meta's policy sealed it. */\n readonly encrypted: boolean;\n /** The value file written, relative to `.penv/`. */\n readonly location: string;\n}\n\n/**\n * Writes one value file into the local tree, sealing it when meta says the\n * parameter is a secret, and removing the twin at that scope — the one correct\n * physics for a store whose envelope penv owns.\n *\n * There is no `--encrypt` flag, deliberately. A flag would make the command line\n * the authority on what is secret, and meta is (invariant 14) — the `.enc` marker\n * is validated *against* the policy, so a marker chosen at the keyboard would\n * invert the direction the check runs in. The policy decides; the writer obeys.\n *\n * Both `set` and the local-tree branch of `rotate` go through here, so a rotated\n * secret is sealed exactly as a `set` one is: the defect was `rotate` writing the\n * live credential as cleartext into `.penv/` — where plaintext outranks `.enc` at\n * the same scope, so it also shadowed any sealed copy already there.\n */\nexport async function sealAwareWrite(\n options: SealAwareWriteOptions,\n): Promise<SealAwareWriteResult> {\n const { project, provider, ref, scope, value, environment } = options;\n const secret = isSecret(await provider.readMeta(ref), environment);\n\n const file: ValueFile = {\n namespace: ref.namespace,\n name: ref.name,\n scope,\n encrypted: secret,\n };\n\n // Sealed before anything is written, so a secret penv has no key for leaves\n // nothing behind. Writing the plaintext first and letting `doctor` report it\n // afterwards would put the secret on disk in order to complain about it.\n const stored = secret ? sealFor(project, file, value, parameterId(ref), environment) : value;\n\n await provider.write(file, stored);\n\n // The twin at this scope is removed, because one scope holds one value.\n //\n // `.enc` is orthogonal to precedence, so `<name>.<env>` and `<name>.<env>.enc`\n // are two candidates at one address, and the plaintext is considered first.\n // Leaving the twin behind therefore does not leave a harmless extra file — it\n // leaves the one that *wins*. Marking a parameter secret and running `penv set`\n // reported writing a sealed file while `penv get` kept handing back the stale\n // plaintext underneath it: the value you set was not the value you got, and the\n // new secret was inert on disk. Written before the removal, so the value is\n // never in neither file.\n await provider.remove({ ...file, encrypted: !secret });\n\n return { encrypted: secret, location: formatValueFile(file) };\n}\n\n/**\n * Writes one value file, sealing it when meta says the parameter is a secret.\n *\n * The scope is chosen from the flags, then the seal-and-twin write is the shared\n * {@link sealAwareWrite}, against the local tree — the store `set` always edits.\n */\nexport async function runSet(options: SetOptions): Promise<SetResult> {\n const project = openProject(options.cwd);\n assertWritableKey(options.key);\n const ref = refFromKey(options.key, project.config);\n\n // An environment is a whitelist entry or nothing, so a scope naming one is\n // checked before it becomes a filename — including under `--local`, where\n // the environment is a filename segment too.\n const scope = targetScope(project, options, options.key);\n const environment = policyEnvironment(project, options);\n\n const { encrypted, location } = await sealAwareWrite({\n project,\n provider: project.provider,\n ref,\n scope,\n value: options.value,\n environment,\n });\n\n return { parameter: options.key, location, encrypted };\n}\n\nexport function renderSet(result: SetResult): string[] {\n return formatRows([\n {\n glyph: CHECK,\n label: \"Wrote\",\n subject: `${PENV_DIR}/${result.location}`,\n // The `.enc` suffix says this already, but only to a reader who knows the\n // grammar. Meta decided it, not the command line, so the command says so.\n ...(result.encrypted ? { detail: \"encrypted, per the parameter's meta policy\" } : {}),\n },\n ]);\n}\n\n/** The value when it is piped in rather than typed: one trailing newline is the shell's. */\nexport async function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin as AsyncIterable<Buffer>) {\n chunks.push(Buffer.from(chunk));\n }\n const text = Buffer.concat(chunks).toString(\"utf8\");\n return text.endsWith(\"\\n\") ? text.slice(0, -1) : text;\n}\n\nexport const setCommand = defineCommand({\n meta: { name: \"set\", description: \"Update a parameter\" },\n args: {\n key: { type: \"positional\", required: true, description: \"The parameter, e.g. redis/password\" },\n value: {\n type: \"positional\",\n required: false,\n description: \"The value; read from stdin if omitted\",\n },\n env: { type: \"string\", description: \"Write the <name>.<env> scope\" },\n local: {\n type: \"boolean\",\n description: \"Write the personal override: <name>.<env>.local with --env, else <name>.local\",\n },\n },\n run({ args }) {\n return guard(async () => {\n const value = args.value ?? (await readStdin());\n write(\n renderSet(\n await runSet({\n cwd: process.cwd(),\n key: args.key,\n value,\n ...(args.env === undefined ? {} : { environment: args.env }),\n ...(args.local === undefined ? {} : { local: args.local }),\n }),\n ),\n );\n });\n },\n});\n","/**\n * `penv fill` — walk the schema's required-but-missing parameters and ask for\n * each one, deriving the value file's name so the user never has to.\n *\n * The schema-first flow writes `.penv/env.ts` before any value exists, and there\n * the user hits a translation they should not have to make: `databaseUrl` in the\n * schema is `database-url` on disk, and typing the wrong one writes a file the\n * schema still cannot see. `fill` reads the same declared drift `validate`\n * computes, and for each missing parameter asks for a value and writes it through\n * the one writer — `runSet` — deriving the kebab filename from the schema key.\n *\n * A value is never invented: a blank answer skips the parameter, because the\n * silent value reaching runtime is the failure penv exists to delete, and a\n * placeholder written here is exactly that value by a friendlier route.\n */\n\nimport { createInterface } from \"node:readline/promises\";\nimport { PenvError } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { PENV_DIR } from \"../project.js\";\nimport { CHECK, formatRows, guard, type Row, WARN, write } from \"../ui.js\";\nimport { runSet } from \"./set.js\";\nimport { runValidate, type ValidateIssueKind } from \"./validate.js\";\n\n/**\n * The validation issue kinds that stop `fill` before it writes a thing. A\n * `schema` issue is, on the ordinary run, the missing value `fill` is about to\n * ask for — so it is deliberately absent here, or `fill` would refuse the very\n * gap it exists to close. A collision, a reserved token, or a config/load\n * failure is a structural fault of the tree itself, and filling would only paper\n * over it: `generate` would still drop a value, and \"what is missing\" is not even\n * a meaningful question against a config that does not load.\n */\nconst BLOCKING: ReadonlySet<ValidateIssueKind> = new Set([\"config\", \"collision\", \"reserved\"]);\n\n/** One question `fill` puts to the user: which parameter, in which environment. */\nexport interface FillPrompt {\n /** The value file's key, kebab and slash-separated — the name the user need never derive. */\n readonly parameter: string;\n readonly environment: string;\n /**\n * Whether meta says this is a secret. Carried so a wrapper can mute the echo;\n * v1 does not, and the drift carries no meta, so this is `false` today.\n */\n readonly secret: boolean;\n readonly description?: string;\n}\n\nexport interface FillOptions {\n readonly cwd: string;\n readonly environment?: string;\n /**\n * How a value is obtained for one prompt. `undefined` or an empty answer skips\n * the parameter — the readline half lives only in the wrapper, so `runFill`\n * stays pure and unit-testable.\n */\n readonly ask: (prompt: FillPrompt) => Promise<string | undefined>;\n}\n\nexport interface FillResult {\n readonly environment: string;\n /** The value files written, one per answered prompt. */\n readonly written: ReadonlyArray<{\n readonly parameter: string;\n /** The value file written, relative to `.penv/`. */\n readonly location: string;\n readonly encrypted: boolean;\n }>;\n /** The parameters a blank answer left for later — never written as an empty value. */\n readonly skipped: readonly string[];\n /**\n * The declared keys no filename reaches (`apiURL`, a reserved token). `fill`\n * cannot ask for a value it could never write, so it carries the rename remedy\n * out rather than prompting for a file that would error.\n */\n readonly unreachable: ReadonlyArray<{ readonly subject: string; readonly remedy: string }>;\n}\n\n/**\n * Asks for every declared-but-missing parameter, and writes the ones answered.\n *\n * The drift is `validate`'s, not a second reading of the schema: `runValidate`\n * already computes exactly the required-but-absent set, so `fill` and `validate`\n * can never disagree about what is missing. The writing is `runSet`'s, so a\n * filled secret is sealed exactly as a `set` one is — `fill` owns neither the\n * resolution nor the write, only the prompting between them.\n */\nexport async function runFill(options: FillOptions): Promise<FillResult> {\n const validation = await runValidate({\n cwd: options.cwd,\n ...(options.environment === undefined ? {} : { environment: options.environment }),\n });\n const environment = validation.environment;\n\n // A tree that fails validation for a *structural* reason is not one `fill`\n // should write into, so it refuses and hands the reasons back rather than\n // prompting. Keying off the issue kinds — not `validation.ok` — is the load-\n // bearing choice: a required parameter with no value fails the schema too, and\n // that failure *is* the drift `fill` exists to close, so blocking on `ok` would\n // refuse every ordinary run. The `EMPTY_DRIFT` sentinel is not consulted: a\n // schema that never loaded surfaces here as a `config` blocker with its real\n // reason, so a provider-list failure no longer masquerades as \"no schema\".\n const blockers = validation.issues.filter((issue) => BLOCKING.has(issue.kind));\n if (blockers.length > 0) {\n const detail = blockers\n .map(\n (issue) => ` - ${issue.message}${issue.remedy === undefined ? \"\" : ` (${issue.remedy})`}`,\n )\n .join(\"\\n\");\n throw new PenvError(\n \"FILL_BLOCKED\",\n `penv fill cannot run: environment ${environment} has ${blockers.length} unresolved ` +\n `configuration ${blockers.length === 1 ? \"issue\" : \"issues\"}:\\n${detail}`,\n \"Fix these — `penv validate` reports them — then run `penv fill`. If you have not written a \" +\n `schema yet, declare the required parameters in ${PENV_DIR}/env.ts.`,\n );\n }\n\n const written: Array<{ parameter: string; location: string; encrypted: boolean }> = [];\n const skipped: string[] = [];\n const unreachable: Array<{ subject: string; remedy: string }> = [];\n\n for (const drift of validation.drift.declared) {\n // A key outside the name transform's image, or a reserved token: no value\n // file reaches it, so the remedy is a rename, not a value. Prompting here\n // would ask for a file penv would then refuse to write.\n if (drift.ref === undefined) {\n unreachable.push({ subject: drift.subject, remedy: drift.remedy });\n continue;\n }\n\n const ref = drift.ref;\n const key = [...ref.namespace, ref.name].join(\"/\");\n // `secret` stays false: the drift carries no meta, and echo-muting is not a\n // v1 feature. The write below still seals per meta — `runSet` reads it there.\n const value = await options.ask({ parameter: key, environment, secret: false });\n if (value === undefined || value === \"\") {\n skipped.push(drift.subject);\n continue;\n }\n\n const result = await runSet({ cwd: options.cwd, key, value, environment });\n written.push({\n parameter: drift.subject,\n location: result.location,\n encrypted: result.encrypted,\n });\n }\n\n return { environment, written, skipped, unreachable };\n}\n\n/** The one line that reports the run's shape when nothing else needs a row. */\nfunction summaryLine(result: FillResult): string {\n const filled = result.written.length;\n if (filled === 0 && result.skipped.length === 0 && result.unreachable.length === 0) {\n return `Nothing to fill for environment ${result.environment}: every declared parameter has a value`;\n }\n const parts = [`${filled} written`];\n if (result.skipped.length > 0) {\n parts.push(`${result.skipped.length} skipped`);\n }\n if (result.unreachable.length > 0) {\n parts.push(`${result.unreachable.length} unreachable`);\n }\n return `${parts.join(\", \")} for environment ${result.environment}`;\n}\n\nexport function renderFill(result: FillResult): string[] {\n const rows: Row[] = result.written.map((entry) => ({\n glyph: CHECK,\n label: \"Wrote\",\n subject: `${PENV_DIR}/${entry.location}`,\n // Meta decided the seal, not the answer, so the line says so — as `set` does.\n ...(entry.encrypted ? { detail: \"encrypted, per the parameter's meta policy\" } : {}),\n }));\n\n // A key no filename reaches is not skipped — it is unwritable until it is\n // renamed, so it carries its rename remedy rather than a value prompt.\n for (const entry of result.unreachable) {\n rows.push({ glyph: WARN, label: \"Unreachable\", subject: entry.subject, detail: entry.remedy });\n }\n\n const lines = formatRows(rows);\n lines.push(summaryLine(result));\n return lines;\n}\n\nexport const fillCommand = defineCommand({\n meta: {\n name: \"fill\",\n description: \"Prompt for each declared parameter the tree has no value for\",\n },\n args: {\n env: { type: \"string\", description: \"The environment to fill\" },\n },\n run({ args }) {\n return guard(async () => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n // TODO: a `prompt.secret` answer still echoes — echo-muting is out of scope\n // for v1. The prompt shows the derived key, so a reader sees the file name\n // their answer becomes.\n const ask = (prompt: FillPrompt): Promise<string> =>\n rl.question(`${prompt.parameter} (${prompt.environment}): `);\n try {\n write(\n renderFill(\n await runFill({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n ask,\n }),\n ),\n );\n } finally {\n rl.close();\n }\n });\n },\n});\n","/**\n * `penv generate` — write a flat `.env` artifact for deploy targets that expect\n * one.\n *\n * The output is an artifact, never an input: invariant 15 makes `.penv/` the\n * source of truth, and a hand-edit here is not absorbed back. Ordering is\n * normalized rather than preserved — one value per file discards the source\n * file's sequence by construction, so `generate` emits a deterministic sorted\n * order and the output is stable and diffable across machines.\n */\n\nimport { writeFileSync } from \"node:fs\";\nimport { isAbsolute, relative, resolve } from \"node:path\";\nimport type { DotenvEntry } from \"@penvhq/core\";\nimport {\n checkNameCollisions,\n effectiveMeta,\n PenvError,\n requireValue,\n serializeDotenv,\n variableName,\n} from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport type { Project } from \"../project.js\";\nimport {\n keySourceFor,\n localTree,\n openProject,\n PENV_DIR,\n refsFrom,\n resolveAllSync,\n targetEnvironment,\n} from \"../project.js\";\nimport { CHECK, formatRows, guard, WARN, write } from \"../ui.js\";\n\nexport const DEFAULT_OUTPUT = \".env\";\n\nexport interface GenerateOptions {\n readonly cwd: string;\n readonly environment?: string;\n /** Where to write, absolute or relative to `cwd`. Defaults to `.env` at the project root. */\n readonly out?: string;\n /** Permits sealed values to be written into the artifact as plaintext. */\n readonly allowDecrypt?: boolean;\n}\n\nexport interface GenerateResult {\n readonly file: string;\n readonly environment: string;\n readonly entries: number;\n /** How many of them were sealed and are now plaintext in the artifact. */\n readonly decrypted: number;\n}\n\n/**\n * The variables for one environment, and how many of them were sealed.\n *\n * The count is returned rather than discarded because decrypting a secret into a\n * plaintext artifact is the one thing this command does that the user cannot see\n * by looking at the tree. `generate` reports it (invariant 13).\n */\ninterface Artifact {\n readonly entries: DotenvEntry[];\n readonly decrypted: number;\n}\n\nfunction entriesFor(project: Project, environment: string, allowDecrypt: boolean): Artifact {\n const keys = keySourceFor(project, environment);\n const tree = localTree(project);\n const resolutions = resolveAllSync(tree, environment, keys);\n\n // Invariant 12, enforced where the loss would happen: two parameters mapping\n // to one variable would silently drop a value from this file.\n const collision = checkNameCollisions(\n refsFrom(resolutions.map((resolution) => resolution.ref)),\n project.config,\n )[0];\n if (collision !== undefined) {\n throw collision;\n }\n\n const entries: DotenvEntry[] = [];\n let decrypted = 0;\n for (const resolution of resolutions) {\n const winner = resolution.winner;\n if (winner?.file.encrypted === true) {\n // A `.env` is plaintext by construction, so writing a sealed value into one\n // unseals it. penv will do that — the leaving guarantee is that a working\n // `.env` is always reachable — but never as a side effect of a command the\n // user ran for another reason. Asking makes the moment the secret becomes\n // plaintext a moment they chose.\n if (!allowDecrypt) {\n throw new PenvError(\n \"ENCRYPTED_VALUE_REFUSED\",\n `Parameter ${resolution.parameter} for environment ${environment} resolves to the encrypted value file ${PENV_DIR}/${winner.location}, and \\`penv generate\\` writes plaintext`,\n `Re-run with \\`--allow-decrypt\\` to write the decrypted value into the artifact, or generate for an environment whose values are plaintext. The artifact is gitignored; a committed plaintext secret is a \\`penv doctor\\` failure.`,\n );\n }\n // Throws when it cannot be opened, naming the reason — never silently\n // omitting the variable, which would produce an artifact that is missing\n // exactly the secret the deploy needs.\n requireValue(resolution, environment);\n decrypted += 1;\n }\n if (resolution.value === undefined) {\n continue;\n }\n // A parameter's description is a comment in the generated file, so the\n // annotation that arrived on import survives the round trip back out.\n const description = effectiveMeta(tree.readMetaSync(resolution.ref), environment).description;\n entries.push({\n key: variableName(resolution.ref, project.config),\n value: resolution.value,\n ...(typeof description === \"string\" ? { description } : {}),\n });\n }\n\n // Sorted by the generated variable, which is what a reader of this file sees.\n entries.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));\n return { entries, decrypted };\n}\n\n/** The `.env` text for one environment — what `penv generate` writes. */\nexport function generateDotenv(options: Omit<GenerateOptions, \"out\">): string {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n return serializeDotenv(entriesFor(project, environment, options.allowDecrypt === true).entries);\n}\n\nexport function runGenerate(options: GenerateOptions): GenerateResult {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const { entries, decrypted } = entriesFor(project, environment, options.allowDecrypt === true);\n\n // `--out` is the caller's path, so it is relative to where they are standing;\n // the default artifact belongs next to the config it was generated from.\n const file =\n options.out === undefined\n ? resolve(project.root, DEFAULT_OUTPUT)\n : isAbsolute(options.out)\n ? options.out\n : resolve(options.cwd, options.out);\n\n writeFileSync(file, serializeDotenv(entries), \"utf8\");\n return { file, environment, entries: entries.length, decrypted };\n}\n\n/** The artifact's path as the caller would type it, when it is below them. */\nfunction displayPath(cwd: string, file: string): string {\n const rel = relative(cwd, file);\n return rel === \"\" || rel.startsWith(\"..\") ? file : rel.split(\"\\\\\").join(\"/\");\n}\n\nexport function renderGenerate(result: GenerateResult, cwd: string): string[] {\n const rows = [\n {\n glyph: CHECK,\n label: \"Generated\",\n subject: displayPath(cwd, result.file),\n detail: `${result.entries} variables for environment ${result.environment}`,\n },\n ];\n // A secret that was sealed a moment ago and is plaintext now is worth a line of\n // its own. The artifact is gitignored, which is a reason it is safe to write —\n // not a reason to write it quietly.\n if (result.decrypted > 0) {\n rows.push({\n glyph: WARN,\n label: \"Decrypted\",\n subject: `${result.decrypted} ${result.decrypted === 1 ? \"secret\" : \"secrets\"}`,\n detail: \"written as plaintext into the artifact\",\n });\n }\n return formatRows(rows);\n}\n\nexport const generateCommand = defineCommand({\n meta: { name: \"generate\", description: \"Write a standard .env artifact for deploy targets\" },\n args: {\n env: { type: \"string\", description: \"The environment to generate for\" },\n out: { type: \"string\", description: \"Where to write, instead of .env\" },\n \"allow-decrypt\": {\n type: \"boolean\",\n description: \"Write encrypted values into the artifact as plaintext\",\n },\n },\n run({ args }) {\n return guard(async () => {\n const cwd = process.cwd();\n const result = runGenerate({\n cwd,\n ...(args.env === undefined ? {} : { environment: args.env }),\n ...(args.out === undefined ? {} : { out: args.out }),\n ...(args[\"allow-decrypt\"] === undefined ? {} : { allowDecrypt: args[\"allow-decrypt\"] }),\n });\n write(renderGenerate(result, cwd));\n });\n },\n});\n","/**\n * `penv get <key>` — read a parameter, or explain which file wins and why.\n *\n * Fallback is never silent, and neither is precedence: `--explain` prints every\n * candidate in the order the cascade considered them, so a value quietly coming\n * from a shared default has nowhere to hide.\n */\n\nimport { PenvError, requireValue, resolveParameter } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { keySourceFor, openProject, PENV_DIR, refFromKey, targetEnvironment } from \"../project.js\";\nimport { columns, guard, write } from \"../ui.js\";\n\nexport interface GetOptions {\n readonly cwd: string;\n readonly key: string;\n readonly environment?: string;\n}\n\nexport interface GetExplanation {\n readonly parameter: string;\n readonly environment: string;\n /** `undefined` when no candidate was present. */\n readonly location: string | undefined;\n /**\n * Why the winning file did not open, when it is `.enc` and did not.\n *\n * A winner that cannot be decrypted is not a skipped candidate — it won, and\n * the cascade is over. Reporting it as a skip would say a lower scope should\n * have been reached, which is the scope-widening answer the cascade refuses.\n */\n readonly undecryptable?: string;\n readonly candidates: readonly GetCandidate[];\n}\n\nexport interface GetCandidate {\n readonly location: string;\n readonly present: boolean;\n readonly wins: boolean;\n /** Why a present candidate did not win, or why it was never considered. */\n readonly skipped: string | undefined;\n}\n\n/**\n * The value, or a named error.\n *\n * `requireValue` answers first, so a winner that exists but did not decrypt is\n * reported as undecryptable rather than as absent. Only a genuine absence — no\n * candidate at any scope — reaches the refusal below, which is what keeps `penv\n * set` from being offered as the fix for a secret the user still has.\n */\nexport async function runGet(options: GetOptions): Promise<string> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const ref = refFromKey(options.key);\n\n const keys = keySourceFor(project, environment);\n const resolution = await resolveParameter(ref, environment, project.provider, keys);\n const value = requireValue(resolution, environment);\n if (value === undefined) {\n throw new PenvError(\n \"PARAMETER_ABSENT\",\n `Parameter ${resolution.parameter} resolves to no value for environment ${environment}`,\n `Set it with \\`penv set ${options.key} --env ${environment}\\`, or run \\`penv get ${options.key} --env ${environment} --explain\\` to see every file penv looked at.`,\n );\n }\n return value;\n}\n\nfunction skipReason(reason: string | undefined): string | undefined {\n if (reason === \"lower-precedence\") {\n // Not \"a more specific scope wins\". Within one scope the plaintext file is\n // considered before its `.enc` twin, so the file that beat this one is\n // sometimes at the *same* scope — and a reader told the winner was more\n // specific would go looking for a scope that does not exist.\n return \"skipped, a higher-precedence file wins\";\n }\n if (reason === \"local-skipped-in-test\") {\n return \"skipped, .local never applies in test\";\n }\n return undefined;\n}\n\n/**\n * Which file wins, and why — never a value, so this must not be stopped by the\n * winner being unreadable. Core describes an `.enc` winner rather than refusing\n * it, so `--explain` is the same walk every other command does.\n */\nexport async function runExplain(options: GetOptions): Promise<GetExplanation> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const ref = refFromKey(options.key);\n\n const keys = keySourceFor(project, environment);\n const resolution = await resolveParameter(ref, environment, project.provider, keys);\n const winner = resolution.winner;\n\n return {\n parameter: resolution.parameter,\n environment,\n location: winner === undefined ? undefined : winner.location,\n ...(resolution.undecryptable === undefined\n ? {}\n : { undecryptable: resolution.undecryptable.detail }),\n candidates: resolution.candidates.map((candidate) => ({\n location: candidate.location,\n present: candidate.present,\n wins: candidate === winner,\n skipped: skipReason(candidate.skippedReason),\n })),\n };\n}\n\nexport function renderExplain(explanation: GetExplanation): string[] {\n const target =\n explanation.location === undefined ? \"nothing\" : `${PENV_DIR}/${explanation.location}`;\n\n // Candidates stay in the order the cascade considered them: the answer to\n // \"why this file\" is the list above it that did not win.\n const rows = explanation.candidates.map((candidate) => [\n candidate.location,\n candidate.wins\n ? \"present, wins\"\n : candidate.present\n ? (candidate.skipped ?? \"present\")\n : (candidate.skipped ?? \"absent\"),\n ]);\n\n return [\n `${explanation.parameter} resolves to ${target} for environment ${explanation.environment}`,\n ...(explanation.undecryptable === undefined\n ? []\n : [` penv cannot decrypt it: ${explanation.undecryptable}`]),\n \"\",\n ...columns(rows).map((line) => ` ${line}`),\n ];\n}\n\nexport const getCommand = defineCommand({\n meta: { name: \"get\", description: \"Read a parameter\" },\n args: {\n key: { type: \"positional\", required: true, description: \"The parameter, e.g. redis/password\" },\n env: { type: \"string\", description: \"The environment to read\" },\n explain: { type: \"boolean\", description: \"Print which file wins, and why\" },\n },\n run({ args }) {\n return guard(async () => {\n const options: GetOptions = {\n cwd: process.cwd(),\n key: args.key,\n ...(args.env === undefined ? {} : { environment: args.env }),\n };\n if (args.explain === true) {\n write(renderExplain(await runExplain(options)));\n return;\n }\n write([await runGet(options)]);\n });\n },\n});\n","/**\n * `penv import <file>` — adopt an existing dotenv file.\n *\n * Invariant 15: this is one-directional. After it runs, `.penv/` is the source of\n * truth and `.env` is an artifact `penv generate` writes; there is no reverse\n * sync of hand-edits back out of the generated file.\n *\n * Import creates flat parameters. `refFromVariable` never infers a namespace,\n * because a flat `.env` carries no structure to read — `REDIS_PASSWORD` cannot\n * say whether it came from `redis/password` or `redis-password`. Namespacing is\n * a deliberate refactor afterwards, not a guess made during adoption.\n *\n * Scope, unlike namespace, *is* readable from the source: the filename says it,\n * in the four-level vocabulary invariant 4 adopts wholesale. `.env.production`\n * carries `production` the way `.env` carries nothing, so import reads it rather\n * than flattening it — a `.env.development.local` written to the unscoped default\n * would serve every environment, and one developer's machine would become\n * production's fallback.\n *\n * `--env` is the other half of that reading. A file the filename says nothing\n * about — `prod-secrets.txt`, or a plain `.env` the user is adopting as one\n * environment's values — has its scope named by the flag instead, because \"these\n * are production's values\" is what `--env production` means at an import. Only a\n * file that names neither is the unscoped default.\n */\n\nimport { copyFileSync, existsSync, readFileSync } from \"node:fs\";\nimport { basename, isAbsolute, relative, resolve } from \"node:path\";\nimport type { DotenvEntry, Meta, ParameterRef, PenvConfig, Scope } from \"@penvhq/core\";\nimport {\n accessPath,\n assertNever,\n checkNameCollisions,\n FilenameGrammarError,\n findConfigFile,\n isReservedToken,\n loadConfigFrom,\n lookupEnvironment,\n PenvError,\n parseDotenv,\n ReservedTokenError,\n refFromVariable,\n roundTripsCleanly,\n schemaFileOf,\n UnknownEnvironmentError,\n variableName,\n} from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { detectAlias } from \"../detect.js\";\nimport { localTree, openProject } from \"../project.js\";\nimport { CHECK, formatSteps, guard, type Step, WARN, write } from \"../ui.js\";\nimport type { InitDecisions, InitStep, SchemaField } from \"./init.js\";\nimport { planInit, scaffold, writeConfigFile } from \"./init.js\";\nimport type { ValidateResult } from \"./validate.js\";\nimport { renderValidate, runValidate } from \"./validate.js\";\n\nexport interface ImportOptions {\n readonly cwd: string;\n /** The dotenv file to adopt, absolute or relative to `cwd`. */\n readonly file: string;\n /**\n * `--env`. It reads as \"these are <environment>'s values\", so for a file whose\n * name carries no environment it names the *scope* as well as the environment\n * to run against: `penv import prod-secrets.txt --env production` writes\n * `<name>.production`, and `--env production` on `.env.local` writes\n * `<name>.production.local`. The filename supplies both when it carries an\n * environment, so the flag is needed only for a file that does not — and\n * contradicting the filename is an error rather than a silent choice between\n * the two.\n */\n readonly environment?: string;\n}\n\nexport interface ImportReport {\n readonly root: string;\n readonly file: string;\n readonly backup: string;\n /** The scope the source named — filename, `--env`, or both — and the scope every value was written at. */\n readonly scope: Scope;\n /**\n * The environment the import ran against, or `undefined` when none is set.\n *\n * Undefined only ever accompanies the unscoped default: any other scope names\n * an environment, so it always has one. It means the values were written and\n * the closing validation was skipped, which the output states.\n */\n readonly environment: string | undefined;\n /** The declared environments, so a skipped validation can name one to pass. */\n readonly environments: readonly string[];\n readonly variables: number;\n /**\n * Comment blocks that belonged to no variable. Reported rather than discarded\n * silently: a file header has no parameter to describe, but that is not a\n * reason to pretend it was never there.\n */\n readonly orphanComments: number;\n readonly steps: readonly InitStep[];\n}\n\nconst BACKUP_SUFFIX = \".backup\";\n\n/** The segment that starts a dotenv filename's scope. `.env`, `.env.production`. */\nconst DOTENV_SEGMENT = \"env\";\nconst LOCAL = \"local\";\n\n/** A URL of any scheme — `postgres://` is as much a URL as `https://`. */\nconst URL_LIKE = /^[a-z][a-z0-9+.-]*:\\/\\/\\S+$/i;\nconst IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n\n/**\n * The Zod expression for one sampled value. Values arrive as strings, so a\n * schema that must accept them declares the coercion: `z.boolean()` would reject\n * the string `\"true\"` this very file just imported.\n */\nfunction inferType(value: string): string {\n if (URL_LIKE.test(value)) {\n return \"z.url()\";\n }\n if (/^(true|false)$/i.test(value)) {\n return \"z.stringbool()\";\n }\n if (value.trim() !== \"\" && Number.isFinite(Number(value))) {\n return \"z.coerce.number()\";\n }\n return \"z.string()\";\n}\n\n/** Sorted, so the draft is identical on every machine. */\nexport function draftFields(entries: readonly DotenvEntry[]): SchemaField[] {\n return entries\n .map((entry) => {\n const key = accessPath(refFromVariable(entry.key)).join(\".\");\n return {\n key: IDENTIFIER.test(key) ? key : JSON.stringify(key),\n type: inferType(entry.value),\n };\n })\n .sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));\n}\n\n/**\n * Filenames are split on `.`, so a variable that becomes a dotted name would\n * parse back as a scope segment rather than the parameter it came from.\n */\nfunction assertImportable(ref: ParameterRef, variable: string): void {\n if (!ref.name.includes(\".\")) {\n return;\n }\n throw new PenvError(\n \"IMPORT_UNPARSEABLE_NAME\",\n `The variable ${variable} becomes the parameter \\`${ref.name}\\`, whose \\`.\\` would be read as a scope`,\n `Filenames are split on \\`.\\`. Rename ${variable} in the source file, then import it again.`,\n );\n}\n\n/**\n * Invariant 11: `enc`, `json`, `toml`, `yml`, `local`, and every declared\n * environment are reserved, and a collision is an error rather than a warning.\n *\n * A written `.penv/enc` does not merely import badly — it re-parses as a scope\n * segment, so every later `list()` throws and `get`, `generate`, `validate`, and\n * even `remove` stop working. The project can only be repaired by deleting the\n * file by hand, which is why this runs before anything is written rather than\n * leaving `penv validate` to report the wreckage afterwards.\n *\n * The error names the *variable*, not the parameter: the user is reading their\n * `.env`, where the line says `ENC=`, and `enc` is penv's word for it.\n */\nfunction assertNotReserved(\n ref: ParameterRef,\n variable: string,\n where: string,\n config: PenvConfig,\n): void {\n if (isReservedToken(ref.name, config)) {\n throw new ReservedTokenError(\"parameter\", variable, where);\n }\n}\n\n/**\n * The v0.1 gate: every variable survives `import` then `generate` unchanged,\n * *modulo declared name overrides*.\n *\n * `MY-VAR` imports to the parameter `my-var` and regenerates as `MY_VAR`, so the\n * application's `process.env[\"MY-VAR\"]` reads `undefined` after a round trip. A\n * flat `.env` cannot tell `MY-VAR` from `MY_VAR` once both collapse to one\n * parameter, so no escape scheme rescues it — the honest move is to refuse. An\n * explicit `names` override is the exception the gate allows: it makes the\n * generated name a stated decision instead of an accident. Silence does not.\n */\nfunction assertRoundTrips(ref: ParameterRef, variable: string, config: PenvConfig): void {\n if (roundTripsCleanly(variable)) {\n return;\n }\n // The declared override the gate's \"modulo\" clause means. Checked against the\n // real transform, so an override that does not actually restore the variable\n // is not mistaken for one that does.\n if (variableName(ref, config) === variable) {\n return;\n }\n const generated = variableName(ref, config);\n throw new PenvError(\n \"IMPORT_LOSSY_NAME\",\n `The variable ${variable} becomes the parameter \\`${ref.name}\\`, which regenerates as ${generated}`,\n `\\`penv generate\\` would write ${generated}, so anything reading ` +\n `\\`process.env[\"${variable}\"]\\` would read \\`undefined\\`. Declare the name you want in the ` +\n `\\`names\\` block of penv.config.ts — \\`names: { \"${ref.name}\": \"${variable}\" }\\` — then ` +\n `import it again. Nothing was imported.`,\n );\n}\n\nfunction collisionsIn(refs: readonly ParameterRef[], config: PenvConfig): void {\n const errors = checkNameCollisions(refs, config);\n const first = errors[0];\n if (first !== undefined) {\n throw first;\n }\n}\n\n/**\n * Invariant 10: a segment is an environment because `penv.config.ts` declares\n * it, never because it looks like one. This matches the whitelist — the thing\n * the invariant permits — and refuses everything else.\n *\n * Refusing is the whole point. Falling back to the unscoped default for an\n * undeclared segment is precisely the leak: `.env.staging` in a project that\n * never declared `staging` would become the value every environment reads.\n */\nfunction assertDeclared(segment: string, config: PenvConfig): string {\n if (config.environments.includes(segment)) {\n return segment;\n }\n throw new UnknownEnvironmentError(segment, config.environments);\n}\n\n/**\n * The scope the source filename names, in the vocabulary invariant 4 shares with\n * Next.js and Vite: `.env` > unscoped, `.env.<env>`, `.env.local`, and\n * `.env.<env>.local`.\n *\n * Parsing starts at the first `env` segment, because `import` reads whatever\n * file it is pointed at and the basename may carry a prefix. A file with no\n * `env` segment at all is the plain-`.env` case — there is no scope written on\n * it, so there is none to read, and the unscoped default is what it means.\n */\nfunction scopeFromFilename(file: string, config: PenvConfig): Scope {\n const name = basename(file);\n const segments = name.split(\".\");\n const start = segments.indexOf(DOTENV_SEGMENT);\n if (start === -1) {\n return { kind: \"unscoped\" };\n }\n\n const rest = segments.slice(start + 1).filter((segment) => segment.length > 0);\n const first = rest[0];\n const second = rest[1];\n\n if (first === undefined) {\n return { kind: \"unscoped\" };\n }\n\n if (second === undefined) {\n if (first === LOCAL) {\n return { kind: LOCAL };\n }\n return { kind: \"environment\", environment: assertDeclared(first, config) };\n }\n\n if (rest.length === 2 && second === LOCAL && first !== LOCAL) {\n return { kind: \"environment-local\", environment: assertDeclared(first, config) };\n }\n\n // The order is fixed at both ends of the import: the environment precedes\n // `local` in the dotenv filename this reads and in the value filename it\n // writes, so `.env.local.production` is an error rather than a synonym.\n if (first === LOCAL && rest.length === 2) {\n throw new FilenameGrammarError(\n name,\n \"`local` precedes the environment segment\",\n `The environment segment always precedes \\`local\\` — \\`.env.${second}.${LOCAL}\\` is the ` +\n `file Next.js and Vite read, and \\`.env.${LOCAL}.${second}\\` is not a synonym for it. ` +\n `Rename it to \\`.env.${second}.${LOCAL}\\`, then import it again. Nothing was imported.`,\n );\n }\n\n throw new FilenameGrammarError(\n name,\n `\\`${rest.join(\"` and `\")}\\` are ${rest.length} scope segments`,\n \"A dotenv file carries exactly one scope: `.env`, `.env.<environment>`, `.env.local`, or \" +\n \"`.env.<environment>.local`. Point `penv import` at one of those. Nothing was imported.\",\n );\n}\n\n/**\n * The environment a scope names, or `undefined` when it names none.\n *\n * The `default` is load-bearing rather than ceremonial: a fifth scope carrying\n * an environment would otherwise report `undefined` here, and import would fall\n * back to `--env` — silently widening exactly the way the three-level cascade did.\n */\nfunction environmentOf(scope: Scope): string | undefined {\n switch (scope.kind) {\n case \"environment\":\n case \"environment-local\":\n return scope.environment;\n case \"unscoped\":\n case \"local\":\n return undefined;\n default:\n return assertNever(scope, \"scope\");\n }\n}\n\n/**\n * The scope `--env <environment>` names, given the scope the filename named.\n *\n * `--env` reads as \"these are <environment>'s values\", so it names a scope and\n * not merely a validation target. Deriving the scope from the filename alone was\n * the scope-widening leak: `penv import prod-secrets.txt --env production` wrote\n * the unscoped default, and `development` read the production secret.\n *\n * A filename that already names an environment keeps its scope untouched: by the\n * time this runs the two agree, because a contradiction is an error. `.env.local`\n * names a scope but no environment, so the two compose — the filename says\n * personal override, `--env` says which environment it overrides, and together\n * they are `.env.<environment>.local`.\n */\nfunction scopeWithEnvironment(scope: Scope, environment: string): Scope {\n switch (scope.kind) {\n case \"unscoped\":\n return { kind: \"environment\", environment };\n case LOCAL:\n return { kind: \"environment-local\", environment };\n case \"environment\":\n case \"environment-local\":\n return scope;\n default:\n return assertNever(scope, \"scope\");\n }\n}\n\n/**\n * `--env`, normalized the way `resolveEnvironment` normalizes it — but a flag\n * that is present and blank is refused rather than normalized away.\n *\n * `--env \"$ENVIRONMENT\"` with the variable unset arrives here as `\"\"`. Reading\n * that as \"no `--env`\" silently demotes the scope the user asked for to the\n * unscoped default, so `penv import prod-secrets.txt --env \"\"` writes the\n * production secret to the file every environment falls back to — the leak this\n * flag exists to close, through a quieter door. An absent flag still means the\n * unscoped default: that is the user declining to name a scope, not failing to.\n */\nfunction explicitEnvironment(options: ImportOptions, source: string, config: PenvConfig): string {\n const value = options.environment?.trim() ?? \"\";\n if (value.length > 0) {\n return value;\n }\n throw new PenvError(\n \"IMPORT_ENV_FLAG_EMPTY\",\n `\\`--env\\` for the import of ${source} names no environment`,\n `Pass a declared environment — ${config.environments.map((e) => `\\`${e}\\``).join(\", \")} — e.g. ` +\n `\\`--env production\\`, or drop \\`--env\\` to import ${source} as the scope that has no ` +\n `environment. Nothing was imported.`,\n );\n}\n\n/**\n * `penv import .env.production --env development` names two environments and\n * means one of them. penv cannot know which, and both readings are destructive:\n * honouring `--env` validates the wrong environment, honouring the filename\n * ignores what the user typed. It says so instead of choosing.\n */\nfunction assertEnvironmentAgrees(\n derived: string | undefined,\n explicit: string | undefined,\n source: string,\n): void {\n if (derived === undefined || explicit === undefined || derived === explicit) {\n return;\n }\n throw new PenvError(\n \"IMPORT_ENV_CONFLICT\",\n `The file ${source} is scoped to environment ${derived}, but \\`--env ${explicit}\\` names ${explicit}`,\n `Drop \\`--env\\` to import ${source} as ${derived}, pass \\`--env ${derived}\\` to say the same ` +\n `thing twice, or point \\`penv import\\` at the file that holds ${explicit}'s values. ` +\n `Nothing was imported.`,\n );\n}\n\n/**\n * The config `import` must judge names against: the project's own when it has\n * one, and otherwise the one `penv init` writes, since that is the config the\n * scaffold below is about to put in place.\n *\n * Writing it *first* is what lets every name check run before a single value\n * file exists. It is safe to leave behind if a check then fails: it is byte for\n * byte the file `penv init` writes, it holds nothing read out of the `.env`, and\n * it is the file the reserved-token and `names` remedies both tell the user to\n * go and edit.\n */\n/**\n * The environment this run names, read lexically — before any config exists to\n * check it against.\n *\n * `scopeFromFilename` cannot answer this: it validates against the whitelist, and\n * on a greenfield project the whitelist is the thing being written. So the\n * segment is read here without being believed, handed to the scaffold as a\n * declaration, and then checked by the ordinary path like any other.\n *\n * Reading it is not inference. Invariant 10 forbids penv deciding that a file in\n * a tree belongs to an environment nobody declared; this is the user typing\n * `penv import .env.production` and thereby saying which environment the file is\n * for. The command line is a declaration — the only one available on a project\n * that has no config yet.\n */\nfunction environmentNamed(file: string, explicit: string | undefined): string | undefined {\n if (explicit !== undefined && explicit.trim().length > 0) {\n return explicit.trim();\n }\n const segments = basename(file).split(\".\");\n const start = segments.indexOf(DOTENV_SEGMENT);\n if (start === -1) {\n return undefined;\n }\n const first = segments.slice(start + 1).filter((segment) => segment.length > 0)[0];\n return first === undefined || first === LOCAL ? undefined : first;\n}\n\n/**\n * The config to check every name against, scaffolding one when the project has none.\n *\n * Writing it *first* is what lets every name check run before a single value\n * file exists. It is safe to leave behind if a check then fails: it holds\n * nothing read out of the `.env`, and it is the file the reserved-token and\n * `names` remedies both tell the user to go and edit.\n *\n * The scaffold declares the environment this import names, and nothing else.\n * `penv init` refuses to invent environments because it cannot observe a\n * deployment — but here the user has named one, and a config that omitted it\n * would be penv writing a file that makes penv's own next step fail.\n */\ninterface Adoption {\n readonly config: PenvConfig;\n /**\n * What the rest of the scaffold must write, and the reason this is returned\n * rather than recomputed.\n *\n * `scaffold` takes `decisions` with a default, so a caller that forgot them\n * compiled and quietly wrote `DEFAULT_DECISIONS` instead. Import forgot them:\n * the config it wrote said `schemaFile: \"src/env.ts\"` while the schema it\n * scaffolded a moment later went to `.penv/env.ts`, and the two disagreed for\n * exactly as long as the project lived. The optional parameter is what hid it\n * from the compiler; carrying the decisions is what stops the two halves of one\n * scaffold answering the same question differently.\n */\n readonly decisions: InitDecisions;\n}\n\n/** The decisions a config already records. The alias is read from the files that resolve it. */\nfunction decisionsOf(config: PenvConfig, cwd: string): InitDecisions {\n return {\n environments: config.environments,\n schemaFile: schemaFileOf(config),\n publicPrefixes: config.publicPrefixes ?? [],\n alias: detectAlias(cwd),\n };\n}\n\nfunction configInEffect(cwd: string, environment: string | undefined): Adoption {\n const existing = findConfigFile(cwd);\n if (existing !== undefined) {\n const config = loadConfigFrom(existing);\n return { config, decisions: decisionsOf(config, cwd) };\n }\n // The same plan `penv init` would make without being asked anything — import\n // is a scaffold too, and two scaffolds that disagreed about where the schema\n // goes would make the answer depend on which command the user reached for.\n const planned = planInit(cwd).decisions;\n const decisions: InitDecisions = {\n ...planned,\n environments: environment === undefined ? planned.environments : [environment],\n };\n writeConfigFile(cwd, decisions);\n return { config: openProject(cwd).config, decisions };\n}\n\n/**\n * Adopts the file: parses it, scaffolds the project, writes one value file per\n * variable and each attached comment into that parameter's meta, and backs the\n * source up. Validation is the caller's next step rather than part of adoption —\n * an inferred schema is a draft, and a draft that needs correcting has still\n * imported every value correctly.\n *\n * Adoption is all or nothing. Every name is checked against the config, and any\n * environment the source names resolved, before the tree is scaffolded or a\n * value written. The two names that fail here fail *destructively*: a reserved\n * name bricks every later command, and a lossy name renames the user's variable\n * behind their back. What the source names is resolved here rather than left to\n * the closing `validate` because a command that writes a tree and *then*\n * discovers it cannot name an environment has already half-adopted the project\n * it just refused. A half-imported tree would be the drift penv exists to\n * remove, introduced by penv itself.\n *\n * An environment nothing names is a different case, and not an error: an\n * unscoped import writes at the unscoped default, which needs no environment.\n * Only the validation that follows needs one, so it is skipped and said to be\n * skipped. Requiring one here would fail `penv import .env` on a greenfield\n * project — the first command the quickstart gives, where no environment could\n * plausibly be set yet — to satisfy a step that is the caller's next one.\n */\nexport function importDotenv(options: ImportOptions): ImportReport {\n const cwd = resolve(options.cwd);\n const file = isAbsolute(options.file) ? options.file : resolve(cwd, options.file);\n if (!existsSync(file)) {\n throw new PenvError(\n \"IMPORT_FILE_MISSING\",\n `There is no file at ${file} to import`,\n \"Point `penv import` at an existing dotenv file, e.g. `penv import .env`.\",\n );\n }\n\n const parsed = parseDotenv(readFileSync(file, \"utf8\"));\n const { config, decisions } = configInEffect(cwd, environmentNamed(file, options.environment));\n const source = displayPath(cwd, file);\n\n const named = scopeFromFilename(file, config);\n const derived = environmentOf(named);\n // Absent means the unscoped default; present-but-blank is refused, never\n // normalized into absent.\n const explicit =\n options.environment === undefined ? undefined : explicitEnvironment(options, source, config);\n assertEnvironmentAgrees(derived, explicit, source);\n // `--env` must reach the scope, not just the environment: reading it into the\n // environment alone is what wrote a production secret to the unscoped default.\n // Invariant 10 first — an undeclared `--env` names no scope to write at.\n const scope =\n explicit === undefined ? named : scopeWithEnvironment(named, assertDeclared(explicit, config));\n // The filename is an environment the user has already stated, so `penv import\n // .env.production` needs no `--env` to mean production. Nothing naming one is\n // the unscoped default's ordinary case, not a failure — the values still have\n // a scope to be written at, and only the closing validate goes without.\n const environment = lookupEnvironment(config, explicit ?? derived);\n\n const refs: ParameterRef[] = [];\n for (const entry of parsed.entries) {\n const ref = refFromVariable(entry.key);\n assertImportable(ref, entry.key);\n assertNotReserved(ref, entry.key, source, config);\n assertRoundTrips(ref, entry.key, config);\n refs.push(ref);\n }\n collisionsIn(refs, config);\n\n // Every check has passed, so from here the import runs to completion.\n // The decisions the config was written from, not the defaults: the two halves\n // of one scaffold must not disagree about where the schema lives.\n const steps = scaffold(cwd, draftFields(parsed.entries), true, decisions);\n const project = openProject(cwd);\n const tree = localTree(project);\n\n for (const [index, entry] of parsed.entries.entries()) {\n const ref = refs[index];\n if (ref === undefined) {\n continue;\n }\n tree.writeSync(\n { namespace: ref.namespace, name: ref.name, scope, encrypted: false },\n entry.value,\n );\n // A comment sitting directly above a variable describes it, so it becomes\n // that parameter's meta description and `generate` re-emits it as a comment.\n if (entry.description !== undefined) {\n const existing = tree.readMetaSync(ref);\n const meta: Meta = { ...existing, description: entry.description };\n tree.writeMetaSync(ref, meta);\n }\n }\n\n const backup = `${file}${BACKUP_SUFFIX}`;\n copyFileSync(file, backup);\n\n return {\n root: project.root,\n file,\n backup,\n scope,\n environment,\n environments: config.environments,\n variables: parsed.entries.length,\n orphanComments: parsed.orphanComments,\n steps,\n };\n}\n\nfunction displayPath(root: string, file: string): string {\n const rel = relative(root, file);\n return rel === \"\" || rel.startsWith(\"..\") ? file : rel.split(\"\\\\\").join(\"/\");\n}\n\n/**\n * Invariant 2 kept the user's `env.ts`; invariant 13 says so out loud.\n *\n * `penv init` then `penv import` is the ordinary path, and it lands here: the\n * schema penv scaffolded is an empty `z.object({})`, the draft that would have\n * declared the imported parameters is not written, and the closing `validate`\n * passes — an empty object validates against an empty schema. A ✓ on that line\n * reports a project where nothing is declared as a project that is fine.\n *\n * The count is every imported parameter, because penv declared none of them: it\n * did not write the draft, and it does not read the user's schema to guess which\n * ones they had already declared themselves.\n */\nfunction keptSchemaStep(step: InitStep, variables: number): Step {\n const plural = variables === 1 ? \"parameter\" : \"parameters\";\n return {\n glyph: WARN,\n // The step's own text, which names the file that was actually kept. This\n // line rebuilt it from a hardcoded `.penv/env.ts`, so a project whose schema\n // lives in `src/` was told penv had kept a file it does not have — the one\n // line whose whole job is \"your schema is untouched\" naming the wrong\n // schema. Only the glyph and the note are this function's business.\n text: step.text,\n note: `(yours — ${variables} imported ${plural} undeclared, draft schema skipped)`,\n };\n}\n\n/**\n * Invariant 13: the validation that did not run says so.\n *\n * A skipped check and a passed check must never look alike — the import wrote\n * every value, so a silent skip would read as a validated tree. The remedy names\n * a declared environment because the user has not chosen one yet; that is the\n * whole reason this line exists.\n */\nfunction skippedValidationStep(environments: readonly string[]): Step {\n const example = environments[0] ?? \"<environment>\";\n return {\n glyph: WARN,\n text: \"Skipped validation\",\n note: `(no environment set — run \\`penv validate --env ${example}\\`)`,\n };\n}\n\nexport function renderImport(\n result: ImportReport,\n validation: ValidateResult | undefined,\n): string[] {\n const steps: Step[] = [{ glyph: CHECK, text: `Found ${result.variables} variables` }];\n\n // Dropped, but never silently: a comment attached to nothing has no parameter\n // to belong to, and how many there were is the user's to know.\n if (result.orphanComments > 0) {\n const plural = result.orphanComments === 1 ? \"comment\" : \"comments\";\n steps.push({\n glyph: WARN,\n text: `Dropped ${result.orphanComments} orphan ${plural}`,\n note: \"attached to no variable, so nothing to describe\",\n });\n }\n\n for (const step of result.steps) {\n if (step.target === \"schema\" && step.action === \"kept\") {\n steps.push(keptSchemaStep(step, result.variables));\n continue;\n }\n // A conflicted step is the one init reports that is not a success — the same\n // reason it wears a warning there.\n const glyph = step.action === \"conflicted\" ? WARN : CHECK;\n steps.push(\n step.note === undefined\n ? { glyph, text: step.text }\n : { glyph, text: step.text, note: step.note },\n );\n }\n steps.push({ glyph: CHECK, text: `Created ${displayPath(result.root, result.backup)}` });\n\n const lines = formatSteps(steps);\n if (validation === undefined) {\n lines.push(...formatSteps([skippedValidationStep(result.environments)]));\n } else if (validation.ok) {\n lines.push(...formatSteps([{ glyph: CHECK, text: \"Validated configuration\" }]));\n } else {\n lines.push(...renderValidate(validation));\n }\n\n lines.push(\"\", \"Done. .penv/ is now your source of truth.\");\n return lines;\n}\n\nexport const importCommand = defineCommand({\n meta: {\n name: \"import\",\n description: \"Import an existing dotenv file; it becomes the source of truth\",\n },\n args: {\n file: {\n type: \"positional\",\n required: true,\n description: \"The dotenv file to import, e.g. .env\",\n },\n env: {\n type: \"string\",\n description:\n \"The environment these are the values of; scopes them to it. The filename supplies it \" +\n \"when it carries one\",\n },\n },\n run({ args }) {\n return guard(async () => {\n const cwd = process.cwd();\n const report = importDotenv({\n cwd,\n file: args.file,\n ...(args.env === undefined ? {} : { environment: args.env }),\n });\n // The environment `import` already resolved, so the closing validate cannot\n // target a different one than the values were just written for. Without one\n // there is nothing to validate against, and the render says it was skipped.\n const validation =\n report.environment === undefined\n ? undefined\n : await runValidate({ cwd, environment: report.environment });\n write(renderImport(report, validation));\n });\n },\n});\n","/**\n * What the codebase already says about itself.\n *\n * `penv init` asks a human to confirm a plan, and a plan the human has to fill\n * in from scratch is an interrogation. So penv reads the two facts it can\n * observe — the framework in `package.json`, and whether a `src/` directory\n * exists — and offers them as a suggestion.\n *\n * The line this module does not cross: a framework is an identity, never a\n * config key. Nothing here is written to `penv.config.ts` as `framework: \"next\"`\n * — the answers become concrete decisions (`schemaFile`, `publicPrefixes`) that\n * mean the same thing in a year, when the project has been rewritten twice and\n * penv would otherwise still be reinterpreting a name it read once.\n *\n * Everything here is a suggestion. The one thing that is never suggested is an\n * environment: deployment topology is not in `package.json`, and invariant 10\n * forbids inferring it.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { DEFAULT_SCHEMA_FILE } from \"@penvhq/core\";\n\n/** A framework penv recognised, and what it implies about a project's layout. */\nexport interface Detected {\n /** The framework's own name, as a human writes it — `\"Next.js\"`. */\n readonly name: string;\n /** Where this framework's projects keep their modules, relative to the root. */\n readonly schemaFile: string;\n /**\n * The conventional path penv stepped aside from, because a module that is not\n * penv's schema already lives there. Set only when it happened, so the plan can\n * say why the schema is not where the convention would have put it.\n */\n readonly displacedFrom?: string;\n /** The prefixes this framework inlines into its client bundle. */\n readonly publicPrefixes: readonly string[];\n}\n\n/**\n * One framework's signature. `packages` is checked against dependencies and\n * devDependencies alike: a framework is a framework wherever it was installed,\n * and the two lists disagree often enough that reading one is reading half.\n */\ninterface Signature {\n readonly name: string;\n readonly packages: readonly string[];\n readonly publicPrefixes: readonly string[];\n}\n\n/**\n * Ordered most specific first: TanStack Start is Vite underneath and Next.js\n * projects carry Vite for their tests, so a signature that matches a framework's\n * *foundation* must never answer before the framework itself does.\n *\n * Remix and React Router 7 are deliberately absent. Their public-variable story\n * is not one prefix, and a guess here is worse than the fallback: the fallback\n * is reported and asks, while a wrong prefix silently arms the one `doctor`\n * check that exists to keep a secret out of a browser bundle.\n */\nconst SIGNATURES: readonly Signature[] = [\n { name: \"Next.js\", packages: [\"next\"], publicPrefixes: [\"NEXT_PUBLIC_\"] },\n {\n name: \"TanStack Start\",\n packages: [\"@tanstack/react-start\", \"@tanstack/start\"],\n publicPrefixes: [\"VITE_\"],\n },\n { name: \"Astro\", packages: [\"astro\"], publicPrefixes: [\"PUBLIC_\"] },\n { name: \"Vite\", packages: [\"vite\"], publicPrefixes: [\"VITE_\"] },\n];\n\n/**\n * Whether the module at `file` looks like it exports penv's schema.\n *\n * A scan, not a parse, and deliberately conservative in one direction: it can\n * fail to recognise an exotic re-export and say \"no\", which costs a note and a\n * different filename. It cannot invent a `schema` that is not written down, so it\n * never claims someone else's module is penv's.\n *\n * The question this answers is not \"does the file exist\". `src/env.ts` existing\n * is the common case on a re-run — it is the schema penv wrote, and keeping it is\n * invariant 2 working. The question is whether the file at the path penv wants is\n * *penv's*, because the alternative is penv choosing a path already occupied by\n * someone else's module and then reporting, later and from somewhere else, that\n * it exports no schema.\n */\nfunction exportsSchema(file: string): boolean {\n let source: string;\n try {\n source = readFileSync(file, \"utf8\");\n } catch {\n return false;\n }\n return (\n // `export const schema = z.object({ ... })` — what penv scaffolds.\n /export\\s+(?:const|let|var)\\s+schema\\b/.test(source) ||\n // `export { schema }`, `export { shape as schema }`.\n /export\\s*\\{[^}]*\\bschema\\b[^}]*\\}/.test(source)\n );\n}\n\n/** True when something that is not penv's schema already lives at `relative`. */\nfunction occupied(cwd: string, relative: string): boolean {\n const file = join(cwd, ...relative.split(\"/\"));\n return existsSync(file) && !exportsSchema(file);\n}\n\n/**\n * Where a framework's projects keep the schema — and where penv puts it instead\n * when that address is already someone else's.\n *\n * `src/env.ts` is the convention and it is also a name projects already use for\n * their own env module. Proposing it regardless is how penv came to scaffold\n * around a file it could not use: it kept the user's module (invariant 2, right),\n * then `validate` failed with \"src/env.ts exports no `schema`\" — a complaint\n * about a path penv itself had chosen.\n *\n * Stepping aside is not a guess. The file being there, and not exporting a\n * schema, is a fact about the codebase — the kind penv may default from, because\n * a wrong answer is visible in the plan and writes nothing over anything.\n */\nexport function schemaFileFor(cwd: string): { file: string; displaced?: string } {\n const dir = existsSync(join(cwd, \"src\")) ? \"src/\" : \"\";\n const preferred = `${dir}env.ts`;\n if (!occupied(cwd, preferred)) {\n return { file: preferred };\n }\n\n const beside = `${dir}penv-env.ts`;\n if (!occupied(cwd, beside)) {\n return { file: beside, displaced: preferred };\n }\n // Both names taken by modules that are not penv's. `.penv/` is penv's own\n // directory, so it is the one address no other tool has a claim on.\n return { file: DEFAULT_SCHEMA_FILE, displaced: preferred };\n}\n\n/**\n * Every dependency name the manifest declares, or `undefined` when there is no\n * manifest to read. An unreadable or malformed `package.json` answers the same\n * way an absent one does — \"I cannot tell\" — because init's fallback is correct\n * and reported, while a parse error thrown from a suggestion would fail a\n * command that had not yet asked the user anything.\n */\nfunction dependenciesOf(cwd: string): ReadonlySet<string> | undefined {\n const manifest = manifestOf(cwd);\n if (manifest === undefined) {\n return undefined;\n }\n\n const names = new Set<string>();\n for (const field of [\"dependencies\", \"devDependencies\"] as const) {\n const block: unknown = manifest[field];\n if (block !== null && typeof block === \"object\" && !Array.isArray(block)) {\n for (const name of Object.keys(block)) {\n names.add(name);\n }\n }\n }\n return names;\n}\n\n/**\n * The project's manifest, or `undefined` when there is nothing readable to read.\n *\n * An absent or unparseable `package.json` is not an error here: detection's whole\n * contract is that it may answer \"I cannot tell\", and a project penv is asked to\n * scaffold before its manifest exists is a project, not a mistake.\n */\nfunction manifestOf(cwd: string): Readonly<Record<string, unknown>> | undefined {\n const file = join(cwd, \"package.json\");\n if (!existsSync(file)) {\n return undefined;\n }\n let manifest: unknown;\n try {\n manifest = JSON.parse(readFileSync(file, \"utf8\"));\n } catch {\n return undefined;\n }\n return manifest === null || typeof manifest !== \"object\" || Array.isArray(manifest)\n ? undefined\n : (manifest as Readonly<Record<string, unknown>>);\n}\n\n/**\n * The framework this project is built with, or `undefined` when penv cannot\n * tell. `undefined` is an answer, not a failure: init falls back to the default\n * schema path and says that it did.\n */\nexport function detectFramework(cwd: string): Detected | undefined {\n const dependencies = dependenciesOf(cwd);\n if (dependencies === undefined) {\n return undefined;\n }\n for (const signature of SIGNATURES) {\n if (signature.packages.some((name) => dependencies.has(name))) {\n const schema = schemaFileFor(cwd);\n return {\n name: signature.name,\n schemaFile: schema.file,\n ...(schema.displaced === undefined ? {} : { displacedFrom: schema.displaced }),\n publicPrefixes: signature.publicPrefixes,\n };\n }\n }\n return undefined;\n}\n\n/** The alias penv writes when the project says nothing about how it names its own modules. */\nexport const DEFAULT_ALIAS = \"@env\";\n\n/** The alias for a project that already speaks Node's subpath imports. */\nexport const IMPORTS_ALIAS = \"#env\";\n\n/**\n * The alias to offer, read from how the project already refers to itself.\n *\n * The two forms are not interchangeable, and the difference is not taste:\n *\n * - `@env` is a `tsconfig.json` `paths` entry. TypeScript understands it and a\n * bundler resolves it. Plain `node dist/index.js` does not — `paths` is erased\n * by the compiler, so the emitted `import ... from \"@env\"` reaches Node as a\n * package that is not installed.\n * - `#env` is a `package.json` `imports` entry, which Node resolves natively and\n * every current bundler honours. It needs a modern `moduleResolution` for the\n * types to follow, which is why it is not simply the default.\n *\n * A project carrying an `imports` block has already answered the question, so\n * that is what is offered. Anything else gets `@env`, which is what the docs\n * describe and what a framework project wants. This is a suggestion either way:\n * the human confirms it, and the answer is written down as a decision.\n */\nexport function detectAlias(cwd: string): string {\n return hasImportsBlock(cwd) ? IMPORTS_ALIAS : DEFAULT_ALIAS;\n}\n\nfunction hasImportsBlock(cwd: string): boolean {\n const manifest = manifestOf(cwd);\n const imports = manifest?.imports;\n return imports !== null && typeof imports === \"object\" && !Array.isArray(imports);\n}\n","/**\n * `penv init` — scaffold a project.\n *\n * Every step is idempotent, and two of them are write-once on purpose: the\n * schema module is yours the moment it exists (invariant 2 — penv scaffolds it,\n * never regenerates it), and `penv.config.ts` is the environment whitelist you\n * declared. Re-running init reports what it kept rather than overwriting it.\n *\n * What init writes is a set of decisions, and the two kinds are kept apart. penv\n * may default what it can *observe* — the framework in `package.json`, whether\n * `src/` exists — because a wrong guess about the codebase is visible in the\n * codebase. It must ask for what it cannot observe: which environments exist is\n * deployment topology, it is nowhere on disk, and a project that carries a\n * `staging` penv invented is a project whose config is fiction (invariant 10).\n * So `environments` starts empty, and `--yes` cannot fill it: `--yes` means \"I\n * trust your defaults for what you can see\", never \"invent my infrastructure\".\n */\n\nimport { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { createInterface } from \"node:readline/promises\";\nimport {\n DEFAULT_SCHEMA_FILE,\n isLegalEnvironmentName,\n loadConfigFrom,\n type PenvConfig,\n PenvError,\n RESERVED_TOKENS,\n schemaFileOf,\n schemaInsideTree,\n validateSchemaFile,\n} from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { DEFAULT_ALIAS, type Detected, detectAlias, detectFramework } from \"../detect.js\";\nimport { CHECK, columns, formatSteps, guard, type Step, WARN, write } from \"../ui.js\";\n\nexport const SCHEMA_FILE = \"env.ts\";\nexport const CONFIG_FILE = \"penv.config.ts\";\nexport const TSCONFIG_FILE = \"tsconfig.json\";\nexport const GITIGNORE_FILE = \".gitignore\";\nexport const PENV_DIR = \".penv\";\n\n/**\n * The alias forms penv can write, and the only two a specifier can take that is\n * not a package: `@name` resolves through tsconfig `paths`, `#name` through\n * package.json `imports`.\n */\nconst ALIAS_NAME = /^[@#][A-Za-z0-9_-]+$/;\n\n/** The prefix that means Node resolves the alias itself, with no bundler involved. */\nconst IMPORTS_PREFIX = \"#\";\n\nconst PACKAGE_FILE = \"package.json\";\n\n/** What init touched, so a caller can report it and a test can assert it. */\nexport type InitTarget = \"penv-dir\" | \"schema\" | \"config\" | \"tsconfig\" | \"gitignore\";\n/**\n * `conflicted` is the one that is not a success. penv wanted to write something,\n * found the user's file already saying something else about the same thing, and\n * left it alone — so the step is reported with a warning rather than a ✓, and the\n * text says what will not work until the user decides.\n */\nexport type InitAction = \"created\" | \"kept\" | \"updated\" | \"conflicted\";\n\nexport interface InitStep {\n readonly target: InitTarget;\n readonly action: InitAction;\n /** The reported line, in the docs' voice. */\n readonly text: string;\n readonly note?: string;\n}\n\n/**\n * The answers init writes down. Every one of these is a decision a human either\n * made or consented to — never an identity penv recorded to reinterpret later.\n * There is deliberately no `framework` here: `schemaFile` and `publicPrefixes`\n * still mean exactly what they say after the project is rewritten in something\n * else, and `framework: \"next\"` would not.\n */\nexport interface InitDecisions {\n /** The whitelist. Empty unless a human named them — penv never infers one. */\n readonly environments: readonly string[];\n /** The schema module, relative to the project root, POSIX. */\n readonly schemaFile: string;\n /** The prefixes the framework inlines into its client bundle. */\n readonly publicPrefixes: readonly string[];\n /**\n * How the user's code names the schema module — `@env` or `#env`.\n *\n * Two forms, resolved by two different things: `@env` is a tsconfig `paths`\n * entry that a bundler resolves and plain Node does not, and `#env` is a\n * package.json `imports` entry that Node resolves itself. Which one a project\n * wants is a fact about the project, so penv reads what it already does and\n * offers that.\n */\n readonly alias: string;\n}\n\n/** What init would write with no further input: the defaults, and nothing invented. */\nexport const DEFAULT_DECISIONS: InitDecisions = {\n environments: [],\n schemaFile: DEFAULT_SCHEMA_FILE,\n publicPrefixes: [],\n alias: DEFAULT_ALIAS,\n};\n\nexport interface InitResult {\n readonly root: string;\n readonly decisions: InitDecisions;\n readonly steps: readonly InitStep[];\n}\n\nexport interface InitOptions {\n readonly cwd: string;\n /** What to write. Omitted means the plan's defaults, as `--yes` takes them. */\n readonly decisions?: InitDecisions;\n}\n\n/*\n * The plan: what penv observed, what it would write, and why.\n */\n\n/** Flags that decide without asking, so a script never meets a prompt. */\nexport interface InitFlags {\n /** `--schema <path>`. */\n readonly schema?: string;\n /** `--env`, already split. Absent means no answer; present means the answer. */\n readonly environments?: readonly string[];\n /** `--alias <name>`. */\n readonly alias?: string;\n}\n\nexport interface InitPlan {\n readonly detected: Detected | undefined;\n /** What init writes unless a human edits it. */\n readonly decisions: InitDecisions;\n /** Environments the `.env*` files on disk are evidence for. Offered, never taken. */\n readonly suggestedEnvironments: readonly string[];\n /** Why each decision is what it is. Printed — a fallback penv takes silently is a guess. */\n readonly notes: readonly string[];\n}\n\n/**\n * Names that look like an environment in a `.env` filename but are not one:\n * `.env.example` is documentation, and the grammar's reserved tokens are\n * scope markers. Suggesting either would put a name into the whitelist that no\n * value file can ever be scoped to.\n */\nconst NOT_ENVIRONMENTS: readonly string[] = [...RESERVED_TOKENS, \"example\", \"sample\", \"template\"];\n\n/**\n * The environments the project's own `.env*` files are evidence for.\n *\n * This is not inference: nothing here reaches `penv.config.ts` unless a human\n * reads the suggestion and presses Enter. Invariant 10 is about what penv\n * *declares*, and showing someone the filenames they wrote is not a declaration\n * — it is the difference between \"you seem to have a production\" and penv\n * quietly deciding that you do.\n */\nexport function suggestEnvironments(root: string): string[] {\n let entries: string[];\n try {\n entries = readdirSync(root);\n } catch {\n return [];\n }\n\n const found = new Set<string>();\n for (const entry of entries) {\n if (!entry.startsWith(\".env.\")) {\n continue;\n }\n const segments = entry.slice(\".env.\".length).split(\".\");\n // `.env.production.local` is production's file; `.env.local` names no\n // environment at all, and neither does anything with more segments left\n // over, which is a filename penv has no reading of.\n const withoutLocal = segments.at(-1) === \"local\" ? segments.slice(0, -1) : segments;\n const name = withoutLocal.length === 1 ? withoutLocal[0] : undefined;\n if (name === undefined || !isLegalEnvironmentName(name) || NOT_ENVIRONMENTS.includes(name)) {\n continue;\n }\n found.add(name);\n }\n // Sorted so the same project shows the same line on every machine: directory\n // order is the filesystem's answer, not the project's.\n return [...found].sort();\n}\n\n/** A flag that is present but says nothing is refused, never read as absent. */\nfunction emptyFlag(flag: \"schema\" | \"env\" | \"alias\"): PenvError {\n return new PenvError(\n \"INIT_FLAG_EMPTY\",\n `\\`--${flag}\\` was given without a value`,\n flag === \"schema\"\n ? \"Name the module that exports the schema, e.g. `--schema src/env.ts`, or drop the flag \" +\n `to use ${DEFAULT_SCHEMA_FILE}.`\n : \"Name the environment, e.g. `--env production`, or drop the flag to leave the whitelist \" +\n \"empty and declare it in penv.config.ts.\",\n );\n}\n\n/** One list of environment names, however it was written. */\nfunction splitEnvironments(value: string): string[] {\n return value\n .split(\",\")\n .map((name) => name.trim())\n .filter((name) => name.length > 0);\n}\n\n/**\n * `--env` as the whitelist it declares, or `undefined` when it was not given —\n * which is no answer, not an empty one. Repeatable and comma-separated both\n * work: `--env development --env production` and `--env development,production`\n * are the same answer, and a shell that made one of them awkward is not a reason\n * to have declared a different set of environments.\n */\nexport function environmentsFromFlag(flag: unknown): readonly string[] | undefined {\n if (flag === undefined) {\n return undefined;\n }\n const given = Array.isArray(flag) ? (flag as readonly unknown[]) : [flag];\n const names = given.flatMap((value) => splitEnvironments(String(value)));\n if (names.length === 0) {\n throw emptyFlag(\"env\");\n }\n return [...new Set(names)];\n}\n\n/** The config the decisions describe, so core answers questions about it, not init. */\nfunction configOf(decisions: InitDecisions): PenvConfig {\n return { environments: decisions.environments, providers: {}, schemaFile: decisions.schemaFile };\n}\n\n/**\n * The decisions this project already recorded, or `undefined` when it has none.\n *\n * Only the config init itself would write or keep — the one beside `root`, not\n * whatever `findConfigFile` turns up two directories above. A monorepo's root\n * config is not this package's declaration, and `writeConfigFile` has always\n * looked exactly here.\n *\n * A config that exists and cannot be read is an error rather than an absence.\n * Treating it as absent is how the re-run bug worked in the first place: penv\n * would decide the project had declared nothing, re-detect, and scaffold a\n * second schema beside the one already there.\n */\nfunction declaredIn(root: string): PenvConfig | undefined {\n const file = join(root, CONFIG_FILE);\n if (!existsSync(file)) {\n return undefined;\n }\n return loadConfigFrom(file);\n}\n\n/**\n * What penv observed and what it proposes to write. The notes are the point as\n * much as the decisions are: a project that ends up with `.penv/env.ts` because\n * detection failed must be told that detection failed, or the fallback is\n * indistinguishable from a choice penv made on their behalf.\n *\n * Precedence is the whole design in one list: a flag is the human deciding now, a\n * config is the human having decided already, and detection is a suggestion that\n * loses to both. Guess once, declare forever — so once `penv.config.ts` exists,\n * re-detection cannot move what it says. Re-running init on a project that\n * declared `src/lib/env.ts` used to scaffold a *second* schema at the detected\n * path, warn that its own correct alias pointed at the wrong file, and announce\n * that a project with `environments: [\"production\"]` had declared none.\n */\nexport function planInit(root: string, flags: InitFlags = {}): InitPlan {\n const declared = declaredIn(root);\n const detected = detectFramework(root);\n const notes: string[] = [];\n\n if (declared !== undefined) {\n notes.push(`${CONFIG_FILE} already exists — init keeps every decision it records.`);\n } else if (detected === undefined) {\n notes.push(\n `No framework detected in package.json — the schema goes to ${DEFAULT_SCHEMA_FILE}.`,\n );\n } else {\n notes.push(`Detected ${detected.name}.`);\n if (detected.displacedFrom !== undefined) {\n notes.push(\n `${detected.displacedFrom} is already a module of yours that exports no \\`schema\\`, so ` +\n `the schema goes to ${detected.schemaFile}. penv never writes over a file it did not ` +\n `write — delete yours and re-run if you want it there, or pass \\`--schema\\`.`,\n );\n }\n }\n\n // Flag, then what the project already declared, then detection. `schemaFileOf`\n // rather than `config.schemaFile`: a config that omits the key has still\n // answered — with the default — and re-detection must not move a schema that\n // is already sitting where the project says it is.\n const schemaFile =\n flags.schema === undefined\n ? declared !== undefined\n ? schemaFileOf(declared)\n : (detected?.schemaFile ?? DEFAULT_SCHEMA_FILE)\n : flags.schema.trim();\n if (flags.schema !== undefined) {\n if (schemaFile.length === 0) {\n throw emptyFlag(\"schema\");\n }\n // Every rule a committed path has to satisfy lives in core, so `--schema`\n // is judged by the same validator `penv validate` will judge the config by.\n // Refusing here is refusing before a file is written; refusing there is\n // refusing after the project already has one in the wrong place.\n const error = validateSchemaFile({ environments: [], providers: {}, schemaFile })[0];\n if (error !== undefined) {\n throw error;\n }\n }\n\n const alias = flags.alias === undefined ? detectAlias(root) : flags.alias.trim();\n if (flags.alias !== undefined && alias.length === 0) {\n throw emptyFlag(\"alias\");\n }\n if (!ALIAS_NAME.test(alias)) {\n throw new PenvError(\n \"INIT_ALIAS_INVALID\",\n `\\`${alias}\\` is not an alias penv can write`,\n `An alias is \\`@name\\` — a tsconfig \\`paths\\` entry a bundler resolves — or \\`#name\\`, a ` +\n \"package.json `imports` entry Node resolves itself. Those are the two things a module \" +\n \"specifier can be that is not a package.\",\n );\n }\n // Only when penv worked it out. `--alias` needs no explanation of why penv\n // chose it, and this note would have explained a reason that was not true:\n // it fired on the *form* of the alias rather than on where it came from, so a\n // forced `#env` was told its own package.json had asked for it.\n if (flags.alias === undefined && alias.startsWith(IMPORTS_PREFIX)) {\n notes.push(\n `Your ${PACKAGE_FILE} declares \\`imports\\`, so the alias is \\`${alias}\\` — Node resolves it without a bundler.`,\n );\n }\n\n const suggestedEnvironments = suggestEnvironments(root);\n const environments = flags.environments ?? declared?.environments ?? [];\n // The empty whitelist is worth a line only when it is still empty. A project\n // that declared `production` being told it has declared nothing is penv\n // reading its own config wrong out loud.\n if (environments.length === 0) {\n notes.push(\n \"No environments declared: penv does not infer them, and a `--yes` run cannot invent them.\",\n );\n if (suggestedEnvironments.length > 0) {\n notes.push(\n `Your \\`.env\\` files mention ${suggestedEnvironments.join(\", \")} — declare the ones you ` +\n `really deploy in ${CONFIG_FILE}, with a provider for each.`,\n );\n }\n }\n\n return {\n detected,\n decisions: {\n environments,\n schemaFile,\n publicPrefixes: declared?.publicPrefixes ?? detected?.publicPrefixes ?? [],\n alias,\n },\n suggestedEnvironments,\n notes,\n };\n}\n\n/*\n * The prompt.\n *\n * A plan the human confirms, not an interrogation they answer: penv already\n * knows everything but the one fact it must not guess, so it shows the whole\n * page and asks once. The io is a parameter so the decision logic is a plain\n * function — the tests call it, they do not spawn a terminal.\n */\n\nexport interface PromptIo {\n readonly ask: (question: string) => Promise<string>;\n readonly write: (line: string) => void;\n}\n\n/** The plan as one screen. */\nexport function renderPlan(plan: InitPlan): string[] {\n const rows: string[][] = [];\n rows.push([\n \" environments\",\n plan.suggestedEnvironments.length === 0 ? \"\" : `[${plan.suggestedEnvironments.join(\", \")}]`,\n plan.suggestedEnvironments.length === 0\n ? \"<- name them, or Enter to leave the whitelist empty\"\n : \"<- from your .env files; edit, or Enter to accept\",\n ]);\n rows.push([\n \" schemaFile\",\n plan.decisions.schemaFile,\n plan.decisions.schemaFile === DEFAULT_SCHEMA_FILE ? \"\" : `(default: ${DEFAULT_SCHEMA_FILE})`,\n ]);\n for (const prefix of plan.decisions.publicPrefixes) {\n rows.push([\" publicPrefix\", prefix, \"\"]);\n }\n\n const headline =\n plan.detected === undefined\n ? \"No framework detected in package.json.\"\n : `Detected ${plan.detected.name}.`;\n return [headline, \"\", ...columns(rows), \"\"];\n}\n\nfunction environmentsHint(plan: InitPlan): string {\n return plan.suggestedEnvironments.length === 0\n ? \"environments (comma-separated, Enter for none) > \"\n : 'environments (Enter to accept, \"none\" for an empty whitelist) > ';\n}\n\n/**\n * The plan, confirmed. `undefined` is the human declining, which is an outcome\n * and not a failure: nothing is written and the run says so.\n *\n * An answer that is neither yes nor no declines, because the two mistakes are\n * not symmetrical — a decline costs a re-run, while reading \"no thanks\" as\n * consent scaffolds a project someone said no to.\n */\nexport async function promptForDecisions(\n plan: InitPlan,\n io: PromptIo,\n): Promise<InitDecisions | undefined> {\n for (const line of renderPlan(plan)) {\n io.write(line);\n }\n\n const answer = (await io.ask(environmentsHint(plan))).trim();\n const environments =\n answer.length === 0\n ? plan.suggestedEnvironments\n : answer.toLowerCase() === \"none\"\n ? []\n : splitEnvironments(answer);\n // The confirmation has to be about what is actually written, so an edited\n // line is echoed before `Proceed?` rather than confirmed in the abstract.\n if (answer.length > 0) {\n io.write(\"\");\n io.write(\n environments.length === 0\n ? \" environments [] (declare them later in penv.config.ts)\"\n : ` environments [${environments.join(\", \")}]`,\n );\n io.write(\"\");\n }\n\n const proceed = (await io.ask(\"Proceed? [Y/n] \")).trim().toLowerCase();\n if (proceed.length > 0 && proceed !== \"y\" && proceed !== \"yes\") {\n return undefined;\n }\n return { ...plan.decisions, environments };\n}\n\n/*\n * Templates.\n */\n\n/** One schema field for the draft `penv import` generates. */\nexport interface SchemaField {\n readonly key: string;\n /** The Zod expression, e.g. `z.url()`. */\n readonly type: string;\n}\n\nconst EMPTY_SCHEMA_BODY =\n \" // One key per parameter, e.g. `databaseUrl: z.url(),`. Nesting a key nests\\n\" +\n \" // the parameter: `redis: z.object({ password: z.string() })` is redis/password.\";\n\nconst DRAFT_HEADER =\n \"// DRAFT — generated by `penv import` from one sample of each value, and yours\\n\" +\n \"// to correct. Single-sample inference cannot know that a boolean seen as `true`\\n\" +\n \"// must also accept `1`/`0`, or that a string is really a URL. penv scaffolds\\n\" +\n \"// this file once and never regenerates it, so edits here are safe.\\n\";\n\nexport function renderSchemaModule(fields: readonly SchemaField[], draft: boolean): string {\n const body =\n fields.length === 0\n ? EMPTY_SCHEMA_BODY\n : fields.map((field) => ` ${field.key}: ${field.type},`).join(\"\\n\");\n\n return (\n `${draft ? DRAFT_HEADER : \"\"}import { z } from \"zod\";\\n` +\n `import { load } from \"@penvhq/penv\";\\n` +\n `\\n` +\n `// The shape. Import this (or z.infer<typeof schema>) when you only need the\\n` +\n `// type — tests, tooling — so you don't trigger config loading.\\n` +\n `export const schema = z.object({\\n${body}\\n});\\n` +\n `\\n` +\n `// The loaded, validated values for the current environment. Import this in app\\n` +\n `// code. Importing it loads configuration and throws (naming the parameter and\\n` +\n `// environment) if anything required is missing or invalid.\\n` +\n `export const env = load(schema);\\n`\n );\n}\n\n/**\n * The whitelist block. Empty is the honest answer to a question nothing on disk\n * can settle, so the comment carries what an empty file cannot: that penv left\n * it empty on purpose, and the exact shape of the two lines that fill it in.\n */\nfunction renderEnvironments(decisions: InitDecisions): string {\n const shared =\n \" // Environments are a whitelist. A filename segment is an environment only if\\n\" +\n \" // it is declared here — penv never infers one from a folder or a filename.\\n\";\n if (decisions.environments.length === 0) {\n return (\n `${shared}` +\n \" // It starts empty because which environments you deploy is not something penv\\n\" +\n \" // can read off your codebase, and an environment you do not have is worse\\n\" +\n \" // than one you have not declared yet. Name yours, and give each a provider:\\n\" +\n ' // environments: [\"development\", \"production\"],\\n' +\n ' // providers: { development: { type: \"filesystem\" }, production: { type: \"filesystem\" } },\\n' +\n \" environments: [],\\n\" +\n \"\\n\" +\n \" providers: {},\\n\"\n );\n }\n const names = decisions.environments.map((name) => JSON.stringify(name)).join(\", \");\n const providers = decisions.environments\n .map((name) => ` ${JSON.stringify(name)}: { type: \"filesystem\" },\\n`)\n .join(\"\");\n return (\n `${shared} environments: [${names}],\\n` +\n \"\\n\" +\n \" // One entry per environment: where that environment's values are read from.\\n\" +\n ` providers: {\\n${providers} },\\n`\n );\n}\n\n/** The config, carrying only the decisions that were actually made. */\nexport function renderConfigModule(decisions: InitDecisions): string {\n let body = renderEnvironments(decisions);\n\n // The default is written by not writing it: a key that restates the default is\n // noise the next reader has to check against the docs before they can ignore it.\n if (decisions.schemaFile !== DEFAULT_SCHEMA_FILE) {\n body +=\n \"\\n // The module that exports the schema. It is yours — penv scaffolds it once\\n\" +\n \" // and never regenerates it — so this says where you keep it.\\n\" +\n ` schemaFile: ${JSON.stringify(decisions.schemaFile)},\\n`;\n }\n if (decisions.publicPrefixes.length > 0) {\n const prefixes = decisions.publicPrefixes.map((prefix) => JSON.stringify(prefix)).join(\", \");\n body +=\n \"\\n // The prefixes your framework inlines into the browser bundle. `penv doctor`\\n\" +\n \" // reports a parameter your meta declares `secret: true` whose variable name\\n\" +\n \" // starts with one of these — penv is the only thing holding both facts.\\n\" +\n ` publicPrefixes: [${prefixes}],\\n`;\n }\n\n return `import { defineConfig } from \"@penvhq/penv\";\\n\\nexport default defineConfig({\\n${body}});\\n`;\n}\n\n/**\n * Invariant 17: value files are never committed; structure, the schema, meta,\n * and config are. The negated directory pattern keeps git descending into\n * namespace folders, which an excluded directory would otherwise hide entirely.\n *\n * The schema is un-ignored by name only when it lives in the tree. Outside it,\n * this file has no opinion on it at all, and a `!env.ts` naming nothing is a\n * line the next reader has to work out is dead.\n */\nexport function renderGitignore(decisions: InitDecisions): string {\n const inside = schemaInsideTree(configOf(decisions));\n const listed = inside === undefined ? \"\" : `${inside}, `;\n return (\n `# Written by penv. Value files hold configuration values and are never\\n` +\n `# committed; only the structure, ${listed}meta, and config are.\\n` +\n `*\\n` +\n `!*/\\n` +\n `!.gitignore\\n` +\n `${inside === undefined ? \"\" : `!${inside}\\n`}` +\n `!*.json\\n`\n );\n}\n\n/*\n * The tsconfig.json edit.\n *\n * The alias is inserted into the user's own file, so the file is scanned rather\n * than parsed and re-emitted: reformatting someone's tsconfig — dropping its\n * comments, resorting its keys — to add one path is not a minimal edit.\n */\n\nfunction skipTrivia(source: string, index: number): number {\n let i = index;\n for (;;) {\n const ch = source.charAt(i);\n if (ch === \" \" || ch === \"\\t\" || ch === \"\\n\" || ch === \"\\r\") {\n i += 1;\n continue;\n }\n if (ch === \"/\" && source.charAt(i + 1) === \"/\") {\n const end = source.indexOf(\"\\n\", i);\n i = end === -1 ? source.length : end + 1;\n continue;\n }\n if (ch === \"/\" && source.charAt(i + 1) === \"*\") {\n const end = source.indexOf(\"*/\", i + 2);\n i = end === -1 ? source.length : end + 2;\n continue;\n }\n return i;\n }\n}\n\n/** Index just past the closing quote of the string opening at `index`. */\nfunction endOfString(source: string, index: number): number {\n let i = index + 1;\n while (i < source.length) {\n const ch = source.charAt(i);\n if (ch === \"\\\\\") {\n i += 2;\n continue;\n }\n if (ch === '\"') {\n return i + 1;\n }\n i += 1;\n }\n return source.length;\n}\n\n/** Index just past the bracket matching the one at `index`. */\nfunction endOfBracket(source: string, index: number): number {\n const open = source.charAt(index);\n const close = open === \"{\" ? \"}\" : \"]\";\n let depth = 0;\n let i = index;\n while (i < source.length) {\n const ch = source.charAt(i);\n if (ch === '\"') {\n i = endOfString(source, i);\n continue;\n }\n if (ch === \"/\" && (source.charAt(i + 1) === \"/\" || source.charAt(i + 1) === \"*\")) {\n i = skipTrivia(source, i);\n continue;\n }\n if (ch === open) {\n depth += 1;\n i += 1;\n continue;\n }\n if (ch === close) {\n depth -= 1;\n i += 1;\n if (depth === 0) {\n return i;\n }\n continue;\n }\n i += 1;\n }\n return source.length;\n}\n\nfunction endOfValue(source: string, index: number): number {\n const ch = source.charAt(index);\n if (ch === '\"') {\n return endOfString(source, index);\n }\n if (ch === \"{\" || ch === \"[\") {\n return endOfBracket(source, index);\n }\n let i = index;\n while (i < source.length) {\n const c = source.charAt(i);\n if (c === \",\" || c === \"}\" || c === \"]\" || c === \"\\n\") {\n return i;\n }\n i += 1;\n }\n return source.length;\n}\n\ninterface Member {\n readonly valueStart: number;\n}\n\n/** The member named `key` directly inside the object whose `{` is at `open`. */\nfunction findMember(source: string, open: number, key: string): Member | undefined {\n const close = endOfBracket(source, open) - 1;\n let i = skipTrivia(source, open + 1);\n while (i < close) {\n if (source.charAt(i) !== '\"') {\n return undefined;\n }\n const keyEnd = endOfString(source, i);\n const name = source.slice(i + 1, keyEnd - 1);\n const colon = skipTrivia(source, keyEnd);\n if (source.charAt(colon) !== \":\") {\n return undefined;\n }\n const valueStart = skipTrivia(source, colon + 1);\n const valueEnd = endOfValue(source, valueStart);\n if (name === key) {\n return { valueStart };\n }\n let next = skipTrivia(source, valueEnd);\n if (source.charAt(next) === \",\") {\n next = skipTrivia(source, next + 1);\n }\n i = next;\n }\n return undefined;\n}\n\n/** The indentation of the line `index` sits on. */\nfunction lineIndent(source: string, index: number): string {\n const lineStart = source.lastIndexOf(\"\\n\", index) + 1;\n const match = /^[ \\t]*/.exec(source.slice(lineStart, index));\n return match?.[0] ?? \"\";\n}\n\n/** The file's own indentation unit, so the inserted line looks like its neighbours. */\nfunction indentUnit(source: string): string {\n const match = /\\n([ \\t]+)\"/.exec(source);\n return match?.[1] ?? \" \";\n}\n\nfunction insertMember(source: string, open: number, member: string, unit: string): string {\n const objectIndent = lineIndent(source, open);\n const entryIndent = objectIndent + unit;\n const close = endOfBracket(source, open) - 1;\n if (skipTrivia(source, open + 1) === close) {\n return `${source.slice(0, open + 1)}\\n${entryIndent}${member}\\n${objectIndent}${source.slice(close)}`;\n }\n return `${source.slice(0, open + 1)}\\n${entryIndent}${member},${source.slice(open + 1)}`;\n}\n\nfunction shapeError(what: string, target: string, alias: string): PenvError {\n return new PenvError(\n \"TSCONFIG_SHAPE\",\n `penv cannot add the \\`${alias}\\` path alias to tsconfig.json: ${what}`,\n `Add it by hand: \\`{ \"compilerOptions\": { \"paths\": { \"${alias}\": [\"${target}\"] } } }\\`.`,\n );\n}\n\nexport interface AliasEdit {\n readonly source: string;\n readonly changed: boolean;\n /**\n * What the alias already points at, when that is not penv's schema.\n *\n * The alias is how the user's code reaches penv, so an alias that resolves\n * somewhere else is not a small problem: `import { env } from \"@env\"` compiles,\n * runs, and hands back another module's export. Reporting \"kept the alias\"\n * because the *key* was present is how penv would say that was fine — a silent\n * seam, in the scaffolder of the tool whose subject is silent seams.\n *\n * Left as the user's, never rewritten: penv cannot tell a stale mapping from a\n * deliberate one, and the file is theirs.\n */\n readonly conflict?: string;\n}\n\n/**\n * `tsconfig.json` with the `@env` alias present, everything else untouched.\n * Already-aliased input comes back unchanged rather than gaining a duplicate.\n *\n * The alias is why the schema can live anywhere: application code imports\n * `@env`, and this line is the only thing that has to know where that is.\n */\nexport function insertEnvAlias(\n source: string,\n target: string = DEFAULT_SCHEMA_FILE,\n name: string = DEFAULT_ALIAS,\n): AliasEdit {\n const alias = `\"${name}\": [\"${target}\"]`;\n const root = skipTrivia(source, 0);\n if (source.charAt(root) !== \"{\") {\n throw shapeError(\"its contents are not a JSON object\", target, name);\n }\n\n const unit = indentUnit(source);\n const compilerOptions = findMember(source, root, \"compilerOptions\");\n if (compilerOptions === undefined) {\n return {\n source: insertMember(source, root, `\"compilerOptions\": { \"paths\": { ${alias} } }`, unit),\n changed: true,\n };\n }\n if (source.charAt(compilerOptions.valueStart) !== \"{\") {\n throw shapeError(\"`compilerOptions` is not an object\", target, name);\n }\n\n const paths = findMember(source, compilerOptions.valueStart, \"paths\");\n if (paths === undefined) {\n return {\n source: insertMember(source, compilerOptions.valueStart, `\"paths\": { ${alias} }`, unit),\n changed: true,\n };\n }\n if (source.charAt(paths.valueStart) !== \"{\") {\n throw shapeError(\"`compilerOptions.paths` is not an object\", target, name);\n }\n\n const existing = findMember(source, paths.valueStart, name);\n if (existing !== undefined) {\n // The key being present is not the question. Where it points is.\n const points = source.slice(existing.valueStart, endOfValue(source, existing.valueStart));\n return points.includes(`\"${target}\"`)\n ? { source, changed: false }\n : { source, changed: false, conflict: points.trim() };\n }\n return { source: insertMember(source, paths.valueStart, alias, unit), changed: true };\n}\n\n/**\n * `package.json` with the `#env` subpath import present, everything else untouched.\n *\n * The same scanning edit the tsconfig gets, for the same reason: a manifest is\n * the project's file, and rewriting it through `JSON.parse`/`stringify` to add\n * one key resorts nothing but reformats everything.\n *\n * `imports` is Node's own mechanism, so an alias written here needs no bundler to\n * resolve — which is the whole reason a project would choose it.\n */\nexport function insertImportsAlias(source: string, target: string, name: string): AliasEdit {\n const entry = `\"${name}\": \"./${target}\"`;\n const root = skipTrivia(source, 0);\n if (source.charAt(root) !== \"{\") {\n throw shapeError(\"its contents are not a JSON object\", target, name);\n }\n\n const unit = indentUnit(source);\n const imports = findMember(source, root, \"imports\");\n if (imports === undefined) {\n return { source: insertMember(source, root, `\"imports\": { ${entry} }`, unit), changed: true };\n }\n if (source.charAt(imports.valueStart) !== \"{\") {\n throw shapeError(\"`imports` is not an object\", target, name);\n }\n\n const existing = findMember(source, imports.valueStart, name);\n if (existing !== undefined) {\n const points = source.slice(existing.valueStart, endOfValue(source, existing.valueStart));\n return points.includes(`\"./${target}\"`)\n ? { source, changed: false }\n : { source, changed: false, conflict: points.trim() };\n }\n return { source: insertMember(source, imports.valueStart, entry, unit), changed: true };\n}\n\nfunction renderTsconfig(target: string, alias: string): string {\n return `{\\n \"compilerOptions\": {\\n \"paths\": { \"${alias}\": [\"${target}\"] }\\n }\\n}\\n`;\n}\n\n/*\n * The steps themselves. Each returns what it did so the caller reports it.\n */\n\nexport function ensurePenvDir(root: string): InitStep {\n const dir = resolve(root, PENV_DIR);\n if (existsSync(dir)) {\n return { target: \"penv-dir\", action: \"kept\", text: `Found ${PENV_DIR}/` };\n }\n mkdirSync(dir, { recursive: true });\n return { target: \"penv-dir\", action: \"created\", text: `Created ${PENV_DIR}/` };\n}\n\n/**\n * Invariant 2: the schema module is scaffolded once and never regenerated. An\n * existing file is the user's, whatever penv would have written instead — and\n * that holds wherever they keep it, so the check is against the chosen path and\n * not the default one.\n */\nexport function writeSchemaFile(\n root: string,\n fields: readonly SchemaField[],\n draft: boolean,\n decisions: InitDecisions = DEFAULT_DECISIONS,\n): InitStep {\n const file = join(root, ...decisions.schemaFile.split(\"/\"));\n if (existsSync(file)) {\n return {\n target: \"schema\",\n action: \"kept\",\n text: `Kept ${decisions.schemaFile}`,\n note: \"(yours — penv never regenerates it)\",\n };\n }\n mkdirSync(dirname(file), { recursive: true });\n writeFileSync(file, renderSchemaModule(fields, draft), \"utf8\");\n return {\n target: \"schema\",\n action: \"created\",\n text: `Generated ${decisions.schemaFile}`,\n note: draft ? \"(draft schema — review it, it's yours)\" : \"(schema + loader — yours to edit)\",\n };\n}\n\nexport function writeConfigFile(\n root: string,\n decisions: InitDecisions = DEFAULT_DECISIONS,\n): InitStep {\n const file = join(root, CONFIG_FILE);\n if (existsSync(file)) {\n return { target: \"config\", action: \"kept\", text: `Kept ${CONFIG_FILE}` };\n }\n writeFileSync(file, renderConfigModule(decisions), \"utf8\");\n return { target: \"config\", action: \"created\", text: `Generated ${CONFIG_FILE}` };\n}\n\nexport function writeTsconfigAlias(\n root: string,\n decisions: InitDecisions = DEFAULT_DECISIONS,\n): InitStep {\n const alias = decisions.alias;\n // `#env` is Node's mechanism and lives in the manifest; `@env` is TypeScript's\n // and lives in the tsconfig. Writing one into the other's file produces a key\n // nothing reads — the alias would simply never resolve, and penv would have\n // reported writing it.\n const imports = alias.startsWith(IMPORTS_PREFIX);\n const file = join(root, imports ? PACKAGE_FILE : TSCONFIG_FILE);\n const where = imports ? PACKAGE_FILE : TSCONFIG_FILE;\n\n if (!existsSync(file)) {\n // A project with no manifest is not one penv invents a manifest for: the\n // manifest is the project's identity, and `imports` is a key on something\n // that already exists. A tsconfig penv can honestly create from nothing.\n if (imports) {\n return {\n target: \"tsconfig\",\n action: \"conflicted\",\n text: `No ${PACKAGE_FILE} to add the ${alias} import to`,\n note: `(run \\`npm init\\` first, or use \\`--alias @env\\` to alias through ${TSCONFIG_FILE})`,\n };\n }\n writeFileSync(file, renderTsconfig(decisions.schemaFile, alias), \"utf8\");\n return {\n target: \"tsconfig\",\n action: \"created\",\n text: `Created ${TSCONFIG_FILE} with the ${alias} path alias`,\n };\n }\n\n const source = readFileSync(file, \"utf8\");\n const edit = imports\n ? insertImportsAlias(source, decisions.schemaFile, alias)\n : insertEnvAlias(source, decisions.schemaFile, alias);\n\n if (edit.conflict !== undefined) {\n return {\n target: \"tsconfig\",\n action: \"conflicted\",\n text: `${where} already maps ${alias} to ${edit.conflict}`,\n note: `(left alone — \\`import { env } from \"${alias}\"\\` will not reach ${decisions.schemaFile})`,\n };\n }\n if (!edit.changed) {\n return {\n target: \"tsconfig\",\n action: \"kept\",\n text: `Kept the ${alias} alias in ${where}`,\n };\n }\n writeFileSync(file, edit.source, \"utf8\");\n return {\n target: \"tsconfig\",\n action: \"updated\",\n text: `Added ${alias} alias to ${where}`,\n };\n}\n\n/**\n * The ignore file lives inside `.penv/`, where the value files are: penv owns it\n * outright, so it is rewritten when it drifts. A weakened ignore file is how a\n * plaintext secret gets committed, which invariant 17 exists to prevent.\n */\nexport function writeGitignore(\n root: string,\n decisions: InitDecisions = DEFAULT_DECISIONS,\n): InitStep {\n const file = join(root, PENV_DIR, GITIGNORE_FILE);\n const relative = `${PENV_DIR}/${GITIGNORE_FILE}`;\n const wanted = renderGitignore(decisions);\n const existing = existsSync(file) ? readFileSync(file, \"utf8\") : undefined;\n if (existing === wanted) {\n return { target: \"gitignore\", action: \"kept\", text: `Kept ${relative}` };\n }\n mkdirSync(join(root, PENV_DIR), { recursive: true });\n writeFileSync(file, wanted, \"utf8\");\n return {\n target: \"gitignore\",\n action: existing === undefined ? \"created\" : \"updated\",\n text: `${existing === undefined ? \"Created\" : \"Updated\"} ${relative}`,\n };\n}\n\n/** Everything `init` scaffolds, in the order it is reported. */\nexport function scaffold(\n root: string,\n fields: readonly SchemaField[],\n draft: boolean,\n decisions: InitDecisions = DEFAULT_DECISIONS,\n): InitStep[] {\n return [\n ensurePenvDir(root),\n writeSchemaFile(root, fields, draft, decisions),\n writeConfigFile(root, decisions),\n writeTsconfigAlias(root, decisions),\n writeGitignore(root, decisions),\n ];\n}\n\nexport function runInit(options: InitOptions): InitResult {\n const root = resolve(options.cwd);\n const decisions = options.decisions ?? planInit(root).decisions;\n return { root, decisions, steps: scaffold(root, [], false, decisions) };\n}\n\nexport function renderInit(result: InitResult): string[] {\n const steps: Step[] = result.steps.map((step) => {\n // A conflict is the one step that is not a success, so it must not wear the\n // glyph every success wears: a ✓ beside \"penv could not wire your alias\" is\n // the line a reader skims past.\n const glyph = step.action === \"conflicted\" ? WARN : CHECK;\n return step.note === undefined\n ? { glyph, text: step.text }\n : { glyph, text: step.text, note: step.note };\n });\n return [\n ...formatSteps(steps),\n \"\",\n `Done. Declare your parameters in ${result.decisions.schemaFile}, then \\`penv set <key>\\`.`,\n ...(result.decisions.environments.length === 0\n ? [\n `Then declare your environments in ${CONFIG_FILE}: penv leaves the whitelist empty ` +\n `rather than inventing one, and every command needs it.`,\n ]\n : []),\n ];\n}\n\n/** The prompt runs only against a real terminal; anything else has nobody to ask. */\nasync function askOnTty(plan: InitPlan): Promise<InitDecisions | undefined> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n try {\n return await promptForDecisions(plan, {\n ask: (question) => rl.question(question),\n write: (line) => process.stdout.write(`${line}\\n`),\n });\n } finally {\n rl.close();\n }\n}\n\nexport const initCommand = defineCommand({\n meta: { name: \"init\", description: \"Initialize a project (.penv/, env.ts, config, @env alias)\" },\n args: {\n yes: {\n type: \"boolean\",\n description:\n \"Take the detected defaults without asking. Environments still start empty — penv \" +\n \"cannot see your infrastructure\",\n },\n schema: {\n type: \"string\",\n description: `Where the schema module goes, e.g. src/env.ts (default: ${DEFAULT_SCHEMA_FILE})`,\n },\n alias: {\n type: \"string\",\n description:\n \"How your code names the schema: @env (tsconfig paths, needs a bundler) or #env \" +\n \"(package.json imports, resolved by node itself)\",\n },\n env: {\n type: \"string\",\n description:\n \"Declare an environment. Repeatable, or comma-separated: --env development,production\",\n },\n },\n run({ args }) {\n return guard(async () => {\n const root = resolve(process.cwd());\n const environments = environmentsFromFlag(args.env);\n const plan = planInit(root, {\n ...(args.schema === undefined ? {} : { schema: args.schema }),\n ...(args.alias === undefined ? {} : { alias: args.alias }),\n ...(environments === undefined ? {} : { environments }),\n });\n\n // No terminal is not a reason to guess: it is a reason to take the\n // defaults and say what they were, so a CI log carries the decisions.\n const asked = process.stdin.isTTY === true && args.yes !== true && environments === undefined;\n const decisions = asked ? await askOnTty(plan) : plan.decisions;\n if (decisions === undefined) {\n write([\"Nothing written. Re-run `penv init` when you want to scaffold.\"]);\n return;\n }\n if (!asked) {\n write([...plan.notes, \"\"]);\n }\n write(renderInit(runInit({ cwd: root, decisions })));\n });\n },\n});\n","/**\n * `penv key create --env <e>` — mint a key of the right shape.\n *\n * This exists because `penv encrypt` refuses to invent one. A key penv generated\n * behind your back is a key nobody can reproduce, restore, or rotate, and the\n * first time it matters is the first time it is gone. So minting is its own act,\n * run deliberately, and the key it prints is yours to store.\n *\n * Where penv stores it depends on the source. With `env`, the key *is* whatever\n * the process environment holds — a deploy unwraps it from a KMS and exports it —\n * so there is nowhere for penv to put it that would not be the repo-adjacent file\n * the design forbids; printing the export line is the whole job. With `keychain`,\n * the OS keychain is exactly the place a key may live, so penv stores it there and\n * prints nothing to copy — the key exists in one place, on this machine, which is\n * the point of the keychain.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport type { Keychain } from \"@penvhq/core\";\nimport { KEY_BYTES, KEYCHAIN_SERVICE, PenvError } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { defaultKeychain } from \"../keychain.js\";\nimport { openProject, targetEnvironment } from \"../project.js\";\nimport { guard, write } from \"../ui.js\";\n\nexport interface KeyCreateOptions {\n readonly cwd: string;\n readonly environment?: string;\n /** Replace an existing keychain key instead of refusing. Orphans values sealed under the old one. */\n readonly force?: boolean;\n /** Injected in tests: the keychain to store into. Defaults to the real OS binding. */\n readonly keychain?: Keychain;\n}\n\nexport interface KeyCreateResult {\n readonly source: \"env\" | \"keychain\";\n readonly environment: string;\n readonly id: string;\n /** Env source only: the variable to export the key under. */\n readonly variable?: string;\n /** Env source only: the key, base64, ready to export. penv holds no copy. */\n readonly key?: string;\n}\n\n/** Mirrors the transform in core's env key source, which is the thing that reads it. */\nfunction envVarFor(id: string): string {\n return `PENV_KEY_${id.replace(/[^A-Za-z0-9]/g, \"_\").toUpperCase()}`;\n}\n\nexport function runKeyCreate(options: KeyCreateOptions): KeyCreateResult {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n\n const declared = project.config.keys?.[environment];\n if (declared === undefined) {\n throw new PenvError(\n \"KEY_SOURCE_UNDECLARED\",\n `Environment ${environment} declares no key source, so penv does not know what a key for it would be`,\n \"Add a `keys` entry to penv.config.ts — e.g. \" +\n `\\`keys: { ${environment}: { source: \"env\", id: \"${environment}\" } }\\` — then run this again.`,\n );\n }\n\n const key = randomBytes(KEY_BYTES).toString(\"base64\");\n\n if (declared.source === \"keychain\") {\n const keychain = options.keychain ?? defaultKeychain;\n if (options.force !== true) {\n // Replacing the key orphans every value already sealed under the old one —\n // they could never be decrypted again. Refuse unless the user forces it.\n let existing: string | null;\n try {\n existing = keychain.getPassword(KEYCHAIN_SERVICE, declared.id);\n } catch (cause) {\n throw new PenvError(\n \"KEYCHAIN_UNAVAILABLE\",\n `penv could not read your OS keychain to check for an existing key \\`${declared.id}\\``,\n `Unlock your keychain and run this again. Original error: ${cause instanceof Error ? cause.message : String(cause)}`,\n );\n }\n if (existing !== null) {\n throw new PenvError(\n \"KEY_EXISTS\",\n `Environment ${environment} already has a key \\`${declared.id}\\` in your OS keychain`,\n \"Replacing it would orphan every value already sealed under it — they could never be \" +\n \"decrypted again. Re-run with `--force` only if you are certain nothing is sealed under \" +\n \"the current key.\",\n );\n }\n }\n keychain.setPassword(KEYCHAIN_SERVICE, declared.id, key);\n return { source: \"keychain\", environment, id: declared.id };\n }\n\n return {\n source: \"env\",\n environment,\n id: declared.id,\n variable: envVarFor(declared.id),\n key,\n };\n}\n\nexport function renderKeyCreate(result: KeyCreateResult): string[] {\n if (result.source === \"keychain\") {\n return [\n `A new key for environment ${result.environment}, stored in your OS keychain as \\`${result.id}\\`.`,\n \"\",\n \"penv kept no copy. Anything sealed under it is unreadable without your keychain, and running\",\n \"`penv key create` again would replace it — so it lives in exactly one place, on this machine.\",\n ];\n }\n return [\n `A new key for environment ${result.environment}. penv did not store it.`,\n \"\",\n ` ${result.variable}=${result.key}`,\n \"\",\n \"Export it where penv runs, and put it wherever this environment's secrets already live —\",\n \"a KMS, your CI's secret store, a password manager. Anything sealed under it is unreadable\",\n \"without it, and penv keeps no copy to fall back on.\",\n ];\n}\n\nexport const keyCommand = defineCommand({\n meta: { name: \"key\", description: \"Work with encryption keys\" },\n subCommands: {\n create: defineCommand({\n meta: { name: \"create\", description: \"Generate a key for an environment\" },\n args: {\n env: { type: \"string\", description: \"The environment the key is for\" },\n force: {\n type: \"boolean\",\n description: \"Replace an existing keychain key (orphans values sealed under the old one)\",\n },\n },\n run({ args }) {\n return guard(async () => {\n write(\n renderKeyCreate(\n runKeyCreate({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n ...(args.force === undefined ? {} : { force: args.force }),\n }),\n ),\n );\n });\n },\n }),\n },\n});\n","/**\n * The OS-keychain binding, and the one place the native module is touched.\n *\n * `@penvhq/core` defines the `Keychain` contract but carries no native dependency:\n * `load` runs in every deploy, and a native module in the runtime's tree is a\n * build failure in someone's container. So the binding lives here, in the CLI —\n * whose dependency budget is looser and which never ships inside a user's app —\n * and is registered into core (see `runMain`). Where it is never registered (the\n * runtime), a keychain source answers `unavailable`, which is the honest verdict.\n *\n * The native module is required lazily, so it loads only when a keychain key is\n * actually read or written — never merely because the CLI started, and never on\n * an env-source path that has no business touching it.\n */\n\nimport { createRequire } from \"node:module\";\nimport type { Keychain } from \"@penvhq/core\";\n\n/** The synchronous slice of `@napi-rs/keyring`'s `Entry` this binding uses. */\ninterface Entry {\n getPassword(): string | null;\n setPassword(password: string): void;\n}\ntype EntryConstructor = new (service: string, account: string) => Entry;\n\nlet cached: EntryConstructor | undefined;\n\nfunction entryConstructor(): EntryConstructor {\n if (cached === undefined) {\n const require = createRequire(import.meta.url);\n cached = (require(\"@napi-rs/keyring\") as { Entry: EntryConstructor }).Entry;\n }\n return cached;\n}\n\n/**\n * The real binding, backed by `@napi-rs/keyring`'s synchronous `Entry`. Its\n * `getPassword` returns `null` for a missing entry (never throws for absence) and\n * throws only when the keychain genuinely cannot be read — which the core source\n * turns into `unavailable`, not `absent`.\n */\nexport const defaultKeychain: Keychain = {\n getPassword(service, account) {\n const Entry = entryConstructor();\n return new Entry(service, account).getPassword();\n },\n setPassword(service, account, password) {\n const Entry = entryConstructor();\n new Entry(service, account).setPassword(password);\n },\n};\n","/**\n * `penv list` — every parameter, and the scope that wins for one environment.\n *\n * The winning scope is the point: `production` and `default` are both \"it\n * resolves\", and only one of them means the value was written for production.\n */\n\nimport type { Scope } from \"@penvhq/core\";\nimport { assertNever, resolveAll, variableName } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { keySourceFor, openProject, PENV_DIR, targetEnvironment } from \"../project.js\";\nimport { columns, guard, write } from \"../ui.js\";\n\nexport interface ListOptions {\n readonly cwd: string;\n readonly environment?: string;\n}\n\nexport interface ListEntry {\n readonly parameter: string;\n /** The generated `.env` variable, so the two names are legible side by side. */\n readonly variable: string;\n /** `<env>.local`, `local`, an environment name, `default`, or `absent`. */\n readonly scope: string;\n /** The winning value file relative to `.penv/`, or `undefined` when nothing wins. */\n readonly location: string | undefined;\n readonly encrypted: boolean;\n readonly viaUnscopedFallback: boolean;\n}\n\nexport interface ListResult {\n readonly environment: string;\n readonly parameters: readonly ListEntry[];\n}\n\n/**\n * The cascade level a winning scope names, spelled as its filename suffix so the\n * column reads back as the file on disk. Each of the four levels is distinct:\n * `production.local` and `local` are different files with different reach, and a\n * column that called both `local` would hide which one won.\n */\nfunction scopeLabel(scope: Scope): string {\n switch (scope.kind) {\n case \"environment\":\n return scope.environment;\n case \"local\":\n return \"local\";\n case \"environment-local\":\n return `${scope.environment}.local`;\n case \"unscoped\":\n return \"default\";\n default:\n return assertNever(scope, \"scope\");\n }\n}\n\nexport async function runList(options: ListOptions): Promise<ListResult> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n\n const keys = keySourceFor(project, environment);\n const parameters: ListEntry[] = [];\n // `list` names which file wins, never a value, so an undecryptable winner is\n // listed exactly like any other: the scope column is the answer here.\n for (const resolution of await resolveAll(environment, project.provider, keys)) {\n const winner = resolution.winner;\n const scope = winner?.file.scope;\n parameters.push({\n parameter: resolution.parameter,\n variable: variableName(resolution.ref, project.config),\n scope: scope === undefined ? \"absent\" : scopeLabel(scope),\n location: winner?.location,\n encrypted: winner?.file.encrypted === true,\n viaUnscopedFallback: resolution.viaUnscopedFallback,\n });\n }\n\n return { environment, parameters };\n}\n\nexport function renderList(result: ListResult): string[] {\n if (result.parameters.length === 0) {\n return [`No parameters in ${PENV_DIR}/ for environment ${result.environment}.`];\n }\n return columns(result.parameters.map((entry) => [entry.parameter, entry.scope, entry.variable]));\n}\n\nexport const listCommand = defineCommand({\n meta: { name: \"list\", description: \"List parameters\" },\n args: {\n env: { type: \"string\", description: \"The environment to resolve against\" },\n json: { type: \"boolean\", description: \"Print machine-readable JSON\" },\n },\n run({ args }) {\n return guard(async () => {\n const result = await runList({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n });\n write(args.json === true ? [JSON.stringify(result, null, 2)] : renderList(result));\n });\n },\n});\n","/**\n * `penv mv <from> <to>` — rename a parameter, every scope at once.\n *\n * A parameter is not one file. It is up to eight — four cascade levels, each\n * with a plaintext and an encrypted address — plus its meta, and a rename that\n * moved some of them would split one parameter into two. So this moves all of\n * them or none of them, and the whole plan is checked before a single byte is\n * written.\n *\n * **This is the only correct way to move an encrypted value.** A ciphertext is\n * sealed against the address it lives at, so `mv redis-password.production.enc\n * redis/password.production.enc` at the shell produces a file that will never\n * open again — the value is not moved, it is destroyed, and the shell reports\n * success. Re-sealing at the new address is the whole reason this command\n * exists: penv asked for namespacing to be \"a deliberate refactor afterwards\"\n * and then, once values could be encrypted, made doing it by hand a way to lose\n * them.\n *\n * It moves the tree and never the schema. `.penv/env.ts` is yours (invariant 2),\n * so renaming `database-url` to `database/url` leaves it declaring the old access\n * path — and the drift report is what says so. penv names the distance; you close\n * it. This command's report says which line to change rather than changing it.\n */\n\nimport type { Meta, ParameterRef, ValueFile } from \"@penvhq/core\";\nimport {\n accessPath,\n formatMetaFile,\n formatValueFile,\n openValue,\n PenvError,\n parameterId,\n sealValue,\n} from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport type { Project } from \"../project.js\";\nimport { assertWritableKey, keySourceFor, openProject, PENV_DIR, refFromKey } from \"../project.js\";\nimport { CHECK, formatRows, guard, type Row, write } from \"../ui.js\";\n\nexport interface MoveOptions {\n readonly cwd: string;\n readonly from: string;\n readonly to: string;\n}\n\nexport interface MovedFile {\n readonly from: string;\n readonly to: string;\n /** True when the value was opened and sealed again for its new address. */\n readonly resealed: boolean;\n}\n\nexport interface MoveResult {\n readonly from: string;\n readonly to: string;\n readonly files: readonly MovedFile[];\n /** The meta file's new location, or `undefined` when the parameter had none. */\n readonly meta: string | undefined;\n /** The access path the schema still declares, and the one it should now. */\n readonly schema: { readonly was: string; readonly now: string };\n}\n\n/** The environment a scope names, or `undefined` for the scopes that name none. */\nfunction environmentOf(file: ValueFile): string | undefined {\n const scope = file.scope;\n return scope.kind === \"environment\" || scope.kind === \"environment-local\"\n ? scope.environment\n : undefined;\n}\n\n/** One file's move, resolved to the bytes that will be written at the far end. */\ninterface Planned {\n readonly source: ValueFile;\n readonly target: ValueFile;\n readonly contents: string;\n readonly resealed: boolean;\n}\n\n/**\n * Reads one file and works out what it must say at its new address.\n *\n * A plaintext value is bytes and moves as bytes. An encrypted one cannot: the\n * address is authenticated, so the ciphertext is only valid where it is. It is\n * opened here and sealed again below — and if it cannot be opened, the whole move\n * is refused rather than carrying a file to a place it will never open from.\n */\nasync function planFile(\n project: Project,\n source: ValueFile,\n target: ValueFile,\n parameter: string,\n): Promise<Planned | undefined> {\n const stored = await project.provider.read(source);\n if (stored === undefined) {\n return undefined;\n }\n if (!source.encrypted) {\n return { source, target, contents: stored, resealed: false };\n }\n\n // A key is declared per environment, so a sealed value at a scope that names\n // none has no key penv can choose — the same refusal `penv set` makes, for the\n // same reason, and the same one that keeps penv from creating such a file.\n const environment = environmentOf(source);\n if (environment === undefined) {\n throw new PenvError(\n \"SECRET_SCOPE_AMBIGUOUS\",\n `${PENV_DIR}/${formatValueFile(source)} is encrypted at a scope that names no environment, so penv cannot tell which key would re-seal it`,\n \"Keys are declared per environment in the `keys` block of penv.config.ts. Decrypt it with \" +\n \"`penv decrypt`, move the parameter, then encrypt it again at its new address.\",\n );\n }\n\n const keys = keySourceFor(project, environment);\n const opened = openValue(source, stored, keys);\n if (opened.kind === \"failed\") {\n throw new PenvError(\n \"VALUE_UNDECRYPTABLE\",\n `${PENV_DIR}/${formatValueFile(source)} could not be decrypted, so penv cannot re-seal it at its new address: ${opened.failure.detail}`,\n \"A sealed value is bound to the file it lives in, so moving it means opening it and \" +\n \"sealing it again. Make the key available and run this again. Nothing has been moved.\",\n );\n }\n\n return {\n source,\n target,\n contents: sealValue(target, opened.value, keys, parameter, environment),\n resealed: true,\n };\n}\n\n/** Every file the provider actually holds for one parameter. */\nfunction filesOf(all: readonly ValueFile[], ref: ParameterRef): ValueFile[] {\n const id = parameterId(ref);\n return all.filter((file) => parameterId(file) === id);\n}\n\nexport async function runMove(options: MoveOptions): Promise<MoveResult> {\n const project = openProject(options.cwd);\n const from = refFromKey(options.from, project.config);\n assertWritableKey(options.to);\n const to = refFromKey(options.to, project.config);\n\n if (parameterId(from) === parameterId(to)) {\n throw new PenvError(\n \"PARAMETER_UNCHANGED\",\n `\\`${options.from}\\` and \\`${options.to}\\` are the same parameter`,\n \"Name a different destination, e.g. `penv mv redis-password redis/password`.\",\n );\n }\n\n const all = await project.provider.list();\n const sources = filesOf(all, from);\n const meta: Meta | undefined = await project.provider.readMeta(from);\n\n if (sources.length === 0 && meta === undefined) {\n throw new PenvError(\n \"PARAMETER_ABSENT\",\n `Parameter ${parameterId(from)} has no value files and no meta, so there is nothing to move`,\n `\\`penv list\\` shows every parameter penv holds.`,\n );\n }\n\n // Nothing is overwritten, ever. A destination that already exists is two\n // parameters being merged into one, which loses whichever penv wrote second —\n // the same loss `validate` refuses for name collisions (invariant 12).\n const occupied = filesOf(all, to);\n if (occupied.length > 0 || (await project.provider.readMeta(to)) !== undefined) {\n throw new PenvError(\n \"PARAMETER_EXISTS\",\n `Parameter ${parameterId(to)} already exists, and penv will not merge two parameters into one`,\n `Remove or rename ${parameterId(to)} first. \\`penv get ${options.to} --explain\\` shows every file it holds.`,\n );\n }\n\n // Planned in full before anything is written. Every read, every decryption and\n // every key lookup happens here, so a move that cannot finish fails having\n // changed nothing — rather than halfway, with a parameter that is now two.\n const planned: Planned[] = [];\n for (const source of sources) {\n const target: ValueFile = { ...source, namespace: to.namespace, name: to.name };\n const one = await planFile(project, source, target, parameterId(to));\n if (one !== undefined) {\n planned.push(one);\n }\n }\n\n for (const file of planned) {\n await project.provider.write(file.target, file.contents);\n }\n if (meta !== undefined) {\n await project.provider.writeMeta(to, meta);\n }\n\n // Removed only once every new file is on disk, so the value is never in\n // neither place. The cost is a window where it is in both, which a crash\n // leaves recoverable; the reverse leaves it gone.\n for (const file of planned) {\n await project.provider.remove(file.source);\n }\n if (meta !== undefined) {\n await project.provider.removeMeta(from);\n }\n\n return {\n from: parameterId(from),\n to: parameterId(to),\n files: planned.map((file) => ({\n from: formatValueFile(file.source),\n to: formatValueFile(file.target),\n resealed: file.resealed,\n })),\n // The meta's path, not the parameter's dotted id: `redis.password` is what\n // the schema calls it and `redis/password.json` is the file, and a report\n // that printed the first while moving the second names no file on disk.\n meta: meta === undefined ? undefined : formatMetaFile({ ...to, format: \"json\" }),\n schema: { was: accessPath(from).join(\".\"), now: accessPath(to).join(\".\") },\n };\n}\n\nexport function renderMove(result: MoveResult): string[] {\n const rows: Row[] = result.files.map((file) => ({\n glyph: CHECK,\n label: \"Moved\",\n subject: `${PENV_DIR}/${file.to}`,\n ...(file.resealed ? { detail: \"re-sealed for its new address\" } : {}),\n }));\n if (result.meta !== undefined) {\n rows.push({ glyph: CHECK, label: \"Moved\", subject: `${PENV_DIR}/${result.meta}` });\n }\n\n const lines = formatRows(rows);\n // The tree moved and the schema did not, because the schema is the user's file\n // and penv does not write it. Saying so here is cheaper than letting them find\n // out from a failing `validate` — and it names the edit rather than the fault.\n lines.push(\n \"\",\n ` .penv/env.ts still declares \\`${result.schema.was}\\`. Rename it to \\`${result.schema.now}\\`,`,\n \" or `penv validate` will report the value as unused and the declaration as unset.\",\n );\n return lines;\n}\n\nexport const mvCommand = defineCommand({\n meta: { name: \"mv\", description: \"Rename a parameter, every scope and its meta at once\" },\n args: {\n from: {\n type: \"positional\",\n required: true,\n description: \"The parameter now, e.g. redis-password\",\n },\n to: {\n type: \"positional\",\n required: true,\n description: \"The parameter after, e.g. redis/password\",\n },\n },\n run({ args }) {\n return guard(async () => {\n write(renderMove(await runMove({ cwd: process.cwd(), from: args.from, to: args.to })));\n });\n },\n});\n","/**\n * `penv pull` — materialise the local `.penv` tree from an environment's\n * source-of-truth provider. It is the inverse of the deploy-time injection most\n * stacks already have: instead of reading the tree to feed a backend, it reads\n * the backend to feed the tree.\n *\n * It only means anything when the environment declares a real backend\n * (`vault`, `mock`): those hold the truth somewhere penv does not edit in place,\n * and pulling copies it down so every other command — which reads the local tree\n * — sees it. An environment with no separate `providers` entry has the local\n * tree *as* its source of truth, so a pull would be the tree copying onto\n * itself; that degenerate case is reported as nothing to do, never a self-copy.\n *\n * Values cross verbatim. They are opaque envelope strings the source holds and\n * penv does not open here — a sealed value stays sealed, byte-for-byte, so the\n * key that opens it never has to be present to pull it.\n */\n\nimport type { Meta } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport {\n localTree,\n openProject,\n refsFrom,\n sourceProviderFor,\n targetEnvironment,\n} from \"../project.js\";\nimport { LOCAL_TREE_TYPE } from \"../registry.js\";\nimport { CHECK, formatRows, guard, write } from \"../ui.js\";\n\nexport interface PullOptions {\n readonly cwd: string;\n readonly environment?: string;\n}\n\nexport interface PullResult {\n readonly environment: string;\n /** The source provider's type — `filesystem` when the environment declares no separate backend. */\n readonly source: string;\n /**\n * True when the source *is* the local tree, so there was nothing to pull. The\n * caller distinguishes \"pulled nothing because the backend was empty\" from\n * \"there is no backend to pull from\" — opposite situations.\n */\n readonly localSource: boolean;\n /** Value files written into the local tree. */\n readonly values: number;\n /** Meta files written into the local tree. */\n readonly meta: number;\n /** Distinct parameters the pull touched, at any scope. */\n readonly refs: number;\n}\n\nexport async function runPull(options: PullOptions): Promise<PullResult> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const source = await sourceProviderFor(project, environment);\n\n // The local tree already IS the source of truth for an environment with no\n // declared backend: `sourceProviderFor` handed back the filesystem tree, and\n // pulling it onto itself would be a no-op dressed as work. Report the truth.\n if (source.type === LOCAL_TREE_TYPE) {\n return { environment, source: source.type, localSource: true, values: 0, meta: 0, refs: 0 };\n }\n\n const tree = localTree(project);\n const files = await source.list();\n\n let values = 0;\n for (const file of files) {\n const value = await source.read(file);\n // Absent is not written: `list` and `read` can disagree across a concurrent\n // prune, and a missing value is nothing to materialise.\n if (value === undefined) {\n continue;\n }\n // Verbatim — the value is an opaque envelope, sealed or not, and penv does\n // not open it to move it.\n tree.writeSync(file, value);\n values += 1;\n }\n\n // Meta is per-parameter, so it is pulled once per distinct ref rather than once\n // per value file — two scopes of one parameter share the one policy.\n const refs = refsFrom(files);\n let meta = 0;\n for (const ref of refs) {\n const block: Meta | undefined = await source.readMeta(ref);\n if (block === undefined) {\n continue;\n }\n tree.writeMetaSync(ref, block);\n meta += 1;\n }\n\n return { environment, source: source.type, localSource: false, values, meta, refs: refs.length };\n}\n\nexport function renderPull(result: PullResult): string[] {\n if (result.localSource) {\n return formatRows([\n {\n glyph: CHECK,\n label: \"Nothing to pull\",\n subject: `environment ${result.environment} has no separate source of truth`,\n detail: \"its values live in the local .penv tree already\",\n },\n ]);\n }\n\n return formatRows([\n {\n glyph: CHECK,\n label: \"Pulled\",\n subject: `${result.values} ${result.values === 1 ? \"value\" : \"values\"}`,\n detail: `from the ${result.source} provider for environment ${result.environment}`,\n },\n {\n glyph: CHECK,\n label: \"Parameters\",\n subject: `${result.refs} ${result.refs === 1 ? \"parameter\" : \"parameters\"}, ${result.meta} with meta`,\n detail: \"written into the local .penv tree\",\n },\n ]);\n}\n\nexport const pullCommand = defineCommand({\n meta: {\n name: \"pull\",\n description: \"Materialise the local .penv tree from an environment's source-of-truth provider\",\n },\n args: {\n env: { type: \"string\", description: \"The environment to pull\" },\n },\n run({ args }) {\n return guard(async () => {\n const result = await runPull({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n });\n write(renderPull(result));\n });\n },\n});\n","/**\n * `penv remove <key>` — delete one value file.\n *\n * The scope is selected exactly as `penv set` selects it, so what you removed is\n * the file you would have written. Meta is left alone: policy is a property of\n * the parameter across every environment, not of the value you just deleted.\n */\n\nimport type { ValueFile } from \"@penvhq/core\";\nimport { formatValueFile } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { openProject, PENV_DIR, refFromKey } from \"../project.js\";\nimport { CHECK, formatRows, guard, type Row, WARN, write } from \"../ui.js\";\nimport { type ScopeOptions, targetScope } from \"./set.js\";\n\nexport interface RemoveOptions extends ScopeOptions {\n readonly cwd: string;\n readonly key: string;\n}\n\nexport interface RemoveResult {\n readonly parameter: string;\n /** The value files that existed and are now gone, relative to `.penv/`. */\n readonly removed: readonly string[];\n /** Both files penv looked at, whether or not they were there. */\n readonly considered: readonly string[];\n}\n\nexport async function runRemove(options: RemoveOptions): Promise<RemoveResult> {\n const project = openProject(options.cwd);\n const ref = refFromKey(options.key);\n\n // The same scope selection `set` writes through, for the same reason: the file\n // `remove` names has to be the file `set` named, byte for byte.\n const scope = targetScope(project, options, options.key);\n // `.enc` is orthogonal to scope: the encrypted file at this scope is the same\n // parameter at the same precedence, so removing the scope removes both.\n const files: ValueFile[] = [false, true].map((encrypted) => ({\n namespace: ref.namespace,\n name: ref.name,\n scope,\n encrypted,\n }));\n\n const removed: string[] = [];\n for (const file of files) {\n if ((await project.provider.read(file)) === undefined) {\n continue;\n }\n await project.provider.remove(file);\n removed.push(formatValueFile(file));\n }\n\n return {\n parameter: options.key,\n removed,\n considered: files.map((file) => formatValueFile(file)),\n };\n}\n\nexport function renderRemove(result: RemoveResult): string[] {\n if (result.removed.length === 0) {\n const first = result.considered[0] ?? result.parameter;\n return formatRows([\n {\n glyph: WARN,\n label: \"Nothing to remove\",\n subject: `${PENV_DIR}/${first}`,\n detail: \"no value file at that scope\",\n },\n ]);\n }\n const rows: Row[] = result.removed.map((location) => ({\n glyph: CHECK,\n label: \"Removed\",\n subject: `${PENV_DIR}/${location}`,\n }));\n return formatRows(rows);\n}\n\nexport const removeCommand = defineCommand({\n meta: { name: \"remove\", description: \"Delete a parameter\" },\n args: {\n key: { type: \"positional\", required: true, description: \"The parameter, e.g. redis/password\" },\n env: { type: \"string\", description: \"Remove the <name>.<env> scope\" },\n local: {\n type: \"boolean\",\n description: \"Remove the personal override: <name>.<env>.local with --env, else <name>.local\",\n },\n },\n run({ args }) {\n return guard(async () => {\n write(\n renderRemove(\n await runRemove({\n cwd: process.cwd(),\n key: args.key,\n ...(args.env === undefined ? {} : { environment: args.env }),\n ...(args.local === undefined ? {} : { local: args.local }),\n }),\n ),\n );\n });\n },\n});\n","/**\n * `penv rotate <key>` — turn one parameter over to a new value, by the mechanism\n * its meta declares, against the environment's source-of-truth provider.\n *\n * The two mechanisms are two different physics, never one code path with a flag\n * (rotation.ts says as much). `dual-valid` is a *window*: the new value goes live\n * while the provider still serves the old one, both credentials valid at once,\n * and the window closes only when every reader has moved over. `atomic-cutover`\n * is an *instant*: one flip, old value gone the moment the new one lands, no\n * overlap to hold open. So the command shape mirrors the physics —\n *\n * - `--begin` / `--complete` bracket a `dual-valid` window (`active → rotating →\n * active`), and demand a {@link RetainingProvider}, because a window whose old\n * value the provider does not retain is not a window at all — the overlap the\n * mechanism promises would silently not exist. penv refuses that up front\n * rather than opening a grace window that is a fiction.\n * - a bare `penv rotate` is the `atomic-cutover` flip: write the new value and\n * stamp the completion in one step, never touching `rotatingSince`, never\n * requiring retention — there is no penv-layer overlap to record or to lean on.\n *\n * Like `push`, the real work is an exported plain function returning a structured\n * result, and `now` is injectable so the meta clocks are testable without mocking\n * time. The rotation clock itself lives in core (`beginRotation` /\n * `completeRotation`); this command only decides *which* to apply, writes the\n * value at the right moment relative to it, and persists both to the provider.\n */\n\nimport type {\n Meta,\n ParameterRef,\n Provider,\n RetainingProvider,\n RotationMechanism,\n RotationState,\n ValueFile,\n} from \"@penvhq/core\";\nimport {\n beginRotation,\n completeRotation,\n PenvError,\n retainsPrevious,\n rotationOf,\n} from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport type { Project } from \"../project.js\";\nimport { openProject, refFromKey, sourceProviderFor, targetEnvironment } from \"../project.js\";\nimport { LOCAL_TREE_TYPE } from \"../registry.js\";\nimport { CHECK, formatRows, guard, write } from \"../ui.js\";\nimport { readStdin, sealAwareWrite } from \"./set.js\";\n\nexport interface RotateOptions {\n readonly cwd: string;\n readonly key: string;\n readonly environment?: string;\n /** Open a `dual-valid` window: write the new value while the old is still retained. */\n readonly begin?: boolean;\n /** Close a `dual-valid` window: return to `active`, stamp the completion. */\n readonly complete?: boolean;\n /**\n * The new value. A `begin` and an `atomic-cutover` flip write it; a `complete`\n * does not touch the value at all, so it needs none. Injected in tests; on the\n * CLI it is the positional argument or stdin, the same source `set` reads.\n */\n readonly value?: string;\n /** Injected in tests: the wall-clock reading recorded in meta. Defaults to now. */\n readonly now?: string;\n}\n\n/** The single step a run performed — the three the two mechanisms decompose into. */\nexport type RotatePhase = \"begin\" | \"complete\" | \"cutover\";\n\nexport interface RotateResult {\n readonly parameter: string;\n readonly environment: string;\n readonly mechanism: RotationMechanism;\n readonly phase: RotatePhase;\n /** The source provider's type — where the value and its meta were written. */\n readonly source: string;\n /** True when this run wrote a new value. `begin` and `cutover` do; `complete` does not. */\n readonly wroteValue: boolean;\n /** The rotation state after this run — `rotating` after a begin, `active` otherwise. */\n readonly state: RotationState;\n /** When the current window opened, ISO. Set only after a `begin`, else `null`. */\n readonly rotatingSince: string | null;\n /** When a rotation last completed, ISO. Set after a `complete` or a `cutover`. */\n readonly lastRotated: string | null;\n}\n\n/**\n * The value file a rotation writes to a *backend* and reads back — the parameter\n * at its environment scope, verbatim.\n *\n * A rotating secret belongs to exactly one environment (the credential Vault\n * issues for production is not development's), so the environment scope is its\n * home, and pinning it here is what lets `readPrevious` find the prior version\n * during the window: the write and the retention read must address the same\n * value file byte-for-byte. `encrypted: false` because the value crosses to a\n * backend source of truth verbatim, the way `push` moves it — the backend holds\n * custody of its own store, and penv's envelope is the *local tree's* concern,\n * not the backend's. When the source of truth is instead the local tree,\n * {@link writeRotatedValue} routes to {@link sealAwareWrite}, which seals per\n * meta and removes the twin; this file shape is only ever the backend's.\n */\nfunction rotatingFile(ref: ParameterRef, environment: string): ValueFile {\n return {\n namespace: ref.namespace,\n name: ref.name,\n scope: { kind: \"environment\", environment },\n encrypted: false,\n };\n}\n\n/**\n * Writes the new value to the environment's source of truth, by the custody rule\n * the store's *type* sets — the fix for a rotation that used to persist the live\n * credential as cleartext.\n *\n * The local `.penv` tree is penv's own to seal, so a secret rotated into it must\n * be sealed and its plaintext twin removed, exactly as `set` does: otherwise the\n * value lands as cleartext `.penv/<name>.<env>`, which is committed to git and,\n * because plaintext outranks `.enc` at one scope, also shadows any sealed copy\n * already there. So the local tree goes through {@link sealAwareWrite}, honouring\n * meta's policy. A real backend (vault, mock) holds custody of its own store and\n * penv's envelope is not its concern — the value crosses verbatim via\n * {@link rotatingFile}, the way `push` sends plaintext for the sink to re-seal.\n *\n * `--begin` only ever reaches a backend (a dual-valid window demands a retaining\n * provider, which the local tree is not), but it is routed here too, so both\n * value-write sites share one custody decision.\n */\nasync function writeRotatedValue(\n project: Project,\n provider: Provider,\n ref: ParameterRef,\n environment: string,\n value: string,\n): Promise<void> {\n if (provider.type === LOCAL_TREE_TYPE) {\n await sealAwareWrite({\n project,\n provider,\n ref,\n scope: { kind: \"environment\", environment },\n value,\n environment,\n });\n return;\n }\n await provider.write(rotatingFile(ref, environment), value);\n}\n\n/** The new value a write step requires, or a refusal that names the phase needing it. */\nfunction requireNewValue(value: string | undefined, phase: RotatePhase, key: string): string {\n if (value === undefined) {\n throw new PenvError(\n \"ROTATION_NO_VALUE\",\n `A ${phase} rotation of ${key} writes a new value, and none was given`,\n \"Pass the new value as the argument — `penv rotate <key> <value>` — or pipe it in on stdin.\",\n );\n }\n return value;\n}\n\n/**\n * A `dual-valid` rotation against a provider that does not retain its previous\n * value — the one situation the mechanism cannot survive, refused before a single\n * write.\n *\n * The window's whole promise is that the old credential keeps working while the\n * new one takes over; a provider that overwrites in place breaks that the instant\n * `begin` writes, and no meta clock can put the old value back. So this is not a\n * best-effort with a warning — it is a hard refusal, thrown here so the caller\n * never opens a grace window that is already a lie. `atomic-cutover` reaches this\n * function's callers not at all: it has no overlap to retain.\n */\nfunction requireRetaining(provider: Provider, environment: string): RetainingProvider {\n if (!retainsPrevious(provider)) {\n throw new PenvError(\n \"ROTATION_NOT_RETAINING\",\n `A dual-valid rotation needs the previous value to stay readable during the grace window, and the \\`${provider.type}\\` provider for environment ${environment} does not retain it`,\n \"Point this environment at a provider that keeps prior versions (its `readPrevious` is what penv reads during the window), \" +\n \"or, if a momentary overlap is not required, declare the parameter `atomic-cutover` in its meta and flip it in one step.\",\n );\n }\n return provider;\n}\n\nexport async function runRotate(options: RotateOptions): Promise<RotateResult> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const ref = refFromKey(options.key, project.config);\n const provider = await sourceProviderFor(project, environment);\n\n const nowIso = options.now ?? new Date().toISOString();\n const before: Meta | undefined = await provider.readMeta(ref);\n const { mechanism } = rotationOf(before, environment);\n\n if (mechanism === undefined) {\n throw new PenvError(\n \"ROTATION_NO_MECHANISM\",\n `Parameter ${options.key} declares no rotation mechanism for environment ${environment}, so penv does not know how to rotate it`,\n 'Set `rotationMechanism` in the parameter\\'s meta to `\"dual-valid\"` (a grace-window overlap) or ' +\n '`\"atomic-cutover\"` (a single flip), then run `penv rotate` again.',\n );\n }\n\n const begin = options.begin === true;\n const complete = options.complete === true;\n\n // atomic-cutover: one flip, and `--begin`/`--complete` have no meaning for it —\n // there is no window to bracket. Refuse the flags rather than silently ignore\n // them, so a user who reached for a two-phase rotation learns their parameter\n // is not one before anything is written.\n if (mechanism === \"atomic-cutover\") {\n if (begin || complete) {\n throw new PenvError(\n \"ROTATION_MECHANISM_MISMATCH\",\n `Parameter ${options.key} is atomic-cutover, which flips in one step, so \\`--begin\\`/\\`--complete\\` do not apply`,\n \"Run `penv rotate <key> <value>` with no phase flag to flip it. `--begin`/`--complete` bracket a \" +\n \"dual-valid grace window, which atomic-cutover has none of.\",\n );\n }\n const value = requireNewValue(options.value, \"cutover\", options.key);\n // Value first, then the completion stamp — the flip and its record, in the\n // order that leaves the value present before anything claims it rotated. The\n // write honours the store's custody rule: sealed into the local tree per\n // meta, verbatim to a backend.\n await writeRotatedValue(project, provider, ref, environment, value);\n const after = completeRotation(before, environment, nowIso);\n await provider.writeMeta(ref, after);\n return result(ref, environment, mechanism, \"cutover\", provider.type, true, after);\n }\n\n // dual-valid from here: every path needs a retaining provider, and the two\n // phases are mutually exclusive — exactly one bracket per run.\n const retaining = requireRetaining(provider, environment);\n\n if (begin === complete) {\n throw new PenvError(\n \"ROTATION_PHASE_REQUIRED\",\n `A dual-valid rotation of ${options.key} needs exactly one of \\`--begin\\` or \\`--complete\\``,\n \"`--begin` writes the new value and opens the grace window; `--complete` closes it once every reader \" +\n \"has moved to the new value. Run them in that order, one at a time.\",\n );\n }\n\n if (begin) {\n const value = requireNewValue(options.value, \"begin\", options.key);\n // The new value is written while the provider still holds the previous one —\n // that co-existence IS the window, and `readPrevious` serves the old value\n // until `--complete` closes it. Value first, then `rotatingSince`, so the\n // clock never claims a window an unwritten value has not yet opened. A\n // retaining provider is always a backend, so this crosses verbatim; routed\n // through the shared helper so both write sites share one custody decision.\n await writeRotatedValue(project, retaining, ref, environment, value);\n const after = beginRotation(before, environment, nowIso);\n await retaining.writeMeta(ref, after);\n return result(ref, environment, mechanism, \"begin\", retaining.type, true, after);\n }\n\n // --complete: the window closes. No value is written — the new value has been\n // live since `--begin`; this only returns the clock to `active` and stamps the\n // completion. The provider's previous version may be pruned any time after.\n const after = completeRotation(before, environment, nowIso);\n await retaining.writeMeta(ref, after);\n return result(ref, environment, mechanism, \"complete\", retaining.type, false, after);\n}\n\n/** Reads the settled clocks back out of the meta just written, so the result is the record. */\nfunction result(\n ref: ParameterRef,\n environment: string,\n mechanism: RotationMechanism,\n phase: RotatePhase,\n source: string,\n wroteValue: boolean,\n after: Meta,\n): RotateResult {\n const { state, rotatingSince, lastRotated } = rotationOf(after, environment);\n return {\n parameter: [...ref.namespace, ref.name].join(\"/\"),\n environment,\n mechanism,\n phase,\n source,\n wroteValue,\n state,\n rotatingSince,\n lastRotated,\n };\n}\n\nexport function renderRotate(result: RotateResult): string[] {\n if (result.phase === \"begin\") {\n return formatRows([\n {\n glyph: CHECK,\n label: \"Rotating\",\n subject: result.parameter,\n detail: `dual-valid window open for environment ${result.environment} (since ${result.rotatingSince})`,\n },\n {\n glyph: CHECK,\n label: \"Previous\",\n subject: \"still readable\",\n detail: `on the ${result.source} provider until \\`penv rotate ${result.parameter} --complete\\``,\n },\n ]);\n }\n if (result.phase === \"complete\") {\n return formatRows([\n {\n glyph: CHECK,\n label: \"Rotated\",\n subject: result.parameter,\n detail: `dual-valid window closed for environment ${result.environment} (completed ${result.lastRotated})`,\n },\n ]);\n }\n return formatRows([\n {\n glyph: CHECK,\n label: \"Rotated\",\n subject: result.parameter,\n detail: `atomic-cutover flip for environment ${result.environment} (completed ${result.lastRotated})`,\n },\n ]);\n}\n\nexport const rotateCommand = defineCommand({\n meta: {\n name: \"rotate\",\n description: \"Rotate a parameter's value by the mechanism its meta declares\",\n },\n args: {\n key: { type: \"positional\", required: true, description: \"The parameter, e.g. redis/password\" },\n value: {\n type: \"positional\",\n required: false,\n description: \"The new value; read from stdin if omitted. Not needed with --complete\",\n },\n env: { type: \"string\", description: \"The environment to rotate in\" },\n begin: { type: \"boolean\", description: \"Open a dual-valid grace window with the new value\" },\n complete: { type: \"boolean\", description: \"Close a dual-valid grace window\" },\n },\n run({ args }) {\n return guard(async () => {\n // `--complete` writes no value, so it never blocks on stdin waiting for one\n // that will not come. Every other path reads the value the way `set` does.\n const value = args.complete === true ? undefined : (args.value ?? (await readStdin()));\n write(\n renderRotate(\n await runRotate({\n cwd: process.cwd(),\n key: args.key,\n ...(value === undefined ? {} : { value }),\n ...(args.env === undefined ? {} : { environment: args.env }),\n ...(args.begin === undefined ? {} : { begin: args.begin }),\n ...(args.complete === undefined ? {} : { complete: args.complete }),\n }),\n ),\n );\n });\n },\n});\n","/**\n * `penv watch` — re-run validation whenever the configuration changes.\n *\n * Watch mode reports `penv validate`'s verdict on a loop, and never a second\n * opinion about it: the diagnostics come from `runValidate` itself, so there is\n * no watch-mode verdict that could drift from the command CI runs.\n *\n * It prints one thing `validate` does not — the schema↔tree drift report, which\n * `runValidate` measures and hands back without letting it touch `ok`. The two\n * commands differ because their readers do. CI wants a verdict, and a warning\n * about a parameter the schema tolerates would be noise in a log nobody reads on\n * a passing run. The person with `watch` open is mid-edit, and the distance\n * between what they have just declared and what the tree holds is the thing they\n * are watching *for*. Same facts, same measurement, one of them worth printing\n * only where someone is looking.\n *\n * Three things decide the answer, so three things are watched: the `.penv/` tree\n * (the values and their meta), `penv.config.ts` (the environment whitelist, and\n * the `names` block), and the schema. The schema is watched on its own only when\n * `schemaFile` puts it outside `.penv/` — at the default it is inside the tree,\n * and a second watcher on it would report every edit twice.\n *\n * `node:fs` does the watching. A dependency-free watcher is worth the handful of\n * lines here: the events this needs are the ones the platform already reports,\n * and debouncing them is the whole of what a library would add.\n */\n\nimport type { FSWatcher } from \"node:fs\";\nimport { existsSync, watch } from \"node:fs\";\nimport { basename, dirname, resolve } from \"node:path\";\nimport { schemaFileOf, schemaInsideTree } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { openProject } from \"../project.js\";\nimport type { DriftReport } from \"../schema.js\";\nimport { formatRows, guard, type Row, reportError, WARN, write } from \"../ui.js\";\nimport type { ValidateResult } from \"./validate.js\";\nimport { renderValidate, runValidate } from \"./validate.js\";\n\n/**\n * Long enough to coalesce an editor's save into one run, short enough to feel\n * immediate. An atomic save is a write, a rename, and sometimes a delete, and a\n * run per event would validate a tree mid-rewrite and report a file that exists\n * again by the time the user reads the line.\n */\nconst DEBOUNCE_MS = 100;\n\nexport interface WatchOptions {\n readonly cwd: string;\n readonly environment?: string;\n /** Defaults to {@link DEBOUNCE_MS}. */\n readonly debounceMs?: number;\n /** Called with every completed validation, starting with the initial one. */\n readonly onResult?: (result: ValidateResult) => void;\n /**\n * Called when a cycle could not produce a result at all — an unreadable\n * config, a watcher the platform dropped. Never called for a *failing*\n * validation: that is a result, and it goes to `onResult`.\n */\n readonly onError?: (error: unknown) => void;\n}\n\nexport interface WatchHandle {\n /** Stops watching. Idempotent, and safe to call from inside a callback. */\n close(): void;\n}\n\n/**\n * Watches, and re-validates on change.\n *\n * Returns a handle rather than blocking, so the loop is a plain object a test\n * can drive and close instead of a live process it would have to spawn. The\n * command below is the only thing that turns it into a process that waits.\n */\nexport function runWatch(options: WatchOptions): WatchHandle {\n // Fails fast, and before any watcher exists: a watch on a directory that is\n // not a penv project would report the same error on every keystroke instead.\n const project = openProject(options.cwd);\n const configFile = basename(project.configFile);\n const debounceMs = options.debounceMs ?? DEBOUNCE_MS;\n\n const watchers = new Set<FSWatcher>();\n let timer: ReturnType<typeof setTimeout> | undefined;\n let running = false;\n let pending = false;\n let closed = false;\n\n async function validate(): Promise<void> {\n if (closed) {\n return;\n }\n // One run at a time: a save that lands mid-run would otherwise read the tree\n // twice at once and report whichever finished last.\n if (running) {\n pending = true;\n return;\n }\n running = true;\n try {\n const result = await runValidate({\n cwd: options.cwd,\n ...(options.environment === undefined ? {} : { environment: options.environment }),\n });\n if (!closed) {\n options.onResult?.(result);\n }\n } catch (error) {\n // A file can vanish between the event and the read — that is what an\n // atomic save looks like from here. Report it and keep watching: the\n // rename that follows will schedule the run that gets the real answer.\n if (!closed) {\n options.onError?.(error);\n }\n } finally {\n running = false;\n if (pending && !closed) {\n pending = false;\n void validate();\n }\n }\n }\n\n function schedule(): void {\n if (closed) {\n return;\n }\n if (timer !== undefined) {\n clearTimeout(timer);\n }\n timer = setTimeout(() => {\n timer = undefined;\n void validate();\n }, debounceMs);\n }\n\n function stop(watcher: FSWatcher): void {\n watchers.delete(watcher);\n watcher.close();\n }\n\n /**\n * Waits for a vanished target to come back, by watching its parent for the\n * name to reappear.\n *\n * A branch switch is a delete and then a create, so a watch that merely\n * stopped at the delete would be silent for the rest of the session — the\n * user would be reading a report of a tree that has since returned. The\n * re-armed watcher validates on arrival rather than trusting the report the\n * deletion produced.\n */\n function armRecovery(target: string, recursive: boolean, only?: string): void {\n const parent = dirname(target);\n const name = basename(target);\n let recovery: FSWatcher | undefined;\n\n try {\n recovery = watch(parent, { recursive: false }, (_event, filename) => {\n if (closed || recovery === undefined) {\n return;\n }\n // The parent went too. Watching it would spin exactly the way the\n // vanished target did, and there is nothing left to recover from.\n if (!existsSync(parent)) {\n stop(recovery);\n return;\n }\n if (filename !== null && basename(filename) !== name) {\n return;\n }\n if (!existsSync(target)) {\n return;\n }\n stop(recovery);\n addWatcher(target, recursive, only);\n schedule();\n });\n } catch (error) {\n options.onError?.(error);\n return;\n }\n\n recovery.on(\"error\", (error) => {\n if (!closed) {\n options.onError?.(error);\n }\n });\n watchers.add(recovery);\n }\n\n /**\n * `recursive` is not available on every platform, so a watcher that cannot\n * have it watches the directory itself. Namespace folders below it go\n * unwatched there, which is a weaker watch — never a wrong validation, since\n * the answer always comes from a fresh `runValidate`.\n */\n function addWatcher(target: string, recursive: boolean, only?: string): void {\n let watcher: FSWatcher | undefined;\n\n const listen = (useRecursive: boolean): FSWatcher =>\n watch(target, { recursive: useRecursive }, (_event, filename) => {\n if (closed) {\n return;\n }\n // A deleted target does not stop its watcher, and on Windows does not\n // error either: it re-fires `rename` for the absent path tens of\n // thousands of times a second, forever. Left alone that pins a core,\n // and every event resets the debounce below, so the watch would burn\n // CPU while reporting nothing at all. The check costs a `stat` per\n // event, which is what a `.penv/` that is still there is worth.\n //\n // Deleting the tree is a change like any other, so it is scheduled\n // rather than reported as a failure: `runValidate` has a real verdict\n // for a missing `.penv/`, and watch's job is to say what validate says.\n if (!existsSync(target)) {\n if (watcher !== undefined) {\n stop(watcher);\n }\n armRecovery(target, recursive, only);\n schedule();\n return;\n }\n // Directories are watched rather than files so that an editor's\n // write-to-temp-then-rename is seen as a change to the real name. The\n // cost is hearing about neighbours, so the ones that matter are named.\n if (only !== undefined && (filename === null || basename(filename) !== only)) {\n return;\n }\n schedule();\n });\n\n try {\n watcher = listen(recursive);\n } catch (error) {\n if (!recursive) {\n options.onError?.(error);\n return;\n }\n try {\n watcher = listen(false);\n } catch (fallbackError) {\n options.onError?.(fallbackError);\n return;\n }\n }\n watcher.on(\"error\", (error) => {\n if (!closed) {\n options.onError?.(error);\n }\n });\n watchers.add(watcher);\n }\n\n addWatcher(project.penvDir, true);\n addWatcher(dirname(project.configFile), false, configFile);\n\n // The schema declares what must exist, so an edit to it changes the answer. A\n // schema inside the tree already has a watcher; one outside would have none,\n // and a watch that keeps reporting a verdict it can no longer see the reason\n // for is the silence this command exists to prevent.\n if (schemaInsideTree(project.config) === undefined) {\n const schemaFile = resolve(project.root, schemaFileOf(project.config));\n addWatcher(dirname(schemaFile), false, basename(schemaFile));\n }\n\n // The current answer, before anything changes: a watch that says nothing until\n // the next keystroke leaves the user guessing at the state they already have.\n void validate();\n\n return {\n close(): void {\n closed = true;\n if (timer !== undefined) {\n clearTimeout(timer);\n timer = undefined;\n }\n for (const watcher of [...watchers]) {\n stop(watcher);\n }\n },\n };\n}\n\n/**\n * One cycle's report: `penv validate`'s, with a rule above it — on a loop, the\n * reader's first question is where the last run ended — and the drift below it.\n *\n * Drift comes last because it is the part that is not a verdict. The rows above\n * say whether the configuration is valid; these say what the schema and the tree\n * disagree about, which is often *why*, and is worth reading even on a run that\n * passed.\n */\nexport function renderWatch(result: ValidateResult): string[] {\n return [\"\", ...renderValidate(result), ...renderDrift(result.drift, result.environment)];\n}\n\n/**\n * The drift rows. Nothing at all when the schema and the tree agree: a loop\n * reprints its whole report on every keystroke, and a block that says \"no drift\"\n * forever is the first thing the eye learns to skip past — taking the block that\n * matters with it.\n */\nexport function renderDrift(drift: DriftReport, environment: string): string[] {\n const rows: Row[] = [\n ...drift.declared.map((item) => ({\n glyph: WARN,\n label: \"Declared, no value\",\n subject: item.subject,\n detail: item.detail,\n })),\n ...drift.undeclared.map((item) => ({\n glyph: WARN,\n label: \"Unused parameter\",\n subject: item.variable,\n detail: \"present, not in schema\",\n })),\n ];\n if (rows.length === 0) {\n return [];\n }\n\n const lines = [\"\", `Schema and tree differ for ${environment}:`, ...formatRows(rows)];\n // The paste block, exactly as `doctor` prints it — the reader who sees drift\n // here and drift there is looking at one report, not two that resemble each other.\n for (const remedy of new Set(drift.declared.map((item) => item.remedy))) {\n lines.push(` ${remedy}`);\n }\n return lines;\n}\n\nexport const watchCommand = defineCommand({\n meta: {\n name: \"watch\",\n description: \"Re-validate whenever .penv/ or penv.config.ts changes\",\n },\n args: {\n env: { type: \"string\", description: \"The environment to validate\" },\n },\n run({ args }) {\n return guard(async () => {\n const handle = runWatch({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n onResult: (result) => {\n write(renderWatch(result));\n },\n // A failing cycle is reported and watching continues. `reportError`\n // marks the process failed, which `validate` wants and a loop does not:\n // a cycle that failed mid-save ten minutes ago must not decide the exit\n // code of a session the user ended deliberately. The message is what is\n // wanted here, not the verdict.\n onError: (error) => {\n const previous = process.exitCode;\n reportError(error);\n process.exitCode = previous;\n },\n });\n write([\"Watching .penv/ and penv.config.ts. Ctrl-C to stop.\"]);\n await new Promise<void>((resolve) => {\n process.once(\"SIGINT\", () => {\n handle.close();\n resolve();\n });\n });\n });\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,IAAAA,gBAA4B;AAC5B,IAAAC,iBAAuD;;;ACwCvD,IAAAC,eAcO;AACP,IAAAC,sBAAiC;AACjC,IAAAC,gBAA8B;;;AC5D9B,IAAAC,oBAAiC;AASjC,IAAAC,eAaO;AACP,IAAAC,8BAAmC;;;ACVnC,yBAA8B;AAC9B,uBAAiC;AACjC,sBAA8B;AAE9B,kBAA0B;AAC1B,iCAAyC;AACzC,iCAAyC;AACzC,2BAAmC;AACnC,0BAAkC;AAClC,4BAAoC;AAiCpC,IAAM,wBAAwB;AAQvB,IAAM,kBAAkB;AAE/B,IAAM,WAAW,oBAAI,IAA6B;AAAA,EAChD,CAAC,iBAAiB,CAAC,EAAE,MAAM,OAAO,UAAM,qDAAyB,EAAE,MAAM,OAAO,CAAC,CAAC;AAAA,EAClF,CAAC,SAAS,CAAC,EAAE,eAAe,UAAM,2CAAoB,EAAE,MAAM,gBAAgB,QAAQ,OAAO,CAAC,CAAC;AAAA,EAC/F,CAAC,OAAO,CAAC,EAAE,eAAe,UAAM,uCAAkB,EAAE,MAAM,gBAAgB,QAAQ,OAAO,CAAC,CAAC;AAAA,EAC3F;AAAA,IACE;AAAA,IACA,CAAC,EAAE,eAAe,UAAM,qDAAyB,kBAAkB,cAAc,CAAC;AAAA,EACpF;AAAA,EACA,CAAC,QAAQ,CAAC,EAAE,KAAK,UAAM,yCAAmB,EAAE,eAAW,0BAAQ,MAAM,iBAAiB,EAAE,CAAC,CAAC;AAC5F,CAAC;AAGD,IAAM,mBAAmB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMA,IAAM,oBAAoB,oBAAI,IAA8C;AAGrE,SAAS,qBAAqB,MAAuB;AAC1D,SAAO,SAAS,IAAI,IAAI;AAC1B;AASO,SAAS,eAAe,MAAc,SAAoC;AAC/E,QAAM,UAAU,SAAS,IAAI,IAAI;AACjC,MAAI,YAAY,QAAW;AACzB,UAAM,gBAAgB,IAAI;AAAA,EAC5B;AACA,SAAO,QAAQ,OAAO;AACxB;AASA,eAAsB,qBACpB,MACA,SACmB;AACnB,MAAI,SAAS,IAAI,IAAI,GAAG;AACtB,WAAO,eAAe,MAAM,OAAO;AAAA,EACrC;AACA,SAAO,mBAAmB,MAAM,OAAO;AACzC;AAEA,eAAe,mBAAmB,MAAc,SAA6C;AAC3F,QAAM,UAAU,eAAe,OAAO;AACtC,QAAM,YAAY,gBAAgB,QAAQ,gBAAgB,IAAI;AAE9D,QAAM,WAAW,cAAc,WAAW,OAAO;AACjD,MAAI,aAAa,QAAW;AAC1B,UAAM,gBAAgB,MAAM,QAAQ,aAAa,SAAS;AAAA,EAC5D;AAEA,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,aAAa,QAAQ;AAAA,EACnC,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,MACA,0BAA0B,SAAS,iBAAiB,IAAI;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,IAAI,qBAAqB;AACzC,MAAI,OAAO,YAAY,YAAY;AACjC,UAAM,IAAI;AAAA,MACR;AAAA,MACA,KAAK,SAAS,wBAAwB,qBAAqB;AAAA,MAC3D,yCAAyC,qBAAqB;AAAA,IAChE;AAAA,EACF;AAEA,QAAM,WAAW,MAAO,QAAkC,OAAO;AACjE,0BAAwB,UAAU,SAAS;AAC3C,SAAO;AACT;AAcO,SAAS,0BAA0B,QAAoB,aAA2B;AACvF,aAAW,CAAC,aAAa,QAAQ,KAAK,OAAO,QAAQ,OAAO,SAAS,GAAG;AACtE,QAAI,qBAAqB,SAAS,IAAI,GAAG;AACvC;AAAA,IACF;AACA,UAAM,YAAY,gBAAgB,UAAU,SAAS,IAAI;AACzD,QAAI,cAAc,WAAW,WAAW,MAAM,QAAW;AACvD,YAAM,gBAAgB,SAAS,MAAM,aAAa,SAAS;AAAA,IAC7D;AAAA,EACF;AACF;AAGA,SAAS,gBAAgB,gBAA4C,MAAsB;AACzF,SAAO,gBAAgB,UAAU,oBAAoB,IAAI;AAC3D;AAGA,SAAS,eAAe,SAAkC;AAGxD,aAAO,0BAAQ,QAAQ,IAAI;AAC7B;AASA,SAAS,cAAc,WAAmB,SAAqC;AAC7E,MAAI;AACF,UAAMC,eAAU,sCAAc,0BAAQ,SAAS,SAAS,CAAC;AACzD,WAAOA,SAAQ,QAAQ,SAAS;AAAA,EAClC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,SAAS,aAAa,cAAwD;AAC5E,QAAMC,UAAS,kBAAkB,IAAI,YAAY;AACjD,MAAIA,YAAW,QAAW;AACxB,WAAOA;AAAA,EACT;AACA,QAAM,UAAU,WAAO,+BAAc,YAAY,EAAE;AACnD,oBAAkB,IAAI,cAAc,OAAO;AAC3C,SAAO;AACT;AAGA,SAAS,wBAAwB,UAAoB,WAAyB;AAC5E,aAAW,UAAU,kBAAkB;AACrC,QAAI,OAAQ,SAAgD,MAAM,MAAM,YAAY;AAClF,YAAM,IAAI;AAAA,QACR;AAAA,QACA,uBAAuB,SAAS,mBAAmB,MAAM;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAQA,SAAS,kBAAkB,gBAGzB;AACA,QAAM,OAAO,gBAAgB,QAAQ;AACrC,QAAM,QAAQ,KAAK,QAAQ,GAAG;AAC9B,MAAI,UAAU,GAAI,QAAO,EAAE,YAAY,KAAK;AAC5C,QAAM,YAAY,KAAK,MAAM,GAAG,KAAK;AACrC,QAAM,aAAa,KAAK,MAAM,QAAQ,CAAC,KAAK;AAC5C,SAAO,cAAc,KAAK,EAAE,WAAW,IAAI,EAAE,WAAW,WAAW;AACrE;AAEA,SAAS,gBAAgB,MAAc,aAAsB,WAA+B;AAC1F,QAAM,QAAQ,CAAC,GAAG,SAAS,KAAK,CAAC,EAAE,IAAI,CAAC,SAAS,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI;AACzE,QAAM,QAAQ,gBAAgB,SAAY,KAAK,oBAAoB,WAAW;AAC9E,QAAM,SACJ,cAAc,SACV,wBAAwB,KAAK,qEAAqE,IAAI,QACtG,oCAAoC,SAAS,oCAAoC,KAAK;AAC5F,SAAO,IAAI;AAAA,IACT;AAAA,IACA,uBAAuB,IAAI,KAAK,KAAK;AAAA,IACrC;AAAA,EACF;AACF;;;AD/OO,IAAM,WAAW;AAiBjB,SAAS,YAAY,KAAsB;AAChD,QAAM,EAAE,QAAQ,KAAK,QAAI,yBAAW,GAAG;AACvC,QAAM,WAAO,2BAAQ,IAAI;AACzB,QAAM,cAAU,2BAAQ,MAAM,QAAQ;AAItC,4BAA0B,QAAQ,IAAI;AACtC,SAAO;AAAA,IACL;AAAA,IACA,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA,UAAU,eAAe,iBAAiB,EAAE,MAAM,SAAS,OAAO,CAAC;AAAA,EACrE;AACF;AAcO,SAAS,UAAU,SAAsC;AAC9D,MAAI,EAAE,QAAQ,oBAAoB,iDAAqB;AACrD,UAAM,IAAI;AAAA,MACR;AAAA,MACA,sEAAsE,QAAQ,SAAS,IAAI;AAAA,MAC3F;AAAA,IACF;AAAA,EACF;AACA,SAAO,QAAQ;AACjB;AAaA,eAAsB,kBAAkB,SAAkB,aAAwC;AAChG,QAAM,iBAAiB,QAAQ,OAAO,UAAU,WAAW;AAC3D,MAAI,mBAAmB,QAAW;AAChC,WAAO,eAAe,iBAAiB,EAAE,MAAM,QAAQ,SAAS,QAAQ,QAAQ,OAAO,CAAC;AAAA,EAC1F;AAIA,SAAO,qBAAqB,eAAe,MAAM;AAAA,IAC/C,MAAM,QAAQ;AAAA,IACd,QAAQ,QAAQ;AAAA,IAChB;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAGO,SAAS,kBAAkB,SAAkB,UAA2B;AAC7E,aAAO,iCAAmB,QAAQ,QAAQ,QAAQ;AACpD;AAGA,IAAM,gBAAgB;AAOtB,IAAM,kBAA8B,EAAE,cAAc,CAAC,GAAG,WAAW,CAAC,EAAE;AAW/D,SAAS,WAAW,KAAa,QAAmC;AACzE,QAAM,WAAW,IAAI,MAAM,aAAa,EAAE,OAAO,CAAC,YAAY,QAAQ,SAAS,CAAC;AAChF,QAAM,OAAO,SAAS,SAAS,SAAS,CAAC;AACzC,MAAI,SAAS,QAAW;AACtB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,KAAK,GAAG;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,UAAI,8BAAgB,MAAM,UAAU,eAAe,GAAG;AACpD,UAAM,IAAI,gCAAmB,aAAa,MAAM,GAAG;AAAA,EACrD;AACA,SAAO,EAAE,WAAW,SAAS,MAAM,GAAG,EAAE,GAAG,KAAK;AAClD;AAgBO,SAAS,kBAAkB,KAAmB;AACnD,QAAM,WAAW,IAAI,MAAM,aAAa,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AACpE,MAAI,SAAS,WAAW,KAAK,SAAS,MAAM,CAAC,UAAM,iCAAmB,CAAC,CAAC,GAAG;AACzE;AAAA,EACF;AACA,QAAM,UAAM,gCAAkB,QAAQ;AACtC,MAAI,QAAQ,QAAW;AACrB,UAAM,aAAa,CAAC,GAAG,IAAI,WAAW,IAAI,IAAI,EAAE,KAAK,GAAG;AACxD,UAAM,IAAI;AAAA,MACR;AAAA,MACA,KAAK,GAAG;AAAA,MACR,iEAAiE,UAAU,yCAAyC,GAAG;AAAA,IACzH;AAAA,EACF;AACA,QAAM,IAAI;AAAA,IACR;AAAA,IACA,6CAA6C,GAAG;AAAA,IAChD;AAAA,EACF;AACF;AAUO,SAAS,aAAa,SAAkB,aAAgC;AAC7E,aAAO,+BAAiB,QAAQ,QAAQ,WAAW;AACrD;AA8BO,SAAS,YACd,UACA,KACA,aACA,MACA,cACgB;AAChB,aAAW,YAAQ,4BAAc,KAAK,aAAa,YAAY,GAAG;AAChE,UAAM,OAAO,SAAS,SAAS,IAAI;AACnC,QAAI,SAAS,QAAW;AACtB;AAAA,IACF;AAIA,UAAM,aAAS,wBAAU,MAAM,MAAM,IAAI;AACzC,WAAO;AAAA,MACL;AAAA,MACA,eAAW,0BAAY,GAAG;AAAA,MAC1B,OAAO,OAAO,SAAS,cAAc,OAAO,QAAQ;AAAA,MACpD,GAAI,OAAO,SAAS,WAAW,EAAE,eAAe,OAAO,QAAQ,IAAI,CAAC;AAAA,MACpE,QAAQ,EAAE,MAAM,cAAU,8BAAgB,IAAI,GAAG,SAAS,KAAK;AAAA,IACjE;AAAA,EACF;AACA,SAAO,EAAE,KAAK,eAAW,0BAAY,GAAG,GAAG,OAAO,QAAW,QAAQ,OAAU;AACjF;AAEO,SAAS,eACd,UACA,aACA,MACA,cACkB;AAClB,SAAO,SAAS,SAAS,SAAS,CAAC,EAAE;AAAA,IAAI,CAAC,QACxC,YAAY,UAAU,KAAK,aAAa,MAAM,YAAY;AAAA,EAC5D;AACF;AAMO,SAAS,SAAS,OAAgD;AACvE,QAAM,OAAO,oBAAI,IAA0B;AAC3C,aAAW,QAAQ,OAAO;AACxB,UAAM,MAAoB,EAAE,WAAW,KAAK,WAAW,MAAM,KAAK,KAAK;AACvE,UAAM,SAAK,0BAAY,GAAG;AAC1B,QAAI,CAAC,KAAK,IAAI,EAAE,GAAG;AACjB,WAAK,IAAI,IAAI,GAAG;AAAA,IAClB;AAAA,EACF;AAEA,SAAO,CAAC,GAAG,KAAK,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM;AACvC,UAAM,WAAO,0BAAY,CAAC;AAC1B,UAAM,YAAQ,0BAAY,CAAC;AAC3B,WAAO,OAAO,QAAQ,KAAK,OAAO,QAAQ,IAAI;AAAA,EAChD,CAAC;AACH;;;AEjRA,IAAAC,eAMO;AAGP,SAAS,MAAM,MAAoD;AACjE,MAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,WAAO;AAAA,EACT;AACA,QAAM,MAAO,KAA2B;AACxC,SAAO,OAAO,QAAQ,YAAY,QAAQ,OAAQ,MAAkC;AACtF;AAEO,SAAS,OAAO,MAAmC;AACxD,QAAM,OAAO,MAAM,IAAI,GAAG;AAC1B,SAAO,OAAO,SAAS,WAAW,OAAO;AAC3C;AAGO,SAAS,OAAO,MAAwB;AAC7C,MAAI,UAAU;AACd,WAAS,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG;AACzC,UAAM,QAAQ,MAAM,OAAO,GAAG;AAC9B,QAAI,UAAU,QAAW;AACvB,aAAO;AAAA,IACT;AACA,cAAU;AAAA,EACZ;AACA,SAAO;AACT;AAEO,SAAS,QAAQ,MAAoD;AAC1E,MAAI,OAAO,IAAI,MAAM,UAAU;AAC7B,WAAO;AAAA,EACT;AACA,QAAM,QAAS,KAA6B;AAC5C,SAAO,OAAO,UAAU,YAAY,UAAU,OACzC,QACD;AACN;AAQO,SAAS,OAAO,MAAiB,MAAiC;AACvE,MAAI,OAAgB,OAAO,IAAI;AAC/B,aAAW,OAAO,MAAM;AACtB,UAAM,QAAQ,QAAQ,IAAI;AAC1B,QAAI,UAAU,QAAW;AACvB,aAAO,EAAE,MAAM,UAAU;AAAA,IAC3B;AACA,QAAI,CAAC,OAAO,OAAO,OAAO,GAAG,GAAG;AAC9B,aAAO,EAAE,MAAM,SAAS;AAAA,IAC1B;AACA,WAAO,OAAO,MAAM,GAAG,CAAC;AAAA,EAC1B;AACA,SAAO,EAAE,MAAM,SAAS,KAAK;AAC/B;AAGO,SAAS,YAAY,MAAmC;AAC7D,MAAI,OAAO,IAAI,MAAM,UAAU;AAC7B,WAAO;AAAA,EACT;AACA,QAAM,MAAO,KAAiC;AAC9C,SAAO,OAAO,QAAQ,WAAW,MAAM;AACzC;AAMA,IAAM,oBAAoB,oBAAI,IAAI,CAAC,YAAY,WAAW,SAAS,UAAU,CAAC;AAQ9E,IAAM,kBAAkB,oBAAI,IAAI,CAAC,YAAY,eAAe,UAAU,CAAC;AAMvE,SAAS,eAAe,MAAoC;AAC1D,MAAI,UAAU;AACd,WAAS,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG;AACzC,UAAM,OAAO,OAAO,OAAO;AAC3B,QAAI,SAAS,UAAa,kBAAkB,IAAI,IAAI,GAAG;AACrD,aAAO;AAAA,IACT;AACA,UAAM,QAAQ,MAAM,OAAO,GAAG;AAC9B,QAAI,UAAU,QAAW;AAEvB,aAAO,SAAS,SAAY,SAAY;AAAA,IAC1C;AACA,QAAI,SAAS,UAAa,CAAC,gBAAgB,IAAI,IAAI,GAAG;AAGpD,aAAO;AAAA,IACT;AACA,cAAU;AAAA,EACZ;AACA,SAAO;AACT;AAmBA,SAAS,OACP,MACA,MACA,WACA,KACM;AAIN,QAAM,MAAM,eAAe,IAAI;AAC/B,QAAM,mBAAmB,cAAc,QAAQ,QAAQ,OAAO,OAAO,QAAQ,WAAW,GAAG;AAE3F,QAAM,QAAQ,QAAQ,OAAO,IAAI,CAAC;AAClC,MAAI,UAAU,QAAW;AACvB,QAAI,KAAK,SAAS,GAAG;AACnB,UAAI,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAAA,IACrC;AACA;AAAA,EACF;AACA,aAAW,OAAO,OAAO,KAAK,KAAK,GAAG;AACpC,WAAO,MAAM,GAAG,GAAG,CAAC,GAAG,MAAM,GAAG,GAAG,kBAAkB,GAAG;AAAA,EAC1D;AACF;AAGA,SAAS,QAAQ,MAA2B,OAAiD;AAC3F,SAAO,SAAS,UAAa,UAAU,SAAY,SAAY;AACjE;AAEO,SAAS,eAAe,QAA2B;AACxD,QAAM,MAAc,CAAC;AACrB,SAAO,QAAQ,CAAC,GAAG,OAAO,GAAG;AAC7B,SAAO;AACT;AA8BO,IAAM,cAA2B,EAAE,UAAU,CAAC,GAAG,YAAY,CAAC,EAAE;AAevE,SAAS,SAAS,YAAiC;AACjD,SAAO,WAAW,WAAW;AAC/B;AAEO,SAAS,aAAa,OAAgC;AAC3D,QAAM,EAAE,QAAQ,aAAa,QAAQ,YAAY,IAAI;AAErD,QAAM,SAAS,IAAI,IAAI,YAAY,OAAO,QAAQ,EAAE,IAAI,CAAC,eAAe,WAAW,SAAS,CAAC;AAE7F,QAAM,WAA4B,CAAC;AACnC,aAAW,QAAQ,eAAe,MAAM,GAAG;AACzC,QAAI,KAAK,qBAAqB,OAAO;AACnC;AAAA,IACF;AACA,UAAM,OAAO,KAAK,KAAK,KAAK,GAAG;AAC/B,UAAM,UAAM,gCAAkB,KAAK,IAAI;AAMvC,QAAI,QAAQ,cAAa,8BAAgB,IAAI,MAAM,MAAM,GAAG;AAC1D,eAAS,KAAK;AAAA,QACZ,SAAS;AAAA,QACT,QACE,gBAAgB,IAAI;AAAA,QAEtB,QAAQ;AAAA,MACV,CAAC;AACD;AAAA,IACF;AACA,QAAI,OAAO,QAAI,0BAAY,GAAG,CAAC,GAAG;AAChC;AAAA,IACF;AACA,aAAS,KAAK;AAAA,MACZ,aAAS,0BAAY,GAAG;AAAA,MACxB;AAAA,MACA,QAAQ,YAAY,CAAC,GAAG,IAAI,WAAW,IAAI,IAAI,EAAE,KAAK,GAAG,CAAC,UAAU,WAAW;AAAA,MAC/E,QAAQ,0CAA0C,WAAW;AAAA,IAC/D,CAAC;AAAA,EACH;AAEA,QAAM,aAAgC,CAAC;AACvC,aAAW,cAAc,aAAa;AACpC,QAAI,OAAO,YAAQ,yBAAW,WAAW,GAAG,CAAC,EAAE,SAAS,UAAU;AAChE;AAAA,IACF;AACA,eAAW,KAAK;AAAA,MACd,KAAK,WAAW;AAAA,MAChB,cAAU,2BAAa,WAAW,KAAK,MAAM;AAAA,IAC/C,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,UAAU,WAAW;AAChC;;;ACnRA,IAAAC,eAA0B;AAEnB,IAAM,QAAQ;AACd,IAAM,OAAO;AAEb,IAAM,UAAU;AAkBvB,IAAM,cAAc;AAEpB,SAAS,OAAO,QAAmC;AACjD,SAAO,OAAO,OAAO,CAAC,KAAK,UAAU,KAAK,IAAI,KAAK,MAAM,MAAM,GAAG,CAAC;AACrE;AAEO,SAAS,WAAW,MAAgC;AACzD,QAAM,aAAa,OAAO,KAAK,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI;AAG1D,QAAM,WAAW,KAAK,OAAO,CAAC,QAAQ,IAAI,WAAW,MAAS;AAC9D,QAAM,eAAe,OAAO,SAAS,IAAI,CAAC,QAAQ,IAAI,WAAW,EAAE,CAAC,IAAI;AAExE,SAAO,KAAK,IAAI,CAAC,QAAQ;AACvB,UAAM,OAAO,GAAG,IAAI,KAAK,IAAI,IAAI,MAAM,OAAO,UAAU,CAAC;AACzD,QAAI,IAAI,WAAW,QAAW;AAC5B,aAAO,GAAG,IAAI,GAAG,IAAI,WAAW,EAAE,GAAG,QAAQ;AAAA,IAC/C;AACA,WAAO,GAAG,IAAI,IAAI,IAAI,WAAW,IAAI,OAAO,YAAY,CAAC,GAAG,IAAI,MAAM,GAAG,QAAQ;AAAA,EACnF,CAAC;AACH;AAMO,SAAS,QAAQ,MAAsC,MAAM,GAAa;AAC/E,QAAM,QAAQ,KAAK,OAAO,CAAC,KAAK,QAAQ,KAAK,IAAI,KAAK,IAAI,MAAM,GAAG,CAAC;AACpE,QAAM,SAAmB,CAAC;AAC1B,WAAS,SAAS,GAAG,SAAS,OAAO,UAAU,GAAG;AAChD,WAAO,KAAK,OAAO,KAAK,IAAI,CAAC,QAAQ,IAAI,MAAM,KAAK,EAAE,CAAC,IAAI,GAAG;AAAA,EAChE;AACA,SAAO,KAAK;AAAA,IAAI,CAAC,QACf,IACG,IAAI,CAAC,MAAM,UAAW,UAAU,IAAI,SAAS,IAAI,OAAO,KAAK,OAAO,OAAO,KAAK,KAAK,CAAC,CAAE,EACxF,KAAK,EAAE,EACP,QAAQ;AAAA,EACb;AACF;AAEO,SAAS,YAAY,OAAkC;AAC5D,SAAO,MAAM,IAAI,CAAC,SAAS;AACzB,QAAI,KAAK,SAAS,QAAW;AAC3B,aAAO,GAAG,KAAK,KAAK,IAAI,KAAK,IAAI;AAAA,IACnC;AAKA,UAAM,OAAO,KAAK,KAAK,UAAU,cAAc,GAAG,KAAK,IAAI,MAAM,KAAK,KAAK,OAAO,WAAW;AAC7F,WAAO,GAAG,KAAK,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI;AAAA,EAC1C,CAAC;AACH;AAEO,SAAS,MAAM,OAAgC;AACpD,aAAW,QAAQ,OAAO;AACxB,YAAQ,OAAO,MAAM,GAAG,IAAI;AAAA,CAAI;AAAA,EAClC;AACF;AAMO,SAAS,YAAY,OAAsB;AAChD,MAAI,iBAAiB,wBAAW;AAC9B,YAAQ,OAAO,MAAM,GAAG,MAAM,OAAO;AAAA,CAAI;AAAA,EAC3C,WAAW,iBAAiB,OAAO;AACjC,YAAQ,OAAO,MAAM,GAAG,MAAM,SAAS,MAAM,OAAO;AAAA,CAAI;AAAA,EAC1D,OAAO;AACL,YAAQ,OAAO,MAAM,GAAG,OAAO,KAAK,CAAC;AAAA,CAAI;AAAA,EAC3C;AACA,UAAQ,WAAW;AACrB;AAGA,eAAsB,MAAM,KAAyC;AACnE,MAAI;AACF,UAAM,IAAI;AAAA,EACZ,SAAS,OAAO;AACd,gBAAY,KAAK;AAAA,EACnB;AACF;;;AChGA,IAAAC,eAA2E;AAE3E,yBAAmD;AACnD,mBAA8B;AAcvB,IAAM,kBAAkB;AAkC/B,SAAS,QACP,SACA,aACA,UAC0C;AAC1C,QAAM,WAAW,QAAQ,OAAO,QAAQ,WAAW;AACnD,MAAI,aAAa,QAAW;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,MACA,eAAe,WAAW;AAAA,MAC1B,0CAA0C,WAAW,wDAAwD,WAAW;AAAA,IAC1H;AAAA,EACF;AACA,QAAM,OAAO,SAAS;AACtB,MAAI,aAAa,QAAW;AAC1B,WAAO,EAAE,MAAM,UAAU,KAAK;AAAA,EAChC;AACA,MAAI,SAAS,SAAS,UAAU;AAC9B,WAAO,EAAE,UAAM,qCAAiB,SAAS,SAAY,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,KAAK;AAAA,EAC5E;AACA,QAAM,IAAI;AAAA,IACR;AAAA,IACA,eAAe,WAAW,yBAAyB,SAAS,IAAI;AAAA,IAChE;AAAA,EACF;AACF;AAQA,SAAS,KACP,aACA,QACA,aACA,cACY;AACZ,QAAM,WAAuB,CAAC;AAC9B,aAAW,cAAc,aAAa;AACpC,UAAM,SAAS,WAAW;AAC1B,QAAI,WAAW,QAAW;AACxB;AAAA,IACF;AACA,QAAI,YAAY;AAChB,QAAI,OAAO,KAAK,WAAW;AACzB,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI;AAAA,UACR;AAAA,UACA,aAAa,WAAW,SAAS,oBAAoB,WAAW,yCAAyC,QAAQ,IAAI,OAAO,QAAQ;AAAA,UACpI;AAAA,QAGF;AAAA,MACF;AAGA,qCAAa,YAAY,WAAW;AACpC,kBAAY;AAAA,IACd;AACA,QAAI,WAAW,UAAU,QAAW;AAClC;AAAA,IACF;AACA,UAAM,QACJ,OAAO,KAAK,MAAM,SAAS,aACvB,EAAE,MAAM,aAAa,IACrB,EAAE,MAAM,eAAe,YAAY;AACzC,aAAS,KAAK;AAAA,MACZ,KAAK,WAAW;AAAA,MAChB,cAAU,2BAAa,WAAW,KAAK,MAAM;AAAA,MAC7C,OAAO,WAAW;AAAA,MAClB;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAGA,SAAS,eAAe,MAAwB,aAAqB,KAAmB;AACtF,QAAM,OAAa,QAAQ,CAAC;AAC5B,QAAM,eAA0C,EAAE,GAAI,KAAK,gBAAgB,CAAC,EAAG;AAC/E,eAAa,WAAW,IAAI,EAAE,GAAI,aAAa,WAAW,KAAK,CAAC,GAAI,CAAC,eAAe,GAAG,IAAI;AAC3F,SAAO,EAAE,GAAG,MAAM,aAAa;AACjC;AAEA,SAAS,WACP,MACA,KACA,aACA,KACM;AACN,QAAM,OAAO,eAAe,KAAK,aAAa,GAAG,GAAG,aAAa,GAAG;AACpE,OAAK,cAAc,KAAK,IAAI;AAC9B;AAEA,eAAsB,QAAQ,SAA2C;AACvE,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,cAAc,kBAAkB,SAAS,QAAQ,WAAW;AAClE,QAAM,EAAE,MAAM,KAAK,IAAI,QAAQ,SAAS,aAAa,QAAQ,IAAI;AAEjE,QAAM,OAAO,UAAU,OAAO;AAC9B,QAAM,OAAO,aAAa,SAAS,WAAW;AAE9C,QAAM,cAAc,eAAe,MAAM,aAAa,MAAM,IAAI;AAChE,QAAM,OAAO,SAAS,YAAY,IAAI,CAAC,eAAe,WAAW,GAAG,CAAC;AAKrE,QAAM,gBAAY,kCAAoB,MAAM,QAAQ,MAAM,EAAE,CAAC;AAC7D,MAAI,cAAc,QAAW;AAC3B,UAAM;AAAA,EACR;AACA,QAAM,gBAAY,qCAAiB,MAAM,QAAQ,MAAM,EAAE,CAAC;AAC1D,MAAI,cAAc,QAAW;AAC3B,UAAM;AAAA,EACR;AAEA,QAAM,WAAW,KAAK,aAAa,QAAQ,QAAQ,aAAa,QAAQ,iBAAiB,IAAI;AAG7F,QAAM,KAAK,OAAO;AAElB,MAAI,oBAAoB;AACxB,MAAI,qBAAqB;AACzB,aAAW,QAAQ,UAAU;AAC3B,UAAM,KAAK,KAAK,KAAK,UAAU,KAAK,OAAO,KAAK,KAAK;AACrD,QAAI,KAAK,MAAM,SAAS,cAAc;AACpC,2BAAqB;AAAA,IACvB,OAAO;AACL,4BAAsB;AAAA,IACxB;AAMA,eAAW,MAAM,KAAK,KAAK,aAAa,QAAQ,QAAO,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA,EACjF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,QAAQ,SAAS;AAAA,IACjB;AAAA,IACA;AAAA,IACA,WAAW,SAAS,OAAO,CAAC,SAAS,KAAK,SAAS,EAAE;AAAA,EACvD;AACF;AAEO,SAAS,WAAWC,SAA8B;AACvD,MAAIA,QAAO,WAAW,GAAG;AACvB,WAAO,WAAW;AAAA,MAChB;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAAS,qCAAqCA,QAAO,WAAW;AAAA,MAClE;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,SAAS,kCAAkCA,QAAO,WAAW,GACjEA,QAAO,SAAS,SAAY,KAAK,KAAKA,QAAO,IAAI,GACnD;AACA,QAAM,OAAO;AAAA,IACX;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS,GAAGA,QAAO,MAAM,IAAIA,QAAO,WAAW,IAAI,WAAW,SAAS;AAAA,MACvE,QAAQ,MAAM,MAAM;AAAA,IACtB;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS,GAAGA,QAAO,kBAAkB,iBAAiBA,QAAO,iBAAiB;AAAA,MAC9E,QACE;AAAA,IACJ;AAAA,EACF;AACA,MAAIA,QAAO,YAAY,GAAG;AACxB,SAAK,KAAK;AAAA,MACR,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS,GAAGA,QAAO,SAAS,IAAIA,QAAO,cAAc,IAAI,WAAW,SAAS;AAAA,MAC7E,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AACA,SAAO,WAAW,IAAI;AACxB;AAEO,IAAM,kBAAc,4BAAc;AAAA,EACvC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,UAAU,aAAa,0BAA0B;AAAA,IAC9D,iBAAiB;AAAA,MACf,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAMA,UAAS,MAAM,QAAQ;AAAA,QAC3B,KAAK,QAAQ,IAAI;AAAA,QACjB,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,QAC1D,GAAI,KAAK,eAAe,MAAM,SAAY,CAAC,IAAI,EAAE,cAAc,KAAK,eAAe,EAAE;AAAA,MACvF,CAAC;AACD,YAAM,WAAWA,OAAM,CAAC;AAAA,IAC1B,CAAC;AAAA,EACH;AACF,CAAC;;;AC/QD,IAAAC,oBAAuC;AACvC,IAAAC,mBAA8B;AAE9B,IAAAC,eAUO;AACP,IAAAC,gBAA8B;AAsC9B,IAAM,gBAAgB;AAEtB,IAAM,SAAsD;AAAA,EAC1D,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,eAAe;AACjB;AAEA,SAAS,UAAU,MAAsB;AACvC,SAAO,KAAK,MAAM,IAAI,EAAE,CAAC,KAAK;AAChC;AAEA,SAAS,UAAU,OAAkB,iBAAwC;AAC3E,QAAM,OAAO;AAAA,IACX,SAAS,UAAU,MAAM,OAAO;AAAA,IAChC,GAAI,MAAM,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,MAAM,OAAO;AAAA,EAC/D;AACA,MAAI,iBAAiB,iCAAoB;AACvC,WAAO,EAAE,MAAM,YAAY,SAAS,MAAM,OAAO,GAAG,KAAK;AAAA,EAC3D;AACA,MAAI,iBAAiB,iCAAoB;AACvC,WAAO,EAAE,MAAM,aAAa,SAAS,MAAM,UAAU,GAAG,KAAK;AAAA,EAC/D;AACA,SAAO,EAAE,MAAM,UAAU,SAAS,iBAAiB,GAAG,KAAK;AAC7D;AAOA,SAAS,MAAM,MAA+B,MAAyB,OAAqB;AAC1F,QAAM,OAAO,KAAK,KAAK,SAAS,CAAC;AACjC,MAAI,SAAS,QAAW;AACtB;AAAA,EACF;AACA,MAAI,OAAO;AACX,aAAW,OAAO,KAAK,MAAM,GAAG,EAAE,GAAG;AACnC,UAAM,WAAW,KAAK,GAAG;AACzB,QAAI,OAAO,aAAa,YAAY,aAAa,MAAM;AACrD,aAAO;AACP;AAAA,IACF;AACA,UAAM,QAAiC,CAAC;AACxC,SAAK,GAAG,IAAI;AACZ,WAAO;AAAA,EACT;AACA,OAAK,IAAI,IAAI;AACf;AAEA,SAAS,UAAU,OAAoC;AACrD,SACE,OAAO,UAAU,YACjB,UAAU,QACV,eAAe,SACf,OAAQ,MAAiC,cAAc;AAE3D;AAgBA,SAAS,mBACP,OACA,YACsC;AACtC,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,WAAO;AAAA,EACT;AACA,QAAM,QAAQ;AACd,MAAI,MAAM,SAAS,uBAAuB,CAAC,MAAM,QAAQ,MAAM,MAAM,GAAG;AACtE,WAAO;AAAA,EACT;AACA,SAAO,MAAM,OAAO,IAAI,CAAC,UAAmB;AAC1C,UAAM,EAAE,WAAW,QAAQ,IAAI;AAC/B,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS,OAAO,cAAc,YAAY,cAAc,KAAK,YAAY;AAAA,MACzE,SAAS,OAAO,YAAY,WAAW,UAAU,OAAO,KAAK;AAAA,MAC7D,QAAQ,0CAA0C,UAAU;AAAA,IAC9D;AAAA,EACF,CAAC;AACH;AAiBA,IAAI,cAAgC,QAAQ,QAAQ;AAEpD,SAAS,YAAe,MAAoC;AAC1D,QAAMC,UAAS,YAAY,KAAK,MAAM,IAAI;AAE1C,gBAAcA,QAAO;AAAA,IACnB,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACA,SAAOA;AACT;AAsBO,SAAS,WAAW,SAAkB,aAA0C;AAGrF,QAAM,iBAAa,2BAAa,QAAQ,MAAM;AAC9C,QAAM,WAAO,oCAAc,kBAAAC,SAAY,QAAQ,MAAM,UAAU,CAAC,EAAE;AAClE,SAAO,YAAY,MAAM,sBAAsB,MAAM,YAAY,WAAW,CAAC;AAC/E;AAGA,eAAe,sBACb,MACA,YACA,aACqB;AAKrB,QAAM,WAAO,sBAAQ,IAAI;AAEzB,QAAM,WAAW,QAAQ,IAAI;AAC7B,UAAQ,IAAI,WAAW;AACvB,MAAI;AACJ,MAAI;AACF,aAAS,MAAM,KAAK,OAAO,IAAI;AAAA,EACjC,SAAS,OAAO;AACd,UAAM,SAAS,mBAAmB,OAAO,UAAU;AACnD,QAAI,WAAW,QAAW;AACxB,aAAO,EAAE,OAAO;AAAA,IAClB;AACA,UAAM,SAAS,iBAAiB,QAAQ,UAAU,MAAM,OAAO,IAAI,OAAO,KAAK;AAC/E,WAAO;AAAA,MACL,QAAQ;AAAA,QACN;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS,GAAG,UAAU,yBAAyB,MAAM;AAAA,UACrD,QAAQ,yCAAyC,aAAa,gBAAgB,UAAU;AAAA,QAC1F;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAE;AACA,QAAI,aAAa,QAAW;AAC1B,aAAO,QAAQ,IAAI;AAAA,IACrB,OAAO;AACL,cAAQ,IAAI,WAAW;AAAA,IACzB;AAAA,EACF;AAEA,QAAM,WACJ,OAAO,WAAW,YAAY,WAAW,OACpC,OAAmC,aAAa,IACjD;AAEN,MAAI,CAAC,UAAU,QAAQ,GAAG;AACxB,WAAO;AAAA,MACL,QAAQ;AAAA,QACN;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS,GAAG,UAAU,iBAAiB,aAAa;AAAA,UACpD,QAAQ,sCAAsC,aAAa;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,QAAQ,UAAU,QAAQ,CAAC,EAAE;AACxC;AAEA,eAAsB,YAAY,SAAmD;AACnF,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,cAAc,kBAAkB,SAAS,QAAQ,WAAW;AAClE,QAAM,iBAAa,2BAAa,QAAQ,MAAM;AAC9C,QAAM,SAA0B,CAAC;AAIjC,MAAI;AACJ,MAAI;AACF,YAAQ,MAAM,QAAQ,SAAS,KAAK;AAAA,EACtC,SAAS,OAAO;AACd,QAAI,EAAE,iBAAiB,yBAAY;AACjC,YAAM;AAAA,IACR;AACA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ;AAAA,MACA,YAAY;AAAA,MACZ,QAAQ,CAAC,UAAU,OAAO,UAAU,CAAC;AAAA,MACrC,OAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,OAAuB,SAAS,KAAK;AAQ3C,aAAW,aAAS,6BAAe,QAAQ,MAAM,GAAG;AAClD,WAAO,KAAK,UAAU,OAAO,gBAAgB,CAAC;AAAA,EAChD;AAIA,aAAW,iBAAa,kCAAoB,MAAM,QAAQ,MAAM,GAAG;AACjE,WAAO,KAAK,UAAU,WAAW,UAAU,QAAQ,CAAC;AAAA,EACtD;AAEA,QAAM,EAAE,QAAQ,QAAQ,aAAa,IAAI,MAAM,WAAW,SAAS,WAAW;AAC9E,SAAO,KAAK,GAAG,YAAY;AAE3B,MAAI,QAAqB;AAEzB,MAAI,WAAW,QAAW;AACxB,UAAM,cAAc,UAAM;AAAA,MACxB;AAAA,MACA,QAAQ;AAAA,MACR,aAAa,SAAS,WAAW;AAAA,IACnC;AACA,UAAM,SAAkC,CAAC;AAGzC,UAAM,gBAAgB,oBAAI,IAAY;AACtC,eAAW,cAAc,aAAa;AACpC,UAAI,WAAW,kBAAkB,QAAW;AAC1C,sBAAc,QAAI,yBAAW,WAAW,GAAG,EAAE,KAAK,GAAG,CAAC;AACtD,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,SAAS,WAAW;AAAA,UACpB,SAAS,GAAG,WAAW,QAAQ,YAAY,wBAAwB,4BAA4B,WAAW,cAAc,MAAM;AAAA,UAC9H,QACE;AAAA,QAEJ,CAAC;AACD;AAAA,MACF;AACA,UAAI,WAAW,UAAU,QAAW;AAClC,cAAM,YAAQ,yBAAW,WAAW,GAAG,GAAG,WAAW,KAAK;AAAA,MAC5D;AAAA,IACF;AAGA,YAAQ,aAAa,EAAE,QAAQ,aAAa,QAAQ,QAAQ,QAAQ,YAAY,CAAC;AAEjF,UAAMD,UAAS,OAAO,UAAU,MAAM;AACtC,QAAI,CAACA,QAAO,SAAS;AACnB,iBAAW,WAAWA,QAAO,MAAM,QAAQ;AACzC,cAAM,OAAO,QAAQ,KAAK,KAAK,GAAG;AAMlC,YAAI,cAAc,IAAI,IAAI,GAAG;AAC3B;AAAA,QACF;AACA,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,SAAS,QAAQ;AAAA,UACjB,SAAS,QAAQ;AAAA,UACjB,QAAQ,0CAA0C,UAAU;AAAA,QAC9D,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,IAAI,OAAO,WAAW,GAAG,aAAa,YAAY,KAAK,QAAQ,QAAQ,MAAM;AACxF;AAEO,SAAS,eAAeA,SAAkC;AAC/D,MAAIA,QAAO,IAAI;AACb,WAAO,WAAW;AAAA,MAChB;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAAS,GAAGA,QAAO,UAAU,+BAA+BA,QAAO,WAAW;AAAA,MAChF;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,OAAcA,QAAO,OAAO,IAAI,CAAC,WAAW;AAAA,IAChD,OAAO;AAAA,IACP,OAAO,OAAO,MAAM,IAAI;AAAA,IACxB,SAAS,MAAM;AAAA,IACf,QAAQ,MAAM;AAAA,EAChB,EAAE;AAEF,QAAM,QAAQ,WAAW,IAAI;AAC7B,QAAM,WAAW,CAAC,GAAG,IAAI,IAAIA,QAAO,OAAO,IAAI,CAAC,UAAU,MAAM,MAAM,CAAC,CAAC;AACxE,aAAW,UAAU,UAAU;AAC7B,QAAI,WAAW,QAAW;AACxB,YAAM,KAAK,KAAK,MAAM,EAAE;AAAA,IAC1B;AAAA,EACF;AACA,SAAO;AACT;AAEO,IAAM,sBAAkB,6BAAc;AAAA,EAC3C,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,UAAU,aAAa,8BAA8B;AAAA,EACpE;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAMA,UAAS,MAAM,YAAY;AAAA,QAC/B,KAAK,QAAQ,IAAI;AAAA,QACjB,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,MAC5D,CAAC;AACD,YAAM,eAAeA,OAAM,CAAC;AAC5B,UAAI,CAACA,QAAO,IAAI;AACd,gBAAQ,WAAW;AAAA,MACrB;AAAA,IACF,CAAC;AAAA,EACH;AACF,CAAC;;;AN3RD,IAAM,qBAAqB;AAY3B,SAAS,QAAQ,OAAoB,OAA8B;AACjE,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA,SAAS;AAAA,IACT,QAAQ;AAAA,EACV;AACF;AAEA,eAAsB,UAAU,SAA+C;AAC7E,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,cAAc,kBAAkB,SAAS,QAAQ,WAAW;AAClE,QAAM,WAA4B,CAAC;AAInC,QAAM,MAAM,IAAI,KAAK,QAAQ,QAAO,oBAAI,KAAK,GAAE,YAAY,CAAC;AAC5D,QAAM,mBAAmB,QAAQ,oBAAoB;AAErD,QAAM,EAAE,QAAQ,OAAO,IAAI,MAAM,WAAW,SAAS,WAAW;AAChE,MAAI,WAAW,QAAW;AACxB,aAAS,KAAK,EAAE,OAAO,UAAU,UAAU,QAAQ,OAAO,eAAe,CAAC;AAAA,EAC5E,OAAO;AACL,eAAW,SAAS,QAAQ;AAC1B,eAAS,KAAK;AAAA,QACZ,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS,MAAM;AAAA,QACf,QAAQ,MAAM;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,cAAc,UAAM;AAAA,IACxB;AAAA,IACA,QAAQ;AAAA,IACR,aAAa,SAAS,WAAW;AAAA,EACnC;AACA,QAAM,WAAsB,MAAM,QAAQ;AAAA,IACxC,YAAY,IAAI,OAAO,gBAAgB;AAAA,MACrC;AAAA,MACA,MAAM,MAAM,QAAQ,SAAS,SAAS,WAAW,GAAG;AAAA,IACtD,EAAE;AAAA,EACJ;AAEA,QAAM,UAAU,gBAAgB,UAAU,WAAW;AACrD,WAAS,KAAK,GAAG,OAAO;AAGxB,MAAI,WAAW,QAAW;AACxB,aAAS;AAAA,MACP,QAAQ,YAAY,iBAAiB;AAAA,MACrC,QAAQ,QAAQ,iBAAiB;AAAA,MACjC,QAAQ,UAAU,gBAAgB;AAAA,IACpC;AAAA,EACF,OAAO;AACL,UAAM,QAAQ,aAAa;AAAA,MACzB;AAAA,MACA,aAAa,SAAS,IAAI,CAAC,EAAE,WAAW,MAAM,UAAU;AAAA,MACxD,QAAQ,QAAQ;AAAA,MAChB;AAAA,IACF,CAAC;AACD,aAAS,KAAK,GAAG,iBAAiB,OAAO,SAAS,WAAW,CAAC;AAC9D,aAAS,KAAK,GAAG,aAAa,UAAU,MAAM,CAAC;AAC/C,aAAS,KAAK,GAAG,eAAe,KAAK,CAAC;AAAA,EACxC;AACA,WAAS,KAAK,GAAG,iBAAiB,UAAU,WAAW,CAAC;AACxD,WAAS,KAAK,GAAG,wBAAwB,UAAU,WAAW,CAAC;AAC/D,WAAS,KAAK,GAAG,qBAAqB,UAAU,aAAa,QAAQ,MAAM,CAAC;AAC5E,WAAS,KAAK,GAAG,mBAAmB,UAAU,WAAW,CAAC;AAO1D,QAAM,WAAW,MAAM,iBAAiB,SAAS,aAAa,UAAU,QAAQ,MAAM;AACtF,MAAI,SAAS,SAAS,eAAe;AACnC,aAAS,KAAK,SAAS,OAAO;AAAA,EAChC,OAAO;AACL,aAAS,KAAK,GAAG,gBAAgB,SAAS,UAAU,aAAa,GAAG,CAAC;AACrE,aAAS,KAAK,GAAG,cAAc,SAAS,UAAU,aAAa,KAAK,gBAAgB,CAAC;AAAA,EACvF;AACA,WAAS,KAAK,GAAI,MAAM,sBAAsB,SAAS,aAAa,QAAQ,MAAM,CAAE;AACpF,WAAS,KAAK,GAAI,MAAM,aAAa,SAAS,aAAa,QAAQ,IAAI,CAAE;AAEzE,WAAS,KAAK;AAAA,IACZ,OAAO;AAAA,IACP,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS,QAAQ,OAAO,UAAU,WAAW,GAAG,QAAQ,QAAQ,SAAS;AAAA,EAC3E,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,IAAI,CAAC,SAAS,KAAK,CAAC,YAAY,QAAQ,aAAa,SAAS;AAAA,EAChE;AACF;AAEA,SAAS,gBAAgB,UAA8B,aAAsC;AAC3F,QAAM,WAAW,SAAS,OAAO,CAAC,EAAE,KAAK,UAAM,yBAAW,MAAM,WAAW,CAAC;AAC5E,QAAM,WAA4B,SAC/B,OAAO,CAAC,EAAE,WAAW,MAAM,WAAW,WAAW,MAAS,EAC1D,IAAI,CAAC,EAAE,WAAW,OAAO;AAAA,IACxB,OAAO;AAAA,IACP,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS,WAAW;AAAA,IACpB,QAAQ,gBAAgB,WAAW;AAAA,IACnC,QAAQ,YAAY,CAAC,GAAG,WAAW,IAAI,WAAW,WAAW,IAAI,IAAI,EAAE,KAAK,GAAG,CAAC,UAAU,WAAW;AAAA,EACvG,EAAE;AAEJ,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SACE,SAAS,WAAW,IAChB,qBAAqB,WAAW,KAChC,GAAG,SAAS,MAAM,iBAAiB,WAAW;AAAA,IACtD;AAAA,EACF;AACF;AAaA,SAAS,iBACP,OACA,SACA,aACiB;AACjB,QAAM,WAAW,IAAI,IAAI,QAAQ,OAAO,CAAC,MAAM,EAAE,aAAa,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AAE3F,QAAM,WAA4B,MAAM,SACrC,OAAO,CAAC,SAAS,CAAC,SAAS,IAAI,KAAK,OAAO,CAAC,EAC5C,IAAI,CAAC,UAAU;AAAA,IACd,OAAO;AAAA,IACP,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS,KAAK;AAAA,IACd,QAAQ,KAAK;AAAA,IACb,QAAQ,KAAK;AAAA,EACf,EAAE;AAEJ,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS,yDAAyD,WAAW;AAAA,IAC/E;AAAA,EACF;AACF;AAEA,SAAS,aAAa,UAA8B,QAAoC;AACtF,QAAM,WAA4B,CAAC;AACnC,MAAI,UAAU;AAEd,aAAW,EAAE,WAAW,KAAK,UAAU;AACrC,UAAM,QAAQ,WAAW;AAOzB,QAAI,UAAU,QAAW;AACvB;AAAA,IACF;AACA,UAAM,QAAQ,OAAO,YAAQ,yBAAW,WAAW,GAAG,CAAC;AACvD,QAAI,MAAM,SAAS,SAAS;AAC1B;AAAA,IACF;AACA,UAAM,UAAU,YAAY,MAAM,IAAI;AACtC,QAAI,YAAY,QAAW;AACzB;AAAA,IACF;AACA,eAAW;AACX,QAAI,MAAM,UAAU,SAAS;AAC3B;AAAA,IACF;AACA,aAAS,KAAK;AAAA,MACZ,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS,WAAW;AAAA,MACpB,QAAQ,GAAG,MAAM,MAAM,iCAA4B,OAAO;AAAA,IAC5D,CAAC;AAAA,EACH;AAEA,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SACE,YAAY,IACR,8CACA,YAAY,IACV,qCACA,GAAG,OAAO;AAAA,IACpB;AAAA,EACF;AACF;AAGA,SAAS,eAAe,OAAqC;AAC3D,QAAM,WAA4B,MAAM,WAAW,IAAI,CAAC,UAAU;AAAA,IAChE,OAAO;AAAA,IACP,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS,KAAK;AAAA,IACd,QAAQ;AAAA,EACV,EAAE;AAEF,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAEA,SAAS,iBAAiB,UAA8B,aAAsC;AAC5F,QAAM,WAA4B,SAC/B,OAAO,CAAC,EAAE,WAAW,MAAM,WAAW,mBAAmB,EACzD,IAAI,CAAC,EAAE,WAAW,OAAO;AAAA,IACxB,OAAO;AAAA,IACP,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS,WAAW;AAAA,IACpB,QAAQ,GAAG,WAAW;AAAA,EACxB,EAAE;AAEJ,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS,uDAAuD,WAAW;AAAA,IAC7E;AAAA,EACF;AACF;AAEA,SAAS,wBACP,UACA,aACiB;AACjB,QAAM,UAAU,SAAS,OAAO,CAAC,EAAE,KAAK,UAAM,uBAAS,MAAM,WAAW,CAAC;AACzE,QAAM,WAA4B,CAAC;AAEnC,aAAW,EAAE,WAAW,KAAK,SAAS;AACpC,UAAM,SAAS,WAAW;AAE1B,QAAI,WAAW,UAAa,OAAO,KAAK,WAAW;AACjD;AAAA,IACF;AACA,aAAS,KAAK;AAAA,MACZ,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS,OAAO;AAAA,MAChB,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAEA,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SACE,QAAQ,WAAW,IACf,uCAAuC,WAAW,KAClD,8BAA8B,WAAW;AAAA,IACjD;AAAA,EACF;AACF;AAoBA,SAAS,qBACP,UACA,aACA,QACiB;AACjB,QAAM,WAAW,OAAO,kBAAkB,CAAC;AAK3C,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO;AAAA,MACL;AAAA,QACE,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,SAAS,OAAO,CAAC,EAAE,KAAK,UAAM,uBAAS,MAAM,WAAW,CAAC;AACzE,QAAM,WAA4B,CAAC;AAEnC,aAAW,EAAE,WAAW,KAAK,SAAS;AACpC,UAAM,eAAW,2BAAa,WAAW,KAAK,MAAM;AACpD,QAAI,KAAC,+BAAiB,UAAU,MAAM,GAAG;AACvC;AAAA,IACF;AAGA,UAAM,SAAS,SAAS,KAAK,CAAC,cAAc,SAAS,WAAW,SAAS,CAAC;AAC1E,aAAS,KAAK;AAAA,MACZ,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS;AAAA,MACT,QACE,WAAW,SACP,uEACA,0CAA0C,MAAM;AAAA,MACtD,QACE;AAAA,IACJ,CAAC;AAAA,EACH;AAEA,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS,2CAA2C,WAAW;AAAA,IACjE;AAAA,EACF;AACF;AAWA,SAAS,mBAAmB,UAA8B,aAAsC;AAC9F,QAAM,SAAS,SAAS,OAAO,CAAC,EAAE,WAAW,MAAM,WAAW,QAAQ,KAAK,cAAc,IAAI;AAC7F,QAAM,WAA4B,CAAC;AAEnC,aAAW,EAAE,WAAW,KAAK,QAAQ;AACnC,UAAM,UAAU,WAAW;AAC3B,QAAI,YAAY,QAAW;AACzB;AAAA,IACF;AACA,aAAS,KAAK;AAAA,MACZ,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS,WAAW,QAAQ,YAAY,WAAW;AAAA,MACnD,QAAQ,QAAQ;AAAA,IAClB,CAAC;AAAA,EACH;AAEA,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO;AAAA,EACT;AAIA,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SACE,OAAO,WAAW,IACd,mCAAmC,WAAW,KAC9C,uCAAuC,WAAW;AAAA,IAC1D;AAAA,EACF;AACF;AAmBA,IAAM,eAAe;AAErB,SAAS,UAAU,UAAsB,UAA8C;AACrF,MAAI,aAAa,QAAW;AAC1B,WAAO;AAAA,EACT;AACA,MAAI,SAAS,SAAS,UAAU;AAC9B,eAAO,sCAAiB,SAAS,SAAS,SAAY,CAAC,IAAI,EAAE,MAAM,SAAS,KAAK,CAAC;AAAA,EACpF;AACA,SAAO;AACT;AAEA,SAAS,YAAY,OAAwB;AAC3C,MAAI,iBAAiB,OAAO;AAC1B,WAAO,MAAM,QAAQ,MAAM,IAAI,EAAE,CAAC,KAAK,MAAM;AAAA,EAC/C;AACA,SAAO,OAAO,KAAK;AACrB;AAEA,SAAS,WAAW,OAA4B;AAC9C,SAAO,MAAM,SAAS,eAClB,uBACA,2BAA2B,MAAM,WAAW;AAClD;AAQA,eAAe,aACb,SACA,aACA,UAC0B;AAC1B,QAAM,WAAW,QAAQ,OAAO,QAAQ,WAAW;AACnD,MAAI,aAAa,QAAW;AAC1B,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,OAAO,UAAU,UAAU,QAAQ;AACzC,MAAI,SAAS,QAAW;AACtB,WAAO;AAAA,MACL;AAAA,QACE,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS,eAAe,SAAS,IAAI;AAAA,QACrC,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AACF,UAAM,KAAK,OAAO;AAAA,EACpB,SAAS,OAAO;AACd,WAAO;AAAA,MACL;AAAA,QACE,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS,uBAAuB,SAAS,IAAI,aAAa,WAAW;AAAA,QACrE,QAAQ,YAAY,KAAK;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACJ,MAAI;AACF,kBAAc,MAAM,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AACpD,iBAAa,MAAM,KAAK,KAAK,EAAE,MAAM,eAAe,YAAY,CAAC;AAAA,EACnE,SAAS,OAAO;AACd,WAAO;AAAA,MACL;AAAA,QACE,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS,iCAAiC,SAAS,IAAI,aAAa,WAAW;AAAA,QAC/E,QAAQ,YAAY,KAAK;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAIA,QAAM,cAAc,UAAM;AAAA,IACxB;AAAA,IACA,QAAQ;AAAA,IACR,aAAa,SAAS,WAAW;AAAA,IACjC;AAAA,EACF;AACA,QAAM,WAAuB,CAAC;AAC9B,aAAW,cAAc,aAAa;AACpC,UAAM,SAAS,WAAW;AAC1B,QAAI,WAAW,QAAW;AACxB;AAAA,IACF;AACA,aAAS,KAAK;AAAA,MACZ,KAAK,WAAW;AAAA,MAChB,cAAU,2BAAa,WAAW,KAAK,QAAQ,MAAM;AAAA,MACrD,OACE,OAAO,KAAK,MAAM,SAAS,aACvB,EAAE,MAAM,aAAa,IACrB,EAAE,MAAM,eAAe,YAAY;AAAA,IAC3C,CAAC;AAAA,EACH;AAIA,QAAM,QAAQ,CAAC,SAAyB,KAAK,YAAY;AACzD,QAAM,aAAa,IAAI,IAAI,YAAY,IAAI,CAAC,WAAW,CAAC,MAAM,OAAO,IAAI,GAAG,MAAM,CAAC,CAAC;AACpF,QAAM,YAAY,IAAI,IAAI,WAAW,IAAI,CAAC,WAAW,CAAC,MAAM,OAAO,IAAI,GAAG,MAAM,CAAC,CAAC;AAClF,QAAM,SAAS,CAAC,UACd,MAAM,SAAS,eAAe,aAAa;AAE7C,QAAM,YAA6B,CAAC;AACpC,QAAM,cAAc,oBAAI,IAAY;AAMpC,QAAM,eAAe,oBAAI,IAAY;AACrC,aAAW,QAAQ,UAAU;AAC3B,UAAM,MAAM,MAAM,KAAK,QAAQ;AAC/B,iBAAa,IAAI,GAAG;AACpB,QAAI,KAAK,MAAM,SAAS,eAAe;AACrC,kBAAY,IAAI,GAAG;AAAA,IACrB;AACA,QAAI,CAAC,OAAO,KAAK,KAAK,EAAE,IAAI,GAAG,GAAG;AAChC,gBAAU,KAAK;AAAA,QACb,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS,KAAK;AAAA,QACd,QAAQ,gBAAgB,WAAW,2BAA2B,WAAW,KAAK,KAAK,CAAC;AAAA,QACpF,QAAQ,mBAAmB,WAAW;AAAA,MACxC,CAAC;AAAA,IACH;AAAA,EACF;AACA,aAAW,UAAU,aAAa;AAChC,QAAI,CAAC,aAAa,IAAI,MAAM,OAAO,IAAI,CAAC,GAAG;AACzC,gBAAU,KAAK;AAAA,QACb,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS,OAAO;AAAA,QAChB,QAAQ,yDAAyD,WAAW;AAAA,MAC9E,CAAC;AAAA,IACH;AAAA,EACF;AACA,aAAW,UAAU,YAAY;AAC/B,QAAI,CAAC,YAAY,IAAI,MAAM,OAAO,IAAI,CAAC,GAAG;AACxC,gBAAU,KAAK;AAAA,QACb,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS,OAAO;AAAA,QAChB,QAAQ,yDAAyD,WAAW;AAAA,MAC9E,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,cAA+B,CAAC;AACtC,aAAW,QAAQ,UAAU;AAC3B,UAAM,SAAS,OAAO,KAAK,KAAK,EAAE,IAAI,MAAM,KAAK,QAAQ,CAAC;AAC1D,QAAI,WAAW,QAAW;AACxB;AAAA,IACF;AACA,UAAM,aAAS,4BAAc,MAAM,QAAQ,SAAS,SAAS,KAAK,GAAG,GAAG,WAAW,EACjF,eACF;AACA,QAAI,OAAO,WAAW,UAAU;AAC9B;AAAA,IACF;AACA,UAAM,WAAW,KAAK,MAAM,OAAO,SAAS;AAC5C,UAAM,WAAW,KAAK,MAAM,MAAM;AAKlC,QAAI,OAAO,MAAM,QAAQ,KAAK,OAAO,MAAM,QAAQ,KAAK,YAAY,WAAW,cAAc;AAC3F;AAAA,IACF;AACA,gBAAY,KAAK;AAAA,MACf,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS,KAAK;AAAA,MACd,QAAQ,iCAAiC,OAAO,SAAS;AAAA,IAC3D,CAAC;AAAA,EACH;AAEA,QAAM,WAA4B,CAAC;AACnC,WAAS;AAAA,IACP,GAAI,UAAU,SAAS,IACnB,YACA;AAAA,MACE;AAAA,QACE,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS,iCAAiC,WAAW;AAAA,MACvD;AAAA,IACF;AAAA,EACN;AACA,WAAS;AAAA,IACP,GAAI,YAAY,SAAS,IACrB,cACA;AAAA,MACE;AAAA,QACE,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS,8DAA8D,WAAW;AAAA,MACpF;AAAA,IACF;AAAA,EACN;AACA,WAAS,KAAK;AAAA,IACZ,OAAO;AAAA,IACP,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,IACT,QAAQ;AAAA,EACV,CAAC;AACD,SAAO;AACT;AAGA,SAAS,WAAW,IAAoB;AACtC,QAAM,MAAM,KAAK,IAAI,GAAG,EAAE;AAC1B,QAAM,MAAM;AACZ,QAAM,OAAO;AACb,QAAM,SAAS;AACf,QAAM,QAAQ,CAAC,OAAe,SAAyB;AACrD,UAAM,IAAI,KAAK,MAAM,KAAK;AAC1B,WAAO,GAAG,CAAC,IAAI,IAAI,GAAG,MAAM,IAAI,KAAK,GAAG;AAAA,EAC1C;AACA,MAAI,OAAO,IAAK,QAAO,MAAM,MAAM,KAAK,KAAK;AAC7C,MAAI,OAAO,KAAM,QAAO,MAAM,MAAM,MAAM,MAAM;AAChD,MAAI,OAAO,OAAQ,QAAO,MAAM,MAAM,QAAQ,QAAQ;AACtD,SAAO,MAAM,MAAM,KAAM,QAAQ;AACnC;AAGA,SAAS,UAAU,KAAgC;AACjD,SAAO,CAAC,GAAG,IAAI,WAAW,IAAI,IAAI,EAAE,KAAK,GAAG;AAC9C;AAwBA,eAAe,iBACb,SACA,aACA,OACA,UAC2B;AAC3B,QAAM,iBAAiB,QAAQ,OAAO,UAAU,WAAW;AAG3D,MACE,aAAa,WACZ,mBAAmB,UAAa,eAAe,SAAS,kBACzD;AACA,WAAO,EAAE,MAAM,QAAQ,UAAU,MAAM;AAAA,EACzC;AAEA,QAAM,SAAS,YAAa,MAAM,kBAAkB,SAAS,WAAW;AACxE,MAAI;AACF,UAAM,WAAsB,MAAM,QAAQ;AAAA,MACxC,MAAM,IAAI,OAAO,EAAE,WAAW,OAAO;AAAA,QACnC;AAAA,QACA,MAAM,MAAM,OAAO,SAAS,WAAW,GAAG;AAAA,MAC5C,EAAE;AAAA,IACJ;AACA,WAAO,EAAE,MAAM,QAAQ,SAAS;AAAA,EAClC,SAAS,OAAO;AACd,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS;AAAA,QACP,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS,uBAAuB,gBAAgB,QAAQ,OAAO,IAAI,wBAAwB,WAAW;AAAA,QACtG,QAAQ,YAAY,KAAK;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACF;AAmBA,SAAS,gBACP,UACA,aACA,KACiB;AACjB,QAAM,WAA4B,CAAC;AACnC,aAAW,EAAE,YAAY,KAAK,KAAK,UAAU;AAC3C,UAAM,EAAE,QAAQ,YAAY,QAAI,yBAAW,MAAM,WAAW;AAE5D,QAAI,WAAW,UAAa,gBAAgB,MAAM;AAChD;AAAA,IACF;AAIA,UAAM,eAAW,+BAAiB,MAAM;AACxC,QAAI,aAAa,QAAW;AAC1B,eAAS,KAAK;AAAA,QACZ,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS,WAAW;AAAA,QACpB,QAAQ,oBAAoB,MAAM;AAAA,MACpC,CAAC;AACD;AAAA,IACF;AACA,UAAM,OAAO,KAAK,MAAM,WAAW;AACnC,QAAI,OAAO,MAAM,IAAI,GAAG;AACtB;AAAA,IACF;AAIA,UAAM,YAAY,IAAI,QAAQ,IAAI,OAAO;AACzC,QAAI,aAAa,GAAG;AAClB;AAAA,IACF;AACA,aAAS,KAAK;AAAA,MACZ,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS,WAAW;AAAA,MACpB,QAAQ,eAAe,WAAW,SAAS,CAAC,YAAY,MAAM;AAAA,MAC9D,QAAQ,eAAe,UAAU,WAAW,GAAG,CAAC,UAAU,WAAW;AAAA,IACvE,CAAC;AAAA,EACH;AAEA,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS,gDAAgD,WAAW;AAAA,IACtE;AAAA,EACF;AACF;AAcA,SAAS,cACP,UACA,aACA,KACA,kBACiB;AACjB,QAAM,WAA4B,CAAC;AACnC,aAAW,EAAE,YAAY,KAAK,KAAK,UAAU;AAC3C,QAAI,KAAC,sBAAQ,MAAM,aAAa,KAAK,gBAAgB,GAAG;AACtD;AAAA,IACF;AACA,UAAM,EAAE,cAAc,QAAI,yBAAW,MAAM,WAAW;AAGtD,QAAI,kBAAkB,MAAM;AAC1B;AAAA,IACF;AACA,UAAM,UAAU,IAAI,QAAQ,IAAI,KAAK,MAAM,aAAa;AACxD,aAAS,KAAK;AAAA,MACZ,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS,WAAW;AAAA,MACpB,QAAQ,2BAA2B,WAAW,OAAO,CAAC,cAAc,WAAW,gBAAgB,CAAC;AAAA,MAChG,QAAQ,eAAe,UAAU,WAAW,GAAG,CAAC,qBAAqB,WAAW;AAAA,IAClF,CAAC;AAAA,EACH;AAEA,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS,oEAAoE,WAAW;AAAA,IAC1F;AAAA,EACF;AACF;AAmBA,SAAS,SAAS,MAAyB;AACzC,SAAO,CAAC,KAAK,UAAU,KAAK,GAAG,GAAG,KAAK,MAAM,SAAS,KAAK,KAAK,CAAC,EAAE,KAAK,GAAG;AAC7E;AAEA,SAAS,SAAS,OAAsB;AACtC,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,eAAe,MAAM,WAAW;AAAA,IACzC,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,qBAAqB,MAAM,WAAW;AAAA,IAC/C;AACE,iBAAO,0BAAY,OAAO,OAAO;AAAA,EACrC;AACF;AAcA,SAAS,sBAAsB,MAAiB,aAA8B;AAC5E,QAAM,QAAQ,KAAK;AACnB,MAAI,MAAM,SAAS,WAAY,QAAO;AACtC,MAAI,MAAM,SAAS,cAAe,QAAO,MAAM,gBAAgB;AAE/D,SAAO;AACT;AAWA,eAAe,aACb,UACA,aACkC;AAClC,QAAM,SAAS,MAAM,SAAS,KAAK,GAAG,OAAO,CAAC,SAAS,sBAAsB,MAAM,WAAW,CAAC;AAC/F,QAAM,SAAS,MAAM,QAAQ,IAAI,MAAM,IAAI,CAAC,SAAS,SAAS,KAAK,IAAI,CAAC,CAAC;AACzE,QAAM,UAAU,oBAAI,IAAwB;AAC5C,aAAW,CAAC,OAAO,IAAI,KAAK,MAAM,QAAQ,GAAG;AAC3C,UAAM,QAAQ,OAAO,KAAK;AAC1B,QAAI,UAAU,QAAW;AACvB,cAAQ,IAAI,SAAS,IAAI,GAAG,EAAE,MAAM,QAAQ,MAAM,CAAC;AAAA,IACrD;AAAA,EACF;AACA,SAAO;AACT;AAsBA,eAAe,sBACb,SACA,aACA,UAC0B;AAC1B,QAAM,iBAAiB,QAAQ,OAAO,UAAU,WAAW;AAC3D,MAAI,mBAAmB,UAAa,eAAe,SAAS,iBAAiB;AAC3E,WAAO;AAAA,MACL;AAAA,QACE,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS,GAAG,WAAW;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,YAAa,MAAM,kBAAkB,SAAS,WAAW;AAExE,MAAI;AACJ,MAAI;AACJ,MAAI;AACF,YAAQ,MAAM,aAAa,QAAQ,UAAU,WAAW;AACxD,aAAS,MAAM,aAAa,QAAQ,WAAW;AAAA,EACjD,SAAS,OAAO;AACd,WAAO;AAAA,MACL;AAAA,QACE,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS,uBAAuB,eAAe,IAAI,iBAAiB,WAAW;AAAA,QAC/E,QAAQ,YAAY,KAAK;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAEA,QAAM,OAAO,aAAa,SAAS,WAAW;AAC9C,QAAM,WAA4B,CAAC;AAEnC,QAAM,YAAY,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,MAAM,KAAK,GAAG,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK;AACzE,aAAW,WAAW,WAAW;AAC/B,UAAM,OAAO,MAAM,IAAI,OAAO;AAC9B,UAAM,QAAQ,OAAO,IAAI,OAAO;AAChC,QAAI,SAAS,UAAa,UAAU,QAAW;AAG7C,YAAM,aAAS,wBAAU,KAAK,MAAM,KAAK,QAAQ,IAAI;AACrD,UAAI,OAAO,SAAS,aAAa;AAI/B,iBAAS,KAAK;AAAA,UACZ,OAAO;AAAA,UACP,UAAU;AAAA,UACV,OAAO;AAAA,UACP,aAAS,8BAAgB,KAAK,IAAI;AAAA,UAClC,QAAQ,oFAAoF,eAAe,IAAI;AAAA,QACjH,CAAC;AACD;AAAA,MACF;AAIA,UAAI,OAAO,UAAU,MAAM,QAAQ;AACjC,iBAAS,KAAK;AAAA,UACZ,OAAO;AAAA,UACP,UAAU;AAAA,UACV,OAAO;AAAA,UACP,aAAS,8BAAgB,KAAK,IAAI;AAAA,UAClC,QAAQ,0BAA0B,eAAe,IAAI;AAAA,QACvD,CAAC;AAAA,MACH;AACA;AAAA,IACF;AACA,UAAM,UAAU,QAAQ;AAExB,QAAI,YAAY,QAAW;AACzB;AAAA,IACF;AACA,aAAS,KAAK;AAAA,MACZ,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO,SAAS,SAAY,2BAA2B;AAAA,MACvD,aAAS,8BAAgB,QAAQ,IAAI;AAAA,MACrC,QACE,SAAS,SACL,oCAAoC,eAAe,IAAI,qBACvD,kBAAkB,eAAe,IAAI;AAAA,IAC7C,CAAC;AAAA,EACH;AAEA,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL;AAAA,MACE,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO;AAAA,MACP,SAAS,2BAA2B,eAAe,IAAI,wBAAwB,WAAW;AAAA,IAC5F;AAAA,EACF;AACF;AAEO,SAAS,aAAa,QAAgC;AAC3D,QAAM,OAAc,OAAO,SAAS,IAAI,CAAC,aAAa;AAAA,IACpD,OAAO,QAAQ,aAAa,SAAS,QAAQ,QAAQ,aAAa,YAAY,UAAU;AAAA,IACxF,OAAO,QAAQ;AAAA,IACf,GAAI,QAAQ,YAAY,SAAY,CAAC,IAAI,EAAE,SAAS,QAAQ,QAAQ;AAAA,IACpE,GAAI,QAAQ,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;AAAA,EACnE,EAAE;AAEF,QAAM,QAAQ,WAAW,IAAI;AAI7B,QAAM,WAAW;AAAA,IACf,GAAG,IAAI;AAAA,MACL,OAAO,SACJ,OAAO,CAAC,YAAY,QAAQ,aAAa,MAAM,EAC/C,IAAI,CAAC,YAAY,QAAQ,MAAM,EAC/B,OAAO,CAAC,WAA6B,WAAW,MAAS;AAAA,IAC9D;AAAA,EACF;AACA,aAAW,UAAU,UAAU;AAC7B,UAAM,KAAK,KAAK,MAAM,EAAE;AAAA,EAC1B;AACA,SAAO;AACT;AAEO,IAAM,oBAAgB,6BAAc;AAAA,EACzC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,UAAU,aAAa,+BAA+B;AAAA,EACrE;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAM,SAAS,MAAM,UAAU;AAAA,QAC7B,KAAK,QAAQ,IAAI;AAAA,QACjB,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,MAC5D,CAAC;AACD,YAAM,aAAa,MAAM,CAAC;AAC1B,UAAI,CAAC,OAAO,IAAI;AACd,gBAAQ,WAAW;AAAA,MACrB;AAAA,IACF,CAAC;AAAA,EACH;AACF,CAAC;;;AOlwCD,IAAAE,eAOO;AACP,IAAAC,gBAA8B;;;AClB9B,IAAAC,eAA6E;AAC7E,IAAAC,gBAA8B;AA2CvB,SAAS,UAAU,SAA8B;AACtD,MAAI,QAAQ,UAAU,MAAM;AAC1B,QAAI,QAAQ,gBAAgB,QAAW;AACrC,aAAO,EAAE,MAAM,qBAAqB,aAAa,QAAQ,YAAY;AAAA,IACvE;AACA,WAAO,EAAE,MAAM,QAAQ;AAAA,EACzB;AACA,MAAI,QAAQ,gBAAgB,QAAW;AACrC,WAAO,EAAE,MAAM,eAAe,aAAa,QAAQ,YAAY;AAAA,EACjE;AACA,SAAO,EAAE,MAAM,WAAW;AAC5B;AAoBO,SAAS,YAAY,SAAkB,SAAuB,KAAoB;AACvF,QAAM,cAAc,QAAQ;AAC5B,MAAI,gBAAgB,QAAW;AAC7B,WAAO,UAAU,OAAO;AAAA,EAC1B;AACA,MAAI,YAAY,KAAK,EAAE,WAAW,GAAG;AACnC,UAAM,IAAI;AAAA,MACR;AAAA,MACA,2BAA2B,GAAG;AAAA,MAC9B,sCAAiC,QAAQ,OAAO,aAAa,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,IAEhG;AAAA,EACF;AACA,SAAO,UAAU,EAAE,GAAG,SAAS,aAAa,kBAAkB,SAAS,WAAW,EAAE,CAAC;AACvF;AAUA,SAAS,kBAAkB,SAAkB,SAA2C;AACtF,SAAO,QAAQ,gBAAgB,SAC3B,SACA,kBAAkB,SAAS,QAAQ,WAAW;AACpD;AAYA,SAAS,QACP,SACA,MACA,OACA,WACA,aACQ;AACR,MAAI,gBAAgB,QAAW;AAC7B,UAAM,IAAI;AAAA,MACR;AAAA,MACA,aAAa,SAAS,qBAAqB,QAAQ,QAAI,8BAAgB,IAAI,CAAC;AAAA,MAC5E;AAAA,IAGF;AAAA,EACF;AACA,aAAO,wBAAU,MAAM,OAAO,aAAa,SAAS,WAAW,GAAG,WAAW,WAAW;AAC1F;AA0CA,eAAsB,eACpB,SAC+B;AAC/B,QAAM,EAAE,SAAS,UAAU,KAAK,OAAO,OAAO,YAAY,IAAI;AAC9D,QAAM,aAAS,uBAAS,MAAM,SAAS,SAAS,GAAG,GAAG,WAAW;AAEjE,QAAM,OAAkB;AAAA,IACtB,WAAW,IAAI;AAAA,IACf,MAAM,IAAI;AAAA,IACV;AAAA,IACA,WAAW;AAAA,EACb;AAKA,QAAM,SAAS,SAAS,QAAQ,SAAS,MAAM,WAAO,0BAAY,GAAG,GAAG,WAAW,IAAI;AAEvF,QAAM,SAAS,MAAM,MAAM,MAAM;AAYjC,QAAM,SAAS,OAAO,EAAE,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC;AAErD,SAAO,EAAE,WAAW,QAAQ,cAAU,8BAAgB,IAAI,EAAE;AAC9D;AAQA,eAAsB,OAAO,SAAyC;AACpE,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,oBAAkB,QAAQ,GAAG;AAC7B,QAAM,MAAM,WAAW,QAAQ,KAAK,QAAQ,MAAM;AAKlD,QAAM,QAAQ,YAAY,SAAS,SAAS,QAAQ,GAAG;AACvD,QAAM,cAAc,kBAAkB,SAAS,OAAO;AAEtD,QAAM,EAAE,WAAW,SAAS,IAAI,MAAM,eAAe;AAAA,IACnD;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB;AAAA,IACA;AAAA,IACA,OAAO,QAAQ;AAAA,IACf;AAAA,EACF,CAAC;AAED,SAAO,EAAE,WAAW,QAAQ,KAAK,UAAU,UAAU;AACvD;AAEO,SAAS,UAAUC,SAA6B;AACrD,SAAO,WAAW;AAAA,IAChB;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS,GAAG,QAAQ,IAAIA,QAAO,QAAQ;AAAA;AAAA;AAAA,MAGvC,GAAIA,QAAO,YAAY,EAAE,QAAQ,6CAA6C,IAAI,CAAC;AAAA,IACrF;AAAA,EACF,CAAC;AACH;AAGA,eAAsB,YAA6B;AACjD,QAAM,SAAmB,CAAC;AAC1B,mBAAiB,SAAS,QAAQ,OAAgC;AAChE,WAAO,KAAK,OAAO,KAAK,KAAK,CAAC;AAAA,EAChC;AACA,QAAM,OAAO,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM;AAClD,SAAO,KAAK,SAAS,IAAI,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;AACnD;AAEO,IAAM,iBAAa,6BAAc;AAAA,EACtC,MAAM,EAAE,MAAM,OAAO,aAAa,qBAAqB;AAAA,EACvD,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,cAAc,UAAU,MAAM,aAAa,qCAAqC;AAAA,IAC7F,OAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU;AAAA,MACV,aAAa;AAAA,IACf;AAAA,IACA,KAAK,EAAE,MAAM,UAAU,aAAa,+BAA+B;AAAA,IACnE,OAAO;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAM,QAAQ,KAAK,SAAU,MAAM,UAAU;AAC7C;AAAA,QACE;AAAA,UACE,MAAM,OAAO;AAAA,YACX,KAAK,QAAQ,IAAI;AAAA,YACjB,KAAK,KAAK;AAAA,YACV;AAAA,YACA,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,YAC1D,GAAI,KAAK,UAAU,SAAY,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM;AAAA,UAC1D,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF,CAAC;;;AD7PD,SAAS,MAAM,SAAkB,KAAa,SAA+C;AAC3F,QAAM,MAAM,WAAW,KAAK,QAAQ,MAAM;AAC1C,QAAM,QAAQ,YAAY,SAAS,SAAS,GAAG;AAC/C,SAAO;AAAA,IACL,EAAE,WAAW,IAAI,WAAW,MAAM,IAAI,MAAM,OAAO,WAAW,MAAM;AAAA,IACpE,EAAE,WAAW,IAAI,WAAW,MAAM,IAAI,MAAM,OAAO,WAAW,KAAK;AAAA,EACrE;AACF;AAWA,SAAS,eAAe,SAAkB,SAAuB,MAAsB;AACrF,MAAI,QAAQ,gBAAgB,QAAW;AACrC,UAAM,IAAI;AAAA,MACR;AAAA,MACA,UAAU,IAAI;AAAA,MACd;AAAA,IAEF;AAAA,EACF;AACA,SAAO,kBAAkB,SAAS,QAAQ,WAAW;AACvD;AAEA,eAAe,QAAQ,SAAkB,MAA8C;AACrF,SAAO,QAAQ,SAAS,KAAK,IAAI;AACnC;AAEA,eAAsB,WAAW,SAA+C;AAC9E,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,cAAc,eAAe,SAAS,SAAS,SAAS;AAC9D,QAAM,CAAC,OAAO,MAAM,IAAI,MAAM,SAAS,QAAQ,KAAK,OAAO;AAC3D,QAAM,gBAAY,0BAAY,KAAK;AAEnC,QAAM,QAAQ,MAAM,QAAQ,SAAS,KAAK;AAC1C,MAAI,UAAU,QAAW;AACvB,UAAM,UAAU,MAAM,QAAQ,SAAS,MAAM;AAC7C,UAAM,IAAI;AAAA,MACR;AAAA,MACA,YAAY,SACR,aAAa,SAAS,yBAAyB,QAAQ,QAAI,8BAAgB,KAAK,CAAC,KACjF,aAAa,SAAS,4BAA4B,QAAQ,QAAI,8BAAgB,MAAM,CAAC;AAAA,MACzF,YAAY,SACR,kCAAkC,QAAQ,GAAG,UAAU,WAAW,qFAElE;AAAA,IACN;AAAA,EACF;AAEA,QAAM,WAAO,wBAAU,QAAQ,OAAO,aAAa,SAAS,WAAW,GAAG,WAAW,WAAW;AAIhG,QAAM,QAAQ,SAAS,MAAM,QAAQ,IAAI;AACzC,QAAM,QAAQ,SAAS,OAAO,KAAK;AAEnC,SAAO;AAAA,IACL;AAAA,IACA,cAAU,8BAAgB,MAAM;AAAA,IAChC,aAAS,8BAAgB,KAAK;AAAA,EAChC;AACF;AAEA,eAAsB,WAAW,SAA+C;AAC9E,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,cAAc,eAAe,SAAS,SAAS,SAAS;AAC9D,QAAM,CAAC,OAAO,MAAM,IAAI,MAAM,SAAS,QAAQ,KAAK,OAAO;AAC3D,QAAM,gBAAY,0BAAY,KAAK;AAKnC,UAAI,uBAAS,MAAM,QAAQ,SAAS,SAAS,KAAK,GAAG,WAAW,GAAG;AACjE,UAAM,IAAI;AAAA,MACR;AAAA,MACA,aAAa,SAAS,yCAAyC,WAAW;AAAA,MAC1E;AAAA,IAGF;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,QAAQ,SAAS,MAAM;AAC5C,MAAI,WAAW,QAAW;AACxB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,aAAa,SAAS,mCAAmC,QAAQ,QAAI,8BAAgB,MAAM,CAAC;AAAA,MAC5F,kCAAkC,QAAQ,GAAG,UAAU,WAAW;AAAA,IACpE;AAAA,EACF;AAEA,QAAM,aAAS,wBAAU,QAAQ,QAAQ,aAAa,SAAS,WAAW,CAAC;AAC3E,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,UACA,8BAAgB,MAAM;AAAA,MACtB,OAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,QAAQ,SAAS,MAAM,OAAO,OAAO,KAAK;AAChD,QAAM,QAAQ,SAAS,OAAO,MAAM;AAEpC,SAAO;AAAA,IACL;AAAA,IACA,cAAU,8BAAgB,KAAK;AAAA,IAC/B,aAAS,8BAAgB,MAAM;AAAA,EACjC;AACF;AAGA,IAAM,kBAAN,cAA8B,uBAAU;AAAA,EACtC,YAAY,WAAmB,aAAqB,UAAkB,QAAgB;AACpF;AAAA,MACE;AAAA,MACA,aAAa,SAAS,oBAAoB,WAAW,iBAAiB,QAAQ,IAAI,QAAQ,iCAAiC,MAAM;AAAA,MACjI;AAAA,IAEF;AAAA,EACF;AACF;AAEO,SAAS,aAAaC,SAAsB,MAA2C;AAC5F,SAAO,WAAW;AAAA,IAChB;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS,GAAG,QAAQ,IAAIA,QAAO,QAAQ;AAAA,MACvC,QAAQ,GAAG,QAAQ,IAAIA,QAAO,OAAO;AAAA,IACvC;AAAA,EACF,CAAC;AACH;AAEA,IAAM,aAAa;AAAA,EACjB,KAAK,EAAE,MAAM,cAAc,UAAU,MAAM,aAAa,qCAAqC;AAAA,EAC7F,KAAK,EAAE,MAAM,UAAU,aAAa,6CAA6C;AAAA,EACjF,OAAO;AAAA,IACL,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AACF;AAEA,SAAS,aAAa,MAGL;AACf,SAAO;AAAA,IACL,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,IAC1D,GAAI,KAAK,UAAU,SAAY,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM;AAAA,EAC1D;AACF;AAEO,IAAM,qBAAiB,6BAAc;AAAA,EAC1C,MAAM,EAAE,MAAM,WAAW,aAAa,kDAAkD;AAAA,EACxF,MAAM;AAAA,EACN,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAMA,UAAS,MAAM,WAAW,EAAE,KAAK,QAAQ,IAAI,GAAG,KAAK,KAAK,KAAK,GAAG,aAAa,IAAI,EAAE,CAAC;AAC5F,YAAM,aAAaA,SAAQ,WAAW,CAAC;AAAA,IACzC,CAAC;AAAA,EACH;AACF,CAAC;AAEM,IAAM,qBAAiB,6BAAc;AAAA,EAC1C,MAAM,EAAE,MAAM,WAAW,aAAa,kDAAkD;AAAA,EACxF,MAAM;AAAA,EACN,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAMA,UAAS,MAAM,WAAW,EAAE,KAAK,QAAQ,IAAI,GAAG,KAAK,KAAK,KAAK,GAAG,aAAa,IAAI,EAAE,CAAC;AAC5F,YAAM,aAAaA,SAAQ,WAAW,CAAC;AAAA,IACzC,CAAC;AAAA,EACH;AACF,CAAC;;;AErND,sBAAgC;AAChC,IAAAC,gBAA0B;AAC1B,IAAAC,gBAA8B;AAe9B,IAAM,WAA2C,oBAAI,IAAI,CAAC,UAAU,aAAa,UAAU,CAAC;AAsD5F,eAAsB,QAAQ,SAA2C;AACvE,QAAM,aAAa,MAAM,YAAY;AAAA,IACnC,KAAK,QAAQ;AAAA,IACb,GAAI,QAAQ,gBAAgB,SAAY,CAAC,IAAI,EAAE,aAAa,QAAQ,YAAY;AAAA,EAClF,CAAC;AACD,QAAM,cAAc,WAAW;AAU/B,QAAM,WAAW,WAAW,OAAO,OAAO,CAAC,UAAU,SAAS,IAAI,MAAM,IAAI,CAAC;AAC7E,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,SAAS,SACZ;AAAA,MACC,CAAC,UAAU,OAAO,MAAM,OAAO,GAAG,MAAM,WAAW,SAAY,KAAK,KAAK,MAAM,MAAM,GAAG;AAAA,IAC1F,EACC,KAAK,IAAI;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,MACA,qCAAqC,WAAW,QAAQ,SAAS,MAAM,6BACpD,SAAS,WAAW,IAAI,UAAU,QAAQ;AAAA,EAAM,MAAM;AAAA,MACzE,2JACoD,QAAQ;AAAA,IAC9D;AAAA,EACF;AAEA,QAAM,UAA8E,CAAC;AACrF,QAAMC,WAAoB,CAAC;AAC3B,QAAM,cAA0D,CAAC;AAEjE,aAAW,SAAS,WAAW,MAAM,UAAU;AAI7C,QAAI,MAAM,QAAQ,QAAW;AAC3B,kBAAY,KAAK,EAAE,SAAS,MAAM,SAAS,QAAQ,MAAM,OAAO,CAAC;AACjE;AAAA,IACF;AAEA,UAAM,MAAM,MAAM;AAClB,UAAM,MAAM,CAAC,GAAG,IAAI,WAAW,IAAI,IAAI,EAAE,KAAK,GAAG;AAGjD,UAAM,QAAQ,MAAM,QAAQ,IAAI,EAAE,WAAW,KAAK,aAAa,QAAQ,MAAM,CAAC;AAC9E,QAAI,UAAU,UAAa,UAAU,IAAI;AACvC,MAAAA,SAAQ,KAAK,MAAM,OAAO;AAC1B;AAAA,IACF;AAEA,UAAMC,UAAS,MAAM,OAAO,EAAE,KAAK,QAAQ,KAAK,KAAK,OAAO,YAAY,CAAC;AACzE,YAAQ,KAAK;AAAA,MACX,WAAW,MAAM;AAAA,MACjB,UAAUA,QAAO;AAAA,MACjB,WAAWA,QAAO;AAAA,IACpB,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,aAAa,SAAS,SAAAD,UAAS,YAAY;AACtD;AAGA,SAAS,YAAYC,SAA4B;AAC/C,QAAM,SAASA,QAAO,QAAQ;AAC9B,MAAI,WAAW,KAAKA,QAAO,QAAQ,WAAW,KAAKA,QAAO,YAAY,WAAW,GAAG;AAClF,WAAO,mCAAmCA,QAAO,WAAW;AAAA,EAC9D;AACA,QAAM,QAAQ,CAAC,GAAG,MAAM,UAAU;AAClC,MAAIA,QAAO,QAAQ,SAAS,GAAG;AAC7B,UAAM,KAAK,GAAGA,QAAO,QAAQ,MAAM,UAAU;AAAA,EAC/C;AACA,MAAIA,QAAO,YAAY,SAAS,GAAG;AACjC,UAAM,KAAK,GAAGA,QAAO,YAAY,MAAM,cAAc;AAAA,EACvD;AACA,SAAO,GAAG,MAAM,KAAK,IAAI,CAAC,oBAAoBA,QAAO,WAAW;AAClE;AAEO,SAAS,WAAWA,SAA8B;AACvD,QAAM,OAAcA,QAAO,QAAQ,IAAI,CAAC,WAAW;AAAA,IACjD,OAAO;AAAA,IACP,OAAO;AAAA,IACP,SAAS,GAAG,QAAQ,IAAI,MAAM,QAAQ;AAAA;AAAA,IAEtC,GAAI,MAAM,YAAY,EAAE,QAAQ,6CAA6C,IAAI,CAAC;AAAA,EACpF,EAAE;AAIF,aAAW,SAASA,QAAO,aAAa;AACtC,SAAK,KAAK,EAAE,OAAO,MAAM,OAAO,eAAe,SAAS,MAAM,SAAS,QAAQ,MAAM,OAAO,CAAC;AAAA,EAC/F;AAEA,QAAM,QAAQ,WAAW,IAAI;AAC7B,QAAM,KAAK,YAAYA,OAAM,CAAC;AAC9B,SAAO;AACT;AAEO,IAAM,kBAAc,6BAAc;AAAA,EACvC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,UAAU,aAAa,0BAA0B;AAAA,EAChE;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAM,SAAK,iCAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAI3E,YAAM,MAAM,CAAC,WACX,GAAG,SAAS,GAAG,OAAO,SAAS,KAAK,OAAO,WAAW,KAAK;AAC7D,UAAI;AACF;AAAA,UACE;AAAA,YACE,MAAM,QAAQ;AAAA,cACZ,KAAK,QAAQ,IAAI;AAAA,cACjB,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,cAC1D;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF,UAAE;AACA,WAAG,MAAM;AAAA,MACX;AAAA,IACF,CAAC;AAAA,EACH;AACF,CAAC;;;AChND,qBAA8B;AAC9B,IAAAC,oBAA8C;AAE9C,IAAAC,gBAOO;AACP,IAAAC,gBAA8B;AAavB,IAAM,iBAAiB;AA+B9B,SAAS,WAAW,SAAkB,aAAqB,cAAiC;AAC1F,QAAM,OAAO,aAAa,SAAS,WAAW;AAC9C,QAAM,OAAO,UAAU,OAAO;AAC9B,QAAM,cAAc,eAAe,MAAM,aAAa,IAAI;AAI1D,QAAM,gBAAY;AAAA,IAChB,SAAS,YAAY,IAAI,CAAC,eAAe,WAAW,GAAG,CAAC;AAAA,IACxD,QAAQ;AAAA,EACV,EAAE,CAAC;AACH,MAAI,cAAc,QAAW;AAC3B,UAAM;AAAA,EACR;AAEA,QAAM,UAAyB,CAAC;AAChC,MAAI,YAAY;AAChB,aAAW,cAAc,aAAa;AACpC,UAAM,SAAS,WAAW;AAC1B,QAAI,QAAQ,KAAK,cAAc,MAAM;AAMnC,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI;AAAA,UACR;AAAA,UACA,aAAa,WAAW,SAAS,oBAAoB,WAAW,yCAAyC,QAAQ,IAAI,OAAO,QAAQ;AAAA,UACpI;AAAA,QACF;AAAA,MACF;AAIA,sCAAa,YAAY,WAAW;AACpC,mBAAa;AAAA,IACf;AACA,QAAI,WAAW,UAAU,QAAW;AAClC;AAAA,IACF;AAGA,UAAM,kBAAc,6BAAc,KAAK,aAAa,WAAW,GAAG,GAAG,WAAW,EAAE;AAClF,YAAQ,KAAK;AAAA,MACX,SAAK,4BAAa,WAAW,KAAK,QAAQ,MAAM;AAAA,MAChD,OAAO,WAAW;AAAA,MAClB,GAAI,OAAO,gBAAgB,WAAW,EAAE,YAAY,IAAI,CAAC;AAAA,IAC3D,CAAC;AAAA,EACH;AAGA,UAAQ,KAAK,CAAC,GAAG,MAAO,EAAE,MAAM,EAAE,MAAM,KAAK,EAAE,MAAM,EAAE,MAAM,IAAI,CAAE;AACnE,SAAO,EAAE,SAAS,UAAU;AAC9B;AAGO,SAAS,eAAe,SAA+C;AAC5E,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,cAAc,kBAAkB,SAAS,QAAQ,WAAW;AAClE,aAAO,+BAAgB,WAAW,SAAS,aAAa,QAAQ,iBAAiB,IAAI,EAAE,OAAO;AAChG;AAEO,SAAS,YAAY,SAA0C;AACpE,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,cAAc,kBAAkB,SAAS,QAAQ,WAAW;AAClE,QAAM,EAAE,SAAS,UAAU,IAAI,WAAW,SAAS,aAAa,QAAQ,iBAAiB,IAAI;AAI7F,QAAM,OACJ,QAAQ,QAAQ,aACZ,2BAAQ,QAAQ,MAAM,cAAc,QACpC,8BAAW,QAAQ,GAAG,IACpB,QAAQ,UACR,2BAAQ,QAAQ,KAAK,QAAQ,GAAG;AAExC,oCAAc,UAAM,+BAAgB,OAAO,GAAG,MAAM;AACpD,SAAO,EAAE,MAAM,aAAa,SAAS,QAAQ,QAAQ,UAAU;AACjE;AAGA,SAAS,YAAY,KAAa,MAAsB;AACtD,QAAM,UAAM,4BAAS,KAAK,IAAI;AAC9B,SAAO,QAAQ,MAAM,IAAI,WAAW,IAAI,IAAI,OAAO,IAAI,MAAM,IAAI,EAAE,KAAK,GAAG;AAC7E;AAEO,SAAS,eAAeC,SAAwB,KAAuB;AAC5E,QAAM,OAAO;AAAA,IACX;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS,YAAY,KAAKA,QAAO,IAAI;AAAA,MACrC,QAAQ,GAAGA,QAAO,OAAO,8BAA8BA,QAAO,WAAW;AAAA,IAC3E;AAAA,EACF;AAIA,MAAIA,QAAO,YAAY,GAAG;AACxB,SAAK,KAAK;AAAA,MACR,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS,GAAGA,QAAO,SAAS,IAAIA,QAAO,cAAc,IAAI,WAAW,SAAS;AAAA,MAC7E,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AACA,SAAO,WAAW,IAAI;AACxB;AAEO,IAAM,sBAAkB,6BAAc;AAAA,EAC3C,MAAM,EAAE,MAAM,YAAY,aAAa,oDAAoD;AAAA,EAC3F,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,UAAU,aAAa,kCAAkC;AAAA,IACtE,KAAK,EAAE,MAAM,UAAU,aAAa,kCAAkC;AAAA,IACtE,iBAAiB;AAAA,MACf,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAM,MAAM,QAAQ,IAAI;AACxB,YAAMA,UAAS,YAAY;AAAA,QACzB;AAAA,QACA,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,QAC1D,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI;AAAA,QAClD,GAAI,KAAK,eAAe,MAAM,SAAY,CAAC,IAAI,EAAE,cAAc,KAAK,eAAe,EAAE;AAAA,MACvF,CAAC;AACD,YAAM,eAAeA,SAAQ,GAAG,CAAC;AAAA,IACnC,CAAC;AAAA,EACH;AACF,CAAC;;;AC9LD,IAAAC,gBAA0D;AAC1D,IAAAC,gBAA8B;AA0C9B,eAAsB,OAAO,SAAsC;AACjE,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,cAAc,kBAAkB,SAAS,QAAQ,WAAW;AAClE,QAAM,MAAM,WAAW,QAAQ,GAAG;AAElC,QAAM,OAAO,aAAa,SAAS,WAAW;AAC9C,QAAM,aAAa,UAAM,gCAAiB,KAAK,aAAa,QAAQ,UAAU,IAAI;AAClF,QAAM,YAAQ,4BAAa,YAAY,WAAW;AAClD,MAAI,UAAU,QAAW;AACvB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,aAAa,WAAW,SAAS,yCAAyC,WAAW;AAAA,MACrF,0BAA0B,QAAQ,GAAG,UAAU,WAAW,yBAAyB,QAAQ,GAAG,UAAU,WAAW;AAAA,IACrH;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,WAAW,QAAgD;AAClE,MAAI,WAAW,oBAAoB;AAKjC,WAAO;AAAA,EACT;AACA,MAAI,WAAW,yBAAyB;AACtC,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAOA,eAAsB,WAAW,SAA8C;AAC7E,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,cAAc,kBAAkB,SAAS,QAAQ,WAAW;AAClE,QAAM,MAAM,WAAW,QAAQ,GAAG;AAElC,QAAM,OAAO,aAAa,SAAS,WAAW;AAC9C,QAAM,aAAa,UAAM,gCAAiB,KAAK,aAAa,QAAQ,UAAU,IAAI;AAClF,QAAM,SAAS,WAAW;AAE1B,SAAO;AAAA,IACL,WAAW,WAAW;AAAA,IACtB;AAAA,IACA,UAAU,WAAW,SAAY,SAAY,OAAO;AAAA,IACpD,GAAI,WAAW,kBAAkB,SAC7B,CAAC,IACD,EAAE,eAAe,WAAW,cAAc,OAAO;AAAA,IACrD,YAAY,WAAW,WAAW,IAAI,CAAC,eAAe;AAAA,MACpD,UAAU,UAAU;AAAA,MACpB,SAAS,UAAU;AAAA,MACnB,MAAM,cAAc;AAAA,MACpB,SAAS,WAAW,UAAU,aAAa;AAAA,IAC7C,EAAE;AAAA,EACJ;AACF;AAEO,SAAS,cAAc,aAAuC;AACnE,QAAM,SACJ,YAAY,aAAa,SAAY,YAAY,GAAG,QAAQ,IAAI,YAAY,QAAQ;AAItF,QAAM,OAAO,YAAY,WAAW,IAAI,CAAC,cAAc;AAAA,IACrD,UAAU;AAAA,IACV,UAAU,OACN,kBACA,UAAU,UACP,UAAU,WAAW,YACrB,UAAU,WAAW;AAAA,EAC9B,CAAC;AAED,SAAO;AAAA,IACL,GAAG,YAAY,SAAS,gBAAgB,MAAM,oBAAoB,YAAY,WAAW;AAAA,IACzF,GAAI,YAAY,kBAAkB,SAC9B,CAAC,IACD,CAAC,6BAA6B,YAAY,aAAa,EAAE;AAAA,IAC7D;AAAA,IACA,GAAG,QAAQ,IAAI,EAAE,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE;AAAA,EAC5C;AACF;AAEO,IAAM,iBAAa,6BAAc;AAAA,EACtC,MAAM,EAAE,MAAM,OAAO,aAAa,mBAAmB;AAAA,EACrD,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,cAAc,UAAU,MAAM,aAAa,qCAAqC;AAAA,IAC7F,KAAK,EAAE,MAAM,UAAU,aAAa,0BAA0B;AAAA,IAC9D,SAAS,EAAE,MAAM,WAAW,aAAa,iCAAiC;AAAA,EAC5E;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAM,UAAsB;AAAA,QAC1B,KAAK,QAAQ,IAAI;AAAA,QACjB,KAAK,KAAK;AAAA,QACV,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,MAC5D;AACA,UAAI,KAAK,YAAY,MAAM;AACzB,cAAM,cAAc,MAAM,WAAW,OAAO,CAAC,CAAC;AAC9C;AAAA,MACF;AACA,YAAM,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC;AAAA,IAC/B,CAAC;AAAA,EACH;AACF,CAAC;;;ACrID,IAAAC,kBAAuD;AACvD,IAAAC,oBAAwD;AAExD,IAAAC,gBAiBO;AACP,IAAAC,iBAA8B;;;AC5B9B,IAAAC,kBAAyC;AACzC,IAAAC,oBAAqB;AACrB,IAAAC,gBAAoC;AAuCpC,IAAM,aAAmC;AAAA,EACvC,EAAE,MAAM,WAAW,UAAU,CAAC,MAAM,GAAG,gBAAgB,CAAC,cAAc,EAAE;AAAA,EACxE;AAAA,IACE,MAAM;AAAA,IACN,UAAU,CAAC,yBAAyB,iBAAiB;AAAA,IACrD,gBAAgB,CAAC,OAAO;AAAA,EAC1B;AAAA,EACA,EAAE,MAAM,SAAS,UAAU,CAAC,OAAO,GAAG,gBAAgB,CAAC,SAAS,EAAE;AAAA,EAClE,EAAE,MAAM,QAAQ,UAAU,CAAC,MAAM,GAAG,gBAAgB,CAAC,OAAO,EAAE;AAChE;AAiBA,SAAS,cAAc,MAAuB;AAC5C,MAAI;AACJ,MAAI;AACF,iBAAS,8BAAa,MAAM,MAAM;AAAA,EACpC,QAAQ;AACN,WAAO;AAAA,EACT;AACA;AAAA;AAAA,IAEE,wCAAwC,KAAK,MAAM;AAAA,IAEnD,oCAAoC,KAAK,MAAM;AAAA;AAEnD;AAGA,SAAS,SAAS,KAAaC,WAA2B;AACxD,QAAM,WAAO,wBAAK,KAAK,GAAGA,UAAS,MAAM,GAAG,CAAC;AAC7C,aAAO,4BAAW,IAAI,KAAK,CAAC,cAAc,IAAI;AAChD;AAgBO,SAAS,cAAc,KAAmD;AAC/E,QAAM,UAAM,gCAAW,wBAAK,KAAK,KAAK,CAAC,IAAI,SAAS;AACpD,QAAM,YAAY,GAAG,GAAG;AACxB,MAAI,CAAC,SAAS,KAAK,SAAS,GAAG;AAC7B,WAAO,EAAE,MAAM,UAAU;AAAA,EAC3B;AAEA,QAAM,SAAS,GAAG,GAAG;AACrB,MAAI,CAAC,SAAS,KAAK,MAAM,GAAG;AAC1B,WAAO,EAAE,MAAM,QAAQ,WAAW,UAAU;AAAA,EAC9C;AAGA,SAAO,EAAE,MAAM,mCAAqB,WAAW,UAAU;AAC3D;AASA,SAAS,eAAe,KAA8C;AACpE,QAAM,WAAW,WAAW,GAAG;AAC/B,MAAI,aAAa,QAAW;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,oBAAI,IAAY;AAC9B,aAAW,SAAS,CAAC,gBAAgB,iBAAiB,GAAY;AAChE,UAAM,QAAiB,SAAS,KAAK;AACrC,QAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AACxE,iBAAW,QAAQ,OAAO,KAAK,KAAK,GAAG;AACrC,cAAM,IAAI,IAAI;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AASA,SAAS,WAAW,KAA4D;AAC9E,QAAM,WAAO,wBAAK,KAAK,cAAc;AACrC,MAAI,KAAC,4BAAW,IAAI,GAAG;AACrB,WAAO;AAAA,EACT;AACA,MAAI;AACJ,MAAI;AACF,eAAW,KAAK,UAAM,8BAAa,MAAM,MAAM,CAAC;AAAA,EAClD,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO,aAAa,QAAQ,OAAO,aAAa,YAAY,MAAM,QAAQ,QAAQ,IAC9E,SACC;AACP;AAOO,SAAS,gBAAgB,KAAmC;AACjE,QAAM,eAAe,eAAe,GAAG;AACvC,MAAI,iBAAiB,QAAW;AAC9B,WAAO;AAAA,EACT;AACA,aAAW,aAAa,YAAY;AAClC,QAAI,UAAU,SAAS,KAAK,CAAC,SAAS,aAAa,IAAI,IAAI,CAAC,GAAG;AAC7D,YAAM,SAAS,cAAc,GAAG;AAChC,aAAO;AAAA,QACL,MAAM,UAAU;AAAA,QAChB,YAAY,OAAO;AAAA,QACnB,GAAI,OAAO,cAAc,SAAY,CAAC,IAAI,EAAE,eAAe,OAAO,UAAU;AAAA,QAC5E,gBAAgB,UAAU;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGO,IAAM,gBAAgB;AAGtB,IAAM,gBAAgB;AAoBtB,SAAS,YAAY,KAAqB;AAC/C,SAAO,gBAAgB,GAAG,IAAI,gBAAgB;AAChD;AAEA,SAAS,gBAAgB,KAAsB;AAC7C,QAAM,WAAW,WAAW,GAAG;AAC/B,QAAM,UAAU,UAAU;AAC1B,SAAO,YAAY,QAAQ,OAAO,YAAY,YAAY,CAAC,MAAM,QAAQ,OAAO;AAClF;;;AC/NA,IAAAC,kBAAgF;AAChF,IAAAC,oBAAuC;AACvC,IAAAC,mBAAgC;AAChC,IAAAC,gBAUO;AACP,IAAAC,gBAA8B;AAKvB,IAAM,cAAc;AACpB,IAAM,gBAAgB;AACtB,IAAM,iBAAiB;AACvB,IAAMC,YAAW;AAOxB,IAAM,aAAa;AAGnB,IAAM,iBAAiB;AAEvB,IAAM,eAAe;AA+Cd,IAAM,oBAAmC;AAAA,EAC9C,cAAc,CAAC;AAAA,EACf,YAAY;AAAA,EACZ,gBAAgB,CAAC;AAAA,EACjB,OAAO;AACT;AA4CA,IAAM,mBAAsC,CAAC,GAAG,+BAAiB,WAAW,UAAU,UAAU;AAWzF,SAAS,oBAAoB,MAAwB;AAC1D,MAAI;AACJ,MAAI;AACF,kBAAU,6BAAY,IAAI;AAAA,EAC5B,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,QAAQ,oBAAI,IAAY;AAC9B,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,WAAW,OAAO,GAAG;AAC9B;AAAA,IACF;AACA,UAAM,WAAW,MAAM,MAAM,QAAQ,MAAM,EAAE,MAAM,GAAG;AAItD,UAAM,eAAe,SAAS,GAAG,EAAE,MAAM,UAAU,SAAS,MAAM,GAAG,EAAE,IAAI;AAC3E,UAAM,OAAO,aAAa,WAAW,IAAI,aAAa,CAAC,IAAI;AAC3D,QAAI,SAAS,UAAa,KAAC,sCAAuB,IAAI,KAAK,iBAAiB,SAAS,IAAI,GAAG;AAC1F;AAAA,IACF;AACA,UAAM,IAAI,IAAI;AAAA,EAChB;AAGA,SAAO,CAAC,GAAG,KAAK,EAAE,KAAK;AACzB;AAGA,SAAS,UAAU,MAA6C;AAC9D,SAAO,IAAI;AAAA,IACT;AAAA,IACA,OAAO,IAAI;AAAA,IACX,SAAS,WACL,kGACY,iCAAmB,MAC/B;AAAA,EAEN;AACF;AAGA,SAAS,kBAAkB,OAAyB;AAClD,SAAO,MACJ,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC;AACrC;AASO,SAAS,qBAAqB,MAA8C;AACjF,MAAI,SAAS,QAAW;AACtB,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,MAAM,QAAQ,IAAI,IAAK,OAA8B,CAAC,IAAI;AACxE,QAAM,QAAQ,MAAM,QAAQ,CAAC,UAAU,kBAAkB,OAAO,KAAK,CAAC,CAAC;AACvE,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,UAAU,KAAK;AAAA,EACvB;AACA,SAAO,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC;AAC3B;AAGA,SAAS,SAAS,WAAsC;AACtD,SAAO,EAAE,cAAc,UAAU,cAAc,WAAW,CAAC,GAAG,YAAY,UAAU,WAAW;AACjG;AAeA,SAAS,WAAW,MAAsC;AACxD,QAAM,WAAO,wBAAK,MAAM,WAAW;AACnC,MAAI,KAAC,4BAAW,IAAI,GAAG;AACrB,WAAO;AAAA,EACT;AACA,aAAO,8BAAe,IAAI;AAC5B;AAgBO,SAAS,SAAS,MAAc,QAAmB,CAAC,GAAa;AACtE,QAAM,WAAW,WAAW,IAAI;AAChC,QAAM,WAAW,gBAAgB,IAAI;AACrC,QAAM,QAAkB,CAAC;AAEzB,MAAI,aAAa,QAAW;AAC1B,UAAM,KAAK,GAAG,WAAW,8DAAyD;AAAA,EACpF,WAAW,aAAa,QAAW;AACjC,UAAM;AAAA,MACJ,mEAA8D,iCAAmB;AAAA,IACnF;AAAA,EACF,OAAO;AACL,UAAM,KAAK,YAAY,SAAS,IAAI,GAAG;AACvC,QAAI,SAAS,kBAAkB,QAAW;AACxC,YAAM;AAAA,QACJ,GAAG,SAAS,aAAa,mFACD,SAAS,UAAU;AAAA,MAE7C;AAAA,IACF;AAAA,EACF;AAMA,QAAM,aACJ,MAAM,WAAW,SACb,aAAa,aACX,4BAAa,QAAQ,IACpB,UAAU,cAAc,oCAC3B,MAAM,OAAO,KAAK;AACxB,MAAI,MAAM,WAAW,QAAW;AAC9B,QAAI,WAAW,WAAW,GAAG;AAC3B,YAAM,UAAU,QAAQ;AAAA,IAC1B;AAKA,UAAM,YAAQ,kCAAmB,EAAE,cAAc,CAAC,GAAG,WAAW,CAAC,GAAG,WAAW,CAAC,EAAE,CAAC;AACnF,QAAI,UAAU,QAAW;AACvB,YAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,QAAQ,MAAM,UAAU,SAAY,YAAY,IAAI,IAAI,MAAM,MAAM,KAAK;AAC/E,MAAI,MAAM,UAAU,UAAa,MAAM,WAAW,GAAG;AACnD,UAAM,UAAU,OAAO;AAAA,EACzB;AACA,MAAI,CAAC,WAAW,KAAK,KAAK,GAAG;AAC3B,UAAM,IAAI;AAAA,MACR;AAAA,MACA,KAAK,KAAK;AAAA,MACV;AAAA,IAGF;AAAA,EACF;AAKA,MAAI,MAAM,UAAU,UAAa,MAAM,WAAW,cAAc,GAAG;AACjE,UAAM;AAAA,MACJ,QAAQ,YAAY,4CAA4C,KAAK;AAAA,IACvE;AAAA,EACF;AAEA,QAAM,wBAAwB,oBAAoB,IAAI;AACtD,QAAM,eAAe,MAAM,gBAAgB,UAAU,gBAAgB,CAAC;AAItE,MAAI,aAAa,WAAW,GAAG;AAC7B,UAAM;AAAA,MACJ;AAAA,IACF;AACA,QAAI,sBAAsB,SAAS,GAAG;AACpC,YAAM;AAAA,QACJ,+BAA+B,sBAAsB,KAAK,IAAI,CAAC,iDACzC,WAAW;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,MACA,gBAAgB,UAAU,kBAAkB,UAAU,kBAAkB,CAAC;AAAA,MACzE;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAiBO,SAAS,WAAWC,OAA0B;AACnD,QAAM,OAAmB,CAAC;AAC1B,OAAK,KAAK;AAAA,IACR;AAAA,IACAA,MAAK,sBAAsB,WAAW,IAAI,KAAK,IAAIA,MAAK,sBAAsB,KAAK,IAAI,CAAC;AAAA,IACxFA,MAAK,sBAAsB,WAAW,IAClC,wDACA;AAAA,EACN,CAAC;AACD,OAAK,KAAK;AAAA,IACR;AAAA,IACAA,MAAK,UAAU;AAAA,IACfA,MAAK,UAAU,eAAe,oCAAsB,KAAK,aAAa,iCAAmB;AAAA,EAC3F,CAAC;AACD,aAAW,UAAUA,MAAK,UAAU,gBAAgB;AAClD,SAAK,KAAK,CAAC,kBAAkB,QAAQ,EAAE,CAAC;AAAA,EAC1C;AAEA,QAAM,WACJA,MAAK,aAAa,SACd,2CACA,YAAYA,MAAK,SAAS,IAAI;AACpC,SAAO,CAAC,UAAU,IAAI,GAAG,QAAQ,IAAI,GAAG,EAAE;AAC5C;AAEA,SAAS,iBAAiBA,OAAwB;AAChD,SAAOA,MAAK,sBAAsB,WAAW,IACzC,sDACA;AACN;AAUA,eAAsB,mBACpBA,OACA,IACoC;AACpC,aAAW,QAAQ,WAAWA,KAAI,GAAG;AACnC,OAAG,MAAM,IAAI;AAAA,EACf;AAEA,QAAM,UAAU,MAAM,GAAG,IAAI,iBAAiBA,KAAI,CAAC,GAAG,KAAK;AAC3D,QAAM,eACJ,OAAO,WAAW,IACdA,MAAK,wBACL,OAAO,YAAY,MAAM,SACvB,CAAC,IACD,kBAAkB,MAAM;AAGhC,MAAI,OAAO,SAAS,GAAG;AACrB,OAAG,MAAM,EAAE;AACX,OAAG;AAAA,MACD,aAAa,WAAW,IACpB,8DACA,oBAAoB,aAAa,KAAK,IAAI,CAAC;AAAA,IACjD;AACA,OAAG,MAAM,EAAE;AAAA,EACb;AAEA,QAAM,WAAW,MAAM,GAAG,IAAI,iBAAiB,GAAG,KAAK,EAAE,YAAY;AACrE,MAAI,QAAQ,SAAS,KAAK,YAAY,OAAO,YAAY,OAAO;AAC9D,WAAO;AAAA,EACT;AACA,SAAO,EAAE,GAAGA,MAAK,WAAW,aAAa;AAC3C;AAaA,IAAM,oBACJ;AAGF,IAAM,eACJ;AAKK,SAAS,mBAAmB,QAAgC,OAAwB;AACzF,QAAM,OACJ,OAAO,WAAW,IACd,oBACA,OAAO,IAAI,CAAC,UAAU,KAAK,MAAM,GAAG,KAAK,MAAM,IAAI,GAAG,EAAE,KAAK,IAAI;AAEvE,SACE,GAAG,QAAQ,eAAe,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKS,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAO7C;AAOA,SAAS,mBAAmB,WAAkC;AAC5D,QAAM,SACJ;AAEF,MAAI,UAAU,aAAa,WAAW,GAAG;AACvC,WACE,GAAG,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUb;AACA,QAAM,QAAQ,UAAU,aAAa,IAAI,CAAC,SAAS,KAAK,UAAU,IAAI,CAAC,EAAE,KAAK,IAAI;AAClF,QAAM,YAAY,UAAU,aACzB,IAAI,CAAC,SAAS,OAAO,KAAK,UAAU,IAAI,CAAC;AAAA,CAA6B,EACtE,KAAK,EAAE;AACV,SACE,GAAG,MAAM,oBAAoB,KAAK;AAAA;AAAA;AAAA;AAAA,EAGf,SAAS;AAAA;AAEhC;AAGO,SAAS,mBAAmB,WAAkC;AACnE,MAAI,OAAO,mBAAmB,SAAS;AAIvC,MAAI,UAAU,eAAe,mCAAqB;AAChD,YACE;AAAA;AAAA;AAAA,gBAEiB,KAAK,UAAU,UAAU,UAAU,CAAC;AAAA;AAAA,EACzD;AACA,MAAI,UAAU,eAAe,SAAS,GAAG;AACvC,UAAM,WAAW,UAAU,eAAe,IAAI,CAAC,WAAW,KAAK,UAAU,MAAM,CAAC,EAAE,KAAK,IAAI;AAC3F,YACE;AAAA;AAAA;AAAA;AAAA,qBAGsB,QAAQ;AAAA;AAAA,EAClC;AAEA,SAAO;AAAA;AAAA;AAAA,EAAkF,IAAI;AAAA;AAC/F;AAWO,SAAS,gBAAgB,WAAkC;AAChE,QAAM,aAAS,gCAAiB,SAAS,SAAS,CAAC;AACnD,QAAM,SAAS,WAAW,SAAY,KAAK,GAAG,MAAM;AACpD,SACE;AAAA,mCACoC,MAAM;AAAA;AAAA;AAAA;AAAA,EAIvC,WAAW,SAAY,KAAK,IAAI,MAAM;AAAA,CAAI;AAAA;AAGjD;AAUA,SAAS,WAAW,QAAgB,OAAuB;AACzD,MAAI,IAAI;AACR,aAAS;AACP,UAAM,KAAK,OAAO,OAAO,CAAC;AAC1B,QAAI,OAAO,OAAO,OAAO,OAAQ,OAAO,QAAQ,OAAO,MAAM;AAC3D,WAAK;AACL;AAAA,IACF;AACA,QAAI,OAAO,OAAO,OAAO,OAAO,IAAI,CAAC,MAAM,KAAK;AAC9C,YAAM,MAAM,OAAO,QAAQ,MAAM,CAAC;AAClC,UAAI,QAAQ,KAAK,OAAO,SAAS,MAAM;AACvC;AAAA,IACF;AACA,QAAI,OAAO,OAAO,OAAO,OAAO,IAAI,CAAC,MAAM,KAAK;AAC9C,YAAM,MAAM,OAAO,QAAQ,MAAM,IAAI,CAAC;AACtC,UAAI,QAAQ,KAAK,OAAO,SAAS,MAAM;AACvC;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAGA,SAAS,YAAY,QAAgB,OAAuB;AAC1D,MAAI,IAAI,QAAQ;AAChB,SAAO,IAAI,OAAO,QAAQ;AACxB,UAAM,KAAK,OAAO,OAAO,CAAC;AAC1B,QAAI,OAAO,MAAM;AACf,WAAK;AACL;AAAA,IACF;AACA,QAAI,OAAO,KAAK;AACd,aAAO,IAAI;AAAA,IACb;AACA,SAAK;AAAA,EACP;AACA,SAAO,OAAO;AAChB;AAGA,SAAS,aAAa,QAAgB,OAAuB;AAC3D,QAAM,OAAO,OAAO,OAAO,KAAK;AAChC,QAAM,QAAQ,SAAS,MAAM,MAAM;AACnC,MAAI,QAAQ;AACZ,MAAI,IAAI;AACR,SAAO,IAAI,OAAO,QAAQ;AACxB,UAAM,KAAK,OAAO,OAAO,CAAC;AAC1B,QAAI,OAAO,KAAK;AACd,UAAI,YAAY,QAAQ,CAAC;AACzB;AAAA,IACF;AACA,QAAI,OAAO,QAAQ,OAAO,OAAO,IAAI,CAAC,MAAM,OAAO,OAAO,OAAO,IAAI,CAAC,MAAM,MAAM;AAChF,UAAI,WAAW,QAAQ,CAAC;AACxB;AAAA,IACF;AACA,QAAI,OAAO,MAAM;AACf,eAAS;AACT,WAAK;AACL;AAAA,IACF;AACA,QAAI,OAAO,OAAO;AAChB,eAAS;AACT,WAAK;AACL,UAAI,UAAU,GAAG;AACf,eAAO;AAAA,MACT;AACA;AAAA,IACF;AACA,SAAK;AAAA,EACP;AACA,SAAO,OAAO;AAChB;AAEA,SAAS,WAAW,QAAgB,OAAuB;AACzD,QAAM,KAAK,OAAO,OAAO,KAAK;AAC9B,MAAI,OAAO,KAAK;AACd,WAAO,YAAY,QAAQ,KAAK;AAAA,EAClC;AACA,MAAI,OAAO,OAAO,OAAO,KAAK;AAC5B,WAAO,aAAa,QAAQ,KAAK;AAAA,EACnC;AACA,MAAI,IAAI;AACR,SAAO,IAAI,OAAO,QAAQ;AACxB,UAAM,IAAI,OAAO,OAAO,CAAC;AACzB,QAAI,MAAM,OAAO,MAAM,OAAO,MAAM,OAAO,MAAM,MAAM;AACrD,aAAO;AAAA,IACT;AACA,SAAK;AAAA,EACP;AACA,SAAO,OAAO;AAChB;AAOA,SAAS,WAAW,QAAgB,MAAc,KAAiC;AACjF,QAAM,QAAQ,aAAa,QAAQ,IAAI,IAAI;AAC3C,MAAI,IAAI,WAAW,QAAQ,OAAO,CAAC;AACnC,SAAO,IAAI,OAAO;AAChB,QAAI,OAAO,OAAO,CAAC,MAAM,KAAK;AAC5B,aAAO;AAAA,IACT;AACA,UAAM,SAAS,YAAY,QAAQ,CAAC;AACpC,UAAM,OAAO,OAAO,MAAM,IAAI,GAAG,SAAS,CAAC;AAC3C,UAAM,QAAQ,WAAW,QAAQ,MAAM;AACvC,QAAI,OAAO,OAAO,KAAK,MAAM,KAAK;AAChC,aAAO;AAAA,IACT;AACA,UAAM,aAAa,WAAW,QAAQ,QAAQ,CAAC;AAC/C,UAAM,WAAW,WAAW,QAAQ,UAAU;AAC9C,QAAI,SAAS,KAAK;AAChB,aAAO,EAAE,WAAW;AAAA,IACtB;AACA,QAAI,OAAO,WAAW,QAAQ,QAAQ;AACtC,QAAI,OAAO,OAAO,IAAI,MAAM,KAAK;AAC/B,aAAO,WAAW,QAAQ,OAAO,CAAC;AAAA,IACpC;AACA,QAAI;AAAA,EACN;AACA,SAAO;AACT;AAGA,SAAS,WAAW,QAAgB,OAAuB;AACzD,QAAM,YAAY,OAAO,YAAY,MAAM,KAAK,IAAI;AACpD,QAAM,QAAQ,UAAU,KAAK,OAAO,MAAM,WAAW,KAAK,CAAC;AAC3D,SAAO,QAAQ,CAAC,KAAK;AACvB;AAGA,SAAS,WAAW,QAAwB;AAC1C,QAAM,QAAQ,cAAc,KAAK,MAAM;AACvC,SAAO,QAAQ,CAAC,KAAK;AACvB;AAEA,SAAS,aAAa,QAAgB,MAAc,QAAgB,MAAsB;AACxF,QAAM,eAAe,WAAW,QAAQ,IAAI;AAC5C,QAAM,cAAc,eAAe;AACnC,QAAM,QAAQ,aAAa,QAAQ,IAAI,IAAI;AAC3C,MAAI,WAAW,QAAQ,OAAO,CAAC,MAAM,OAAO;AAC1C,WAAO,GAAG,OAAO,MAAM,GAAG,OAAO,CAAC,CAAC;AAAA,EAAK,WAAW,GAAG,MAAM;AAAA,EAAK,YAAY,GAAG,OAAO,MAAM,KAAK,CAAC;AAAA,EACrG;AACA,SAAO,GAAG,OAAO,MAAM,GAAG,OAAO,CAAC,CAAC;AAAA,EAAK,WAAW,GAAG,MAAM,IAAI,OAAO,MAAM,OAAO,CAAC,CAAC;AACxF;AAEA,SAAS,WAAW,MAAc,QAAgB,OAA0B;AAC1E,SAAO,IAAI;AAAA,IACT;AAAA,IACA,yBAAyB,KAAK,mCAAmC,IAAI;AAAA,IACrE,wDAAwD,KAAK,QAAQ,MAAM;AAAA,EAC7E;AACF;AA2BO,SAAS,eACd,QACA,SAAiB,mCACjB,OAAe,eACJ;AACX,QAAM,QAAQ,IAAI,IAAI,QAAQ,MAAM;AACpC,QAAM,OAAO,WAAW,QAAQ,CAAC;AACjC,MAAI,OAAO,OAAO,IAAI,MAAM,KAAK;AAC/B,UAAM,WAAW,sCAAsC,QAAQ,IAAI;AAAA,EACrE;AAEA,QAAM,OAAO,WAAW,MAAM;AAC9B,QAAM,kBAAkB,WAAW,QAAQ,MAAM,iBAAiB;AAClE,MAAI,oBAAoB,QAAW;AACjC,WAAO;AAAA,MACL,QAAQ,aAAa,QAAQ,MAAM,mCAAmC,KAAK,QAAQ,IAAI;AAAA,MACvF,SAAS;AAAA,IACX;AAAA,EACF;AACA,MAAI,OAAO,OAAO,gBAAgB,UAAU,MAAM,KAAK;AACrD,UAAM,WAAW,sCAAsC,QAAQ,IAAI;AAAA,EACrE;AAEA,QAAM,QAAQ,WAAW,QAAQ,gBAAgB,YAAY,OAAO;AACpE,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,MACL,QAAQ,aAAa,QAAQ,gBAAgB,YAAY,cAAc,KAAK,MAAM,IAAI;AAAA,MACtF,SAAS;AAAA,IACX;AAAA,EACF;AACA,MAAI,OAAO,OAAO,MAAM,UAAU,MAAM,KAAK;AAC3C,UAAM,WAAW,4CAA4C,QAAQ,IAAI;AAAA,EAC3E;AAEA,QAAM,WAAW,WAAW,QAAQ,MAAM,YAAY,IAAI;AAC1D,MAAI,aAAa,QAAW;AAE1B,UAAM,SAAS,OAAO,MAAM,SAAS,YAAY,WAAW,QAAQ,SAAS,UAAU,CAAC;AACxF,WAAO,OAAO,SAAS,IAAI,MAAM,GAAG,IAChC,EAAE,QAAQ,SAAS,MAAM,IACzB,EAAE,QAAQ,SAAS,OAAO,UAAU,OAAO,KAAK,EAAE;AAAA,EACxD;AACA,SAAO,EAAE,QAAQ,aAAa,QAAQ,MAAM,YAAY,OAAO,IAAI,GAAG,SAAS,KAAK;AACtF;AAYO,SAAS,mBAAmB,QAAgB,QAAgB,MAAyB;AAC1F,QAAM,QAAQ,IAAI,IAAI,SAAS,MAAM;AACrC,QAAM,OAAO,WAAW,QAAQ,CAAC;AACjC,MAAI,OAAO,OAAO,IAAI,MAAM,KAAK;AAC/B,UAAM,WAAW,sCAAsC,QAAQ,IAAI;AAAA,EACrE;AAEA,QAAM,OAAO,WAAW,MAAM;AAC9B,QAAM,UAAU,WAAW,QAAQ,MAAM,SAAS;AAClD,MAAI,YAAY,QAAW;AACzB,WAAO,EAAE,QAAQ,aAAa,QAAQ,MAAM,gBAAgB,KAAK,MAAM,IAAI,GAAG,SAAS,KAAK;AAAA,EAC9F;AACA,MAAI,OAAO,OAAO,QAAQ,UAAU,MAAM,KAAK;AAC7C,UAAM,WAAW,8BAA8B,QAAQ,IAAI;AAAA,EAC7D;AAEA,QAAM,WAAW,WAAW,QAAQ,QAAQ,YAAY,IAAI;AAC5D,MAAI,aAAa,QAAW;AAC1B,UAAM,SAAS,OAAO,MAAM,SAAS,YAAY,WAAW,QAAQ,SAAS,UAAU,CAAC;AACxF,WAAO,OAAO,SAAS,MAAM,MAAM,GAAG,IAClC,EAAE,QAAQ,SAAS,MAAM,IACzB,EAAE,QAAQ,SAAS,OAAO,UAAU,OAAO,KAAK,EAAE;AAAA,EACxD;AACA,SAAO,EAAE,QAAQ,aAAa,QAAQ,QAAQ,YAAY,OAAO,IAAI,GAAG,SAAS,KAAK;AACxF;AAEA,SAAS,eAAe,QAAgB,OAAuB;AAC7D,SAAO;AAAA;AAAA,kBAA8C,KAAK,QAAQ,MAAM;AAAA;AAAA;AAAA;AAC1E;AAMO,SAAS,cAAc,MAAwB;AACpD,QAAM,UAAM,2BAAQ,MAAMD,SAAQ;AAClC,UAAI,4BAAW,GAAG,GAAG;AACnB,WAAO,EAAE,QAAQ,YAAY,QAAQ,QAAQ,MAAM,SAASA,SAAQ,IAAI;AAAA,EAC1E;AACA,iCAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAClC,SAAO,EAAE,QAAQ,YAAY,QAAQ,WAAW,MAAM,WAAWA,SAAQ,IAAI;AAC/E;AAQO,SAAS,gBACd,MACA,QACA,OACA,YAA2B,mBACjB;AACV,QAAM,WAAO,wBAAK,MAAM,GAAG,UAAU,WAAW,MAAM,GAAG,CAAC;AAC1D,UAAI,4BAAW,IAAI,GAAG;AACpB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,MAAM,QAAQ,UAAU,UAAU;AAAA,MAClC,MAAM;AAAA,IACR;AAAA,EACF;AACA,qCAAU,2BAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5C,qCAAc,MAAM,mBAAmB,QAAQ,KAAK,GAAG,MAAM;AAC7D,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,MAAM,aAAa,UAAU,UAAU;AAAA,IACvC,MAAM,QAAQ,gDAA2C;AAAA,EAC3D;AACF;AAEO,SAAS,gBACd,MACA,YAA2B,mBACjB;AACV,QAAM,WAAO,wBAAK,MAAM,WAAW;AACnC,UAAI,4BAAW,IAAI,GAAG;AACpB,WAAO,EAAE,QAAQ,UAAU,QAAQ,QAAQ,MAAM,QAAQ,WAAW,GAAG;AAAA,EACzE;AACA,qCAAc,MAAM,mBAAmB,SAAS,GAAG,MAAM;AACzD,SAAO,EAAE,QAAQ,UAAU,QAAQ,WAAW,MAAM,aAAa,WAAW,GAAG;AACjF;AAEO,SAAS,mBACd,MACA,YAA2B,mBACjB;AACV,QAAM,QAAQ,UAAU;AAKxB,QAAM,UAAU,MAAM,WAAW,cAAc;AAC/C,QAAM,WAAO,wBAAK,MAAM,UAAU,eAAe,aAAa;AAC9D,QAAM,QAAQ,UAAU,eAAe;AAEvC,MAAI,KAAC,4BAAW,IAAI,GAAG;AAIrB,QAAI,SAAS;AACX,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,MAAM,MAAM,YAAY,eAAe,KAAK;AAAA,QAC5C,MAAM,qEAAqE,aAAa;AAAA,MAC1F;AAAA,IACF;AACA,uCAAc,MAAM,eAAe,UAAU,YAAY,KAAK,GAAG,MAAM;AACvE,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,MAAM,WAAW,aAAa,aAAa,KAAK;AAAA,IAClD;AAAA,EACF;AAEA,QAAM,aAAS,8BAAa,MAAM,MAAM;AACxC,QAAM,OAAO,UACT,mBAAmB,QAAQ,UAAU,YAAY,KAAK,IACtD,eAAe,QAAQ,UAAU,YAAY,KAAK;AAEtD,MAAI,KAAK,aAAa,QAAW;AAC/B,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,MAAM,GAAG,KAAK,iBAAiB,KAAK,OAAO,KAAK,QAAQ;AAAA,MACxD,MAAM,6CAAwC,KAAK,sBAAsB,UAAU,UAAU;AAAA,IAC/F;AAAA,EACF;AACA,MAAI,CAAC,KAAK,SAAS;AACjB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,MAAM,YAAY,KAAK,aAAa,KAAK;AAAA,IAC3C;AAAA,EACF;AACA,qCAAc,MAAM,KAAK,QAAQ,MAAM;AACvC,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,MAAM,SAAS,KAAK,aAAa,KAAK;AAAA,EACxC;AACF;AAOO,SAAS,eACd,MACA,YAA2B,mBACjB;AACV,QAAM,WAAO,wBAAK,MAAMA,WAAU,cAAc;AAChD,QAAME,YAAW,GAAGF,SAAQ,IAAI,cAAc;AAC9C,QAAM,SAAS,gBAAgB,SAAS;AACxC,QAAM,eAAW,4BAAW,IAAI,QAAI,8BAAa,MAAM,MAAM,IAAI;AACjE,MAAI,aAAa,QAAQ;AACvB,WAAO,EAAE,QAAQ,aAAa,QAAQ,QAAQ,MAAM,QAAQE,SAAQ,GAAG;AAAA,EACzE;AACA,qCAAU,wBAAK,MAAMF,SAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AACnD,qCAAc,MAAM,QAAQ,MAAM;AAClC,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ,aAAa,SAAY,YAAY;AAAA,IAC7C,MAAM,GAAG,aAAa,SAAY,YAAY,SAAS,IAAIE,SAAQ;AAAA,EACrE;AACF;AAGO,SAAS,SACd,MACA,QACA,OACA,YAA2B,mBACf;AACZ,SAAO;AAAA,IACL,cAAc,IAAI;AAAA,IAClB,gBAAgB,MAAM,QAAQ,OAAO,SAAS;AAAA,IAC9C,gBAAgB,MAAM,SAAS;AAAA,IAC/B,mBAAmB,MAAM,SAAS;AAAA,IAClC,eAAe,MAAM,SAAS;AAAA,EAChC;AACF;AAEO,SAAS,QAAQ,SAAkC;AACxD,QAAM,WAAO,2BAAQ,QAAQ,GAAG;AAChC,QAAM,YAAY,QAAQ,aAAa,SAAS,IAAI,EAAE;AACtD,SAAO,EAAE,MAAM,WAAW,OAAO,SAAS,MAAM,CAAC,GAAG,OAAO,SAAS,EAAE;AACxE;AAEO,SAAS,WAAWC,SAA8B;AACvD,QAAM,QAAgBA,QAAO,MAAM,IAAI,CAAC,SAAS;AAI/C,UAAM,QAAQ,KAAK,WAAW,eAAe,OAAO;AACpD,WAAO,KAAK,SAAS,SACjB,EAAE,OAAO,MAAM,KAAK,KAAK,IACzB,EAAE,OAAO,MAAM,KAAK,MAAM,MAAM,KAAK,KAAK;AAAA,EAChD,CAAC;AACD,SAAO;AAAA,IACL,GAAG,YAAY,KAAK;AAAA,IACpB;AAAA,IACA,oCAAoCA,QAAO,UAAU,UAAU;AAAA,IAC/D,GAAIA,QAAO,UAAU,aAAa,WAAW,IACzC;AAAA,MACE,qCAAqC,WAAW;AAAA,IAElD,IACA,CAAC;AAAA,EACP;AACF;AAGA,eAAe,SAASF,OAAoD;AAC1E,QAAM,SAAK,kCAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAC3E,MAAI;AACF,WAAO,MAAM,mBAAmBA,OAAM;AAAA,MACpC,KAAK,CAAC,aAAa,GAAG,SAAS,QAAQ;AAAA,MACvC,OAAO,CAAC,SAAS,QAAQ,OAAO,MAAM,GAAG,IAAI;AAAA,CAAI;AAAA,IACnD,CAAC;AAAA,EACH,UAAE;AACA,OAAG,MAAM;AAAA,EACX;AACF;AAEO,IAAM,kBAAc,6BAAc;AAAA,EACvC,MAAM,EAAE,MAAM,QAAQ,aAAa,4DAA4D;AAAA,EAC/F,MAAM;AAAA,IACJ,KAAK;AAAA,MACH,MAAM;AAAA,MACN,aACE;AAAA,IAEJ;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa,2DAA2D,iCAAmB;AAAA,IAC7F;AAAA,IACA,OAAO;AAAA,MACL,MAAM;AAAA,MACN,aACE;AAAA,IAEJ;AAAA,IACA,KAAK;AAAA,MACH,MAAM;AAAA,MACN,aACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAM,WAAO,2BAAQ,QAAQ,IAAI,CAAC;AAClC,YAAM,eAAe,qBAAqB,KAAK,GAAG;AAClD,YAAMA,QAAO,SAAS,MAAM;AAAA,QAC1B,GAAI,KAAK,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,KAAK,OAAO;AAAA,QAC3D,GAAI,KAAK,UAAU,SAAY,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM;AAAA,QACxD,GAAI,iBAAiB,SAAY,CAAC,IAAI,EAAE,aAAa;AAAA,MACvD,CAAC;AAID,YAAM,QAAQ,QAAQ,MAAM,UAAU,QAAQ,KAAK,QAAQ,QAAQ,iBAAiB;AACpF,YAAM,YAAY,QAAQ,MAAM,SAASA,KAAI,IAAIA,MAAK;AACtD,UAAI,cAAc,QAAW;AAC3B,cAAM,CAAC,gEAAgE,CAAC;AACxE;AAAA,MACF;AACA,UAAI,CAAC,OAAO;AACV,cAAM,CAAC,GAAGA,MAAK,OAAO,EAAE,CAAC;AAAA,MAC3B;AACA,YAAM,WAAW,QAAQ,EAAE,KAAK,MAAM,UAAU,CAAC,CAAC,CAAC;AAAA,IACrD,CAAC;AAAA,EACH;AACF,CAAC;;;AFz+BD,IAAM,gBAAgB;AAGtB,IAAM,iBAAiB;AACvB,IAAM,QAAQ;AAGd,IAAM,WAAW;AACjB,IAAM,aAAa;AAOnB,SAAS,UAAU,OAAuB;AACxC,MAAI,SAAS,KAAK,KAAK,GAAG;AACxB,WAAO;AAAA,EACT;AACA,MAAI,kBAAkB,KAAK,KAAK,GAAG;AACjC,WAAO;AAAA,EACT;AACA,MAAI,MAAM,KAAK,MAAM,MAAM,OAAO,SAAS,OAAO,KAAK,CAAC,GAAG;AACzD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGO,SAAS,YAAY,SAAgD;AAC1E,SAAO,QACJ,IAAI,CAAC,UAAU;AACd,UAAM,UAAM,8BAAW,+BAAgB,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG;AAC3D,WAAO;AAAA,MACL,KAAK,WAAW,KAAK,GAAG,IAAI,MAAM,KAAK,UAAU,GAAG;AAAA,MACpD,MAAM,UAAU,MAAM,KAAK;AAAA,IAC7B;AAAA,EACF,CAAC,EACA,KAAK,CAAC,GAAG,MAAO,EAAE,MAAM,EAAE,MAAM,KAAK,EAAE,MAAM,EAAE,MAAM,IAAI,CAAE;AAChE;AAMA,SAAS,iBAAiB,KAAmB,UAAwB;AACnE,MAAI,CAAC,IAAI,KAAK,SAAS,GAAG,GAAG;AAC3B;AAAA,EACF;AACA,QAAM,IAAI;AAAA,IACR;AAAA,IACA,gBAAgB,QAAQ,4BAA4B,IAAI,IAAI;AAAA,IAC5D,wCAAwC,QAAQ;AAAA,EAClD;AACF;AAeA,SAAS,kBACP,KACA,UACA,OACA,QACM;AACN,UAAI,+BAAgB,IAAI,MAAM,MAAM,GAAG;AACrC,UAAM,IAAI,iCAAmB,aAAa,UAAU,KAAK;AAAA,EAC3D;AACF;AAaA,SAAS,iBAAiB,KAAmB,UAAkB,QAA0B;AACvF,UAAI,iCAAkB,QAAQ,GAAG;AAC/B;AAAA,EACF;AAIA,UAAI,4BAAa,KAAK,MAAM,MAAM,UAAU;AAC1C;AAAA,EACF;AACA,QAAM,gBAAY,4BAAa,KAAK,MAAM;AAC1C,QAAM,IAAI;AAAA,IACR;AAAA,IACA,gBAAgB,QAAQ,4BAA4B,IAAI,IAAI,4BAA4B,SAAS;AAAA,IACjG,iCAAiC,SAAS,wCACtB,QAAQ,wHACyB,IAAI,IAAI,OAAO,QAAQ;AAAA,EAE9E;AACF;AAEA,SAAS,aAAa,MAA+B,QAA0B;AAC7E,QAAM,aAAS,mCAAoB,MAAM,MAAM;AAC/C,QAAM,QAAQ,OAAO,CAAC;AACtB,MAAI,UAAU,QAAW;AACvB,UAAM;AAAA,EACR;AACF;AAWA,SAAS,eAAe,SAAiB,QAA4B;AACnE,MAAI,OAAO,aAAa,SAAS,OAAO,GAAG;AACzC,WAAO;AAAA,EACT;AACA,QAAM,IAAI,sCAAwB,SAAS,OAAO,YAAY;AAChE;AAYA,SAAS,kBAAkB,MAAc,QAA2B;AAClE,QAAM,WAAO,4BAAS,IAAI;AAC1B,QAAM,WAAW,KAAK,MAAM,GAAG;AAC/B,QAAM,QAAQ,SAAS,QAAQ,cAAc;AAC7C,MAAI,UAAU,IAAI;AAChB,WAAO,EAAE,MAAM,WAAW;AAAA,EAC5B;AAEA,QAAM,OAAO,SAAS,MAAM,QAAQ,CAAC,EAAE,OAAO,CAAC,YAAY,QAAQ,SAAS,CAAC;AAC7E,QAAM,QAAQ,KAAK,CAAC;AACpB,QAAM,SAAS,KAAK,CAAC;AAErB,MAAI,UAAU,QAAW;AACvB,WAAO,EAAE,MAAM,WAAW;AAAA,EAC5B;AAEA,MAAI,WAAW,QAAW;AACxB,QAAI,UAAU,OAAO;AACnB,aAAO,EAAE,MAAM,MAAM;AAAA,IACvB;AACA,WAAO,EAAE,MAAM,eAAe,aAAa,eAAe,OAAO,MAAM,EAAE;AAAA,EAC3E;AAEA,MAAI,KAAK,WAAW,KAAK,WAAW,SAAS,UAAU,OAAO;AAC5D,WAAO,EAAE,MAAM,qBAAqB,aAAa,eAAe,OAAO,MAAM,EAAE;AAAA,EACjF;AAKA,MAAI,UAAU,SAAS,KAAK,WAAW,GAAG;AACxC,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA,mEAA8D,MAAM,IAAI,KAAK,oDACjC,KAAK,IAAI,MAAM,mDAClC,MAAM,IAAI,KAAK;AAAA,IAC1C;AAAA,EACF;AAEA,QAAM,IAAI;AAAA,IACR;AAAA,IACA,KAAK,KAAK,KAAK,SAAS,CAAC,UAAU,KAAK,MAAM;AAAA,IAC9C;AAAA,EAEF;AACF;AASA,SAAS,cAAc,OAAkC;AACvD,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AAAA,IACL,KAAK;AACH,aAAO,MAAM;AAAA,IACf,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,iBAAO,2BAAY,OAAO,OAAO;AAAA,EACrC;AACF;AAgBA,SAAS,qBAAqB,OAAc,aAA4B;AACtE,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO,EAAE,MAAM,eAAe,YAAY;AAAA,IAC5C,KAAK;AACH,aAAO,EAAE,MAAM,qBAAqB,YAAY;AAAA,IAClD,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,iBAAO,2BAAY,OAAO,OAAO;AAAA,EACrC;AACF;AAaA,SAAS,oBAAoB,SAAwB,QAAgB,QAA4B;AAC/F,QAAM,QAAQ,QAAQ,aAAa,KAAK,KAAK;AAC7C,MAAI,MAAM,SAAS,GAAG;AACpB,WAAO;AAAA,EACT;AACA,QAAM,IAAI;AAAA,IACR;AAAA,IACA,+BAA+B,MAAM;AAAA,IACrC,sCAAiC,OAAO,aAAa,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,kEAC/B,MAAM;AAAA,EAE/D;AACF;AAQA,SAAS,wBACP,SACA,UACA,QACM;AACN,MAAI,YAAY,UAAa,aAAa,UAAa,YAAY,UAAU;AAC3E;AAAA,EACF;AACA,QAAM,IAAI;AAAA,IACR;AAAA,IACA,YAAY,MAAM,6BAA6B,OAAO,iBAAiB,QAAQ,YAAY,QAAQ;AAAA,IACnG,4BAA4B,MAAM,OAAO,OAAO,kBAAkB,OAAO,mFACP,QAAQ;AAAA,EAE5E;AACF;AA4BA,SAAS,iBAAiB,MAAc,UAAkD;AACxF,MAAI,aAAa,UAAa,SAAS,KAAK,EAAE,SAAS,GAAG;AACxD,WAAO,SAAS,KAAK;AAAA,EACvB;AACA,QAAM,eAAW,4BAAS,IAAI,EAAE,MAAM,GAAG;AACzC,QAAM,QAAQ,SAAS,QAAQ,cAAc;AAC7C,MAAI,UAAU,IAAI;AAChB,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,SAAS,MAAM,QAAQ,CAAC,EAAE,OAAO,CAAC,YAAY,QAAQ,SAAS,CAAC,EAAE,CAAC;AACjF,SAAO,UAAU,UAAa,UAAU,QAAQ,SAAY;AAC9D;AAiCA,SAAS,YAAY,QAAoB,KAA4B;AACnE,SAAO;AAAA,IACL,cAAc,OAAO;AAAA,IACrB,gBAAY,4BAAa,MAAM;AAAA,IAC/B,gBAAgB,OAAO,kBAAkB,CAAC;AAAA,IAC1C,OAAO,YAAY,GAAG;AAAA,EACxB;AACF;AAEA,SAAS,eAAe,KAAa,aAA2C;AAC9E,QAAM,eAAW,8BAAe,GAAG;AACnC,MAAI,aAAa,QAAW;AAC1B,UAAM,aAAS,8BAAe,QAAQ;AACtC,WAAO,EAAE,QAAQ,WAAW,YAAY,QAAQ,GAAG,EAAE;AAAA,EACvD;AAIA,QAAM,UAAU,SAAS,GAAG,EAAE;AAC9B,QAAM,YAA2B;AAAA,IAC/B,GAAG;AAAA,IACH,cAAc,gBAAgB,SAAY,QAAQ,eAAe,CAAC,WAAW;AAAA,EAC/E;AACA,kBAAgB,KAAK,SAAS;AAC9B,SAAO,EAAE,QAAQ,YAAY,GAAG,EAAE,QAAQ,UAAU;AACtD;AA0BO,SAAS,aAAa,SAAsC;AACjE,QAAM,UAAM,2BAAQ,QAAQ,GAAG;AAC/B,QAAM,WAAO,8BAAW,QAAQ,IAAI,IAAI,QAAQ,WAAO,2BAAQ,KAAK,QAAQ,IAAI;AAChF,MAAI,KAAC,4BAAW,IAAI,GAAG;AACrB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,uBAAuB,IAAI;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAS,+BAAY,8BAAa,MAAM,MAAM,CAAC;AACrD,QAAM,EAAE,QAAQ,UAAU,IAAI,eAAe,KAAK,iBAAiB,MAAM,QAAQ,WAAW,CAAC;AAC7F,QAAM,SAASG,aAAY,KAAK,IAAI;AAEpC,QAAM,QAAQ,kBAAkB,MAAM,MAAM;AAC5C,QAAM,UAAU,cAAc,KAAK;AAGnC,QAAM,WACJ,QAAQ,gBAAgB,SAAY,SAAY,oBAAoB,SAAS,QAAQ,MAAM;AAC7F,0BAAwB,SAAS,UAAU,MAAM;AAIjD,QAAM,QACJ,aAAa,SAAY,QAAQ,qBAAqB,OAAO,eAAe,UAAU,MAAM,CAAC;AAK/F,QAAM,kBAAc,iCAAkB,QAAQ,YAAY,OAAO;AAEjE,QAAM,OAAuB,CAAC;AAC9B,aAAW,SAAS,OAAO,SAAS;AAClC,UAAM,UAAM,+BAAgB,MAAM,GAAG;AACrC,qBAAiB,KAAK,MAAM,GAAG;AAC/B,sBAAkB,KAAK,MAAM,KAAK,QAAQ,MAAM;AAChD,qBAAiB,KAAK,MAAM,KAAK,MAAM;AACvC,SAAK,KAAK,GAAG;AAAA,EACf;AACA,eAAa,MAAM,MAAM;AAKzB,QAAM,QAAQ,SAAS,KAAK,YAAY,OAAO,OAAO,GAAG,MAAM,SAAS;AACxE,QAAM,UAAU,YAAY,GAAG;AAC/B,QAAM,OAAO,UAAU,OAAO;AAE9B,aAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACrD,UAAM,MAAM,KAAK,KAAK;AACtB,QAAI,QAAQ,QAAW;AACrB;AAAA,IACF;AACA,SAAK;AAAA,MACH,EAAE,WAAW,IAAI,WAAW,MAAM,IAAI,MAAM,OAAO,WAAW,MAAM;AAAA,MACpE,MAAM;AAAA,IACR;AAGA,QAAI,MAAM,gBAAgB,QAAW;AACnC,YAAM,WAAW,KAAK,aAAa,GAAG;AACtC,YAAM,OAAa,EAAE,GAAG,UAAU,aAAa,MAAM,YAAY;AACjE,WAAK,cAAc,KAAK,IAAI;AAAA,IAC9B;AAAA,EACF;AAEA,QAAM,SAAS,GAAG,IAAI,GAAG,aAAa;AACtC,oCAAa,MAAM,MAAM;AAEzB,SAAO;AAAA,IACL,MAAM,QAAQ;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,OAAO;AAAA,IACrB,WAAW,OAAO,QAAQ;AAAA,IAC1B,gBAAgB,OAAO;AAAA,IACvB;AAAA,EACF;AACF;AAEA,SAASA,aAAY,MAAc,MAAsB;AACvD,QAAM,UAAM,4BAAS,MAAM,IAAI;AAC/B,SAAO,QAAQ,MAAM,IAAI,WAAW,IAAI,IAAI,OAAO,IAAI,MAAM,IAAI,EAAE,KAAK,GAAG;AAC7E;AAeA,SAAS,eAAe,MAAgB,WAAyB;AAC/D,QAAM,SAAS,cAAc,IAAI,cAAc;AAC/C,SAAO;AAAA,IACL,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMP,MAAM,KAAK;AAAA,IACX,MAAM,iBAAY,SAAS,aAAa,MAAM;AAAA,EAChD;AACF;AAUA,SAAS,sBAAsB,cAAuC;AACpE,QAAM,UAAU,aAAa,CAAC,KAAK;AACnC,SAAO;AAAA,IACL,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM,wDAAmD,OAAO;AAAA,EAClE;AACF;AAEO,SAAS,aACdC,SACA,YACU;AACV,QAAM,QAAgB,CAAC,EAAE,OAAO,OAAO,MAAM,SAASA,QAAO,SAAS,aAAa,CAAC;AAIpF,MAAIA,QAAO,iBAAiB,GAAG;AAC7B,UAAM,SAASA,QAAO,mBAAmB,IAAI,YAAY;AACzD,UAAM,KAAK;AAAA,MACT,OAAO;AAAA,MACP,MAAM,WAAWA,QAAO,cAAc,WAAW,MAAM;AAAA,MACvD,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AAEA,aAAW,QAAQA,QAAO,OAAO;AAC/B,QAAI,KAAK,WAAW,YAAY,KAAK,WAAW,QAAQ;AACtD,YAAM,KAAK,eAAe,MAAMA,QAAO,SAAS,CAAC;AACjD;AAAA,IACF;AAGA,UAAM,QAAQ,KAAK,WAAW,eAAe,OAAO;AACpD,UAAM;AAAA,MACJ,KAAK,SAAS,SACV,EAAE,OAAO,MAAM,KAAK,KAAK,IACzB,EAAE,OAAO,MAAM,KAAK,MAAM,MAAM,KAAK,KAAK;AAAA,IAChD;AAAA,EACF;AACA,QAAM,KAAK,EAAE,OAAO,OAAO,MAAM,WAAWD,aAAYC,QAAO,MAAMA,QAAO,MAAM,CAAC,GAAG,CAAC;AAEvF,QAAM,QAAQ,YAAY,KAAK;AAC/B,MAAI,eAAe,QAAW;AAC5B,UAAM,KAAK,GAAG,YAAY,CAAC,sBAAsBA,QAAO,YAAY,CAAC,CAAC,CAAC;AAAA,EACzE,WAAW,WAAW,IAAI;AACxB,UAAM,KAAK,GAAG,YAAY,CAAC,EAAE,OAAO,OAAO,MAAM,0BAA0B,CAAC,CAAC,CAAC;AAAA,EAChF,OAAO;AACL,UAAM,KAAK,GAAG,eAAe,UAAU,CAAC;AAAA,EAC1C;AAEA,QAAM,KAAK,IAAI,2CAA2C;AAC1D,SAAO;AACT;AAEO,IAAM,oBAAgB,8BAAc;AAAA,EACzC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,UAAU;AAAA,MACV,aAAa;AAAA,IACf;AAAA,IACA,KAAK;AAAA,MACH,MAAM;AAAA,MACN,aACE;AAAA,IAEJ;AAAA,EACF;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAM,MAAM,QAAQ,IAAI;AACxB,YAAM,SAAS,aAAa;AAAA,QAC1B;AAAA,QACA,MAAM,KAAK;AAAA,QACX,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,MAC5D,CAAC;AAID,YAAM,aACJ,OAAO,gBAAgB,SACnB,SACA,MAAM,YAAY,EAAE,KAAK,aAAa,OAAO,YAAY,CAAC;AAChE,YAAM,aAAa,QAAQ,UAAU,CAAC;AAAA,IACxC,CAAC;AAAA,EACH;AACF,CAAC;;;AGpsBD,yBAA4B;AAE5B,IAAAC,gBAAuD;AACvD,IAAAC,iBAA8B;;;ACL9B,IAAAC,sBAA8B;AAf9B;AAyBA,IAAI;AAEJ,SAAS,mBAAqC;AAC5C,MAAI,WAAW,QAAW;AACxB,UAAMC,eAAU,mCAAc,YAAY,GAAG;AAC7C,aAAUA,SAAQ,kBAAkB,EAAkC;AAAA,EACxE;AACA,SAAO;AACT;AAQO,IAAM,kBAA4B;AAAA,EACvC,YAAY,SAAS,SAAS;AAC5B,UAAM,QAAQ,iBAAiB;AAC/B,WAAO,IAAI,MAAM,SAAS,OAAO,EAAE,YAAY;AAAA,EACjD;AAAA,EACA,YAAY,SAAS,SAAS,UAAU;AACtC,UAAM,QAAQ,iBAAiB;AAC/B,QAAI,MAAM,SAAS,OAAO,EAAE,YAAY,QAAQ;AAAA,EAClD;AACF;;;ADLA,SAAS,UAAU,IAAoB;AACrC,SAAO,YAAY,GAAG,QAAQ,iBAAiB,GAAG,EAAE,YAAY,CAAC;AACnE;AAEO,SAAS,aAAa,SAA4C;AACvE,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,cAAc,kBAAkB,SAAS,QAAQ,WAAW;AAElE,QAAM,WAAW,QAAQ,OAAO,OAAO,WAAW;AAClD,MAAI,aAAa,QAAW;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,MACA,eAAe,WAAW;AAAA,MAC1B,gEACe,WAAW,2BAA2B,WAAW;AAAA,IAClE;AAAA,EACF;AAEA,QAAM,UAAM,gCAAY,uBAAS,EAAE,SAAS,QAAQ;AAEpD,MAAI,SAAS,WAAW,YAAY;AAClC,UAAM,WAAW,QAAQ,YAAY;AACrC,QAAI,QAAQ,UAAU,MAAM;AAG1B,UAAI;AACJ,UAAI;AACF,mBAAW,SAAS,YAAY,gCAAkB,SAAS,EAAE;AAAA,MAC/D,SAAS,OAAO;AACd,cAAM,IAAI;AAAA,UACR;AAAA,UACA,uEAAuE,SAAS,EAAE;AAAA,UAClF,4DAA4D,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QACpH;AAAA,MACF;AACA,UAAI,aAAa,MAAM;AACrB,cAAM,IAAI;AAAA,UACR;AAAA,UACA,eAAe,WAAW,wBAAwB,SAAS,EAAE;AAAA,UAC7D;AAAA,QAGF;AAAA,MACF;AAAA,IACF;AACA,aAAS,YAAY,gCAAkB,SAAS,IAAI,GAAG;AACvD,WAAO,EAAE,QAAQ,YAAY,aAAa,IAAI,SAAS,GAAG;AAAA,EAC5D;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,IACA,IAAI,SAAS;AAAA,IACb,UAAU,UAAU,SAAS,EAAE;AAAA,IAC/B;AAAA,EACF;AACF;AAEO,SAAS,gBAAgBC,SAAmC;AACjE,MAAIA,QAAO,WAAW,YAAY;AAChC,WAAO;AAAA,MACL,6BAA6BA,QAAO,WAAW,qCAAqCA,QAAO,EAAE;AAAA,MAC7F;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL,6BAA6BA,QAAO,WAAW;AAAA,IAC/C;AAAA,IACA,KAAKA,QAAO,QAAQ,IAAIA,QAAO,GAAG;AAAA,IAClC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,IAAM,iBAAa,8BAAc;AAAA,EACtC,MAAM,EAAE,MAAM,OAAO,aAAa,4BAA4B;AAAA,EAC9D,aAAa;AAAA,IACX,YAAQ,8BAAc;AAAA,MACpB,MAAM,EAAE,MAAM,UAAU,aAAa,oCAAoC;AAAA,MACzE,MAAM;AAAA,QACJ,KAAK,EAAE,MAAM,UAAU,aAAa,iCAAiC;AAAA,QACrE,OAAO;AAAA,UACL,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,MACF;AAAA,MACA,IAAI,EAAE,KAAK,GAAG;AACZ,eAAO,MAAM,YAAY;AACvB;AAAA,YACE;AAAA,cACE,aAAa;AAAA,gBACX,KAAK,QAAQ,IAAI;AAAA,gBACjB,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,gBAC1D,GAAI,KAAK,UAAU,SAAY,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM;AAAA,cAC1D,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AACF,CAAC;;;AE9ID,IAAAC,gBAAsD;AACtD,IAAAC,iBAA8B;AAgC9B,SAASC,YAAW,OAAsB;AACxC,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO,MAAM;AAAA,IACf,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,GAAG,MAAM,WAAW;AAAA,IAC7B,KAAK;AACH,aAAO;AAAA,IACT;AACE,iBAAO,2BAAY,OAAO,OAAO;AAAA,EACrC;AACF;AAEA,eAAsB,QAAQ,SAA2C;AACvE,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,cAAc,kBAAkB,SAAS,QAAQ,WAAW;AAElE,QAAM,OAAO,aAAa,SAAS,WAAW;AAC9C,QAAM,aAA0B,CAAC;AAGjC,aAAW,cAAc,UAAM,0BAAW,aAAa,QAAQ,UAAU,IAAI,GAAG;AAC9E,UAAM,SAAS,WAAW;AAC1B,UAAM,QAAQ,QAAQ,KAAK;AAC3B,eAAW,KAAK;AAAA,MACd,WAAW,WAAW;AAAA,MACtB,cAAU,4BAAa,WAAW,KAAK,QAAQ,MAAM;AAAA,MACrD,OAAO,UAAU,SAAY,WAAWA,YAAW,KAAK;AAAA,MACxD,UAAU,QAAQ;AAAA,MAClB,WAAW,QAAQ,KAAK,cAAc;AAAA,MACtC,qBAAqB,WAAW;AAAA,IAClC,CAAC;AAAA,EACH;AAEA,SAAO,EAAE,aAAa,WAAW;AACnC;AAEO,SAAS,WAAWC,SAA8B;AACvD,MAAIA,QAAO,WAAW,WAAW,GAAG;AAClC,WAAO,CAAC,oBAAoB,QAAQ,qBAAqBA,QAAO,WAAW,GAAG;AAAA,EAChF;AACA,SAAO,QAAQA,QAAO,WAAW,IAAI,CAAC,UAAU,CAAC,MAAM,WAAW,MAAM,OAAO,MAAM,QAAQ,CAAC,CAAC;AACjG;AAEO,IAAM,kBAAc,8BAAc;AAAA,EACvC,MAAM,EAAE,MAAM,QAAQ,aAAa,kBAAkB;AAAA,EACrD,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,UAAU,aAAa,qCAAqC;AAAA,IACzE,MAAM,EAAE,MAAM,WAAW,aAAa,8BAA8B;AAAA,EACtE;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAMA,UAAS,MAAM,QAAQ;AAAA,QAC3B,KAAK,QAAQ,IAAI;AAAA,QACjB,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,MAC5D,CAAC;AACD,YAAM,KAAK,SAAS,OAAO,CAAC,KAAK,UAAUA,SAAQ,MAAM,CAAC,CAAC,IAAI,WAAWA,OAAM,CAAC;AAAA,IACnF,CAAC;AAAA,EACH;AACF,CAAC;;;AC7ED,IAAAC,gBAQO;AACP,IAAAC,iBAA8B;AA6B9B,SAASC,eAAc,MAAqC;AAC1D,QAAM,QAAQ,KAAK;AACnB,SAAO,MAAM,SAAS,iBAAiB,MAAM,SAAS,sBAClD,MAAM,cACN;AACN;AAkBA,eAAe,SACb,SACA,QACA,QACA,WAC8B;AAC9B,QAAM,SAAS,MAAM,QAAQ,SAAS,KAAK,MAAM;AACjD,MAAI,WAAW,QAAW;AACxB,WAAO;AAAA,EACT;AACA,MAAI,CAAC,OAAO,WAAW;AACrB,WAAO,EAAE,QAAQ,QAAQ,UAAU,QAAQ,UAAU,MAAM;AAAA,EAC7D;AAKA,QAAM,cAAcA,eAAc,MAAM;AACxC,MAAI,gBAAgB,QAAW;AAC7B,UAAM,IAAI;AAAA,MACR;AAAA,MACA,GAAG,QAAQ,QAAI,+BAAgB,MAAM,CAAC;AAAA,MACtC;AAAA,IAEF;AAAA,EACF;AAEA,QAAM,OAAO,aAAa,SAAS,WAAW;AAC9C,QAAM,aAAS,yBAAU,QAAQ,QAAQ,IAAI;AAC7C,MAAI,OAAO,SAAS,UAAU;AAC5B,UAAM,IAAI;AAAA,MACR;AAAA,MACA,GAAG,QAAQ,QAAI,+BAAgB,MAAM,CAAC,0EAA0E,OAAO,QAAQ,MAAM;AAAA,MACrI;AAAA,IAEF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,cAAU,yBAAU,QAAQ,OAAO,OAAO,MAAM,WAAW,WAAW;AAAA,IACtE,UAAU;AAAA,EACZ;AACF;AAGA,SAAS,QAAQ,KAA2B,KAAgC;AAC1E,QAAM,SAAK,2BAAY,GAAG;AAC1B,SAAO,IAAI,OAAO,CAAC,aAAS,2BAAY,IAAI,MAAM,EAAE;AACtD;AAEA,eAAsB,QAAQ,SAA2C;AACvE,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,OAAO,WAAW,QAAQ,MAAM,QAAQ,MAAM;AACpD,oBAAkB,QAAQ,EAAE;AAC5B,QAAM,KAAK,WAAW,QAAQ,IAAI,QAAQ,MAAM;AAEhD,UAAI,2BAAY,IAAI,UAAM,2BAAY,EAAE,GAAG;AACzC,UAAM,IAAI;AAAA,MACR;AAAA,MACA,KAAK,QAAQ,IAAI,YAAY,QAAQ,EAAE;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,MAAM,MAAM,QAAQ,SAAS,KAAK;AACxC,QAAM,UAAU,QAAQ,KAAK,IAAI;AACjC,QAAM,OAAyB,MAAM,QAAQ,SAAS,SAAS,IAAI;AAEnE,MAAI,QAAQ,WAAW,KAAK,SAAS,QAAW;AAC9C,UAAM,IAAI;AAAA,MACR;AAAA,MACA,iBAAa,2BAAY,IAAI,CAAC;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AAKA,QAAMC,YAAW,QAAQ,KAAK,EAAE;AAChC,MAAIA,UAAS,SAAS,KAAM,MAAM,QAAQ,SAAS,SAAS,EAAE,MAAO,QAAW;AAC9E,UAAM,IAAI;AAAA,MACR;AAAA,MACA,iBAAa,2BAAY,EAAE,CAAC;AAAA,MAC5B,wBAAoB,2BAAY,EAAE,CAAC,sBAAsB,QAAQ,EAAE;AAAA,IACrE;AAAA,EACF;AAKA,QAAM,UAAqB,CAAC;AAC5B,aAAW,UAAU,SAAS;AAC5B,UAAM,SAAoB,EAAE,GAAG,QAAQ,WAAW,GAAG,WAAW,MAAM,GAAG,KAAK;AAC9E,UAAM,MAAM,MAAM,SAAS,SAAS,QAAQ,YAAQ,2BAAY,EAAE,CAAC;AACnE,QAAI,QAAQ,QAAW;AACrB,cAAQ,KAAK,GAAG;AAAA,IAClB;AAAA,EACF;AAEA,aAAW,QAAQ,SAAS;AAC1B,UAAM,QAAQ,SAAS,MAAM,KAAK,QAAQ,KAAK,QAAQ;AAAA,EACzD;AACA,MAAI,SAAS,QAAW;AACtB,UAAM,QAAQ,SAAS,UAAU,IAAI,IAAI;AAAA,EAC3C;AAKA,aAAW,QAAQ,SAAS;AAC1B,UAAM,QAAQ,SAAS,OAAO,KAAK,MAAM;AAAA,EAC3C;AACA,MAAI,SAAS,QAAW;AACtB,UAAM,QAAQ,SAAS,WAAW,IAAI;AAAA,EACxC;AAEA,SAAO;AAAA,IACL,UAAM,2BAAY,IAAI;AAAA,IACtB,QAAI,2BAAY,EAAE;AAAA,IAClB,OAAO,QAAQ,IAAI,CAAC,UAAU;AAAA,MAC5B,UAAM,+BAAgB,KAAK,MAAM;AAAA,MACjC,QAAI,+BAAgB,KAAK,MAAM;AAAA,MAC/B,UAAU,KAAK;AAAA,IACjB,EAAE;AAAA;AAAA;AAAA;AAAA,IAIF,MAAM,SAAS,SAAY,aAAY,8BAAe,EAAE,GAAG,IAAI,QAAQ,OAAO,CAAC;AAAA,IAC/E,QAAQ,EAAE,SAAK,0BAAW,IAAI,EAAE,KAAK,GAAG,GAAG,SAAK,0BAAW,EAAE,EAAE,KAAK,GAAG,EAAE;AAAA,EAC3E;AACF;AAEO,SAAS,WAAWC,SAA8B;AACvD,QAAM,OAAcA,QAAO,MAAM,IAAI,CAAC,UAAU;AAAA,IAC9C,OAAO;AAAA,IACP,OAAO;AAAA,IACP,SAAS,GAAG,QAAQ,IAAI,KAAK,EAAE;AAAA,IAC/B,GAAI,KAAK,WAAW,EAAE,QAAQ,gCAAgC,IAAI,CAAC;AAAA,EACrE,EAAE;AACF,MAAIA,QAAO,SAAS,QAAW;AAC7B,SAAK,KAAK,EAAE,OAAO,OAAO,OAAO,SAAS,SAAS,GAAG,QAAQ,IAAIA,QAAO,IAAI,GAAG,CAAC;AAAA,EACnF;AAEA,QAAM,QAAQ,WAAW,IAAI;AAI7B,QAAM;AAAA,IACJ;AAAA,IACA,mCAAmCA,QAAO,OAAO,GAAG,sBAAsBA,QAAO,OAAO,GAAG;AAAA,IAC3F;AAAA,EACF;AACA,SAAO;AACT;AAEO,IAAM,gBAAY,8BAAc;AAAA,EACrC,MAAM,EAAE,MAAM,MAAM,aAAa,uDAAuD;AAAA,EACxF,MAAM;AAAA,IACJ,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,UAAU;AAAA,MACV,aAAa;AAAA,IACf;AAAA,IACA,IAAI;AAAA,MACF,MAAM;AAAA,MACN,UAAU;AAAA,MACV,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAM,WAAW,MAAM,QAAQ,EAAE,KAAK,QAAQ,IAAI,GAAG,MAAM,KAAK,MAAM,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;AAAA,IACvF,CAAC;AAAA,EACH;AACF,CAAC;;;ACpPD,IAAAC,iBAA8B;AAkC9B,eAAsB,QAAQ,SAA2C;AACvE,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,cAAc,kBAAkB,SAAS,QAAQ,WAAW;AAClE,QAAM,SAAS,MAAM,kBAAkB,SAAS,WAAW;AAK3D,MAAI,OAAO,SAAS,iBAAiB;AACnC,WAAO,EAAE,aAAa,QAAQ,OAAO,MAAM,aAAa,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,EAAE;AAAA,EAC5F;AAEA,QAAM,OAAO,UAAU,OAAO;AAC9B,QAAM,QAAQ,MAAM,OAAO,KAAK;AAEhC,MAAI,SAAS;AACb,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,MAAM,OAAO,KAAK,IAAI;AAGpC,QAAI,UAAU,QAAW;AACvB;AAAA,IACF;AAGA,SAAK,UAAU,MAAM,KAAK;AAC1B,cAAU;AAAA,EACZ;AAIA,QAAM,OAAO,SAAS,KAAK;AAC3B,MAAI,OAAO;AACX,aAAW,OAAO,MAAM;AACtB,UAAM,QAA0B,MAAM,OAAO,SAAS,GAAG;AACzD,QAAI,UAAU,QAAW;AACvB;AAAA,IACF;AACA,SAAK,cAAc,KAAK,KAAK;AAC7B,YAAQ;AAAA,EACV;AAEA,SAAO,EAAE,aAAa,QAAQ,OAAO,MAAM,aAAa,OAAO,QAAQ,MAAM,MAAM,KAAK,OAAO;AACjG;AAEO,SAAS,WAAWC,SAA8B;AACvD,MAAIA,QAAO,aAAa;AACtB,WAAO,WAAW;AAAA,MAChB;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAAS,eAAeA,QAAO,WAAW;AAAA,QAC1C,QAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO,WAAW;AAAA,IAChB;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS,GAAGA,QAAO,MAAM,IAAIA,QAAO,WAAW,IAAI,UAAU,QAAQ;AAAA,MACrE,QAAQ,YAAYA,QAAO,MAAM,6BAA6BA,QAAO,WAAW;AAAA,IAClF;AAAA,IACA;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS,GAAGA,QAAO,IAAI,IAAIA,QAAO,SAAS,IAAI,cAAc,YAAY,KAAKA,QAAO,IAAI;AAAA,MACzF,QAAQ;AAAA,IACV;AAAA,EACF,CAAC;AACH;AAEO,IAAM,kBAAc,8BAAc;AAAA,EACvC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,UAAU,aAAa,0BAA0B;AAAA,EAChE;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAMA,UAAS,MAAM,QAAQ;AAAA,QAC3B,KAAK,QAAQ,IAAI;AAAA,QACjB,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,MAC5D,CAAC;AACD,YAAM,WAAWA,OAAM,CAAC;AAAA,IAC1B,CAAC;AAAA,EACH;AACF,CAAC;;;ACtID,IAAAC,gBAAgC;AAChC,IAAAC,iBAA8B;AAkB9B,eAAsB,UAAU,SAA+C;AAC7E,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,MAAM,WAAW,QAAQ,GAAG;AAIlC,QAAM,QAAQ,YAAY,SAAS,SAAS,QAAQ,GAAG;AAGvD,QAAM,QAAqB,CAAC,OAAO,IAAI,EAAE,IAAI,CAAC,eAAe;AAAA,IAC3D,WAAW,IAAI;AAAA,IACf,MAAM,IAAI;AAAA,IACV;AAAA,IACA;AAAA,EACF,EAAE;AAEF,QAAM,UAAoB,CAAC;AAC3B,aAAW,QAAQ,OAAO;AACxB,QAAK,MAAM,QAAQ,SAAS,KAAK,IAAI,MAAO,QAAW;AACrD;AAAA,IACF;AACA,UAAM,QAAQ,SAAS,OAAO,IAAI;AAClC,YAAQ,SAAK,+BAAgB,IAAI,CAAC;AAAA,EACpC;AAEA,SAAO;AAAA,IACL,WAAW,QAAQ;AAAA,IACnB;AAAA,IACA,YAAY,MAAM,IAAI,CAAC,aAAS,+BAAgB,IAAI,CAAC;AAAA,EACvD;AACF;AAEO,SAAS,aAAaC,SAAgC;AAC3D,MAAIA,QAAO,QAAQ,WAAW,GAAG;AAC/B,UAAM,QAAQA,QAAO,WAAW,CAAC,KAAKA,QAAO;AAC7C,WAAO,WAAW;AAAA,MAChB;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAAS,GAAG,QAAQ,IAAI,KAAK;AAAA,QAC7B,QAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH;AACA,QAAM,OAAcA,QAAO,QAAQ,IAAI,CAAC,cAAc;AAAA,IACpD,OAAO;AAAA,IACP,OAAO;AAAA,IACP,SAAS,GAAG,QAAQ,IAAI,QAAQ;AAAA,EAClC,EAAE;AACF,SAAO,WAAW,IAAI;AACxB;AAEO,IAAM,oBAAgB,8BAAc;AAAA,EACzC,MAAM,EAAE,MAAM,UAAU,aAAa,qBAAqB;AAAA,EAC1D,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,cAAc,UAAU,MAAM,aAAa,qCAAqC;AAAA,IAC7F,KAAK,EAAE,MAAM,UAAU,aAAa,gCAAgC;AAAA,IACpE,OAAO;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB;AAAA,QACE;AAAA,UACE,MAAM,UAAU;AAAA,YACd,KAAK,QAAQ,IAAI;AAAA,YACjB,KAAK,KAAK;AAAA,YACV,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,YAC1D,GAAI,KAAK,UAAU,SAAY,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM;AAAA,UAC1D,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF,CAAC;;;ACpED,IAAAC,gBAMO;AACP,IAAAC,iBAA8B;AA4D9B,SAAS,aAAa,KAAmB,aAAgC;AACvE,SAAO;AAAA,IACL,WAAW,IAAI;AAAA,IACf,MAAM,IAAI;AAAA,IACV,OAAO,EAAE,MAAM,eAAe,YAAY;AAAA,IAC1C,WAAW;AAAA,EACb;AACF;AAoBA,eAAe,kBACb,SACA,UACA,KACA,aACA,OACe;AACf,MAAI,SAAS,SAAS,iBAAiB;AACrC,UAAM,eAAe;AAAA,MACnB;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,EAAE,MAAM,eAAe,YAAY;AAAA,MAC1C;AAAA,MACA;AAAA,IACF,CAAC;AACD;AAAA,EACF;AACA,QAAM,SAAS,MAAM,aAAa,KAAK,WAAW,GAAG,KAAK;AAC5D;AAGA,SAAS,gBAAgB,OAA2B,OAAoB,KAAqB;AAC3F,MAAI,UAAU,QAAW;AACvB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,KAAK,KAAK,gBAAgB,GAAG;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAcA,SAAS,iBAAiB,UAAoB,aAAwC;AACpF,MAAI,KAAC,+BAAgB,QAAQ,GAAG;AAC9B,UAAM,IAAI;AAAA,MACR;AAAA,MACA,sGAAsG,SAAS,IAAI,+BAA+B,WAAW;AAAA,MAC7J;AAAA,IAEF;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,UAAU,SAA+C;AAC7E,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,cAAc,kBAAkB,SAAS,QAAQ,WAAW;AAClE,QAAM,MAAM,WAAW,QAAQ,KAAK,QAAQ,MAAM;AAClD,QAAM,WAAW,MAAM,kBAAkB,SAAS,WAAW;AAE7D,QAAM,SAAS,QAAQ,QAAO,oBAAI,KAAK,GAAE,YAAY;AACrD,QAAM,SAA2B,MAAM,SAAS,SAAS,GAAG;AAC5D,QAAM,EAAE,UAAU,QAAI,0BAAW,QAAQ,WAAW;AAEpD,MAAI,cAAc,QAAW;AAC3B,UAAM,IAAI;AAAA,MACR;AAAA,MACA,aAAa,QAAQ,GAAG,mDAAmD,WAAW;AAAA,MACtF;AAAA,IAEF;AAAA,EACF;AAEA,QAAM,QAAQ,QAAQ,UAAU;AAChC,QAAM,WAAW,QAAQ,aAAa;AAMtC,MAAI,cAAc,kBAAkB;AAClC,QAAI,SAAS,UAAU;AACrB,YAAM,IAAI;AAAA,QACR;AAAA,QACA,aAAa,QAAQ,GAAG;AAAA,QACxB;AAAA,MAEF;AAAA,IACF;AACA,UAAM,QAAQ,gBAAgB,QAAQ,OAAO,WAAW,QAAQ,GAAG;AAKnE,UAAM,kBAAkB,SAAS,UAAU,KAAK,aAAa,KAAK;AAClE,UAAMC,aAAQ,gCAAiB,QAAQ,aAAa,MAAM;AAC1D,UAAM,SAAS,UAAU,KAAKA,MAAK;AACnC,WAAO,OAAO,KAAK,aAAa,WAAW,WAAW,SAAS,MAAM,MAAMA,MAAK;AAAA,EAClF;AAIA,QAAM,YAAY,iBAAiB,UAAU,WAAW;AAExD,MAAI,UAAU,UAAU;AACtB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,4BAA4B,QAAQ,GAAG;AAAA,MACvC;AAAA,IAEF;AAAA,EACF;AAEA,MAAI,OAAO;AACT,UAAM,QAAQ,gBAAgB,QAAQ,OAAO,SAAS,QAAQ,GAAG;AAOjE,UAAM,kBAAkB,SAAS,WAAW,KAAK,aAAa,KAAK;AACnE,UAAMA,aAAQ,6BAAc,QAAQ,aAAa,MAAM;AACvD,UAAM,UAAU,UAAU,KAAKA,MAAK;AACpC,WAAO,OAAO,KAAK,aAAa,WAAW,SAAS,UAAU,MAAM,MAAMA,MAAK;AAAA,EACjF;AAKA,QAAM,YAAQ,gCAAiB,QAAQ,aAAa,MAAM;AAC1D,QAAM,UAAU,UAAU,KAAK,KAAK;AACpC,SAAO,OAAO,KAAK,aAAa,WAAW,YAAY,UAAU,MAAM,OAAO,KAAK;AACrF;AAGA,SAAS,OACP,KACA,aACA,WACA,OACA,QACA,YACA,OACc;AACd,QAAM,EAAE,OAAO,eAAe,YAAY,QAAI,0BAAW,OAAO,WAAW;AAC3E,SAAO;AAAA,IACL,WAAW,CAAC,GAAG,IAAI,WAAW,IAAI,IAAI,EAAE,KAAK,GAAG;AAAA,IAChD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,aAAaC,SAAgC;AAC3D,MAAIA,QAAO,UAAU,SAAS;AAC5B,WAAO,WAAW;AAAA,MAChB;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAASA,QAAO;AAAA,QAChB,QAAQ,0CAA0CA,QAAO,WAAW,WAAWA,QAAO,aAAa;AAAA,MACrG;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAAS;AAAA,QACT,QAAQ,UAAUA,QAAO,MAAM,iCAAiCA,QAAO,SAAS;AAAA,MAClF;AAAA,IACF,CAAC;AAAA,EACH;AACA,MAAIA,QAAO,UAAU,YAAY;AAC/B,WAAO,WAAW;AAAA,MAChB;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAASA,QAAO;AAAA,QAChB,QAAQ,4CAA4CA,QAAO,WAAW,eAAeA,QAAO,WAAW;AAAA,MACzG;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO,WAAW;AAAA,IAChB;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAASA,QAAO;AAAA,MAChB,QAAQ,uCAAuCA,QAAO,WAAW,eAAeA,QAAO,WAAW;AAAA,IACpG;AAAA,EACF,CAAC;AACH;AAEO,IAAM,oBAAgB,8BAAc;AAAA,EACzC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,cAAc,UAAU,MAAM,aAAa,qCAAqC;AAAA,IAC7F,OAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU;AAAA,MACV,aAAa;AAAA,IACf;AAAA,IACA,KAAK,EAAE,MAAM,UAAU,aAAa,+BAA+B;AAAA,IACnE,OAAO,EAAE,MAAM,WAAW,aAAa,oDAAoD;AAAA,IAC3F,UAAU,EAAE,MAAM,WAAW,aAAa,kCAAkC;AAAA,EAC9E;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AAGvB,YAAM,QAAQ,KAAK,aAAa,OAAO,SAAa,KAAK,SAAU,MAAM,UAAU;AACnF;AAAA,QACE;AAAA,UACE,MAAM,UAAU;AAAA,YACd,KAAK,QAAQ,IAAI;AAAA,YACjB,KAAK,KAAK;AAAA,YACV,GAAI,UAAU,SAAY,CAAC,IAAI,EAAE,MAAM;AAAA,YACvC,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,YAC1D,GAAI,KAAK,UAAU,SAAY,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM;AAAA,YACxD,GAAI,KAAK,aAAa,SAAY,CAAC,IAAI,EAAE,UAAU,KAAK,SAAS;AAAA,UACnE,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF,CAAC;;;AChVD,IAAAC,kBAAkC;AAClC,IAAAC,oBAA2C;AAC3C,IAAAC,gBAA+C;AAC/C,IAAAC,iBAA8B;AAa9B,IAAM,cAAc;AA6Bb,SAAS,SAAS,SAAoC;AAG3D,QAAM,UAAU,YAAY,QAAQ,GAAG;AACvC,QAAM,iBAAa,4BAAS,QAAQ,UAAU;AAC9C,QAAM,aAAa,QAAQ,cAAc;AAEzC,QAAM,WAAW,oBAAI,IAAe;AACpC,MAAI;AACJ,MAAI,UAAU;AACd,MAAI,UAAU;AACd,MAAI,SAAS;AAEb,iBAAe,WAA0B;AACvC,QAAI,QAAQ;AACV;AAAA,IACF;AAGA,QAAI,SAAS;AACX,gBAAU;AACV;AAAA,IACF;AACA,cAAU;AACV,QAAI;AACF,YAAMC,UAAS,MAAM,YAAY;AAAA,QAC/B,KAAK,QAAQ;AAAA,QACb,GAAI,QAAQ,gBAAgB,SAAY,CAAC,IAAI,EAAE,aAAa,QAAQ,YAAY;AAAA,MAClF,CAAC;AACD,UAAI,CAAC,QAAQ;AACX,gBAAQ,WAAWA,OAAM;AAAA,MAC3B;AAAA,IACF,SAAS,OAAO;AAId,UAAI,CAAC,QAAQ;AACX,gBAAQ,UAAU,KAAK;AAAA,MACzB;AAAA,IACF,UAAE;AACA,gBAAU;AACV,UAAI,WAAW,CAAC,QAAQ;AACtB,kBAAU;AACV,aAAK,SAAS;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,WAAS,WAAiB;AACxB,QAAI,QAAQ;AACV;AAAA,IACF;AACA,QAAI,UAAU,QAAW;AACvB,mBAAa,KAAK;AAAA,IACpB;AACA,YAAQ,WAAW,MAAM;AACvB,cAAQ;AACR,WAAK,SAAS;AAAA,IAChB,GAAG,UAAU;AAAA,EACf;AAEA,WAAS,KAAK,SAA0B;AACtC,aAAS,OAAO,OAAO;AACvB,YAAQ,MAAM;AAAA,EAChB;AAYA,WAAS,YAAY,QAAgB,WAAoB,MAAqB;AAC5E,UAAM,aAAS,2BAAQ,MAAM;AAC7B,UAAM,WAAO,4BAAS,MAAM;AAC5B,QAAI;AAEJ,QAAI;AACF,qBAAW,uBAAM,QAAQ,EAAE,WAAW,MAAM,GAAG,CAAC,QAAQ,aAAa;AACnE,YAAI,UAAU,aAAa,QAAW;AACpC;AAAA,QACF;AAGA,YAAI,KAAC,4BAAW,MAAM,GAAG;AACvB,eAAK,QAAQ;AACb;AAAA,QACF;AACA,YAAI,aAAa,YAAQ,4BAAS,QAAQ,MAAM,MAAM;AACpD;AAAA,QACF;AACA,YAAI,KAAC,4BAAW,MAAM,GAAG;AACvB;AAAA,QACF;AACA,aAAK,QAAQ;AACb,mBAAW,QAAQ,WAAW,IAAI;AAClC,iBAAS;AAAA,MACX,CAAC;AAAA,IACH,SAAS,OAAO;AACd,cAAQ,UAAU,KAAK;AACvB;AAAA,IACF;AAEA,aAAS,GAAG,SAAS,CAAC,UAAU;AAC9B,UAAI,CAAC,QAAQ;AACX,gBAAQ,UAAU,KAAK;AAAA,MACzB;AAAA,IACF,CAAC;AACD,aAAS,IAAI,QAAQ;AAAA,EACvB;AAQA,WAAS,WAAW,QAAgB,WAAoB,MAAqB;AAC3E,QAAI;AAEJ,UAAM,SAAS,CAAC,qBACd,uBAAM,QAAQ,EAAE,WAAW,aAAa,GAAG,CAAC,QAAQ,aAAa;AAC/D,UAAI,QAAQ;AACV;AAAA,MACF;AAWA,UAAI,KAAC,4BAAW,MAAM,GAAG;AACvB,YAAI,YAAY,QAAW;AACzB,eAAK,OAAO;AAAA,QACd;AACA,oBAAY,QAAQ,WAAW,IAAI;AACnC,iBAAS;AACT;AAAA,MACF;AAIA,UAAI,SAAS,WAAc,aAAa,YAAQ,4BAAS,QAAQ,MAAM,OAAO;AAC5E;AAAA,MACF;AACA,eAAS;AAAA,IACX,CAAC;AAEH,QAAI;AACF,gBAAU,OAAO,SAAS;AAAA,IAC5B,SAAS,OAAO;AACd,UAAI,CAAC,WAAW;AACd,gBAAQ,UAAU,KAAK;AACvB;AAAA,MACF;AACA,UAAI;AACF,kBAAU,OAAO,KAAK;AAAA,MACxB,SAAS,eAAe;AACtB,gBAAQ,UAAU,aAAa;AAC/B;AAAA,MACF;AAAA,IACF;AACA,YAAQ,GAAG,SAAS,CAAC,UAAU;AAC7B,UAAI,CAAC,QAAQ;AACX,gBAAQ,UAAU,KAAK;AAAA,MACzB;AAAA,IACF,CAAC;AACD,aAAS,IAAI,OAAO;AAAA,EACtB;AAEA,aAAW,QAAQ,SAAS,IAAI;AAChC,iBAAW,2BAAQ,QAAQ,UAAU,GAAG,OAAO,UAAU;AAMzD,UAAI,gCAAiB,QAAQ,MAAM,MAAM,QAAW;AAClD,UAAM,iBAAa,2BAAQ,QAAQ,UAAM,4BAAa,QAAQ,MAAM,CAAC;AACrE,mBAAW,2BAAQ,UAAU,GAAG,WAAO,4BAAS,UAAU,CAAC;AAAA,EAC7D;AAIA,OAAK,SAAS;AAEd,SAAO;AAAA,IACL,QAAc;AACZ,eAAS;AACT,UAAI,UAAU,QAAW;AACvB,qBAAa,KAAK;AAClB,gBAAQ;AAAA,MACV;AACA,iBAAW,WAAW,CAAC,GAAG,QAAQ,GAAG;AACnC,aAAK,OAAO;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACF;AAWO,SAAS,YAAYA,SAAkC;AAC5D,SAAO,CAAC,IAAI,GAAG,eAAeA,OAAM,GAAG,GAAG,YAAYA,QAAO,OAAOA,QAAO,WAAW,CAAC;AACzF;AAQO,SAAS,YAAY,OAAoB,aAA+B;AAC7E,QAAM,OAAc;AAAA,IAClB,GAAG,MAAM,SAAS,IAAI,CAAC,UAAU;AAAA,MAC/B,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS,KAAK;AAAA,MACd,QAAQ,KAAK;AAAA,IACf,EAAE;AAAA,IACF,GAAG,MAAM,WAAW,IAAI,CAAC,UAAU;AAAA,MACjC,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS,KAAK;AAAA,MACd,QAAQ;AAAA,IACV,EAAE;AAAA,EACJ;AACA,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,QAAQ,CAAC,IAAI,8BAA8B,WAAW,KAAK,GAAG,WAAW,IAAI,CAAC;AAGpF,aAAW,UAAU,IAAI,IAAI,MAAM,SAAS,IAAI,CAAC,SAAS,KAAK,MAAM,CAAC,GAAG;AACvE,UAAM,KAAK,KAAK,MAAM,EAAE;AAAA,EAC1B;AACA,SAAO;AACT;AAEO,IAAM,mBAAe,8BAAc;AAAA,EACxC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,KAAK,EAAE,MAAM,UAAU,aAAa,8BAA8B;AAAA,EACpE;AAAA,EACA,IAAI,EAAE,KAAK,GAAG;AACZ,WAAO,MAAM,YAAY;AACvB,YAAM,SAAS,SAAS;AAAA,QACtB,KAAK,QAAQ,IAAI;AAAA,QACjB,GAAI,KAAK,QAAQ,SAAY,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI;AAAA,QAC1D,UAAU,CAACA,YAAW;AACpB,gBAAM,YAAYA,OAAM,CAAC;AAAA,QAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMA,SAAS,CAAC,UAAU;AAClB,gBAAM,WAAW,QAAQ;AACzB,sBAAY,KAAK;AACjB,kBAAQ,WAAW;AAAA,QACrB;AAAA,MACF,CAAC;AACD,YAAM,CAAC,qDAAqD,CAAC;AAC7D,YAAM,IAAI,QAAc,CAACC,aAAY;AACnC,gBAAQ,KAAK,UAAU,MAAM;AAC3B,iBAAO,MAAM;AACb,UAAAA,SAAQ;AAAA,QACV,CAAC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF,CAAC;;;AvB9UM,IAAM,WAAO,8BAAc;AAAA,EAChC,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,aAAa;AAAA,IACX,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,KAAK;AAAA,IACL,KAAK;AAAA,IACL,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,IACT,KAAK;AAAA,IACL,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,OAAO;AAAA,EACT;AACF,CAAC;AAEM,SAAS,UAAyB;AAIvC,iCAAY,eAAe;AAC3B,aAAO,eAAAC,SAAa,IAAI;AAC1B;","names":["import_core","import_citty","import_core","import_sink_github","import_citty","import_node_path","import_core","import_provider_filesystem","require","cached","import_core","import_core","import_core","result","import_node_path","import_node_url","import_core","import_citty","result","resolvePath","import_core","import_citty","import_core","import_citty","result","result","import_core","import_citty","skipped","result","import_node_path","import_core","import_citty","result","import_core","import_citty","import_node_fs","import_node_path","import_core","import_citty","import_node_fs","import_node_path","import_core","relative","import_node_fs","import_node_path","import_promises","import_core","import_citty","PENV_DIR","plan","relative","result","displayPath","result","import_core","import_citty","import_node_module","require","result","import_core","import_citty","scopeLabel","result","import_core","import_citty","environmentOf","occupied","result","import_citty","result","import_core","import_citty","result","import_core","import_citty","after","result","import_node_fs","import_node_path","import_core","import_citty","result","resolve","cittyRunMain"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/doctor.ts","../src/project.ts","../src/registry.ts","../src/schema.ts","../src/ui.ts","../src/commands/push.ts","../src/commands/validate.ts","../src/commands/encrypt.ts","../src/commands/set.ts","../src/commands/fill.ts","../src/commands/generate.ts","../src/commands/get.ts","../src/commands/import.ts","../src/detect.ts","../src/commands/init.ts","../src/commands/key.ts","../src/keychain.ts","../src/commands/list.ts","../src/commands/mv.ts","../src/commands/pull.ts","../src/commands/remove.ts","../src/commands/rotate.ts","../src/commands/watch.ts"],"sourcesContent":["/**\n * penv's command line.\n *\n * The wiring here is deliberately thin: every command's real work is a plain\n * exported function that takes a `cwd` and returns a result, and citty only\n * parses arguments, calls it, and prints what it returned. That is what lets the\n * tests call the commands rather than spawn them.\n */\n\nimport { setKeychain } from \"@penvhq/core\";\nimport { runMain as cittyRunMain, defineCommand } from \"citty\";\nimport { doctorCommand } from \"./commands/doctor.js\";\nimport { decryptCommand, encryptCommand } from \"./commands/encrypt.js\";\nimport { fillCommand } from \"./commands/fill.js\";\nimport { generateCommand } from \"./commands/generate.js\";\nimport { getCommand } from \"./commands/get.js\";\nimport { importCommand } from \"./commands/import.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { keyCommand } from \"./commands/key.js\";\nimport { listCommand } from \"./commands/list.js\";\nimport { mvCommand } from \"./commands/mv.js\";\nimport { pullCommand } from \"./commands/pull.js\";\nimport { pushCommand } from \"./commands/push.js\";\nimport { removeCommand } from \"./commands/remove.js\";\nimport { rotateCommand } from \"./commands/rotate.js\";\nimport { setCommand } from \"./commands/set.js\";\nimport { validateCommand } from \"./commands/validate.js\";\nimport { watchCommand } from \"./commands/watch.js\";\nimport { defaultKeychain } from \"./keychain.js\";\n\nexport const main = defineCommand({\n meta: {\n name: \"penv\",\n description: \"Configuration that shares a data model with your production secret manager\",\n },\n subCommands: {\n init: initCommand,\n import: importCommand,\n generate: generateCommand,\n get: getCommand,\n set: setCommand,\n fill: fillCommand,\n mv: mvCommand,\n pull: pullCommand,\n push: pushCommand,\n rotate: rotateCommand,\n remove: removeCommand,\n list: listCommand,\n encrypt: encryptCommand,\n decrypt: decryptCommand,\n key: keyCommand,\n validate: validateCommand,\n doctor: doctorCommand,\n watch: watchCommand,\n },\n});\n\nexport function runMain(): Promise<void> {\n // The CLI is where the keychain is read and written; core stays native-free and\n // the runtime never registers a binding. Idempotent, and the binding is lazy —\n // the native module loads only if a keychain key is actually touched.\n setKeychain(defaultKeychain);\n return cittyRunMain(main);\n}\n\nexport type {\n DoctorCheck,\n DoctorFinding,\n DoctorReport,\n DoctorSeverity,\n} from \"./commands/doctor.js\";\nexport { renderDoctor, runDoctor } from \"./commands/doctor.js\";\nexport type { ResealResult } from \"./commands/encrypt.js\";\nexport { runDecrypt, runEncrypt } from \"./commands/encrypt.js\";\nexport type { FillOptions, FillPrompt, FillResult } from \"./commands/fill.js\";\nexport { renderFill, runFill } from \"./commands/fill.js\";\nexport type { GenerateResult } from \"./commands/generate.js\";\nexport { generateDotenv, runGenerate } from \"./commands/generate.js\";\nexport type { GetExplanation } from \"./commands/get.js\";\nexport { runExplain, runGet } from \"./commands/get.js\";\nexport type { ImportReport } from \"./commands/import.js\";\nexport { importDotenv } from \"./commands/import.js\";\nexport type { InitResult, InitStep } from \"./commands/init.js\";\nexport { insertEnvAlias, runInit } from \"./commands/init.js\";\nexport type { ListResult } from \"./commands/list.js\";\nexport { runList } from \"./commands/list.js\";\nexport type { MoveResult } from \"./commands/mv.js\";\nexport { renderMove, runMove } from \"./commands/mv.js\";\nexport type { PullOptions, PullResult } from \"./commands/pull.js\";\nexport { renderPull, runPull } from \"./commands/pull.js\";\nexport type { PushOptions, PushResult } from \"./commands/push.js\";\nexport { LAST_PUSHED_KEY, renderPush, runPush } from \"./commands/push.js\";\nexport type { RemoveResult } from \"./commands/remove.js\";\nexport { runRemove } from \"./commands/remove.js\";\nexport type { RotateOptions, RotatePhase, RotateResult } from \"./commands/rotate.js\";\nexport { renderRotate, runRotate } from \"./commands/rotate.js\";\nexport type { SetResult } from \"./commands/set.js\";\nexport { runSet } from \"./commands/set.js\";\nexport type { ValidateIssue, ValidateResult } from \"./commands/validate.js\";\nexport { runValidate } from \"./commands/validate.js\";\nexport type { WatchHandle, WatchOptions } from \"./commands/watch.js\";\nexport { renderWatch, runWatch } from \"./commands/watch.js\";\n","/**\n * `penv doctor` — one report of everything that has drifted.\n *\n * Each check earns its place by catching something no other command can:\n *\n * - **missing** — meta marks a parameter required for this environment and it\n * resolves to nothing. Requiredness per environment is meta policy, not a\n * second schema (invariant 1).\n * - **declared** — the schema declares a parameter the tree has no value for.\n * The other half of the same distance `unused` measures, and a different\n * question from `missing`: this one is asked of the schema and answered for\n * every declared key, including one with no file anywhere — which no\n * tree-driven check can see, because a parameter with no file has no meta\n * either. It reports, and never writes: see `../schema.ts`.\n * - **weak** — the schema declares a minimum length the value does not meet.\n * - **unused** — a value file exists that the schema has no key for.\n * - **unscoped-fallback** — a real environment resolving via the unscoped\n * default. Invariant 13: fallback is never silent.\n * - **plaintext-secret** — meta declares the parameter a secret and the winning\n * value file carries no `.enc` marker. Invariant 14: encryption is\n * policy-driven, so the filename is checked *against* the policy and is never\n * the authority on what is secret.\n * - **public-secret** — meta declares the parameter a secret and its generated\n * variable carries a prefix the framework inlines into the client bundle.\n * - **rotation-overdue** — meta declares a rotation policy and more than its\n * interval has elapsed since the last completed rotation. A clock no other\n * check keeps: `missing` sees an absent value, never a stale present one.\n * - **rotation-stuck** — a `dual-valid` grace window opened and never closed. The\n * overdue clock's opposite: not a rotation that never ran, but one that started\n * and stalled with two credentials live at once.\n * - **provider-value-drift** — the local tree and the environment's readable\n * source-of-truth provider hold different opaque values for the same address.\n * The one drift the write-only sink can never report, because a provider can be\n * read back and a sink cannot.\n *\n * Warnings are reported; failures are reported and exit non-zero.\n */\n\nimport type {\n Meta,\n PenvConfig,\n Provider,\n Resolution,\n Scope,\n SecretScope,\n Sink,\n SinkConfig,\n SinkSecret,\n ValueFile,\n} from \"@penvhq/core\";\nimport {\n accessPath,\n assertNever,\n effectiveMeta,\n formatValueFile,\n isPublicVariable,\n isRequired,\n isSecret,\n isStuck,\n openValue,\n resolveAll,\n rotationOf,\n tryParseDuration,\n variableName,\n} from \"@penvhq/core\";\nimport { createGithubSink } from \"@penvhq/sink-github\";\nimport { defineCommand } from \"citty\";\nimport type { z } from \"zod\";\nimport type { Project } from \"../project.js\";\nimport { keySourceFor, openProject, sourceProviderFor, targetEnvironment } from \"../project.js\";\nimport { LOCAL_TREE_TYPE } from \"../registry.js\";\nimport type { DriftReport } from \"../schema.js\";\nimport { computeDrift, lookup, minLengthOf } from \"../schema.js\";\nimport { CHECK, formatRows, guard, type Row, UNKNOWN, WARN, write } from \"../ui.js\";\nimport { LAST_PUSHED_KEY } from \"./push.js\";\nimport { loadSchema } from \"./validate.js\";\n\n/**\n * A check reports one of four verdicts. `unknown` — a check that ran but could\n * not reach a verdict — is never rendered as a pass: \"I looked and found nothing\n * wrong\" and \"I could not look\" are opposite situations with opposite remedies,\n * and a write-only sink makes most of what doctor can say the second kind.\n */\nexport type DoctorSeverity = \"pass\" | \"warning\" | \"failure\" | \"unknown\";\n\nexport type DoctorCheck =\n | \"schema\"\n | \"missing\"\n | \"declared\"\n | \"weak\"\n | \"unused\"\n | \"unscoped-fallback\"\n | \"plaintext-secret\"\n | \"public-secret\"\n | \"encryption\"\n | \"rotation-overdue\"\n | \"rotation-stuck\"\n | \"provider-value-drift\"\n | \"provider\"\n | \"sink-unreachable\"\n | \"sink-name-drift\"\n | \"sink-manual-edit\"\n | \"sink-value-drift\";\n\nexport interface DoctorFinding {\n readonly check: DoctorCheck;\n readonly severity: DoctorSeverity;\n readonly label: string;\n readonly subject?: string;\n readonly detail?: string;\n /** A line the reader can act on — the `penv set` to paste, where there is one. */\n readonly remedy?: string;\n}\n\nexport interface DoctorReport {\n readonly environment: string;\n readonly findings: readonly DoctorFinding[];\n /** False when any finding is a failure. Warnings and unknowns do not fail the run. */\n readonly ok: boolean;\n}\n\nexport interface DoctorOptions {\n readonly cwd: string;\n readonly environment?: string;\n /** Injected in tests: the sink to check against. Defaults to the one the config declares. */\n readonly sink?: Sink;\n /**\n * Injected in tests: the source-of-truth provider to compare the local tree\n * against. Defaults to the one the config declares (`sourceProviderFor`).\n * Mirrors `sink`, for the same reason — the drift checks stay driveable without\n * a live backend.\n */\n readonly source?: Provider;\n /** Injected in tests: the wall-clock reading the rotation clocks are read against. Defaults to now. */\n readonly now?: string;\n /** Injected in tests: how long a `dual-valid` window may stay open before it reads as stuck. Defaults to 24h. */\n readonly stuckThresholdMs?: number;\n}\n\n/**\n * How long a `dual-valid` grace window may stay open before `rotation-stuck`\n * flags it. A day is generous for the overlap most rotations need — long enough\n * that a healthy rotation completing within a deploy or two never trips it, short\n * enough that a window left open for a week is caught while it still matters.\n */\nconst STUCK_THRESHOLD_MS = 86_400_000;\n\ninterface Subject {\n readonly resolution: Resolution;\n readonly meta: Meta | undefined;\n}\n\n/**\n * A check the schema failure above made impossible: `unknown`, not `warning`.\n * penv did not look, so it cannot claim there is nothing to find — and it cannot\n * claim a problem either. The verdict is \"I could not tell\".\n */\nfunction skipped(check: DoctorCheck, label: string): DoctorFinding {\n return {\n check,\n severity: \"unknown\",\n label,\n subject: \"not checked\",\n detail: \"the schema did not load, so this check could not run\",\n };\n}\n\nexport async function runDoctor(options: DoctorOptions): Promise<DoctorReport> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const findings: DoctorFinding[] = [];\n // The wall clock, read once and passed down — never read inside a check — so the\n // rotation boundaries the roadmap names are testable without mocking time, the\n // same discipline `rotation.ts` and `push.ts` keep.\n const now = new Date(options.now ?? new Date().toISOString());\n const stuckThresholdMs = options.stuckThresholdMs ?? STUCK_THRESHOLD_MS;\n\n const { schema, issues } = await loadSchema(project, environment);\n if (schema !== undefined) {\n findings.push({ check: \"schema\", severity: \"pass\", label: \"Schema valid\" });\n } else {\n for (const issue of issues) {\n findings.push({\n check: \"schema\",\n severity: \"failure\",\n label: \"Schema\",\n subject: issue.subject,\n detail: issue.message,\n });\n }\n }\n\n const resolutions = await resolveAll(\n environment,\n project.provider,\n keySourceFor(project, environment),\n );\n const subjects: Subject[] = await Promise.all(\n resolutions.map(async (resolution) => ({\n resolution,\n meta: await project.provider.readMeta(resolution.ref),\n })),\n );\n\n const missing = missingFindings(subjects, environment);\n findings.push(...missing);\n // A check that could not run says so. Printing nothing where a check belongs\n // reads as \"nothing found\", which is the one thing a report must never imply.\n if (schema === undefined) {\n findings.push(\n skipped(\"declared\", \"Schema coverage\"),\n skipped(\"weak\", \"Secret strength\"),\n skipped(\"unused\", \"Value coverage\"),\n );\n } else {\n const drift = computeDrift({\n schema,\n resolutions: subjects.map(({ resolution }) => resolution),\n config: project.config,\n environment,\n });\n findings.push(...declaredFindings(drift, missing, environment));\n findings.push(...weakFindings(subjects, schema));\n findings.push(...unusedFindings(drift));\n }\n findings.push(...fallbackFindings(subjects, environment));\n findings.push(...plaintextSecretFindings(subjects, environment));\n findings.push(...publicSecretFindings(subjects, environment, project.config));\n findings.push(...encryptionFindings(subjects, environment));\n // The rotation clocks read the environment's SOURCE provider, not `subjects`,\n // whose meta is the local tree's. `penv rotate` writes `rotatingSince` /\n // `state` / `lastRotated` to the source of truth (a `dual-valid` rotation\n // REQUIRES a retaining backend, so its rotating-state meta is never in the\n // local tree at all) — reading `subjects` here saw stale local meta and never\n // fired for a backend-backed environment.\n const rotation = await rotationSubjects(project, environment, subjects, options.source);\n if (rotation.kind === \"unreachable\") {\n findings.push(rotation.finding);\n } else {\n findings.push(...overdueFindings(rotation.subjects, environment, now));\n findings.push(...stuckFindings(rotation.subjects, environment, now, stuckThresholdMs));\n }\n findings.push(...(await providerDriftFindings(project, environment, options.source)));\n findings.push(...(await sinkFindings(project, environment, options.sink)));\n\n findings.push({\n check: \"provider\",\n severity: \"pass\",\n label: \"Provider\",\n subject: project.config.providers[environment]?.type ?? project.provider.type,\n });\n\n return {\n environment,\n findings,\n ok: !findings.some((finding) => finding.severity === \"failure\"),\n };\n}\n\nfunction missingFindings(subjects: readonly Subject[], environment: string): DoctorFinding[] {\n const required = subjects.filter(({ meta }) => isRequired(meta, environment));\n const findings: DoctorFinding[] = required\n .filter(({ resolution }) => resolution.winner === undefined)\n .map(({ resolution }) => ({\n check: \"missing\",\n severity: \"failure\",\n label: \"Missing parameter\",\n subject: resolution.parameter,\n detail: `required for ${environment}, absent`,\n remedy: `penv set ${[...resolution.ref.namespace, resolution.ref.name].join(\"/\")} --env ${environment}`,\n }));\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"missing\",\n severity: \"pass\",\n label: \"Required parameters\",\n subject:\n required.length === 0\n ? `none required for ${environment}`\n : `${required.length} required for ${environment}, all present`,\n },\n ];\n}\n\n/**\n * Schema → tree: declared, with no value for this environment.\n *\n * A warning, not a failure. The schema decides whether an absent value is fatal\n * and `penv validate` is where that verdict is reached; saying it twice, in two\n * voices, would make this report the second authority the design does not have.\n *\n * Parameters the `missing` check already named are dropped rather than repeated:\n * that line is the same absence with meta's stronger verdict on it, and it now\n * carries the same paste line. One absence, one line.\n */\nfunction declaredFindings(\n drift: DriftReport,\n missing: readonly DoctorFinding[],\n environment: string,\n): DoctorFinding[] {\n const reported = new Set(missing.filter((f) => f.severity !== \"pass\").map((f) => f.subject));\n\n const findings: DoctorFinding[] = drift.declared\n .filter((item) => !reported.has(item.subject))\n .map((item) => ({\n check: \"declared\",\n severity: \"warning\",\n label: \"Declared, no value\",\n subject: item.subject,\n detail: item.detail,\n remedy: item.remedy,\n }));\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"declared\",\n severity: \"pass\",\n label: \"Schema coverage\",\n subject: `every parameter .penv/env.ts requires has a value for ${environment}`,\n },\n ];\n}\n\nfunction weakFindings(subjects: readonly Subject[], schema: z.ZodType): DoctorFinding[] {\n const findings: DoctorFinding[] = [];\n let checked = 0;\n\n for (const { resolution } of subjects) {\n const value = resolution.value;\n // A decrypted secret has a value here, so it is length-checked like any\n // other — an encrypted secret used to be invisible to this check, which made\n // \"the schema declares a minimum\" a promise that quietly excluded exactly the\n // values a minimum is for. Absence is two other checks' business: an\n // undecryptable winner is the encryption check's, and nothing at all is the\n // missing check's.\n if (value === undefined) {\n continue;\n }\n const field = lookup(schema, accessPath(resolution.ref));\n if (field.kind !== \"found\") {\n continue;\n }\n const minimum = minLengthOf(field.node);\n if (minimum === undefined) {\n continue;\n }\n checked += 1;\n if (value.length >= minimum) {\n continue;\n }\n findings.push({\n check: \"weak\",\n severity: \"failure\",\n label: \"Weak secret\",\n subject: resolution.parameter,\n detail: `${value.length} chars, schema requires ≥${minimum}`,\n });\n }\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"weak\",\n severity: \"pass\",\n label: \"Secret strength\",\n subject:\n checked === 0\n ? \"no schema field declares a minimum length\"\n : checked === 1\n ? \"1 value meets the schema minimum\"\n : `${checked} values meet the schema minimum`,\n },\n ];\n}\n\n/** Tree → schema: a value the application has no declared way to read. */\nfunction unusedFindings(drift: DriftReport): DoctorFinding[] {\n const findings: DoctorFinding[] = drift.undeclared.map((item) => ({\n check: \"unused\",\n severity: \"warning\",\n label: \"Unused parameter\",\n subject: item.variable,\n detail: \"present, not in schema\",\n }));\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"unused\",\n severity: \"pass\",\n label: \"Value coverage\",\n subject: \"every value file has a schema key\",\n },\n ];\n}\n\nfunction fallbackFindings(subjects: readonly Subject[], environment: string): DoctorFinding[] {\n const findings: DoctorFinding[] = subjects\n .filter(({ resolution }) => resolution.viaUnscopedFallback)\n .map(({ resolution }) => ({\n check: \"unscoped-fallback\",\n severity: \"warning\",\n label: \"Unscoped fallback in use\",\n subject: resolution.parameter,\n detail: `${environment} resolving to default`,\n }));\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"unscoped-fallback\",\n severity: \"pass\",\n label: \"Scoped resolution\",\n subject: `no parameter falls back to the unscoped default for ${environment}`,\n },\n ];\n}\n\nfunction plaintextSecretFindings(\n subjects: readonly Subject[],\n environment: string,\n): DoctorFinding[] {\n const secrets = subjects.filter(({ meta }) => isSecret(meta, environment));\n const findings: DoctorFinding[] = [];\n\n for (const { resolution } of secrets) {\n const winner = resolution.winner;\n // Nothing resolves: that is the missing check's business, not this one's.\n if (winner === undefined || winner.file.encrypted) {\n continue;\n }\n findings.push({\n check: \"plaintext-secret\",\n severity: \"failure\",\n label: \"Plaintext secret\",\n subject: winner.location,\n detail: \"value file is not encrypted\",\n });\n }\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"plaintext-secret\",\n severity: \"pass\",\n label: \"Encryption policy\",\n subject:\n secrets.length === 0\n ? `no parameter is declared secret for ${environment}`\n : `every secret resolving for ${environment} is encrypted`,\n },\n ];\n}\n\n/**\n * The third face of the same policy: is it sealed, can it be opened, and is it\n * public. A secret whose generated variable starts with a framework's public\n * prefix is inlined into the client bundle — `NEXT_PUBLIC_STRIPE_SECRET` reaches\n * every browser that loads the page, permanently, in a bundle nobody can recall.\n *\n * Nothing else in the stack can see this. To the framework the prefix *is* the\n * intent: Next inlines `NEXT_PUBLIC_*` by definition and has no notion that the\n * value is secret. The application's own env module knows the name and not the\n * policy. penv holds both — meta says secret, the name transform says public —\n * so this contradiction is only visible from here.\n *\n * Read of the *generated* variable rather than the parameter name, because a\n * `names` override is what decides the string the framework sees, and it is the\n * one place the prefix can appear with nothing in the tree hinting at it.\n * Absence of a value is deliberately not a reprieve: the name is already wrong,\n * and the next `penv set` is what ships it.\n */\nfunction publicSecretFindings(\n subjects: readonly Subject[],\n environment: string,\n config: PenvConfig,\n): DoctorFinding[] {\n const prefixes = config.publicPrefixes ?? [];\n // Nothing declared, nothing checkable: a prefix penv was never told about is\n // one it cannot recognise. This is the \"I cannot tell\" answer, and it is not\n // the same as a clean report — saying \"no secret is exposed\" here would be a\n // promise made by a check that never looked at anything.\n if (prefixes.length === 0) {\n return [\n {\n check: \"public-secret\",\n severity: \"unknown\",\n label: \"Browser exposure\",\n subject: \"not checked — penv.config.ts declares no `publicPrefixes`\",\n detail: \"penv cannot tell which variables a framework inlines into the browser\",\n },\n ];\n }\n\n const secrets = subjects.filter(({ meta }) => isSecret(meta, environment));\n const findings: DoctorFinding[] = [];\n\n for (const { resolution } of secrets) {\n const variable = variableName(resolution.ref, config);\n if (!isPublicVariable(variable, config)) {\n continue;\n }\n // Which prefix matched is for the message alone; core stays the authority on\n // whether the variable is public at all.\n const prefix = prefixes.find((candidate) => variable.startsWith(candidate));\n findings.push({\n check: \"public-secret\",\n severity: \"failure\",\n label: \"Secret exposed to the browser\",\n subject: variable,\n detail:\n prefix === undefined\n ? \"meta declares this a secret, and its public prefix makes it public\"\n : `meta declares this a secret, and the \\`${prefix}\\` prefix makes it public`,\n remedy:\n \"rename the parameter so it carries no public prefix, or drop `secret` from its meta if it is not one\",\n });\n }\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"public-secret\",\n severity: \"pass\",\n label: \"Browser exposure\",\n subject: `no secret is exposed to the browser for ${environment}`,\n },\n ];\n}\n\n/**\n * The other half of the encryption policy: `plaintext-secret` catches a secret\n * that should be sealed and is not; this catches a sealed value penv cannot open.\n *\n * A failure, not a warning. An unopenable value is indistinguishable from an\n * absent one to everything downstream — the app gets nothing either way — and\n * the whole point of the `undecryptable` field is that penv can tell the\n * difference even when the application cannot.\n */\nfunction encryptionFindings(subjects: readonly Subject[], environment: string): DoctorFinding[] {\n const sealed = subjects.filter(({ resolution }) => resolution.winner?.file.encrypted === true);\n const findings: DoctorFinding[] = [];\n\n for (const { resolution } of sealed) {\n const failure = resolution.undecryptable;\n if (failure === undefined) {\n continue;\n }\n findings.push({\n check: \"encryption\",\n severity: \"failure\",\n label: \"Undecryptable value\",\n subject: resolution.winner?.location ?? resolution.parameter,\n detail: failure.detail,\n });\n }\n\n if (findings.length > 0) {\n return findings;\n }\n // Two different quiets, reported differently. \"Nothing is encrypted here\" and\n // \"everything encrypted here opens\" are both passes, and a reader who cannot\n // tell them apart cannot tell whether the check ran.\n return [\n {\n check: \"encryption\",\n severity: \"pass\",\n label: \"Encryption\",\n subject:\n sealed.length === 0\n ? `no encrypted value resolves for ${environment}`\n : `every encrypted value resolving for ${environment} decrypts`,\n },\n ];\n}\n\n/**\n * A sink report is mostly `unknown` by construction, and honest about it. Three\n * tiers, rendered differently (RFC \"A sink is a destination, not a provider\"):\n *\n * - **names** are exact, because listing them is the one read the destination\n * allows: declared-but-never-pushed, and present-in-the-destination-but-\n * undeclared — the `declared`/`unused` pair pointed at a sink.\n * - **manual edits** are detectable indirectly: GitHub's `updated_at` newer than\n * penv's own last-push time (kept per environment in committed meta) means the\n * secret was touched outside penv. A warning, never a failure — it detects that\n * something was touched, not that the copies differ.\n * - **values** are `unknown`, permanently, because they cannot be read back.\n *\n * The whole report is `unknown` when the destination cannot be reached — the\n * fourth verdict earning its keep against a write-only store.\n */\n/** Slack between penv's local push time and the destination's server `updated_at` before a difference reads as a hand-edit. */\nconst EDIT_SKEW_MS = 120_000;\n\nfunction buildSink(declared: SinkConfig, override: Sink | undefined): Sink | undefined {\n if (override !== undefined) {\n return override;\n }\n if (declared.type === \"github\") {\n return createGithubSink(declared.repo === undefined ? {} : { repo: declared.repo });\n }\n return undefined;\n}\n\nfunction errorDetail(error: unknown): string {\n if (error instanceof Error) {\n return error.message.split(\"\\n\")[0] ?? error.message;\n }\n return String(error);\n}\n\nfunction scopeLabel(scope: SecretScope): string {\n return scope.kind === \"repository\"\n ? \"repository secrets\"\n : `environment secrets for ${scope.environment}`;\n}\n\ninterface Expected {\n readonly ref: Resolution[\"ref\"];\n readonly variable: string;\n readonly scope: SecretScope;\n}\n\nasync function sinkFindings(\n project: Project,\n environment: string,\n override: Sink | undefined,\n): Promise<DoctorFinding[]> {\n const declared = project.config.sinks?.[environment];\n if (declared === undefined) {\n return [];\n }\n\n const sink = buildSink(declared, override);\n if (sink === undefined) {\n return [\n {\n check: \"sink-unreachable\",\n severity: \"unknown\",\n label: \"Sink\",\n subject: `sink type \\`${declared.type}\\` is not one penv knows`,\n detail: \"penv cannot check a sink it cannot build\",\n },\n ];\n }\n\n try {\n await sink.verify();\n } catch (error) {\n return [\n {\n check: \"sink-unreachable\",\n severity: \"unknown\",\n label: \"Sink\",\n subject: `could not reach the ${declared.type} sink for ${environment}`,\n detail: errorDetail(error),\n },\n ];\n }\n\n let repoSecrets: SinkSecret[];\n let envSecrets: SinkSecret[];\n try {\n repoSecrets = await sink.list({ kind: \"repository\" });\n envSecrets = await sink.list({ kind: \"environment\", environment });\n } catch (error) {\n return [\n {\n check: \"sink-unreachable\",\n severity: \"unknown\",\n label: \"Sink\",\n subject: `could not list secrets in the ${declared.type} sink for ${environment}`,\n detail: errorDetail(error),\n },\n ];\n }\n\n // The push view: what a push would place, `.local` dropped, so doctor compares\n // the same set a push would send.\n const resolutions = await resolveAll(\n environment,\n project.provider,\n keySourceFor(project, environment),\n true,\n );\n const expected: Expected[] = [];\n for (const resolution of resolutions) {\n const winner = resolution.winner;\n if (winner === undefined) {\n continue;\n }\n expected.push({\n ref: resolution.ref,\n variable: variableName(resolution.ref, project.config),\n scope:\n winner.file.scope.kind === \"unscoped\"\n ? { kind: \"repository\" }\n : { kind: \"environment\", environment },\n });\n }\n\n // GitHub secret names are case-insensitive, and the pre-flight already refused\n // any case collision, so comparing by uppercase is exact and safe.\n const upper = (name: string): string => name.toUpperCase();\n const repoByName = new Map(repoSecrets.map((secret) => [upper(secret.name), secret]));\n const envByName = new Map(envSecrets.map((secret) => [upper(secret.name), secret]));\n const destOf = (scope: SecretScope): Map<string, SinkSecret> =>\n scope.kind === \"repository\" ? repoByName : envByName;\n\n const nameDrift: DoctorFinding[] = [];\n const expectedEnv = new Set<string>();\n // Every variable this environment maps, at any scope. A repository secret is\n // shared across all environments, so it is \"declared\" as long as *some*\n // parameter produces its name — even one this environment resolves to an\n // environment-scoped override. Judging a repository secret against only this\n // environment's unscoped winners would flag another environment's default.\n const allVariables = new Set<string>();\n for (const item of expected) {\n const key = upper(item.variable);\n allVariables.add(key);\n if (item.scope.kind === \"environment\") {\n expectedEnv.add(key);\n }\n if (!destOf(item.scope).has(key)) {\n nameDrift.push({\n check: \"sink-name-drift\",\n severity: \"warning\",\n label: \"Declared, not pushed\",\n subject: item.variable,\n detail: `resolves for ${environment} but is absent from the ${scopeLabel(item.scope)}`,\n remedy: `penv push --env ${environment}`,\n });\n }\n }\n for (const secret of repoSecrets) {\n if (!allVariables.has(upper(secret.name))) {\n nameDrift.push({\n check: \"sink-name-drift\",\n severity: \"warning\",\n label: \"In destination, not declared\",\n subject: secret.name,\n detail: `a repository secret with no parameter penv pushes for ${environment}`,\n });\n }\n }\n for (const secret of envSecrets) {\n if (!expectedEnv.has(upper(secret.name))) {\n nameDrift.push({\n check: \"sink-name-drift\",\n severity: \"warning\",\n label: \"In destination, not declared\",\n subject: secret.name,\n detail: `an environment secret with no parameter resolving for ${environment}`,\n });\n }\n }\n\n const manualEdits: DoctorFinding[] = [];\n for (const item of expected) {\n const secret = destOf(item.scope).get(upper(item.variable));\n if (secret === undefined) {\n continue;\n }\n const pushed = effectiveMeta(await project.provider.readMeta(item.ref), environment)[\n LAST_PUSHED_KEY\n ];\n if (typeof pushed !== \"string\") {\n continue;\n }\n const destTime = Date.parse(secret.updatedAt);\n const pushTime = Date.parse(pushed);\n // The tolerance absorbs the skew between penv's local clock and GitHub's\n // server clock (and GitHub's whole-second truncation of `updated_at`), so a\n // clean push does not read as an edit. A genuine UI edit lands minutes to\n // days later, well outside it — this is a sensitive detector, not a proof.\n if (Number.isNaN(destTime) || Number.isNaN(pushTime) || destTime <= pushTime + EDIT_SKEW_MS) {\n continue;\n }\n manualEdits.push({\n check: \"sink-manual-edit\",\n severity: \"warning\",\n label: \"Edited outside penv\",\n subject: item.variable,\n detail: `changed in the destination at ${secret.updatedAt}, after penv last pushed it`,\n });\n }\n\n const findings: DoctorFinding[] = [];\n findings.push(\n ...(nameDrift.length > 0\n ? nameDrift\n : [\n {\n check: \"sink-name-drift\" as const,\n severity: \"pass\" as const,\n label: \"Sink names\",\n subject: `every parameter resolving for ${environment} is present, and nothing undeclared is`,\n },\n ]),\n );\n findings.push(\n ...(manualEdits.length > 0\n ? manualEdits\n : [\n {\n check: \"sink-manual-edit\" as const,\n severity: \"pass\" as const,\n label: \"Sink hand-edits\",\n subject: `no secret has changed outside penv since its last push for ${environment}`,\n },\n ]),\n );\n findings.push({\n check: \"sink-value-drift\",\n severity: \"unknown\",\n label: \"Sink values\",\n subject: \"cannot be read back from a write-only destination\",\n detail: \"value drift between the tree and the destination is unknowable by design\",\n });\n return findings;\n}\n\n/** A rough, human-facing span — the largest whole unit that fits. Never precise, and never claims to be. */\nfunction humanizeMs(ms: number): string {\n const abs = Math.max(0, ms);\n const day = 86_400_000;\n const hour = 3_600_000;\n const minute = 60_000;\n const round = (value: number, unit: string): string => {\n const n = Math.round(value);\n return `${n} ${unit}${n === 1 ? \"\" : \"s\"}`;\n };\n if (abs >= day) return round(abs / day, \"day\");\n if (abs >= hour) return round(abs / hour, \"hour\");\n if (abs >= minute) return round(abs / minute, \"minute\");\n return round(abs / 1000, \"second\");\n}\n\n/** The `<namespace>/<name>` path a `penv rotate` remedy pastes. */\nfunction refPathOf(ref: Resolution[\"ref\"]): string {\n return [...ref.namespace, ref.name].join(\"/\");\n}\n\n/**\n * The rotation clocks read the environment's source of truth, so this reads each\n * parameter's meta from the SOURCE provider rather than the local tree.\n *\n * `penv rotate` writes rotation state (`rotatingSince` / `state` / `lastRotated`)\n * to `sourceProviderFor(environment)` — a backend for a vault/mock env — and a\n * `dual-valid` rotation cannot run without one, so a backend-backed env's\n * rotating-state meta is NEVER in the local `.penv` tree. Reading `subjects`\n * (whose meta is the local tree's) left the overdue/stuck checks reading stale\n * local meta that never fired.\n *\n * When the source IS the local tree — the env declares no backend, or declares\n * `filesystem` — the two coincide, so the metas already read for `subjects` are\n * reused rather than round-tripping the identical files a second time. A backend\n * is read once, wrapped in try/catch: an unreachable source yields a single\n * `unknown` rotation finding, mirroring `sinkFindings`' tiering, because \"the\n * clock says overdue\" and \"penv could not read the clock\" are opposite verdicts.\n */\ntype RotationSubjects =\n | { readonly kind: \"read\"; readonly subjects: readonly Subject[] }\n | { readonly kind: \"unreachable\"; readonly finding: DoctorFinding };\n\nasync function rotationSubjects(\n project: Project,\n environment: string,\n local: readonly Subject[],\n override: Provider | undefined,\n): Promise<RotationSubjects> {\n const providerConfig = project.config.providers[environment];\n // No override and a local-tree source: the meta is the same meta `subjects`\n // already hold, so reuse it and make no extra round-trips.\n if (\n override === undefined &&\n (providerConfig === undefined || providerConfig.type === LOCAL_TREE_TYPE)\n ) {\n return { kind: \"read\", subjects: local };\n }\n\n const source = override ?? (await sourceProviderFor(project, environment));\n try {\n const subjects: Subject[] = await Promise.all(\n local.map(async ({ resolution }) => ({\n resolution,\n meta: await source.readMeta(resolution.ref),\n })),\n );\n return { kind: \"read\", subjects };\n } catch (error) {\n return {\n kind: \"unreachable\",\n finding: {\n check: \"rotation-overdue\",\n severity: \"unknown\",\n label: \"Rotation\",\n subject: `could not reach the ${providerConfig?.type ?? source.type} source of truth for ${environment}`,\n detail: errorDetail(error),\n },\n };\n }\n}\n\n/**\n * A staleness clock no other check keeps: `missing` reports a value that is\n * absent, and this reports one that is present and too old. The two are opposite\n * failures — a value nobody set, and a value nobody has changed in longer than\n * its own policy allows — and only meta's `rotationPolicy` plus `lastRotated`\n * make the second visible at all.\n *\n * The policy is parsed ONCE, here, inside `tryParseDuration`. The old code called\n * `isOverdue` (which parses via the throwing `parseDuration`) in this unguarded\n * loop, then parsed a SECOND time for the `overdueBy` text — so a single policy\n * `parseDuration` rejects (`1h30m`, `3 months`) threw straight out and aborted\n * the entire doctor run through `guard()`, blinding every other check on one bad\n * meta field. Now an unparseable policy is a warning on that one parameter and\n * the sweep continues, and the single parsed interval feeds both the overdue\n * decision and the message. A parameter with no policy, or one that has never\n * rotated, is not on a clock and is silently not overdue.\n */\nfunction overdueFindings(\n subjects: readonly Subject[],\n environment: string,\n now: Date,\n): DoctorFinding[] {\n const findings: DoctorFinding[] = [];\n for (const { resolution, meta } of subjects) {\n const { policy, lastRotated } = rotationOf(meta, environment);\n // Not on a clock: no interval declared, or never rotated. Not late.\n if (policy === undefined || lastRotated === null) {\n continue;\n }\n // Parse once, non-throwing. A policy penv cannot read used to throw here and\n // abort the whole run; now it is this parameter's own warning and nothing\n // else is lost.\n const interval = tryParseDuration(policy);\n if (interval === undefined) {\n findings.push({\n check: \"rotation-overdue\",\n severity: \"warning\",\n label: \"Rotation policy invalid\",\n subject: resolution.parameter,\n detail: `rotationPolicy \\`${policy}\\` is not a duration penv can parse (e.g. \\`90d\\`, \\`24h\\`)`,\n });\n continue;\n }\n const last = Date.parse(lastRotated);\n if (Number.isNaN(last)) {\n continue;\n }\n // The same boundary `isOverdue` keeps: exactly at the interval is not yet\n // overdue, strictly past it is. Reusing `interval` is what kills the second\n // parse the old `overdueBy` line made.\n const overdueBy = now.getTime() - last - interval;\n if (overdueBy <= 0) {\n continue;\n }\n findings.push({\n check: \"rotation-overdue\",\n severity: \"warning\",\n label: \"Rotation overdue\",\n subject: resolution.parameter,\n detail: `overdue by ~${humanizeMs(overdueBy)}, policy ${policy}`,\n remedy: `penv rotate ${refPathOf(resolution.ref)} --env ${environment}`,\n });\n }\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"rotation-overdue\",\n severity: \"pass\",\n label: \"Rotation freshness\",\n subject: `no parameter is past its rotation policy for ${environment}`,\n },\n ];\n}\n\n/**\n * The overdue clock's opposite: not a rotation that never ran, but one that\n * started and stalled. A `dual-valid` window is meant to open, let readers move\n * over, and close; a `rotatingSince` older than the threshold is a window that\n * opened and never did.\n *\n * Gated to `dual-valid` entirely — `isStuck` refuses every other mechanism, and\n * that refusal is the point. An `atomic-cutover` parameter overlaps only at the\n * infra layer and holds no penv-layer grace window, so a long-lived\n * `rotatingSince` on one is not stuck and must never be flagged; this check keeps\n * that promise by asking `isStuck` and never re-deriving the mechanism itself.\n */\nfunction stuckFindings(\n subjects: readonly Subject[],\n environment: string,\n now: Date,\n stuckThresholdMs: number,\n): DoctorFinding[] {\n const findings: DoctorFinding[] = [];\n for (const { resolution, meta } of subjects) {\n if (!isStuck(meta, environment, now, stuckThresholdMs)) {\n continue;\n }\n const { rotatingSince } = rotationOf(meta, environment);\n // isStuck was true, so the window is open with a parseable clock; the guard is\n // for the types, not a reachable path.\n if (rotatingSince === null) {\n continue;\n }\n const openFor = now.getTime() - Date.parse(rotatingSince);\n findings.push({\n check: \"rotation-stuck\",\n severity: \"warning\",\n label: \"Rotation stuck\",\n subject: resolution.parameter,\n detail: `dual-valid window open ~${humanizeMs(openFor)}, past the ${humanizeMs(stuckThresholdMs)} grace window`,\n remedy: `penv rotate ${refPathOf(resolution.ref)} --complete --env ${environment}`,\n });\n }\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"rotation-stuck\",\n severity: \"pass\",\n label: \"Rotation progress\",\n subject: `no dual-valid rotation has stayed open past its grace window for ${environment}`,\n },\n ];\n}\n\n/** One value file the drift check has read, kept with its raw stored string so a sealed local value can still be opened. */\ninterface DriftEntry {\n readonly file: ValueFile;\n readonly stored: string;\n}\n\n/**\n * The LOGICAL identity of a value file — namespace, name, and scope — with the\n * `.enc` marker deliberately dropped.\n *\n * `formatValueFile` encodes `encrypted`, so keying by it split an encrypted-local\n * value from its plaintext-source twin: the same logical parameter at the same\n * scope read as two one-sided addresses, a perpetual false drift the byte compare\n * never got to run. Encryption is a property of the local envelope, not of the\n * address, so it must not be part of the key two stores are matched on. Mirrors\n * the mock provider's `valueKey`, minus exactly that `encrypted` field.\n */\nfunction driftKey(file: ValueFile): string {\n return [file.namespace.join(\"/\"), file.name, scopeKey(file.scope)].join(\" \");\n}\n\nfunction scopeKey(scope: Scope): string {\n switch (scope.kind) {\n case \"unscoped\":\n return \"unscoped\";\n case \"environment\":\n return `environment:${scope.environment}`;\n case \"local\":\n return \"local\";\n case \"environment-local\":\n return `environment-local:${scope.environment}`;\n default:\n return assertNever(scope, \"scope\");\n }\n}\n\n/**\n * The value files that have a source-of-truth twin to drift against: the pushable\n * set for this environment — the unscoped default and this environment's own\n * scope, and nothing else.\n *\n * The old check compared the ENTIRE local tree (`project.provider.list()` is\n * every environment's files) against one env's source, so `doctor --env\n * production` flooded \"Only in the local tree\" for every development/staging\n * value. Both `.local` scopes are personal and never reach a backend; every other\n * environment's scoped file is that environment's business, not this one's. The\n * same filter is applied to both sides.\n */\nfunction relevantToEnvironment(file: ValueFile, environment: string): boolean {\n const scope = file.scope;\n if (scope.kind === \"unscoped\") return true;\n if (scope.kind === \"environment\") return scope.environment === environment;\n // Both `.local` scopes, and every other environment's scope: not pushed here.\n return false;\n}\n\n/**\n * Reads a provider's value files relevant to this environment into a logical\n * address → entry map, the raw stored strings kept unopened.\n *\n * Values are read in `list` order and mapped afterwards, so a same-address\n * collision (a plaintext and a sealed file at one scope) resolves the same way on\n * every machine rather than by Promise race. An address that `list` names but\n * `read` returns absent — a concurrent prune — is dropped, nothing to compare.\n */\nasync function readRelevant(\n provider: Provider,\n environment: string,\n): Promise<Map<string, DriftEntry>> {\n const files = (await provider.list()).filter((file) => relevantToEnvironment(file, environment));\n const stored = await Promise.all(files.map((file) => provider.read(file)));\n const entries = new Map<string, DriftEntry>();\n for (const [index, file] of files.entries()) {\n const value = stored[index];\n if (value !== undefined) {\n entries.set(driftKey(file), { file, stored: value });\n }\n }\n return entries;\n}\n\n/**\n * The one drift the sink can never report. `sink-value-drift` is permanently\n * `unknown` because a write-only destination cannot be read back; a provider is\n * the system of record precisely because it can, so here penv actually looks —\n * comparing PLAINTEXT, value by value.\n *\n * Custody model: the source of truth holds verbatim plaintext (the way `pull` and\n * `rotate` move it there), while the local tree may hold the value sealed. So a\n * sealed local value is opened before the compare — an encrypted-local vs\n * plaintext-source pair carrying the same secret is IN SYNC, not drift. A sealed\n * value that cannot be opened (the key is gone) is `unknown` for that parameter,\n * never a false disagreement: penv could not read one side, so it cannot say the\n * two agree or differ.\n *\n * When the environment keeps its values in the local tree there is no second\n * system of record, so this is a plain `pass` — \"not applicable\", never\n * `unknown`: penv could look and there was one copy by design. An unreachable\n * source *is* `unknown`, mirroring `sinkFindings`' try/catch tiering: a differing\n * value and an unreachable store are opposite verdicts with opposite remedies.\n */\nasync function providerDriftFindings(\n project: Project,\n environment: string,\n override: Provider | undefined,\n): Promise<DoctorFinding[]> {\n const providerConfig = project.config.providers[environment];\n if (providerConfig === undefined || providerConfig.type === LOCAL_TREE_TYPE) {\n return [\n {\n check: \"provider-value-drift\",\n severity: \"pass\",\n label: \"Provider values\",\n subject: `${environment} keeps its values in the local .penv tree, so there is no other source of truth to compare against`,\n },\n ];\n }\n\n const source = override ?? (await sourceProviderFor(project, environment));\n\n let local: Map<string, DriftEntry>;\n let remote: Map<string, DriftEntry>;\n try {\n local = await readRelevant(project.provider, environment);\n remote = await readRelevant(source, environment);\n } catch (error) {\n return [\n {\n check: \"provider-value-drift\",\n severity: \"unknown\",\n label: \"Provider values\",\n subject: `could not reach the ${providerConfig.type} provider for ${environment}`,\n detail: errorDetail(error),\n },\n ];\n }\n\n const keys = keySourceFor(project, environment);\n const findings: DoctorFinding[] = [];\n // Sorted so the report is identical on every machine, the same rule `refsFrom` keeps.\n const addresses = [...new Set([...local.keys(), ...remote.keys()])].sort();\n for (const address of addresses) {\n const here = local.get(address);\n const there = remote.get(address);\n if (here !== undefined && there !== undefined) {\n // Open the local value if it is sealed; the source is verbatim plaintext.\n // `openValue` returns a plaintext file unchanged, so this is unconditional.\n const opened = openValue(here.file, here.stored, keys);\n if (opened.kind !== \"plaintext\") {\n // A sealed value penv cannot open: the key is gone. Not drift — penv\n // could not read this side, so it cannot claim the two stores agree or\n // differ. The opposite of a false failure.\n findings.push({\n check: \"provider-value-drift\",\n severity: \"unknown\",\n label: \"Provider value unreadable\",\n subject: formatValueFile(here.file),\n detail: `the local value is sealed and did not open, so it cannot be compared against the ${providerConfig.type} source of truth`,\n });\n continue;\n }\n // A plaintext comparison. Drift in the system of record is serious: the\n // tree and the backend claim different truths for one address, and\n // something deploys the wrong one.\n if (opened.value !== there.stored) {\n findings.push({\n check: \"provider-value-drift\",\n severity: \"failure\",\n label: \"Provider value drift\",\n subject: formatValueFile(here.file),\n detail: `the local tree and the ${providerConfig.type} source of truth hold different values`,\n });\n }\n continue;\n }\n const present = here ?? there;\n // `present` is defined: the address is in the union, so at least one side has it.\n if (present === undefined) {\n continue;\n }\n findings.push({\n check: \"provider-value-drift\",\n severity: \"warning\",\n label: here !== undefined ? \"Only in the local tree\" : \"Only in the source\",\n subject: formatValueFile(present.file),\n detail:\n here !== undefined\n ? `present locally, absent from the ${providerConfig.type} source of truth`\n : `present in the ${providerConfig.type} source of truth, absent from the local tree`,\n });\n }\n\n if (findings.length > 0) {\n return findings;\n }\n return [\n {\n check: \"provider-value-drift\",\n severity: \"pass\",\n label: \"Provider values\",\n subject: `every value matches the ${providerConfig.type} source of truth for ${environment}`,\n },\n ];\n}\n\nexport function renderDoctor(report: DoctorReport): string[] {\n const rows: Row[] = report.findings.map((finding) => ({\n glyph: finding.severity === \"pass\" ? CHECK : finding.severity === \"unknown\" ? UNKNOWN : WARN,\n label: finding.label,\n ...(finding.subject === undefined ? {} : { subject: finding.subject }),\n ...(finding.detail === undefined ? {} : { detail: finding.detail }),\n }));\n\n const lines = formatRows(rows);\n // Below the table rather than beside it: these are lines to paste, and a line\n // to paste has to survive being selected without a report's columns coming\n // with it. Deduped, because two parameters can share a remedy.\n const remedies = [\n ...new Set(\n report.findings\n .filter((finding) => finding.severity !== \"pass\")\n .map((finding) => finding.remedy)\n .filter((remedy): remedy is string => remedy !== undefined),\n ),\n ];\n for (const remedy of remedies) {\n lines.push(` ${remedy}`);\n }\n return lines;\n}\n\nexport const doctorCommand = defineCommand({\n meta: {\n name: \"doctor\",\n description: \"Report missing, weak, unused, fallback, plaintext-secret, and sink-drift issues\",\n },\n args: {\n env: { type: \"string\", description: \"The environment to report on\" },\n },\n run({ args }) {\n return guard(async () => {\n const report = await runDoctor({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n });\n write(renderDoctor(report));\n if (!report.ok) {\n process.exitCode = 1;\n }\n });\n },\n});\n","/**\n * Opening a penv project from a working directory, and the pieces every command\n * needs once it is open: the config, the environment to act on, the provider\n * rooted at `.penv/`, and the parameter a CLI key names.\n */\n\nimport { dirname, resolve } from \"node:path\";\nimport type {\n DecryptFailure,\n KeySource,\n ParameterRef,\n PenvConfig,\n Provider,\n ResolutionCandidate,\n} from \"@penvhq/core\";\nimport {\n candidatesFor,\n formatValueFile,\n isCanonicalSegment,\n isReservedToken,\n loadConfig,\n openValue,\n PenvError,\n parameterId,\n ReservedTokenError,\n refFromAccessPath,\n resolveEnvironment,\n resolveKeySource,\n} from \"@penvhq/core\";\nimport { FilesystemProvider } from \"@penvhq/provider-filesystem\";\nimport {\n assertProvidersRegistered,\n createProvider,\n createSourceProvider,\n LOCAL_TREE_TYPE,\n} from \"./registry.js\";\n\nexport const PENV_DIR = \".penv\";\n\nexport interface Project {\n /** The directory holding `penv.config.ts`. */\n readonly root: string;\n readonly configFile: string;\n readonly config: PenvConfig;\n readonly penvDir: string;\n /**\n * The project's provider, as the contract — never the concrete\n * implementation. Shared commands speak the async interface and nothing more;\n * the sync twins a command genuinely needs are reached through `localTree`,\n * which is the one place the filesystem-only surface is named.\n */\n readonly provider: Provider;\n}\n\nexport function openProject(cwd: string): Project {\n const { config, file } = loadConfig(cwd);\n const root = dirname(file);\n const penvDir = resolve(root, PENV_DIR);\n // Refuse a config naming a provider this build cannot construct here, at open\n // time, rather than as a crash from whichever command first reached it. Plugin\n // types are resolved against the project (`root`), where the user installed them.\n assertProvidersRegistered(config, root);\n return {\n root,\n configFile: file,\n config,\n penvDir,\n provider: createProvider(LOCAL_TREE_TYPE, { root: penvDir, config }),\n };\n}\n\n/**\n * The project's provider as the concrete filesystem tree, for the sync reads and\n * writes a synchronous command cannot get from the async contract.\n *\n * `import`, `generate`, and `push` are synchronous — they are the adoption path\n * and the leaving guarantee — and they act on the local `.penv` tree, which is\n * always the filesystem provider (`penv pull` materialises it; the runtime reads\n * it). This narrows to that provider and names the reliance, so the type of\n * `Project.provider` stays the contract everywhere else. The refusal is a\n * belt-and-braces guard: `openProject` builds the tree as filesystem, so a\n * project in hand always narrows.\n */\nexport function localTree(project: Project): FilesystemProvider {\n if (!(project.provider instanceof FilesystemProvider)) {\n throw new PenvError(\n \"PROVIDER_NOT_LOCAL\",\n `This command reads the local .penv tree synchronously, which the \\`${project.provider.type}\\` provider is not`,\n \"Run this against a filesystem-backed project, or use a command that speaks the async provider contract.\",\n );\n }\n return project.provider;\n}\n\n/**\n * The environment's DECLARED source-of-truth provider — the backend that holds\n * the truth, as opposed to `Project.provider`, which is always the local\n * filesystem tree every command edits.\n *\n * `pull` and cross-provider `doctor` read here: they compare or copy against what\n * the config says the environment's values live in. An environment with no\n * `providers` entry has no separate source of truth, so this falls back to the\n * local tree — the two coincide, and there is nothing to pull from elsewhere.\n * `openProject` is untouched: the working copy stays filesystem regardless.\n */\nexport async function sourceProviderFor(project: Project, environment: string): Promise<Provider> {\n const providerConfig = project.config.providers[environment];\n if (providerConfig === undefined) {\n return createProvider(LOCAL_TREE_TYPE, { root: project.penvDir, config: project.config });\n }\n // A declared backend may be a plugin (`penv-cloud`, a third-party provider), so\n // this goes through the async, plugin-aware path rather than the built-in-only\n // `createProvider`. The local tree above is always a built-in and stays sync.\n return createSourceProvider(providerConfig.type, {\n root: project.penvDir,\n config: project.config,\n providerConfig,\n environment,\n });\n}\n\n/** The environment to act on: `--env`, then `PENV_ENV`, then `NODE_ENV`. */\nexport function targetEnvironment(project: Project, explicit?: string): string {\n return resolveEnvironment(project.config, explicit);\n}\n\n/** A namespace separator on the command line, either spelling. */\nconst KEY_SEPARATOR = /[./\\\\]/;\n\n/**\n * The reserved set for a caller that has no config to hand: the static tokens\n * and nothing else. Environments are a config whitelist (invariant 10), so a\n * caller without a config cannot know which environment names are reserved.\n */\nconst NO_ENVIRONMENTS: PenvConfig = { environments: [], providers: {} };\n\n/**\n * The parameter a CLI key names — `redis/password` and `redis.password` are one.\n *\n * `config` is optional because the reserved set is config-driven: given one,\n * a declared environment name is refused here too; without one, only the static\n * tokens are. Pass the open project's config whenever there is one — this is the\n * early, better-worded half of a check the filename grammar makes again when the\n * file is read, never the only half.\n */\nexport function refFromKey(key: string, config?: PenvConfig): ParameterRef {\n const segments = key.split(KEY_SEPARATOR).filter((segment) => segment.length > 0);\n const name = segments[segments.length - 1];\n if (name === undefined) {\n throw new PenvError(\n \"PARAMETER_KEY\",\n `\\`${key}\\` names no parameter`,\n \"A key is `<namespace>/<name>` or `<namespace>.<name>`, e.g. `redis/password`.\",\n );\n }\n if (isReservedToken(name, config ?? NO_ENVIRONMENTS)) {\n throw new ReservedTokenError(\"parameter\", name, key);\n }\n return { namespace: segments.slice(0, -1), name };\n}\n\n/**\n * Refuses a key that no canonical value file can back — the guard for the *write*\n * path only, `set` and the destination of `mv`.\n *\n * It lives apart from {@link refFromKey} deliberately. Read, remove and the\n * source of a rename address a file that already exists by its literal name, and\n * the filename grammar admits a non-canonical name (`dbHost`, `database_url`)\n * that the transform will never *produce* but a hand-written file or an older\n * penv may already have on disk. Guarding those paths would leave such a tree\n * repairable only by deleting the file by hand — the very lockout this function\n * is here to avoid. So only creation is refused: a `set` or a rename *into* a\n * name the schema cannot read is a file that would sit inert, and refusing it\n * early names the file that actually backs the key instead of writing a dead one.\n */\nexport function assertWritableKey(key: string): void {\n const segments = key.split(KEY_SEPARATOR).filter((s) => s.length > 0);\n if (segments.length === 0 || segments.every((s) => isCanonicalSegment(s))) {\n return;\n }\n const ref = refFromAccessPath(segments);\n if (ref !== undefined) {\n const suggestion = [...ref.namespace, ref.name].join(\"/\");\n throw new PenvError(\n \"PARAMETER_KEY_CASING\",\n `\\`${key}\\` is not a canonical parameter name`,\n `Parameter files are lower-case and hyphenated. Did you mean \\`${suggestion}\\`? That is the file that backs the \\`${key}\\` key in your schema.`,\n );\n }\n throw new PenvError(\n \"PARAMETER_KEY_UNREACHABLE\",\n `No value file can be named that reaches \\`${key}\\``,\n \"Parameter files are lower-case and hyphenated, and this key maps to no such file — a run of capitals like `apiURL` cannot be reached (use `api-url`, which the schema reads as `apiUrl`). Run `penv validate` or `penv fill` to see the names penv expects.\",\n );\n}\n\n/**\n * The key source for one environment, chosen by core.\n *\n * The CLI does not decide where keys live — it asks. Two choosers would be two\n * answers to one question, and the runtime is the other caller: a CLI that\n * sealed under a key the runtime could not find would make `penv set` and `load`\n * disagree about the same file.\n */\nexport function keySourceFor(project: Project, environment: string): KeySource {\n return resolveKeySource(project.config, environment);\n}\n\n/**\n * One parameter resolved against the filesystem, without reading it twice.\n *\n * The winner is a `ResolutionCandidate` rather than a bare `ValueFile` so this\n * satisfies core's `ResolvedValue`: the sync walk and the async one then hand the\n * same shape to the same `requireValue`, and there is one place that decides\n * what an unreadable value is.\n */\nexport interface SyncResolution {\n readonly ref: ParameterRef;\n readonly parameter: string;\n /** `undefined` when nothing is present, or when the winner did not open. */\n readonly value: string | undefined;\n readonly winner: ResolutionCandidate | undefined;\n /** Set only when the winner is `.enc` and did not decrypt. Mirrors `Resolution`. */\n readonly undecryptable?: DecryptFailure;\n}\n\n/**\n * The synchronous half of the cascade.\n *\n * `import` and `generate` are synchronous — they are the adoption path, and the\n * v0.1 gate exercises them as plain calls — while the provider contract is\n * async because a network-backed provider cannot be anything else. This walks\n * the filesystem provider's *additional* sync reads, exactly as the runtime\n * loader does for the same reason. It does not restate the precedence rule:\n * `candidatesFor` owns the order, and this only walks the list it returns.\n */\nexport function resolveSync(\n provider: FilesystemProvider,\n ref: ParameterRef,\n environment: string,\n keys: KeySource,\n skipPersonal?: boolean,\n): SyncResolution {\n for (const file of candidatesFor(ref, environment, skipPersonal)) {\n const read = provider.readSync(file);\n if (read === undefined) {\n continue;\n }\n // Unconditional, including for a plaintext file, which comes back verbatim:\n // a branch on `file.encrypted` here would be a second place deciding what\n // encryption means, and this walker is already the second walker.\n const opened = openValue(file, read, keys);\n return {\n ref,\n parameter: parameterId(ref),\n value: opened.kind === \"plaintext\" ? opened.value : undefined,\n ...(opened.kind === \"failed\" ? { undecryptable: opened.failure } : {}),\n winner: { file, location: formatValueFile(file), present: true },\n };\n }\n return { ref, parameter: parameterId(ref), value: undefined, winner: undefined };\n}\n\nexport function resolveAllSync(\n provider: FilesystemProvider,\n environment: string,\n keys: KeySource,\n skipPersonal?: boolean,\n): SyncResolution[] {\n return refsFrom(provider.listSync()).map((ref) =>\n resolveSync(provider, ref, environment, keys, skipPersonal),\n );\n}\n\n/**\n * The parameters a provider holds, scopes collapsed and ordered identically\n * everywhere.\n */\nexport function refsFrom(files: readonly ParameterRef[]): ParameterRef[] {\n const refs = new Map<string, ParameterRef>();\n for (const file of files) {\n const ref: ParameterRef = { namespace: file.namespace, name: file.name };\n const id = parameterId(ref);\n if (!refs.has(id)) {\n refs.set(id, ref);\n }\n }\n // Code-unit order, not locale order: a report must be identical on every machine.\n return [...refs.values()].sort((a, b) => {\n const left = parameterId(a);\n const right = parameterId(b);\n return left < right ? -1 : left > right ? 1 : 0;\n });\n}\n","/**\n * The provider registry: the one place the CLI turns a `providers.*.type` into a\n * concrete provider.\n *\n * It lives in the CLI, not in `@penvhq/core` and not in `@penvhq/runtime`. Core owns\n * the `Provider` *contract* and must not know which implementations exist —\n * knowing would make the interface answerable to its callers. The runtime never\n * selects a provider at all: it reads the local `.penv` tree whatever an\n * environment declares (see `runtime/src/resolve.ts`), so a registry there would\n * be the ability to dial a network provider at boot, which the design forbids.\n *\n * So the registry is exactly the portability seam. A built-in provider is one\n * entry in {@link REGISTRY}. A provider that cannot live in this repo — a private\n * or third-party backend — is resolved by convention instead: a `type` with no\n * built-in entry is loaded from the package `@penvhq/provider-<type>` (or the\n * `module` the config names), exactly as ESLint resolves `eslint-plugin-<name>`.\n * Either way, nothing else in the CLI names an implementation.\n */\n\nimport { createRequire } from \"node:module\";\nimport { dirname, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type { PenvConfig, Provider, ProviderConfig } from \"@penvhq/core\";\nimport { PenvError } from \"@penvhq/core\";\nimport { createFilesystemProvider } from \"@penvhq/provider-filesystem\";\nimport { createKubernetesProvider } from \"@penvhq/provider-kubernetes\";\nimport { createMockProvider } from \"@penvhq/provider-mock\";\nimport { createSsmProvider } from \"@penvhq/provider-ssm\";\nimport { createVaultProvider } from \"@penvhq/provider-vault\";\n\n/** What a factory needs to build a provider rooted at one project's `.penv`. */\nexport interface ProviderContext {\n /** The `.penv/` directory, absolute. */\n readonly root: string;\n /**\n * Required because a provider parses environment segments, and a segment is an\n * environment only if the config declares it — never inferred from the store.\n */\n readonly config: PenvConfig;\n /**\n * The one environment's own `providers.*` entry, when building its declared\n * source of truth. Carries provider-side settings — a Vault base `path`, say —\n * that the config authored, never inferred. The local-tree factory ignores it:\n * the filesystem tree is `.penv/` whatever an environment declares.\n */\n readonly providerConfig?: ProviderConfig;\n /**\n * The environment this provider is the source of truth *for*, when that is what\n * is being built. Unused by the filesystem tree, which is one store across\n * every environment.\n */\n readonly environment?: string;\n}\n\n/** Turns a project's `.penv` context into a provider of one `type`. */\nexport type ProviderFactory = (context: ProviderContext) => Provider;\n\n/** The factory shape a convention-loaded provider package exports. May be async. */\ntype PluginProviderFactory = (context: ProviderContext) => Provider | Promise<Provider>;\n\n/** The symbol a provider plugin package exports — the entry point this seam calls. */\nconst PLUGIN_FACTORY_EXPORT = \"penvProviderFactory\";\n\n/**\n * The local `.penv` tree is always served by the filesystem provider: it is the\n * working copy `penv pull` materialises and every command edits, whatever backend\n * an environment's source of truth lives in. Naming it here keeps the one string\n * literal that means \"the tree on disk\" out of `openProject`.\n */\nexport const LOCAL_TREE_TYPE = \"filesystem\";\n\nconst REGISTRY = new Map<string, ProviderFactory>([\n [LOCAL_TREE_TYPE, ({ root, config }) => createFilesystemProvider({ root, config })],\n [\"vault\", ({ providerConfig }) => createVaultProvider({ path: providerConfig?.path ?? \"penv\" })],\n [\"ssm\", ({ providerConfig }) => createSsmProvider({ path: providerConfig?.path ?? \"penv\" })],\n [\n \"kubernetes\",\n ({ providerConfig }) => createKubernetesProvider(kubernetesOptions(providerConfig)),\n ],\n [\"mock\", ({ root }) => createMockProvider({ storePath: resolve(root, \".penv-mock.json\") })],\n]);\n\n/** The contract methods a loaded plugin must carry before penv will trust it. */\nconst CONTRACT_METHODS = [\n \"read\",\n \"write\",\n \"list\",\n \"remove\",\n \"readMeta\",\n \"writeMeta\",\n \"removeMeta\",\n] as const;\n\n/**\n * Loaded plugin modules, memoized by resolved path, so a command touching several\n * environments backed by one package imports it once.\n */\nconst pluginModuleCache = new Map<string, Promise<Record<string, unknown>>>();\n\n/** Whether a `providers.*.type` names a provider penv builds in. */\nexport function isProviderRegistered(type: string): boolean {\n return REGISTRY.has(type);\n}\n\n/**\n * Builds a *built-in* provider of `type`, refusing an unregistered one loudly.\n * This is the synchronous path `openProject` uses for the local filesystem tree,\n * which is always a built-in — so it stays sync and never dials a plugin. A\n * declared source of truth that may be a plugin is built through\n * {@link createSourceProvider} instead.\n */\nexport function createProvider(type: string, context: ProviderContext): Provider {\n const factory = REGISTRY.get(type);\n if (factory === undefined) {\n throw unknownProvider(type);\n }\n return factory(context);\n}\n\n/**\n * Builds a provider of `type`, resolving a non-built-in `type` as a plugin. A\n * built-in comes from the static map (synchronously); anything else is imported\n * from `@penvhq/provider-<type>`, or the config's `module`, and validated against\n * the contract before it is trusted. The import is async, which is why this is —\n * a network or plugin provider cannot be constructed on a synchronous path.\n */\nexport async function createSourceProvider(\n type: string,\n context: ProviderContext,\n): Promise<Provider> {\n if (REGISTRY.has(type)) {\n return createProvider(type, context);\n }\n return loadPluginProvider(type, context);\n}\n\nasync function loadPluginProvider(type: string, context: ProviderContext): Promise<Provider> {\n const fromDir = resolutionBase(context);\n const specifier = pluginSpecifier(context.providerConfig, type);\n\n const resolved = resolvePlugin(specifier, fromDir);\n if (resolved === undefined) {\n throw unknownProvider(type, context.environment, specifier);\n }\n\n let mod: Record<string, unknown>;\n try {\n mod = await importPlugin(resolved);\n } catch {\n throw new PenvError(\n \"PROVIDER_PLUGIN_LOAD\",\n `The provider package \\`${specifier}\\` for type \\`${type}\\` failed to load`,\n \"It resolved but threw while importing. Check it builds and its dependencies are installed.\",\n );\n }\n\n const factory = mod[PLUGIN_FACTORY_EXPORT];\n if (typeof factory !== \"function\") {\n throw new PenvError(\n \"PROVIDER_PLUGIN_INVALID\",\n `\\`${specifier}\\` does not export \\`${PLUGIN_FACTORY_EXPORT}\\``,\n `A penv provider package must export \\`${PLUGIN_FACTORY_EXPORT}(context) => Provider\\`.`,\n );\n }\n\n const provider = await (factory as PluginProviderFactory)(context);\n assertSatisfiesContract(provider, specifier);\n return provider;\n}\n\n/**\n * Refuses at open time every environment whose `providers.*.type` names a backend\n * this project cannot construct — the whole config in one pass, so a user with two\n * unknown providers hears about both, and never as a crash from the later command\n * that would have been the first to reach one.\n *\n * A built-in type passes on the map; a plugin type passes only if its package\n * resolves from the project — a *synchronous* existence check that runs no plugin\n * code, so the open-time guarantee holds without `openProject` turning async. The\n * plugin's module is imported and its contract checked later, when the\n * environment's source is actually built.\n */\nexport function assertProvidersRegistered(config: PenvConfig, projectRoot: string): void {\n for (const [environment, provider] of Object.entries(config.providers)) {\n if (isProviderRegistered(provider.type)) {\n continue;\n }\n const specifier = pluginSpecifier(provider, provider.type);\n if (resolvePlugin(specifier, projectRoot) === undefined) {\n throw unknownProvider(provider.type, environment, specifier);\n }\n }\n}\n\n/** The package a non-built-in `type` loads from: the config's `module`, or the convention. */\nfunction pluginSpecifier(providerConfig: ProviderConfig | undefined, type: string): string {\n return providerConfig?.module ?? `@penvhq/provider-${type}`;\n}\n\n/** The project the user installed the plugin into — where resolution must start. */\nfunction resolutionBase(context: ProviderContext): string {\n // `context.root` is the `.penv/` directory; its parent is the project root,\n // where `penv.config.ts` and the project's `node_modules` live.\n return dirname(context.root);\n}\n\n/**\n * Resolves a plugin specifier from the project, synchronously and without running\n * it. Returns the absolute module path, or `undefined` when the package is not\n * installed. `createRequire` is anchored at the project (not the CLI's own\n * install), so a globally-installed penv still finds a plugin the project depends\n * on.\n */\nfunction resolvePlugin(specifier: string, fromDir: string): string | undefined {\n try {\n const require = createRequire(resolve(fromDir, \"noop.js\"));\n return require.resolve(specifier);\n } catch {\n return undefined;\n }\n}\n\n/** Imports the resolved module by path, memoized, working from both the ESM and CJS builds. */\nfunction importPlugin(resolvedPath: string): Promise<Record<string, unknown>> {\n const cached = pluginModuleCache.get(resolvedPath);\n if (cached !== undefined) {\n return cached;\n }\n const loading = import(pathToFileURL(resolvedPath).href) as Promise<Record<string, unknown>>;\n pluginModuleCache.set(resolvedPath, loading);\n return loading;\n}\n\n/** Fails loudly if a loaded plugin is missing a contract method — at load, not mid-write. */\nfunction assertSatisfiesContract(provider: Provider, specifier: string): void {\n for (const method of CONTRACT_METHODS) {\n if (typeof (provider as unknown as Record<string, unknown>)[method] !== \"function\") {\n throw new PenvError(\n \"PROVIDER_PLUGIN_INVALID\",\n `The provider from \\`${specifier}\\` is missing \\`${method}()\\``,\n \"It must satisfy the @penvhq/core Provider contract that the filesystem provider defines.\",\n );\n }\n }\n}\n\n/**\n * The Kubernetes provider's `providers.*.path` is `<namespace>/<secretName>`, or\n * just `<secretName>` to use the current `kubectl` context's namespace. Splitting\n * it here is what lets a Secret in a non-`default` namespace be reached from config\n * — `ProviderConfig` has no namespace field of its own.\n */\nfunction kubernetesOptions(providerConfig: ProviderConfig | undefined): {\n namespace?: string;\n secretName: string;\n} {\n const path = providerConfig?.path ?? \"penv\";\n const slash = path.indexOf(\"/\");\n if (slash === -1) return { secretName: path };\n const namespace = path.slice(0, slash);\n const secretName = path.slice(slash + 1) || \"penv\";\n return namespace === \"\" ? { secretName } : { namespace, secretName };\n}\n\nfunction unknownProvider(type: string, environment?: string, specifier?: string): PenvError {\n const known = [...REGISTRY.keys()].map((name) => `\\`${name}\\``).join(\", \");\n const where = environment === undefined ? \"\" : ` for environment ${environment}`;\n const remedy =\n specifier === undefined\n ? `This build registers ${known}. Name a registered provider, or install the build that carries \\`${type}\\`.`\n : `Install its package with \\`npm i ${specifier}\\`, or name a built-in provider: ${known}.`;\n return new PenvError(\n \"UNKNOWN_PROVIDER\",\n `The provider type \\`${type}\\`${where} in penv.config.ts is not one this penv build carries`,\n remedy,\n );\n}\n","/**\n * Reading the user's schema, and the distance between it and the parameter tree.\n *\n * `.penv/env.ts` declares what must exist and the tree holds what does. The gap\n * between them is the signal `penv validate` exists to raise; this module makes\n * it legible without closing it. Nothing here writes or deletes a value file —\n * a declaration has no value, so materialising one could only invent it, and an\n * invented value is the silent-value-reaching-runtime failure penv exists to\n * delete. `penv set` stays the only writer.\n *\n * The introspection below lives here, not in `doctor`, because `doctor` and\n * `watch` both report drift and two readers of the same schema would be two\n * answers to one question.\n *\n * Every helper answers \"I cannot tell\" rather than guessing. A report is only\n * worth reading if every line in it is true, so a field this module cannot\n * understand produces no line at all.\n */\n\nimport type { ParameterRef, PenvConfig, Resolution } from \"@penvhq/core\";\nimport {\n accessPath,\n isReservedToken,\n parameterId,\n refFromAccessPath,\n variableName,\n} from \"@penvhq/core\";\nimport type { z } from \"zod\";\n\nfunction defOf(node: unknown): Record<string, unknown> | undefined {\n if (typeof node !== \"object\" || node === null) {\n return undefined;\n }\n const def = (node as { def?: unknown }).def;\n return typeof def === \"object\" && def !== null ? (def as Record<string, unknown>) : undefined;\n}\n\nexport function typeOf(node: unknown): string | undefined {\n const type = defOf(node)?.type;\n return typeof type === \"string\" ? type : undefined;\n}\n\n/** Peels `.optional()`, `.default()`, `.nullable()` — wrappers, not shapes. */\nexport function unwrap(node: unknown): unknown {\n let current = node;\n for (let depth = 0; depth < 8; depth += 1) {\n const inner = defOf(current)?.innerType;\n if (inner === undefined) {\n return current;\n }\n current = inner;\n }\n return current;\n}\n\nexport function shapeOf(node: unknown): Record<string, unknown> | undefined {\n if (typeOf(node) !== \"object\") {\n return undefined;\n }\n const shape = (node as { shape?: unknown }).shape;\n return typeof shape === \"object\" && shape !== null\n ? (shape as Record<string, unknown>)\n : undefined;\n}\n\nexport type Lookup =\n | { readonly kind: \"found\"; readonly node: unknown }\n | { readonly kind: \"absent\" }\n /** The schema is not introspectable this far down. Every check skips it. */\n | { readonly kind: \"unknown\" };\n\nexport function lookup(root: z.ZodType, path: readonly string[]): Lookup {\n let node: unknown = unwrap(root);\n for (const key of path) {\n const shape = shapeOf(node);\n if (shape === undefined) {\n return { kind: \"unknown\" };\n }\n if (!Object.hasOwn(shape, key)) {\n return { kind: \"absent\" };\n }\n node = unwrap(shape[key]);\n }\n return { kind: \"found\", node };\n}\n\n/** The declared minimum length, when the field is a string that declares one. */\nexport function minLengthOf(node: unknown): number | undefined {\n if (typeOf(node) !== \"string\") {\n return undefined;\n }\n const min = (node as { minLength?: unknown }).minLength;\n return typeof min === \"number\" ? min : undefined;\n}\n\n/**\n * Wrappers that make an absent key legal: the schema itself says this parameter\n * need not have a value, so its absence is a declaration, not drift.\n */\nconst ABSENCE_PERMITTED = new Set([\"optional\", \"default\", \"catch\", \"prefault\"]);\n\n/**\n * Wrappers that still demand the key be present. `z.string().nullable()` accepts\n * `null`, which no value file can produce — a missing file is `undefined`, and\n * `undefined` is what the schema rejects. So a nullable field with no value is\n * drift exactly as a bare one is.\n */\nconst ABSENCE_REFUSED = new Set([\"nullable\", \"nonoptional\", \"readonly\"]);\n\n/**\n * Whether the schema permits this field to have no value at all.\n * `undefined` when a wrapper is not recognised — see the module note.\n */\nfunction permitsAbsence(node: unknown): boolean | undefined {\n let current = node;\n for (let depth = 0; depth < 8; depth += 1) {\n const type = typeOf(current);\n if (type !== undefined && ABSENCE_PERMITTED.has(type)) {\n return true;\n }\n const inner = defOf(current)?.innerType;\n if (inner === undefined) {\n // A plain type, wrapped in nothing that excuses absence.\n return type === undefined ? undefined : false;\n }\n if (type === undefined || !ABSENCE_REFUSED.has(type)) {\n // A wrapper this module has never heard of. It may or may not excuse\n // absence, and guessing either way puts an untrue line in the report.\n return undefined;\n }\n current = inner;\n }\n return undefined;\n}\n\n/** One schema key that takes a value: the leaf of a path through the object shapes. */\ninterface Leaf {\n readonly path: readonly string[];\n /** False only when this key, and every namespace above it, must be present. */\n readonly absencePermitted: boolean | undefined;\n}\n\n/**\n * Every leaf the schema declares. An object is a namespace and is descended\n * into; anything else is a value. A branch whose shape cannot be read is left\n * alone rather than reported as a leaf — an unreadable object is not a string.\n *\n * Absence permission is inherited, because it is inherited in fact: under\n * `z.object({ ... }).optional()` the whole namespace may be absent, so every\n * value beneath it may be too, and a leaf judged on its own wrapper would be\n * reported as drift while the schema is perfectly happy without it.\n */\nfunction leaves(\n node: unknown,\n path: readonly string[],\n inherited: boolean | undefined,\n out: Leaf[],\n): void {\n // `undefined` — a wrapper this module does not understand — is inherited as\n // \"cannot tell\" rather than collapsing to false, so an unreadable namespace\n // never makes its children look required.\n const own = permitsAbsence(node);\n const absencePermitted = inherited === true || own === true ? true : combine(inherited, own);\n\n const shape = shapeOf(unwrap(node));\n if (shape === undefined) {\n if (path.length > 0) {\n out.push({ path, absencePermitted });\n }\n return;\n }\n for (const key of Object.keys(shape)) {\n leaves(shape[key], [...path, key], absencePermitted, out);\n }\n}\n\n/** False only when both answers are a definite false; unknown is contagious. */\nfunction combine(left: boolean | undefined, right: boolean | undefined): boolean | undefined {\n return left === undefined || right === undefined ? undefined : false;\n}\n\nexport function declaredLeaves(schema: z.ZodType): Leaf[] {\n const out: Leaf[] = [];\n leaves(schema, [], false, out);\n return out;\n}\n\n/** A parameter `.penv/env.ts` declares that the tree has no value for. */\nexport interface DeclaredDrift {\n /** The parameter id, or the dotted schema path when no filename could reach it. */\n readonly subject: string;\n /** Absent when no filename reaches this key, which is drift `penv set` cannot close. */\n readonly ref?: ParameterRef;\n /** The line to paste: the `penv set` that closes this, or the rename that must precede it. */\n readonly remedy: string;\n readonly detail: string;\n}\n\n/** A parameter the tree holds a value for that `.penv/env.ts` does not declare. */\nexport interface UndeclaredDrift {\n readonly ref: ParameterRef;\n /** The generated variable, which is the name the application would have read. */\n readonly variable: string;\n}\n\n/**\n * The distance between `.penv/env.ts` and the tree, in both directions. Named\n * `declared`/`undeclared` for the side that has it, not for a verdict: neither\n * direction is by itself an error, and only `validate` decides that.\n */\nexport interface DriftReport {\n readonly declared: readonly DeclaredDrift[];\n readonly undeclared: readonly UndeclaredDrift[];\n}\n\nexport const EMPTY_DRIFT: DriftReport = { declared: [], undeclared: [] };\n\nexport interface DriftInput {\n readonly schema: z.ZodType;\n /** Every parameter the tree holds, resolved for `environment`. */\n readonly resolutions: readonly Resolution[];\n readonly config: PenvConfig;\n readonly environment: string;\n}\n\n/**\n * A parameter has a value for this environment when *some* file wins, not when\n * penv can read it: an `.enc` winner is a value that exists, and reporting it as\n * missing would send the user to `penv set` to overwrite a secret they have.\n */\nfunction hasValue(resolution: Resolution): boolean {\n return resolution.winner !== undefined;\n}\n\nexport function computeDrift(input: DriftInput): DriftReport {\n const { schema, resolutions, config, environment } = input;\n\n const valued = new Set(resolutions.filter(hasValue).map((resolution) => resolution.parameter));\n\n const declared: DeclaredDrift[] = [];\n for (const leaf of declaredLeaves(schema)) {\n if (leaf.absencePermitted !== false) {\n continue;\n }\n const path = leaf.path.join(\".\");\n const ref = refFromAccessPath(leaf.path);\n // Declared, and permanently unreachable — two ways, one consequence. Either\n // the key is outside the name transform's image (`apiURL`), or it spells a\n // reserved token, which the filename grammar refuses as a parameter name\n // (invariant 11). No value file resolves to this key either way, so the\n // remedy is a rename: a `penv set` line here would be a command that errors.\n if (ref === undefined || isReservedToken(ref.name, config)) {\n declared.push({\n subject: path,\n remedy:\n `Rename the \\`${path}\\` key in .penv/env.ts — a parameter name is lower-case, ` +\n `hyphenated, and never a reserved token, so no value file reaches this key.`,\n detail: \"declared, no filename reaches it\",\n });\n continue;\n }\n if (valued.has(parameterId(ref))) {\n continue;\n }\n declared.push({\n subject: parameterId(ref),\n ref,\n remedy: `penv set ${[...ref.namespace, ref.name].join(\"/\")} --env ${environment}`,\n detail: `declared in .penv/env.ts, no value for ${environment}`,\n });\n }\n\n const undeclared: UndeclaredDrift[] = [];\n for (const resolution of resolutions) {\n if (lookup(schema, accessPath(resolution.ref)).kind !== \"absent\") {\n continue;\n }\n undeclared.push({\n ref: resolution.ref,\n variable: variableName(resolution.ref, config),\n });\n }\n\n return { declared, undeclared };\n}\n","/**\n * The CLI's output voice.\n *\n * Reports are tables: a glyph, a label, and the parameter the line is about.\n * Columns are sized to the widest cell in one block so that a report reads down\n * the page as well as across it, and every command that reports uses this module\n * rather than assembling its own spacing.\n */\n\nimport { PenvError } from \"@penvhq/core\";\n\nexport const CHECK = \"✓\";\nexport const WARN = \"⚠\";\n/** \"I could not look\" — a check that ran but could not reach a verdict. Never a pass. */\nexport const UNKNOWN = \"?\";\n\n/** One reported line. `detail` is the last column and is never padded. */\nexport interface Row {\n readonly glyph: string;\n readonly label: string;\n readonly subject?: string;\n readonly detail?: string;\n}\n\n/** A step in a scaffolding run: what penv did, and an aligned aside. */\nexport interface Step {\n readonly glyph: string;\n readonly text: string;\n readonly note?: string;\n}\n\n/** Where a step's aside starts, measured from the glyph. */\nconst NOTE_COLUMN = 29;\n\nfunction widest(values: readonly string[]): number {\n return values.reduce((max, value) => Math.max(max, value.length), 0);\n}\n\nexport function formatRows(rows: readonly Row[]): string[] {\n const labelWidth = widest(rows.map((row) => row.label)) + 2;\n // Only rows that carry a detail need their subject padded; a row whose subject\n // is its last column must not widen the table for every other row.\n const detailed = rows.filter((row) => row.detail !== undefined);\n const subjectWidth = widest(detailed.map((row) => row.subject ?? \"\")) + 1;\n\n return rows.map((row) => {\n const head = `${row.glyph} ${row.label.padEnd(labelWidth)}`;\n if (row.detail === undefined) {\n return `${head}${row.subject ?? \"\"}`.trimEnd();\n }\n return `${head}${(row.subject ?? \"\").padEnd(subjectWidth)}${row.detail}`.trimEnd();\n });\n}\n\n/**\n * Free-form aligned columns, for output that is a table rather than a report.\n * Every column but the last is padded to its widest cell.\n */\nexport function columns(rows: readonly (readonly string[])[], gap = 2): string[] {\n const count = rows.reduce((max, row) => Math.max(max, row.length), 0);\n const widths: number[] = [];\n for (let column = 0; column < count; column += 1) {\n widths.push(widest(rows.map((row) => row[column] ?? \"\")) + gap);\n }\n return rows.map((row) =>\n row\n .map((cell, index) => (index === row.length - 1 ? cell : cell.padEnd(widths[index] ?? 0)))\n .join(\"\")\n .trimEnd(),\n );\n}\n\nexport function formatSteps(steps: readonly Step[]): string[] {\n return steps.map((step) => {\n if (step.note === undefined) {\n return `${step.glyph} ${step.text}`;\n }\n // A text wider than the column gets a single space instead of alignment.\n // `padEnd` returns the string untouched when it is already too long, so the\n // aside ran straight into the last word — legible right up until the day a\n // step had something long to say, which is the day it mattered.\n const text = step.text.length >= NOTE_COLUMN ? `${step.text} ` : step.text.padEnd(NOTE_COLUMN);\n return `${step.glyph} ${text}${step.note}`;\n });\n}\n\nexport function write(lines: readonly string[]): void {\n for (const line of lines) {\n process.stdout.write(`${line}\\n`);\n }\n}\n\n/**\n * A `PenvError` already names the parameter, the environment, and the remedy, so\n * it is printed as written. Anything else is a bug in penv and keeps its stack.\n */\nexport function reportError(error: unknown): void {\n if (error instanceof PenvError) {\n process.stderr.write(`${error.message}\\n`);\n } else if (error instanceof Error) {\n process.stderr.write(`${error.stack ?? error.message}\\n`);\n } else {\n process.stderr.write(`${String(error)}\\n`);\n }\n process.exitCode = 1;\n}\n\n/** Turns a thrown error into a printed one and a non-zero exit code. */\nexport async function guard(run: () => Promise<void>): Promise<void> {\n try {\n await run();\n } catch (error) {\n reportError(error);\n }\n}\n","/**\n * `penv push` — resolve an environment's values and ship them to its sink.\n *\n * This is `penv generate` pointed at CI. It resolves the tree exactly as a\n * deploy would read it — **both `.local` scopes skipped**, because a developer's\n * personal override is not CI's business — judges every generated name against\n * the destination's grammar *before* the first PUT, and only then pushes. The\n * push is all or nothing: a name refused mid-run would leave CI in a state\n * neither the tree nor the destination describes.\n *\n * The mapping is the RFC's: an environment-scoped value becomes a GitHub\n * environment secret of the same name, the unscoped default becomes a repository\n * secret, and GitHub resolves the two in penv's own order — environment over\n * repository — so the cascade is reproduced by the destination's native\n * mechanism rather than flattened at the boundary.\n */\n\nimport type { Meta, MetaBlock, ParameterRef, PenvConfig, SecretScope, Sink } from \"@penvhq/core\";\nimport { checkNameCollisions, PenvError, requireValue, variableName } from \"@penvhq/core\";\nimport type { FilesystemProvider } from \"@penvhq/provider-filesystem\";\nimport { checkGithubNames, createGithubSink } from \"@penvhq/sink-github\";\nimport { defineCommand } from \"citty\";\nimport type { Project, SyncResolution } from \"../project.js\";\nimport {\n keySourceFor,\n localTree,\n openProject,\n PENV_DIR,\n refsFrom,\n resolveAllSync,\n targetEnvironment,\n} from \"../project.js\";\nimport { CHECK, formatRows, guard, WARN, write } from \"../ui.js\";\n\n/** The per-environment meta field recording penv's last push, compared against the destination's `updatedAt`. */\nexport const LAST_PUSHED_KEY = \"lastPushedAt\";\n\nexport interface PushOptions {\n readonly cwd: string;\n readonly environment?: string;\n /** Permits sealed values to be decrypted locally and pushed as plaintext for the destination to re-seal. */\n readonly allowDecrypt?: boolean;\n /** Injected in tests: the sink to push to. Defaults to the one the config declares. */\n readonly sink?: Sink;\n /** Injected in tests: the wall-clock reading recorded in meta. Defaults to now. */\n readonly now?: string;\n}\n\nexport interface PushResult {\n readonly environment: string;\n /** The `owner/repo` targeted, when the config named one. */\n readonly repo: string | undefined;\n readonly pushed: number;\n readonly repositorySecrets: number;\n readonly environmentSecrets: number;\n /** How many were sealed and crossed as plaintext for the destination to re-seal. */\n readonly decrypted: number;\n}\n\n/** One value ready to send, with the destination scope it lands in. */\ninterface Outbound {\n readonly ref: ParameterRef;\n readonly variable: string;\n readonly value: string;\n readonly scope: SecretScope;\n readonly encrypted: boolean;\n}\n\n/** The sink the config declares for this environment, or the injected one. */\nfunction sinkFor(\n project: Project,\n environment: string,\n override: Sink | undefined,\n): { sink: Sink; repo: string | undefined } {\n const declared = project.config.sinks?.[environment];\n if (declared === undefined) {\n throw new PenvError(\n \"NO_SINK\",\n `Environment ${environment} declares no sink in penv.config.ts, so penv has nowhere to push`,\n `Add a \\`sinks\\` entry, e.g. \\`sinks: { ${environment}: { type: \"github\" } }\\`, then run \\`penv push --env ${environment}\\` again.`,\n );\n }\n const repo = declared.repo;\n if (override !== undefined) {\n return { sink: override, repo };\n }\n if (declared.type === \"github\") {\n return { sink: createGithubSink(repo === undefined ? {} : { repo }), repo };\n }\n throw new PenvError(\n \"UNKNOWN_SINK\",\n `Environment ${environment} declares sink type \\`${declared.type}\\`, which penv does not know`,\n 'The only sink in this release is `github`. Set `type: \"github\"`.',\n );\n}\n\n/**\n * Every value to send, resolved up front so the encrypted/allow-decrypt refusal\n * also happens before anything is pushed. A `.local` scope is already gone (the\n * push resolution dropped it), so a winner is only ever environment-scoped or the\n * unscoped default — the destination scope is that binary.\n */\nfunction plan(\n resolutions: readonly SyncResolution[],\n config: PenvConfig,\n environment: string,\n allowDecrypt: boolean,\n): Outbound[] {\n const outbound: Outbound[] = [];\n for (const resolution of resolutions) {\n const winner = resolution.winner;\n if (winner === undefined) {\n continue;\n }\n let encrypted = false;\n if (winner.file.encrypted) {\n if (!allowDecrypt) {\n throw new PenvError(\n \"ENCRYPTED_VALUE_REFUSED\",\n `Parameter ${resolution.parameter} for environment ${environment} resolves to the encrypted value file ${PENV_DIR}/${winner.location}, and a push sends plaintext for GitHub to re-seal`,\n \"Re-run with `--allow-decrypt` to decrypt it locally and push it, or push an environment \" +\n \"whose values are plaintext. penv's encryption stops at the sink; the destination seals it \" +\n \"under its own key.\",\n );\n }\n // Throws naming the reason if a sealed winner cannot be opened — never\n // silently dropping the secret CI needs.\n requireValue(resolution, environment);\n encrypted = true;\n }\n if (resolution.value === undefined) {\n continue;\n }\n const scope: SecretScope =\n winner.file.scope.kind === \"unscoped\"\n ? { kind: \"repository\" }\n : { kind: \"environment\", environment };\n outbound.push({\n ref: resolution.ref,\n variable: variableName(resolution.ref, config),\n value: resolution.value,\n scope,\n encrypted,\n });\n }\n return outbound;\n}\n\n/** Records what penv did, per environment, in the committed meta — never a value read back. */\nfunction withLastPushed(meta: Meta | undefined, environment: string, iso: string): Meta {\n const base: Meta = meta ?? {};\n const environments: Record<string, MetaBlock> = { ...(base.environments ?? {}) };\n environments[environment] = { ...(environments[environment] ?? {}), [LAST_PUSHED_KEY]: iso };\n return { ...base, environments };\n}\n\nfunction recordPush(\n tree: FilesystemProvider,\n ref: ParameterRef,\n environment: string,\n iso: string,\n): void {\n const meta = withLastPushed(tree.readMetaSync(ref), environment, iso);\n tree.writeMetaSync(ref, meta);\n}\n\nexport async function runPush(options: PushOptions): Promise<PushResult> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const { sink, repo } = sinkFor(project, environment, options.sink);\n\n const tree = localTree(project);\n const keys = keySourceFor(project, environment);\n // The push resolution: both `.local` scopes dropped. CI receives what CI would read.\n const resolutions = resolveAllSync(tree, environment, keys, true);\n const refs = refsFrom(resolutions.map((resolution) => resolution.ref));\n\n // Every name judged before a single PUT. Exact-string collisions are core's;\n // GitHub's reserved prefix, leading digit, charset, and case-insensitive\n // collisions are the sink's. Both refuse the whole push, never half of it.\n const collision = checkNameCollisions(refs, project.config)[0];\n if (collision !== undefined) {\n throw collision;\n }\n const nameError = checkGithubNames(refs, project.config)[0];\n if (nameError !== undefined) {\n throw nameError;\n }\n\n const outbound = plan(resolutions, project.config, environment, options.allowDecrypt === true);\n\n // Reachable and writable, or penv stops here having placed nothing.\n await sink.verify();\n\n let repositorySecrets = 0;\n let environmentSecrets = 0;\n for (const item of outbound) {\n await sink.push(item.variable, item.value, item.scope);\n if (item.scope.kind === \"repository\") {\n repositorySecrets += 1;\n } else {\n environmentSecrets += 1;\n }\n // Stamped AFTER the push, per item — not once before the loop. The destination\n // stamps each secret's `updated_at` when its own PUT lands, and one `gh`\n // process runs per parameter, so a single pre-loop time would sit seconds\n // behind the destination's and make `doctor`'s hand-edit check fire on a clean\n // push. A tolerance in `doctor` still absorbs the residual clock skew.\n recordPush(tree, item.ref, environment, options.now ?? new Date().toISOString());\n }\n\n return {\n environment,\n repo,\n pushed: outbound.length,\n repositorySecrets,\n environmentSecrets,\n decrypted: outbound.filter((item) => item.encrypted).length,\n };\n}\n\nexport function renderPush(result: PushResult): string[] {\n if (result.pushed === 0) {\n return formatRows([\n {\n glyph: CHECK,\n label: \"Nothing to push\",\n subject: `no values resolve for environment ${result.environment}`,\n },\n ]);\n }\n\n const target = `GitHub Actions for environment ${result.environment}${\n result.repo === undefined ? \"\" : ` (${result.repo})`\n }`;\n const rows = [\n {\n glyph: CHECK,\n label: \"Pushed\",\n subject: `${result.pushed} ${result.pushed === 1 ? \"secret\" : \"secrets\"}`,\n detail: `to ${target}`,\n },\n {\n glyph: CHECK,\n label: \"Scopes\",\n subject: `${result.environmentSecrets} environment, ${result.repositorySecrets} repository`,\n detail:\n \"environment secrets override repository secrets, as penv's env scope overrides the default\",\n },\n ];\n if (result.decrypted > 0) {\n rows.push({\n glyph: WARN,\n label: \"Decrypted\",\n subject: `${result.decrypted} ${result.decrypted === 1 ? \"secret\" : \"secrets\"}`,\n detail: \"sent as plaintext for GitHub to re-seal under its own key\",\n });\n }\n return formatRows(rows);\n}\n\nexport const pushCommand = defineCommand({\n meta: {\n name: \"push\",\n description: \"Push an environment's resolved values to its sink (GitHub Actions Secrets)\",\n },\n args: {\n env: { type: \"string\", description: \"The environment to push\" },\n \"allow-decrypt\": {\n type: \"boolean\",\n description: \"Decrypt sealed values locally and push them as plaintext for GitHub to re-seal\",\n },\n },\n run({ args }) {\n return guard(async () => {\n const result = await runPush({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n ...(args[\"allow-decrypt\"] === undefined ? {} : { allowDecrypt: args[\"allow-decrypt\"] }),\n });\n write(renderPush(result));\n });\n },\n});\n","/**\n * `penv validate` — build the target environment's configuration and check it\n * against the one schema.\n *\n * Three failures land here rather than anywhere else, and all three are errors:\n * a reserved token in a name (invariant 11), two parameters mapping to one\n * generated variable (invariant 12 — never last-write-wins), and a config object\n * the schema rejects. A passing run means the schema is internally consistent;\n * it does not mean the schema is correct. That is your review, especially after\n * an inferred import.\n */\n\nimport { resolve as resolvePath } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type { ParameterRef, ValueFile } from \"@penvhq/core\";\nimport {\n accessPath,\n checkNameCollisions,\n jitiFor,\n NameCollisionError,\n PenvError,\n ReservedTokenError,\n resolveAll,\n SCHEMA_HARVEST_ENV,\n schemaFileOf,\n validateConfig,\n} from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport type { z } from \"zod\";\nimport type { Project } from \"../project.js\";\nimport { keySourceFor, openProject, refsFrom, targetEnvironment } from \"../project.js\";\nimport type { DriftReport } from \"../schema.js\";\nimport { computeDrift, EMPTY_DRIFT } from \"../schema.js\";\nimport { CHECK, formatRows, guard, type Row, WARN, write } from \"../ui.js\";\n\nexport type ValidateIssueKind = \"config\" | \"reserved\" | \"collision\" | \"schema\" | \"undecryptable\";\n\nexport interface ValidateIssue {\n readonly kind: ValidateIssueKind;\n /** What the line is about: a parameter, a variable, a token, or a file. */\n readonly subject: string;\n readonly message: string;\n readonly remedy?: string;\n}\n\nexport interface ValidateResult {\n readonly ok: boolean;\n readonly environment: string;\n readonly parameters: number;\n readonly issues: readonly ValidateIssue[];\n /**\n * The distance between the schema and the tree, carried for the callers\n * that report it (`watch`). Never folded into `ok` and never rendered by\n * `renderValidate`: drift is a report, and CI's verdict must not move because\n * a parameter the schema tolerates is absent. Empty when the schema did not\n * load, since there is nothing to measure against.\n */\n readonly drift: DriftReport;\n}\n\nexport interface ValidateOptions {\n readonly cwd: string;\n readonly environment?: string;\n}\n\nconst SCHEMA_EXPORT = \"schema\";\n\nconst LABELS: Readonly<Record<ValidateIssueKind, string>> = {\n config: \"Config\",\n reserved: \"Reserved token\",\n collision: \"Name collision\",\n schema: \"Invalid parameter\",\n undecryptable: \"Undecryptable value\",\n};\n\nfunction firstLine(text: string): string {\n return text.split(\"\\n\")[0] ?? text;\n}\n\nfunction issueFrom(error: PenvError, fallbackSubject: string): ValidateIssue {\n const base = {\n message: firstLine(error.message),\n ...(error.remedy === undefined ? {} : { remedy: error.remedy }),\n };\n if (error instanceof ReservedTokenError) {\n return { kind: \"reserved\", subject: error.token, ...base };\n }\n if (error instanceof NameCollisionError) {\n return { kind: \"collision\", subject: error.variable, ...base };\n }\n return { kind: \"config\", subject: fallbackSubject, ...base };\n}\n\n/**\n * Places a value at its access path. Values are placed exactly as the provider\n * holds them: coercion is the schema's job, so a value file's contents stay a\n * string here.\n */\nfunction place(root: Record<string, unknown>, path: readonly string[], value: string): void {\n const leaf = path[path.length - 1];\n if (leaf === undefined) {\n return;\n }\n let node = root;\n for (const key of path.slice(0, -1)) {\n const existing = node[key];\n if (typeof existing === \"object\" && existing !== null) {\n node = existing as Record<string, unknown>;\n continue;\n }\n const child: Record<string, unknown> = {};\n node[key] = child;\n node = child;\n }\n node[leaf] = value;\n}\n\nfunction isZodType(value: unknown): value is z.ZodType {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"safeParse\" in value &&\n typeof (value as { safeParse: unknown }).safeParse === \"function\"\n );\n}\n\nexport interface SchemaLoad {\n /** Absent when the module could not be evaluated. `issues` says why. */\n readonly schema?: z.ZodType;\n readonly issues: readonly ValidateIssue[];\n}\n\n/**\n * A penv error raised inside the user's own schema module, identified by its\n * `code` rather than by `instanceof`.\n *\n * The error is thrown by *their* copy of penv, which is a different module realm\n * from this one, so `instanceof` is false across the boundary. `code` is the\n * stable, machine-readable discriminator, and this is exactly what it is for.\n */\nfunction validationIssuesOf(\n cause: unknown,\n schemaPath: string,\n): readonly ValidateIssue[] | undefined {\n if (typeof cause !== \"object\" || cause === null) {\n return undefined;\n }\n const error = cause as { code?: unknown; issues?: unknown };\n if (error.code !== \"VALIDATION_FAILED\" || !Array.isArray(error.issues)) {\n return undefined;\n }\n return error.issues.map((issue: unknown) => {\n const { parameter, message } = issue as { parameter?: unknown; message?: unknown };\n return {\n kind: \"schema\" as const,\n subject: typeof parameter === \"string\" && parameter !== \"\" ? parameter : schemaPath,\n message: typeof message === \"string\" ? message : String(issue),\n remedy: `Fix the value, or adjust the schema in ${schemaPath} if the shape is wrong.`,\n };\n });\n}\n\n/**\n * Serialises the `PENV_ENV` pin in {@link loadSchema}.\n *\n * The environment reaches the user's module through a process global, because\n * that is the only channel their scaffolded `load(schema)` reads. A global\n * pinned across an `await` is not re-entrant: two overlapping loads interleave,\n * the second captures the first's value as `previous`, and restoring it on the\n * way out leaves the global pinned to an environment nobody asked for — every\n * later cycle then silently validates the wrong one. The window is real because\n * `runValidate` is exported and nothing stops a caller validating two\n * environments at once; `watch` is safe only by accident of its single-flight.\n *\n * A queue rather than a fix to the channel: the global *is* the contract with\n * the user's module, so the pin cannot go away. Only one load may hold it.\n */\nlet schemaLoads: Promise<unknown> = Promise.resolve();\n\nfunction exclusively<T>(work: () => Promise<T>): Promise<T> {\n const result = schemaLoads.then(work, work);\n // Never let a rejection break the chain for the next caller.\n schemaLoads = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n}\n\n/**\n * The one schema, read from wherever `schemaFile` puts it.\n *\n * Only the `schema` export is read, never `env` — a command whose job is to\n * *report* on configuration must not be stopped by it. That is the whole reason\n * the docs tell type-only consumers to import `schema`: a type-only import is\n * erased and never evaluates the module at all.\n *\n * A *runtime* read cannot have that guarantee: evaluating the module runs its\n * top level, and the scaffolded module ends in an eager\n * `export const env = load(schema)`. Against a tree with no values yet that load\n * would throw and take the whole namespace — including the `schema` export —\n * down with it, leaving `fill` blind to the very gap it exists to close. So the\n * schema-harvest flag is pinned alongside `PENV_ENV` for this one import:\n * `load()` defers under it (see `SCHEMA_HARVEST_ENV` in core), the module\n * evaluates, and the schema is always reachable. A module that fails for its own\n * reasons still reports honestly — a penv validation error raised at its top\n * level is unwrapped back into per-parameter issues, and anything else is a\n * config issue naming the file.\n *\n * The pins are process globals, so only one load may hold them at a time — see\n * {@link exclusively}. Loads queue rather than overlap.\n */\nexport function loadSchema(project: Project, environment: string): Promise<SchemaLoad> {\n // Resolved against the project root, not `.penv/`: `schemaFile` is relative to\n // penv.config.ts, so a schema at `src/env.ts` is looked for where it is.\n const schemaPath = schemaFileOf(project.config);\n const file = pathToFileURL(resolvePath(project.root, schemaPath)).href;\n return exclusively(() => loadSchemaExclusively(file, schemaPath, environment));\n}\n\n/** {@link loadSchema}'s body, run only while it holds the `PENV_ENV` + harvest pins. */\nasync function loadSchemaExclusively(\n file: string,\n schemaPath: string,\n environment: string,\n): Promise<SchemaLoad> {\n // Resolved from the user's own file: `zod` and `penv` are their dependencies,\n // not the CLI's. Shared with config loading (jitiFor) so both evaluate user modules\n // identically — including resolving `server-only` to its no-throw variant so a\n // server-guarded `.penv/env.ts` still yields its `schema` export.\n const jiti = jitiFor(file);\n\n // Two pins, one window: `PENV_ENV` so anything the module resolves targets the\n // environment being validated, and the schema-harvest flag so the scaffolded\n // eager `export const env = load(schema)` defers instead of throwing — a tree\n // with no values yet would otherwise take the `schema` export down with it,\n // and `fill` could never see the gap it exists to close.\n const previous = process.env.PENV_ENV;\n const previousHarvest = process.env[SCHEMA_HARVEST_ENV];\n process.env.PENV_ENV = environment;\n process.env[SCHEMA_HARVEST_ENV] = \"1\";\n let loaded: unknown;\n try {\n loaded = await jiti.import(file);\n } catch (cause) {\n const issues = validationIssuesOf(cause, schemaPath);\n if (issues !== undefined) {\n return { issues };\n }\n const detail = cause instanceof Error ? firstLine(cause.message) : String(cause);\n return {\n issues: [\n {\n kind: \"config\",\n subject: schemaPath,\n message: `${schemaPath} could not be loaded: ${detail}`,\n remedy: `Fix the error above. penv reads the \\`${SCHEMA_EXPORT}\\` export of ${schemaPath}, which is yours to edit.`,\n },\n ],\n };\n } finally {\n if (previous === undefined) {\n delete process.env.PENV_ENV;\n } else {\n process.env.PENV_ENV = previous;\n }\n if (previousHarvest === undefined) {\n delete process.env[SCHEMA_HARVEST_ENV];\n } else {\n process.env[SCHEMA_HARVEST_ENV] = previousHarvest;\n }\n }\n\n const exported =\n typeof loaded === \"object\" && loaded !== null\n ? (loaded as Record<string, unknown>)[SCHEMA_EXPORT]\n : undefined;\n\n if (!isZodType(exported)) {\n return {\n issues: [\n {\n kind: \"config\",\n subject: schemaPath,\n message: `${schemaPath} exports no \\`${SCHEMA_EXPORT}\\``,\n remedy: `Export the shape as \\`export const ${SCHEMA_EXPORT} = z.object({ ... })\\`. One schema drives both validation and types.`,\n },\n ],\n };\n }\n return { schema: exported, issues: [] };\n}\n\nexport async function runValidate(options: ValidateOptions): Promise<ValidateResult> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const schemaPath = schemaFileOf(project.config);\n const issues: ValidateIssue[] = [];\n\n // Invariant 11: a reserved token in a filename is an error, never a silent\n // misparse — so listing the tree is itself a check.\n let files: ValueFile[];\n try {\n files = await project.provider.list();\n } catch (error) {\n if (!(error instanceof PenvError)) {\n throw error;\n }\n return {\n ok: false,\n environment,\n parameters: 0,\n issues: [issueFrom(error, schemaPath)],\n drift: EMPTY_DRIFT,\n };\n }\n\n const refs: ParameterRef[] = refsFrom(files);\n\n // The config decides what an environment is, so a broken config is not a\n // smaller problem than a broken value — it is the problem that makes value\n // files unreadable. `validateConfig` collects every one of them, and until it\n // was called from here it collected them for nobody: a config declaring an\n // environment with no provider, or a name no filename can hold, passed\n // `penv validate` with a ✓.\n for (const error of validateConfig(project.config)) {\n issues.push(issueFrom(error, \"penv.config.ts\"));\n }\n\n // Invariant 12: two parameters mapping to one generated variable would lose a\n // value on `penv generate`. It fails here rather than there.\n for (const collision of checkNameCollisions(refs, project.config)) {\n issues.push(issueFrom(collision, collision.variable));\n }\n\n const { schema, issues: schemaIssues } = await loadSchema(project, environment);\n issues.push(...schemaIssues);\n\n let drift: DriftReport = EMPTY_DRIFT;\n\n if (schema !== undefined) {\n const resolutions = await resolveAll(\n environment,\n project.provider,\n keySourceFor(project, environment),\n );\n const object: Record<string, unknown> = {};\n // The access paths whose value exists and could not be read. Nothing is\n // placed at them, so the schema will call each one absent — see below.\n const undecryptable = new Set<string>();\n for (const resolution of resolutions) {\n if (resolution.undecryptable !== undefined) {\n undecryptable.add(accessPath(resolution.ref).join(\".\"));\n issues.push({\n kind: \"undecryptable\",\n subject: resolution.parameter,\n message: `${resolution.winner?.location ?? \"the winning value file\"} could not be decrypted: ${resolution.undecryptable.detail}`,\n remedy:\n \"Make the key available, or re-seal the value under a key you hold with `penv encrypt`. \" +\n \"The value is there — penv cannot read it.\",\n });\n continue;\n }\n if (resolution.value !== undefined) {\n place(object, accessPath(resolution.ref), resolution.value);\n }\n }\n // Measured from the same resolutions the verdict below is reached on, so the\n // report can never describe a tree the verdict did not read.\n drift = computeDrift({ schema, resolutions, config: project.config, environment });\n\n const result = schema.safeParse(object);\n if (!result.success) {\n for (const problem of result.error.issues) {\n const path = problem.path.join(\".\");\n // One absence, one line. The schema is right that nothing is there, but\n // \"expected string, received undefined\" is the wrong answer to why: the\n // value exists and penv could not read it, which is already reported\n // above with the remedy that fixes it. Printing both puts the true line\n // and the misleading one next to each other and lets the reader pick.\n if (undecryptable.has(path)) {\n continue;\n }\n issues.push({\n kind: \"schema\",\n subject: path || schemaPath,\n message: problem.message,\n remedy: `Fix the value, or adjust the schema in ${schemaPath} if the shape is wrong.`,\n });\n }\n }\n }\n\n return { ok: issues.length === 0, environment, parameters: refs.length, issues, drift };\n}\n\nexport function renderValidate(result: ValidateResult): string[] {\n if (result.ok) {\n return formatRows([\n {\n glyph: CHECK,\n label: \"Schema valid\",\n subject: `${result.parameters} parameters for environment ${result.environment}`,\n },\n ]);\n }\n\n const rows: Row[] = result.issues.map((issue) => ({\n glyph: WARN,\n label: LABELS[issue.kind],\n subject: issue.subject,\n detail: issue.message,\n }));\n\n const lines = formatRows(rows);\n const remedies = [...new Set(result.issues.map((issue) => issue.remedy))];\n for (const remedy of remedies) {\n if (remedy !== undefined) {\n lines.push(` ${remedy}`);\n }\n }\n return lines;\n}\n\nexport const validateCommand = defineCommand({\n meta: {\n name: \"validate\",\n description: \"Validate configuration against the schema; non-zero on failure\",\n },\n args: {\n env: { type: \"string\", description: \"The environment to validate\" },\n },\n run({ args }) {\n return guard(async () => {\n const result = await runValidate({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n });\n write(renderValidate(result));\n if (!result.ok) {\n process.exitCode = 1;\n }\n });\n },\n});\n","/**\n * `penv encrypt <key>` and `penv decrypt <key>` — change whether one value file\n * is sealed, without changing what it says.\n *\n * These act on one parameter at one scope, because a scope is the address the\n * provider actually has: `db-password.production` and `db-password` are two\n * files, and a command that \"encrypted the parameter\" would have to guess which.\n *\n * They exist for two moments the policy cannot handle by itself. The first is\n * adoption: `secret: true` added to a parameter that already has values leaves\n * every existing file plaintext, and `penv set` only seals what it writes. The\n * second is re-sealing after a move — a ciphertext is bound to the address it\n * lives at, so a value file that is renamed or re-scoped must be sealed again for\n * its new address.\n *\n * Neither invents a key. `penv encrypt` with no key refuses, because a key penv\n * chose is a key nobody can reproduce — the same reason `penv set` is the only\n * thing that writes a value, and never a value it made up.\n */\n\nimport type { ValueFile } from \"@penvhq/core\";\nimport {\n formatValueFile,\n isSecret,\n openValue,\n PenvError,\n parameterId,\n sealValue,\n} from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport type { Project } from \"../project.js\";\nimport { keySourceFor, openProject, PENV_DIR, refFromKey, targetEnvironment } from \"../project.js\";\nimport { CHECK, formatRows, guard, write } from \"../ui.js\";\nimport type { ScopeOptions } from \"./set.js\";\nimport { targetScope } from \"./set.js\";\n\nexport interface ResealOptions extends ScopeOptions {\n readonly cwd: string;\n readonly key: string;\n}\n\nexport interface ResealResult {\n readonly parameter: string;\n /** The file that now holds the value. */\n readonly location: string;\n /** The file that no longer exists, because its twin replaced it. */\n readonly removed: string;\n}\n\n/** The two files one value can live in at a scope. Exactly one of them exists. */\nfunction twins(project: Project, key: string, options: ScopeOptions): [ValueFile, ValueFile] {\n const ref = refFromKey(key, project.config);\n const scope = targetScope(project, options, key);\n return [\n { namespace: ref.namespace, name: ref.name, scope, encrypted: false },\n { namespace: ref.namespace, name: ref.name, scope, encrypted: true },\n ];\n}\n\n/**\n * The environment this scope's policy and key are read from.\n *\n * Unlike `set`, this refuses rather than falling back to the base block: both\n * commands here need a *key*, and a key is declared per environment. A scope that\n * names none has no key penv can choose, and choosing the ambient environment's\n * would seal a file every other environment reads under a key only one of them\n * has.\n */\nfunction environmentFor(project: Project, options: ScopeOptions, verb: string): string {\n if (options.environment === undefined) {\n throw new PenvError(\n \"SECRET_SCOPE_AMBIGUOUS\",\n `\\`penv ${verb}\\` names no environment, and keys are declared per environment`,\n \"Pass `--env <environment>`. penv cannot tell which environment's key applies to a file \" +\n \"that names none, and will not pick one for you.\",\n );\n }\n return targetEnvironment(project, options.environment);\n}\n\nasync function readOne(project: Project, file: ValueFile): Promise<string | undefined> {\n return project.provider.read(file);\n}\n\nexport async function runEncrypt(options: ResealOptions): Promise<ResealResult> {\n const project = openProject(options.cwd);\n const environment = environmentFor(project, options, \"encrypt\");\n const [plain, sealed] = twins(project, options.key, options);\n const parameter = parameterId(plain);\n\n const value = await readOne(project, plain);\n if (value === undefined) {\n const already = await readOne(project, sealed);\n throw new PenvError(\n \"PARAMETER_ABSENT\",\n already === undefined\n ? `Parameter ${parameter} has no value file at ${PENV_DIR}/${formatValueFile(plain)}`\n : `Parameter ${parameter} is already encrypted at ${PENV_DIR}/${formatValueFile(sealed)}`,\n already === undefined\n ? `Write it first with \\`penv set ${options.key} --env ${environment}\\`, which seals it ` +\n \"automatically when the parameter's meta declares it a secret.\"\n : \"Nothing to do.\",\n );\n }\n\n const text = sealValue(sealed, value, keySourceFor(project, environment), parameter, environment);\n\n // Written before the plaintext is removed. The reverse order has a window in\n // which the value exists nowhere, and the value is the thing being protected.\n await project.provider.write(sealed, text);\n await project.provider.remove(plain);\n\n return {\n parameter,\n location: formatValueFile(sealed),\n removed: formatValueFile(plain),\n };\n}\n\nexport async function runDecrypt(options: ResealOptions): Promise<ResealResult> {\n const project = openProject(options.cwd);\n const environment = environmentFor(project, options, \"decrypt\");\n const [plain, sealed] = twins(project, options.key, options);\n const parameter = parameterId(plain);\n\n // penv does not ship a command whose purpose is to fail its own check. A\n // secret written in plaintext is a `doctor` failure by policy (invariant 14),\n // and decrypting one on request would manufacture exactly that.\n if (isSecret(await project.provider.readMeta(plain), environment)) {\n throw new PenvError(\n \"SECRET_DECRYPT_REFUSED\",\n `Parameter ${parameter} is declared a secret for environment ${environment}, so penv will not write it in plaintext`,\n \"A secret with a plaintext value file is a `penv doctor` failure. Drop `secret` from the \" +\n \"parameter's meta if it is not one, or run `penv generate --allow-decrypt` if you need \" +\n \"the plaintext value in a `.env` artifact.\",\n );\n }\n\n const stored = await readOne(project, sealed);\n if (stored === undefined) {\n throw new PenvError(\n \"PARAMETER_ABSENT\",\n `Parameter ${parameter} has no encrypted value file at ${PENV_DIR}/${formatValueFile(sealed)}`,\n `Nothing to decrypt. \\`penv get ${options.key} --env ${environment} --explain\\` shows every file penv looked at.`,\n );\n }\n\n const opened = openValue(sealed, stored, keySourceFor(project, environment));\n if (opened.kind === \"failed\") {\n throw new UndecryptableAt(\n parameter,\n environment,\n formatValueFile(sealed),\n opened.failure.detail,\n );\n }\n\n await project.provider.write(plain, opened.value);\n await project.provider.remove(sealed);\n\n return {\n parameter,\n location: formatValueFile(plain),\n removed: formatValueFile(sealed),\n };\n}\n\n/** The one thing `decrypt` can fail at that `requireValue` does not cover: a named file. */\nclass UndecryptableAt extends PenvError {\n constructor(parameter: string, environment: string, location: string, detail: string) {\n super(\n \"VALUE_UNDECRYPTABLE\",\n `Parameter ${parameter} for environment ${environment} is sealed at ${PENV_DIR}/${location}, and penv could not open it: ${detail}`,\n \"Make the key available and run the command again. penv will not replace a value it \" +\n \"cannot read.\",\n );\n }\n}\n\nexport function renderReseal(result: ResealResult, verb: \"Encrypted\" | \"Decrypted\"): string[] {\n return formatRows([\n {\n glyph: CHECK,\n label: verb,\n subject: `${PENV_DIR}/${result.location}`,\n detail: `${PENV_DIR}/${result.removed} removed`,\n },\n ]);\n}\n\nconst SCOPE_ARGS = {\n key: { type: \"positional\", required: true, description: \"The parameter, e.g. redis/password\" },\n env: { type: \"string\", description: \"The environment whose value file to act on\" },\n local: {\n type: \"boolean\",\n description: \"Act on the personal override rather than the shared file\",\n },\n} as const;\n\nfunction scopeOptions(args: {\n env?: string | undefined;\n local?: boolean | undefined;\n}): ScopeOptions {\n return {\n ...(args.env === undefined ? {} : { environment: args.env }),\n ...(args.local === undefined ? {} : { local: args.local }),\n };\n}\n\nexport const encryptCommand = defineCommand({\n meta: { name: \"encrypt\", description: \"Encrypt one parameter's value file at one scope\" },\n args: SCOPE_ARGS,\n run({ args }) {\n return guard(async () => {\n const result = await runEncrypt({ cwd: process.cwd(), key: args.key, ...scopeOptions(args) });\n write(renderReseal(result, \"Encrypted\"));\n });\n },\n});\n\nexport const decryptCommand = defineCommand({\n meta: { name: \"decrypt\", description: \"Decrypt one parameter's value file at one scope\" },\n args: SCOPE_ARGS,\n run({ args }) {\n return guard(async () => {\n const result = await runDecrypt({ cwd: process.cwd(), key: args.key, ...scopeOptions(args) });\n write(renderReseal(result, \"Decrypted\"));\n });\n },\n});\n","/**\n * `penv set <key> [value]` — write one value file.\n *\n * The scope is chosen, never inferred: `--env <name>` writes `<name>.<env>`,\n * `--local` writes the personal override — for one environment when combined\n * with `--env`, for every environment on its own — and the default is the\n * unscoped one every environment falls back to. Writing to `--env production`\n * when you meant the default is a different file, so penv never picks for you.\n */\n\nimport type { ParameterRef, Provider, Scope, ValueFile } from \"@penvhq/core\";\nimport { formatValueFile, isSecret, PenvError, parameterId, sealValue } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport type { Project } from \"../project.js\";\nimport {\n assertWritableKey,\n keySourceFor,\n openProject,\n PENV_DIR,\n refFromKey,\n targetEnvironment,\n} from \"../project.js\";\nimport { CHECK, formatRows, guard, write } from \"../ui.js\";\n\nexport interface ScopeOptions {\n /** The environment scope. Combined with `local`, the environment-scoped override. */\n readonly environment?: string;\n readonly local?: boolean;\n}\n\nexport interface SetOptions extends ScopeOptions {\n readonly cwd: string;\n readonly key: string;\n readonly value: string;\n}\n\nexport interface SetResult {\n readonly parameter: string;\n /** The value file written, relative to `.penv/`. */\n readonly location: string;\n /** Whether meta's policy sealed it. Reported, so the marker is never a surprise. */\n readonly encrypted: boolean;\n}\n\n/**\n * The scope the flags name — one flag combination per cascade level, all four.\n *\n * `--local --env <e>` is the environment-scoped personal override, mirroring\n * `.env.<e>.local`: the flags compose, because the cascade has a level where\n * both are true. Refusing the combination is what used to leave that level\n * unaddressable from the CLI.\n *\n * `environment` must already be the name {@link targetScope} validated, never\n * the raw flag — the string here becomes a filename segment verbatim.\n */\nexport function scopeFrom(options: ScopeOptions): Scope {\n if (options.local === true) {\n if (options.environment !== undefined) {\n return { kind: \"environment-local\", environment: options.environment };\n }\n return { kind: \"local\" };\n }\n if (options.environment !== undefined) {\n return { kind: \"environment\", environment: options.environment };\n }\n return { kind: \"unscoped\" };\n}\n\n/**\n * The scope a writer may act on: the environment as `targetEnvironment`\n * *returned* it, never as the flag carried it.\n *\n * `resolveEnvironment` trims before it checks the whitelist, so the validated\n * name and the raw flag are two different strings and only the returned one has\n * been checked against `config.environments`. Passing the raw one to\n * `formatValueFile` is what let `--env \"production \"` write `api-key.production `\n * — a file the filename grammar refuses to read (invariant 10), so every later\n * `list`/`get`/`generate`/`validate`/`remove` throws and the tree is repairable\n * only by deleting the file by hand. Validation is what makes a string safe to\n * put in a filename, so the validated value is the only one that may reach one.\n *\n * A blank `--env` is refused rather than resolved: `resolveEnvironment` answers\n * it from `PENV_ENV`/`NODE_ENV`, and a writer scoping a file to an environment\n * the user never named is the same wrong file by a quieter route (invariants 10\n * and 13).\n */\nexport function targetScope(project: Project, options: ScopeOptions, key: string): Scope {\n const environment = options.environment;\n if (environment === undefined) {\n return scopeFrom(options);\n }\n if (environment.trim().length === 0) {\n throw new PenvError(\n \"ENVIRONMENT_FLAG_EMPTY\",\n `\\`--env\\` for parameter ${key} names no environment`,\n `Pass a declared environment — ${project.config.environments.map((e) => `\\`${e}\\``).join(\", \")} — ` +\n \"e.g. `--env production`, or drop `--env` to write the scope that has no environment.\",\n );\n }\n return scopeFrom({ ...options, environment: targetEnvironment(project, environment) });\n}\n\n/**\n * The environment whose policy governs the file being written.\n *\n * `undefined` for a scope that carries no environment, which asks meta for its\n * base block — the honest authority for a file every environment reads. Asking\n * `production`'s block about the unscoped default would apply one environment's\n * policy to a file the others fall back to.\n */\nfunction policyEnvironment(project: Project, options: ScopeOptions): string | undefined {\n return options.environment === undefined\n ? undefined\n : targetEnvironment(project, options.environment);\n}\n\n/**\n * Seals a secret, or refuses for a reason it can name.\n *\n * A key source is declared per environment, so a scope that names no environment\n * has no key penv can choose. It refuses rather than reaching for the ambient\n * environment's key: that key would seal a file every *other* environment also\n * reads, and each of them would then fail to open it — a scope-widening leak\n * dressed as a convenience. `penv set redis/password --env production` is one\n * more word and is unambiguous.\n */\nfunction sealFor(\n project: Project,\n file: ValueFile,\n value: string,\n parameter: string,\n environment: string | undefined,\n): string {\n if (environment === undefined) {\n throw new PenvError(\n \"SECRET_SCOPE_AMBIGUOUS\",\n `Parameter ${parameter} is a secret, and ${PENV_DIR}/${formatValueFile(file)} names no environment`,\n \"Keys are declared per environment in the `keys` block of penv.config.ts, so penv cannot \" +\n \"tell which key should seal a file that every environment reads. Write it at an \" +\n \"environment scope — add `--env <environment>` — or drop `secret` from the parameter's meta.\",\n );\n }\n return sealValue(file, value, keySourceFor(project, environment), parameter, environment);\n}\n\n/** What {@link sealAwareWrite} was told to write, and to which store. */\nexport interface SealAwareWriteOptions {\n readonly project: Project;\n /**\n * The store the value lands in, and the meta whose policy governs it is read\n * *from*. `set` passes the local tree; `rotate` passes it only when the\n * environment's source of truth IS the local tree, so the seal-and-twin rule\n * applies exactly where penv's envelope is penv's concern.\n */\n readonly provider: Provider;\n readonly ref: ParameterRef;\n readonly scope: Scope;\n readonly value: string;\n /** The environment whose meta block decides the policy, or `undefined` for the base block. */\n readonly environment: string | undefined;\n}\n\n/** What {@link sealAwareWrite} did: the marker meta chose, and the file it wrote. */\nexport interface SealAwareWriteResult {\n /** Whether meta's policy sealed it. */\n readonly encrypted: boolean;\n /** The value file written, relative to `.penv/`. */\n readonly location: string;\n}\n\n/**\n * Writes one value file into the local tree, sealing it when meta says the\n * parameter is a secret, and removing the twin at that scope — the one correct\n * physics for a store whose envelope penv owns.\n *\n * There is no `--encrypt` flag, deliberately. A flag would make the command line\n * the authority on what is secret, and meta is (invariant 14) — the `.enc` marker\n * is validated *against* the policy, so a marker chosen at the keyboard would\n * invert the direction the check runs in. The policy decides; the writer obeys.\n *\n * Both `set` and the local-tree branch of `rotate` go through here, so a rotated\n * secret is sealed exactly as a `set` one is: the defect was `rotate` writing the\n * live credential as cleartext into `.penv/` — where plaintext outranks `.enc` at\n * the same scope, so it also shadowed any sealed copy already there.\n */\nexport async function sealAwareWrite(\n options: SealAwareWriteOptions,\n): Promise<SealAwareWriteResult> {\n const { project, provider, ref, scope, value, environment } = options;\n const secret = isSecret(await provider.readMeta(ref), environment);\n\n const file: ValueFile = {\n namespace: ref.namespace,\n name: ref.name,\n scope,\n encrypted: secret,\n };\n\n // Sealed before anything is written, so a secret penv has no key for leaves\n // nothing behind. Writing the plaintext first and letting `doctor` report it\n // afterwards would put the secret on disk in order to complain about it.\n const stored = secret ? sealFor(project, file, value, parameterId(ref), environment) : value;\n\n await provider.write(file, stored);\n\n // The twin at this scope is removed, because one scope holds one value.\n //\n // `.enc` is orthogonal to precedence, so `<name>.<env>` and `<name>.<env>.enc`\n // are two candidates at one address, and the plaintext is considered first.\n // Leaving the twin behind therefore does not leave a harmless extra file — it\n // leaves the one that *wins*. Marking a parameter secret and running `penv set`\n // reported writing a sealed file while `penv get` kept handing back the stale\n // plaintext underneath it: the value you set was not the value you got, and the\n // new secret was inert on disk. Written before the removal, so the value is\n // never in neither file.\n await provider.remove({ ...file, encrypted: !secret });\n\n return { encrypted: secret, location: formatValueFile(file) };\n}\n\n/**\n * Writes one value file, sealing it when meta says the parameter is a secret.\n *\n * The scope is chosen from the flags, then the seal-and-twin write is the shared\n * {@link sealAwareWrite}, against the local tree — the store `set` always edits.\n */\nexport async function runSet(options: SetOptions): Promise<SetResult> {\n const project = openProject(options.cwd);\n assertWritableKey(options.key);\n const ref = refFromKey(options.key, project.config);\n\n // An environment is a whitelist entry or nothing, so a scope naming one is\n // checked before it becomes a filename — including under `--local`, where\n // the environment is a filename segment too.\n const scope = targetScope(project, options, options.key);\n const environment = policyEnvironment(project, options);\n\n const { encrypted, location } = await sealAwareWrite({\n project,\n provider: project.provider,\n ref,\n scope,\n value: options.value,\n environment,\n });\n\n return { parameter: options.key, location, encrypted };\n}\n\nexport function renderSet(result: SetResult): string[] {\n return formatRows([\n {\n glyph: CHECK,\n label: \"Wrote\",\n subject: `${PENV_DIR}/${result.location}`,\n // The `.enc` suffix says this already, but only to a reader who knows the\n // grammar. Meta decided it, not the command line, so the command says so.\n ...(result.encrypted ? { detail: \"encrypted, per the parameter's meta policy\" } : {}),\n },\n ]);\n}\n\n/** The value when it is piped in rather than typed: one trailing newline is the shell's. */\nexport async function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin as AsyncIterable<Buffer>) {\n chunks.push(Buffer.from(chunk));\n }\n const text = Buffer.concat(chunks).toString(\"utf8\");\n return text.endsWith(\"\\n\") ? text.slice(0, -1) : text;\n}\n\nexport const setCommand = defineCommand({\n meta: { name: \"set\", description: \"Update a parameter\" },\n args: {\n key: { type: \"positional\", required: true, description: \"The parameter, e.g. redis/password\" },\n value: {\n type: \"positional\",\n required: false,\n description: \"The value; read from stdin if omitted\",\n },\n env: { type: \"string\", description: \"Write the <name>.<env> scope\" },\n local: {\n type: \"boolean\",\n description: \"Write the personal override: <name>.<env>.local with --env, else <name>.local\",\n },\n },\n run({ args }) {\n return guard(async () => {\n const value = args.value ?? (await readStdin());\n write(\n renderSet(\n await runSet({\n cwd: process.cwd(),\n key: args.key,\n value,\n ...(args.env === undefined ? {} : { environment: args.env }),\n ...(args.local === undefined ? {} : { local: args.local }),\n }),\n ),\n );\n });\n },\n});\n","/**\n * `penv fill` — walk the schema's required-but-missing parameters and ask for\n * each one, deriving the value file's name so the user never has to.\n *\n * The schema-first flow writes `.penv/env.ts` before any value exists, and there\n * the user hits a translation they should not have to make: `databaseUrl` in the\n * schema is `database-url` on disk, and typing the wrong one writes a file the\n * schema still cannot see. `fill` reads the same declared drift `validate`\n * computes, and for each missing parameter asks for a value and writes it through\n * the one writer — `runSet` — deriving the kebab filename from the schema key.\n *\n * A value is never invented: a blank answer skips the parameter, because the\n * silent value reaching runtime is the failure penv exists to delete, and a\n * placeholder written here is exactly that value by a friendlier route.\n */\n\nimport { createInterface } from \"node:readline/promises\";\nimport { PenvError } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { PENV_DIR } from \"../project.js\";\nimport { CHECK, formatRows, guard, type Row, WARN, write } from \"../ui.js\";\nimport { runSet } from \"./set.js\";\nimport { runValidate, type ValidateIssueKind } from \"./validate.js\";\n\n/**\n * The validation issue kinds that stop `fill` before it writes a thing. A\n * `schema` issue is, on the ordinary run, the missing value `fill` is about to\n * ask for — so it is deliberately absent here, or `fill` would refuse the very\n * gap it exists to close. A collision, a reserved token, or a config/load\n * failure is a structural fault of the tree itself, and filling would only paper\n * over it: `generate` would still drop a value, and \"what is missing\" is not even\n * a meaningful question against a config that does not load.\n */\nconst BLOCKING: ReadonlySet<ValidateIssueKind> = new Set([\"config\", \"collision\", \"reserved\"]);\n\n/** One question `fill` puts to the user: which parameter, in which environment. */\nexport interface FillPrompt {\n /** The value file's key, kebab and slash-separated — the name the user need never derive. */\n readonly parameter: string;\n readonly environment: string;\n /**\n * Whether meta says this is a secret. Carried so a wrapper can mute the echo;\n * v1 does not, and the drift carries no meta, so this is `false` today.\n */\n readonly secret: boolean;\n readonly description?: string;\n}\n\nexport interface FillOptions {\n readonly cwd: string;\n readonly environment?: string;\n /**\n * How a value is obtained for one prompt. `undefined` or an empty answer skips\n * the parameter — the readline half lives only in the wrapper, so `runFill`\n * stays pure and unit-testable.\n */\n readonly ask: (prompt: FillPrompt) => Promise<string | undefined>;\n}\n\nexport interface FillResult {\n readonly environment: string;\n /** The value files written, one per answered prompt. */\n readonly written: ReadonlyArray<{\n readonly parameter: string;\n /** The value file written, relative to `.penv/`. */\n readonly location: string;\n readonly encrypted: boolean;\n }>;\n /** The parameters a blank answer left for later — never written as an empty value. */\n readonly skipped: readonly string[];\n /**\n * The declared keys no filename reaches (`apiURL`, a reserved token). `fill`\n * cannot ask for a value it could never write, so it carries the rename remedy\n * out rather than prompting for a file that would error.\n */\n readonly unreachable: ReadonlyArray<{ readonly subject: string; readonly remedy: string }>;\n}\n\n/**\n * Asks for every declared-but-missing parameter, and writes the ones answered.\n *\n * The drift is `validate`'s, not a second reading of the schema: `runValidate`\n * already computes exactly the required-but-absent set, so `fill` and `validate`\n * can never disagree about what is missing. The writing is `runSet`'s, so a\n * filled secret is sealed exactly as a `set` one is — `fill` owns neither the\n * resolution nor the write, only the prompting between them.\n */\nexport async function runFill(options: FillOptions): Promise<FillResult> {\n const validation = await runValidate({\n cwd: options.cwd,\n ...(options.environment === undefined ? {} : { environment: options.environment }),\n });\n const environment = validation.environment;\n\n // A tree that fails validation for a *structural* reason is not one `fill`\n // should write into, so it refuses and hands the reasons back rather than\n // prompting. Keying off the issue kinds — not `validation.ok` — is the load-\n // bearing choice: a required parameter with no value fails the schema too, and\n // that failure *is* the drift `fill` exists to close, so blocking on `ok` would\n // refuse every ordinary run. The `EMPTY_DRIFT` sentinel is not consulted: a\n // schema that never loaded surfaces here as a `config` blocker with its real\n // reason, so a provider-list failure no longer masquerades as \"no schema\".\n const blockers = validation.issues.filter((issue) => BLOCKING.has(issue.kind));\n if (blockers.length > 0) {\n const detail = blockers\n .map(\n (issue) => ` - ${issue.message}${issue.remedy === undefined ? \"\" : ` (${issue.remedy})`}`,\n )\n .join(\"\\n\");\n throw new PenvError(\n \"FILL_BLOCKED\",\n `penv fill cannot run: environment ${environment} has ${blockers.length} unresolved ` +\n `configuration ${blockers.length === 1 ? \"issue\" : \"issues\"}:\\n${detail}`,\n \"Fix these — `penv validate` reports them — then run `penv fill`. If you have not written a \" +\n `schema yet, declare the required parameters in ${PENV_DIR}/env.ts.`,\n );\n }\n\n const written: Array<{ parameter: string; location: string; encrypted: boolean }> = [];\n const skipped: string[] = [];\n const unreachable: Array<{ subject: string; remedy: string }> = [];\n\n for (const drift of validation.drift.declared) {\n // A key outside the name transform's image, or a reserved token: no value\n // file reaches it, so the remedy is a rename, not a value. Prompting here\n // would ask for a file penv would then refuse to write.\n if (drift.ref === undefined) {\n unreachable.push({ subject: drift.subject, remedy: drift.remedy });\n continue;\n }\n\n const ref = drift.ref;\n const key = [...ref.namespace, ref.name].join(\"/\");\n // `secret` stays false: the drift carries no meta, and echo-muting is not a\n // v1 feature. The write below still seals per meta — `runSet` reads it there.\n const value = await options.ask({ parameter: key, environment, secret: false });\n if (value === undefined || value === \"\") {\n skipped.push(drift.subject);\n continue;\n }\n\n const result = await runSet({ cwd: options.cwd, key, value, environment });\n written.push({\n parameter: drift.subject,\n location: result.location,\n encrypted: result.encrypted,\n });\n }\n\n return { environment, written, skipped, unreachable };\n}\n\n/** The one line that reports the run's shape when nothing else needs a row. */\nfunction summaryLine(result: FillResult): string {\n const filled = result.written.length;\n if (filled === 0 && result.skipped.length === 0 && result.unreachable.length === 0) {\n return `Nothing to fill for environment ${result.environment}: every declared parameter has a value`;\n }\n const parts = [`${filled} written`];\n if (result.skipped.length > 0) {\n parts.push(`${result.skipped.length} skipped`);\n }\n if (result.unreachable.length > 0) {\n parts.push(`${result.unreachable.length} unreachable`);\n }\n return `${parts.join(\", \")} for environment ${result.environment}`;\n}\n\nexport function renderFill(result: FillResult): string[] {\n const rows: Row[] = result.written.map((entry) => ({\n glyph: CHECK,\n label: \"Wrote\",\n subject: `${PENV_DIR}/${entry.location}`,\n // Meta decided the seal, not the answer, so the line says so — as `set` does.\n ...(entry.encrypted ? { detail: \"encrypted, per the parameter's meta policy\" } : {}),\n }));\n\n // A key no filename reaches is not skipped — it is unwritable until it is\n // renamed, so it carries its rename remedy rather than a value prompt.\n for (const entry of result.unreachable) {\n rows.push({ glyph: WARN, label: \"Unreachable\", subject: entry.subject, detail: entry.remedy });\n }\n\n const lines = formatRows(rows);\n lines.push(summaryLine(result));\n return lines;\n}\n\nexport const fillCommand = defineCommand({\n meta: {\n name: \"fill\",\n description: \"Prompt for each declared parameter the tree has no value for\",\n },\n args: {\n env: { type: \"string\", description: \"The environment to fill\" },\n },\n run({ args }) {\n return guard(async () => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n // TODO: a `prompt.secret` answer still echoes — echo-muting is out of scope\n // for v1. The prompt shows the derived key, so a reader sees the file name\n // their answer becomes.\n const ask = (prompt: FillPrompt): Promise<string> =>\n rl.question(`${prompt.parameter} (${prompt.environment}): `);\n try {\n write(\n renderFill(\n await runFill({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n ask,\n }),\n ),\n );\n } finally {\n rl.close();\n }\n });\n },\n});\n","/**\n * `penv generate` — write a flat `.env` artifact for deploy targets that expect\n * one.\n *\n * The output is an artifact, never an input: invariant 15 makes `.penv/` the\n * source of truth, and a hand-edit here is not absorbed back. Ordering is\n * normalized rather than preserved — one value per file discards the source\n * file's sequence by construction, so `generate` emits a deterministic sorted\n * order and the output is stable and diffable across machines.\n */\n\nimport { writeFileSync } from \"node:fs\";\nimport { isAbsolute, relative, resolve } from \"node:path\";\nimport type { DotenvEntry } from \"@penvhq/core\";\nimport {\n checkNameCollisions,\n effectiveMeta,\n PenvError,\n requireValue,\n serializeDotenv,\n variableName,\n} from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport type { Project } from \"../project.js\";\nimport {\n keySourceFor,\n localTree,\n openProject,\n PENV_DIR,\n refsFrom,\n resolveAllSync,\n targetEnvironment,\n} from \"../project.js\";\nimport { CHECK, formatRows, guard, WARN, write } from \"../ui.js\";\n\nexport const DEFAULT_OUTPUT = \".env\";\n\nexport interface GenerateOptions {\n readonly cwd: string;\n readonly environment?: string;\n /** Where to write, absolute or relative to `cwd`. Defaults to `.env` at the project root. */\n readonly out?: string;\n /** Permits sealed values to be written into the artifact as plaintext. */\n readonly allowDecrypt?: boolean;\n}\n\nexport interface GenerateResult {\n readonly file: string;\n readonly environment: string;\n readonly entries: number;\n /** How many of them were sealed and are now plaintext in the artifact. */\n readonly decrypted: number;\n}\n\n/**\n * The variables for one environment, and how many of them were sealed.\n *\n * The count is returned rather than discarded because decrypting a secret into a\n * plaintext artifact is the one thing this command does that the user cannot see\n * by looking at the tree. `generate` reports it (invariant 13).\n */\ninterface Artifact {\n readonly entries: DotenvEntry[];\n readonly decrypted: number;\n}\n\nfunction entriesFor(project: Project, environment: string, allowDecrypt: boolean): Artifact {\n const keys = keySourceFor(project, environment);\n const tree = localTree(project);\n const resolutions = resolveAllSync(tree, environment, keys);\n\n // Invariant 12, enforced where the loss would happen: two parameters mapping\n // to one variable would silently drop a value from this file.\n const collision = checkNameCollisions(\n refsFrom(resolutions.map((resolution) => resolution.ref)),\n project.config,\n )[0];\n if (collision !== undefined) {\n throw collision;\n }\n\n const entries: DotenvEntry[] = [];\n let decrypted = 0;\n for (const resolution of resolutions) {\n const winner = resolution.winner;\n if (winner?.file.encrypted === true) {\n // A `.env` is plaintext by construction, so writing a sealed value into one\n // unseals it. penv will do that — the leaving guarantee is that a working\n // `.env` is always reachable — but never as a side effect of a command the\n // user ran for another reason. Asking makes the moment the secret becomes\n // plaintext a moment they chose.\n if (!allowDecrypt) {\n throw new PenvError(\n \"ENCRYPTED_VALUE_REFUSED\",\n `Parameter ${resolution.parameter} for environment ${environment} resolves to the encrypted value file ${PENV_DIR}/${winner.location}, and \\`penv generate\\` writes plaintext`,\n `Re-run with \\`--allow-decrypt\\` to write the decrypted value into the artifact, or generate for an environment whose values are plaintext. The artifact is gitignored; a committed plaintext secret is a \\`penv doctor\\` failure.`,\n );\n }\n // Throws when it cannot be opened, naming the reason — never silently\n // omitting the variable, which would produce an artifact that is missing\n // exactly the secret the deploy needs.\n requireValue(resolution, environment);\n decrypted += 1;\n }\n if (resolution.value === undefined) {\n continue;\n }\n // A parameter's description is a comment in the generated file, so the\n // annotation that arrived on import survives the round trip back out.\n const description = effectiveMeta(tree.readMetaSync(resolution.ref), environment).description;\n entries.push({\n key: variableName(resolution.ref, project.config),\n value: resolution.value,\n ...(typeof description === \"string\" ? { description } : {}),\n });\n }\n\n // Sorted by the generated variable, which is what a reader of this file sees.\n entries.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));\n return { entries, decrypted };\n}\n\n/** The `.env` text for one environment — what `penv generate` writes. */\nexport function generateDotenv(options: Omit<GenerateOptions, \"out\">): string {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n return serializeDotenv(entriesFor(project, environment, options.allowDecrypt === true).entries);\n}\n\nexport function runGenerate(options: GenerateOptions): GenerateResult {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const { entries, decrypted } = entriesFor(project, environment, options.allowDecrypt === true);\n\n // `--out` is the caller's path, so it is relative to where they are standing;\n // the default artifact belongs next to the config it was generated from.\n const file =\n options.out === undefined\n ? resolve(project.root, DEFAULT_OUTPUT)\n : isAbsolute(options.out)\n ? options.out\n : resolve(options.cwd, options.out);\n\n writeFileSync(file, serializeDotenv(entries), \"utf8\");\n return { file, environment, entries: entries.length, decrypted };\n}\n\n/** The artifact's path as the caller would type it, when it is below them. */\nfunction displayPath(cwd: string, file: string): string {\n const rel = relative(cwd, file);\n return rel === \"\" || rel.startsWith(\"..\") ? file : rel.split(\"\\\\\").join(\"/\");\n}\n\nexport function renderGenerate(result: GenerateResult, cwd: string): string[] {\n const rows = [\n {\n glyph: CHECK,\n label: \"Generated\",\n subject: displayPath(cwd, result.file),\n detail: `${result.entries} variables for environment ${result.environment}`,\n },\n ];\n // A secret that was sealed a moment ago and is plaintext now is worth a line of\n // its own. The artifact is gitignored, which is a reason it is safe to write —\n // not a reason to write it quietly.\n if (result.decrypted > 0) {\n rows.push({\n glyph: WARN,\n label: \"Decrypted\",\n subject: `${result.decrypted} ${result.decrypted === 1 ? \"secret\" : \"secrets\"}`,\n detail: \"written as plaintext into the artifact\",\n });\n }\n return formatRows(rows);\n}\n\nexport const generateCommand = defineCommand({\n meta: { name: \"generate\", description: \"Write a standard .env artifact for deploy targets\" },\n args: {\n env: { type: \"string\", description: \"The environment to generate for\" },\n out: { type: \"string\", description: \"Where to write, instead of .env\" },\n \"allow-decrypt\": {\n type: \"boolean\",\n description: \"Write encrypted values into the artifact as plaintext\",\n },\n },\n run({ args }) {\n return guard(async () => {\n const cwd = process.cwd();\n const result = runGenerate({\n cwd,\n ...(args.env === undefined ? {} : { environment: args.env }),\n ...(args.out === undefined ? {} : { out: args.out }),\n ...(args[\"allow-decrypt\"] === undefined ? {} : { allowDecrypt: args[\"allow-decrypt\"] }),\n });\n write(renderGenerate(result, cwd));\n });\n },\n});\n","/**\n * `penv get <key>` — read a parameter, or explain which file wins and why.\n *\n * Fallback is never silent, and neither is precedence: `--explain` prints every\n * candidate in the order the cascade considered them, so a value quietly coming\n * from a shared default has nowhere to hide.\n */\n\nimport { PenvError, requireValue, resolveParameter } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { keySourceFor, openProject, PENV_DIR, refFromKey, targetEnvironment } from \"../project.js\";\nimport { columns, guard, write } from \"../ui.js\";\n\nexport interface GetOptions {\n readonly cwd: string;\n readonly key: string;\n readonly environment?: string;\n}\n\nexport interface GetExplanation {\n readonly parameter: string;\n readonly environment: string;\n /** `undefined` when no candidate was present. */\n readonly location: string | undefined;\n /**\n * Why the winning file did not open, when it is `.enc` and did not.\n *\n * A winner that cannot be decrypted is not a skipped candidate — it won, and\n * the cascade is over. Reporting it as a skip would say a lower scope should\n * have been reached, which is the scope-widening answer the cascade refuses.\n */\n readonly undecryptable?: string;\n readonly candidates: readonly GetCandidate[];\n}\n\nexport interface GetCandidate {\n readonly location: string;\n readonly present: boolean;\n readonly wins: boolean;\n /** Why a present candidate did not win, or why it was never considered. */\n readonly skipped: string | undefined;\n}\n\n/**\n * The value, or a named error.\n *\n * `requireValue` answers first, so a winner that exists but did not decrypt is\n * reported as undecryptable rather than as absent. Only a genuine absence — no\n * candidate at any scope — reaches the refusal below, which is what keeps `penv\n * set` from being offered as the fix for a secret the user still has.\n */\nexport async function runGet(options: GetOptions): Promise<string> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const ref = refFromKey(options.key);\n\n const keys = keySourceFor(project, environment);\n const resolution = await resolveParameter(ref, environment, project.provider, keys);\n const value = requireValue(resolution, environment);\n if (value === undefined) {\n throw new PenvError(\n \"PARAMETER_ABSENT\",\n `Parameter ${resolution.parameter} resolves to no value for environment ${environment}`,\n `Set it with \\`penv set ${options.key} --env ${environment}\\`, or run \\`penv get ${options.key} --env ${environment} --explain\\` to see every file penv looked at.`,\n );\n }\n return value;\n}\n\nfunction skipReason(reason: string | undefined): string | undefined {\n if (reason === \"lower-precedence\") {\n // Not \"a more specific scope wins\". Within one scope the plaintext file is\n // considered before its `.enc` twin, so the file that beat this one is\n // sometimes at the *same* scope — and a reader told the winner was more\n // specific would go looking for a scope that does not exist.\n return \"skipped, a higher-precedence file wins\";\n }\n if (reason === \"local-skipped-in-test\") {\n return \"skipped, .local never applies in test\";\n }\n return undefined;\n}\n\n/**\n * Which file wins, and why — never a value, so this must not be stopped by the\n * winner being unreadable. Core describes an `.enc` winner rather than refusing\n * it, so `--explain` is the same walk every other command does.\n */\nexport async function runExplain(options: GetOptions): Promise<GetExplanation> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const ref = refFromKey(options.key);\n\n const keys = keySourceFor(project, environment);\n const resolution = await resolveParameter(ref, environment, project.provider, keys);\n const winner = resolution.winner;\n\n return {\n parameter: resolution.parameter,\n environment,\n location: winner === undefined ? undefined : winner.location,\n ...(resolution.undecryptable === undefined\n ? {}\n : { undecryptable: resolution.undecryptable.detail }),\n candidates: resolution.candidates.map((candidate) => ({\n location: candidate.location,\n present: candidate.present,\n wins: candidate === winner,\n skipped: skipReason(candidate.skippedReason),\n })),\n };\n}\n\nexport function renderExplain(explanation: GetExplanation): string[] {\n const target =\n explanation.location === undefined ? \"nothing\" : `${PENV_DIR}/${explanation.location}`;\n\n // Candidates stay in the order the cascade considered them: the answer to\n // \"why this file\" is the list above it that did not win.\n const rows = explanation.candidates.map((candidate) => [\n candidate.location,\n candidate.wins\n ? \"present, wins\"\n : candidate.present\n ? (candidate.skipped ?? \"present\")\n : (candidate.skipped ?? \"absent\"),\n ]);\n\n return [\n `${explanation.parameter} resolves to ${target} for environment ${explanation.environment}`,\n ...(explanation.undecryptable === undefined\n ? []\n : [` penv cannot decrypt it: ${explanation.undecryptable}`]),\n \"\",\n ...columns(rows).map((line) => ` ${line}`),\n ];\n}\n\nexport const getCommand = defineCommand({\n meta: { name: \"get\", description: \"Read a parameter\" },\n args: {\n key: { type: \"positional\", required: true, description: \"The parameter, e.g. redis/password\" },\n env: { type: \"string\", description: \"The environment to read\" },\n explain: { type: \"boolean\", description: \"Print which file wins, and why\" },\n },\n run({ args }) {\n return guard(async () => {\n const options: GetOptions = {\n cwd: process.cwd(),\n key: args.key,\n ...(args.env === undefined ? {} : { environment: args.env }),\n };\n if (args.explain === true) {\n write(renderExplain(await runExplain(options)));\n return;\n }\n write([await runGet(options)]);\n });\n },\n});\n","/**\n * `penv import <file>` — adopt an existing dotenv file.\n *\n * Invariant 15: this is one-directional. After it runs, `.penv/` is the source of\n * truth and `.env` is an artifact `penv generate` writes; there is no reverse\n * sync of hand-edits back out of the generated file.\n *\n * Import creates flat parameters. `refFromVariable` never infers a namespace,\n * because a flat `.env` carries no structure to read — `REDIS_PASSWORD` cannot\n * say whether it came from `redis/password` or `redis-password`. Namespacing is\n * a deliberate refactor afterwards, not a guess made during adoption.\n *\n * Scope, unlike namespace, *is* readable from the source: the filename says it,\n * in the four-level vocabulary invariant 4 adopts wholesale. `.env.production`\n * carries `production` the way `.env` carries nothing, so import reads it rather\n * than flattening it — a `.env.development.local` written to the unscoped default\n * would serve every environment, and one developer's machine would become\n * production's fallback.\n *\n * `--env` is the other half of that reading. A file the filename says nothing\n * about — `prod-secrets.txt`, or a plain `.env` the user is adopting as one\n * environment's values — has its scope named by the flag instead, because \"these\n * are production's values\" is what `--env production` means at an import. Only a\n * file that names neither is the unscoped default.\n */\n\nimport { copyFileSync, existsSync, readFileSync } from \"node:fs\";\nimport { basename, isAbsolute, relative, resolve } from \"node:path\";\nimport type { DotenvEntry, Meta, ParameterRef, PenvConfig, Scope } from \"@penvhq/core\";\nimport {\n accessPath,\n assertNever,\n checkNameCollisions,\n FilenameGrammarError,\n findConfigFile,\n isReservedToken,\n loadConfigFrom,\n lookupEnvironment,\n PenvError,\n parseDotenv,\n ReservedTokenError,\n refFromVariable,\n roundTripsCleanly,\n schemaFileOf,\n UnknownEnvironmentError,\n variableName,\n} from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { detectAlias } from \"../detect.js\";\nimport { localTree, openProject } from \"../project.js\";\nimport { CHECK, formatSteps, guard, type Step, WARN, write } from \"../ui.js\";\nimport type { InitDecisions, InitStep, SchemaField } from \"./init.js\";\nimport { planInit, scaffold, writeConfigFile } from \"./init.js\";\nimport type { ValidateResult } from \"./validate.js\";\nimport { renderValidate, runValidate } from \"./validate.js\";\n\nexport interface ImportOptions {\n readonly cwd: string;\n /** The dotenv file to adopt, absolute or relative to `cwd`. */\n readonly file: string;\n /**\n * `--env`. It reads as \"these are <environment>'s values\", so for a file whose\n * name carries no environment it names the *scope* as well as the environment\n * to run against: `penv import prod-secrets.txt --env production` writes\n * `<name>.production`, and `--env production` on `.env.local` writes\n * `<name>.production.local`. The filename supplies both when it carries an\n * environment, so the flag is needed only for a file that does not — and\n * contradicting the filename is an error rather than a silent choice between\n * the two.\n */\n readonly environment?: string;\n}\n\nexport interface ImportReport {\n readonly root: string;\n readonly file: string;\n readonly backup: string;\n /** The scope the source named — filename, `--env`, or both — and the scope every value was written at. */\n readonly scope: Scope;\n /**\n * The environment the import ran against, or `undefined` when none is set.\n *\n * Undefined only ever accompanies the unscoped default: any other scope names\n * an environment, so it always has one. It means the values were written and\n * the closing validation was skipped, which the output states.\n */\n readonly environment: string | undefined;\n /** The declared environments, so a skipped validation can name one to pass. */\n readonly environments: readonly string[];\n readonly variables: number;\n /**\n * Comment blocks that belonged to no variable. Reported rather than discarded\n * silently: a file header has no parameter to describe, but that is not a\n * reason to pretend it was never there.\n */\n readonly orphanComments: number;\n readonly steps: readonly InitStep[];\n}\n\nconst BACKUP_SUFFIX = \".backup\";\n\n/** The segment that starts a dotenv filename's scope. `.env`, `.env.production`. */\nconst DOTENV_SEGMENT = \"env\";\nconst LOCAL = \"local\";\n\n/** A URL of any scheme — `postgres://` is as much a URL as `https://`. */\nconst URL_LIKE = /^[a-z][a-z0-9+.-]*:\\/\\/\\S+$/i;\nconst IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n\n/**\n * The Zod expression for one sampled value. Values arrive as strings, so a\n * schema that must accept them declares the coercion: `z.boolean()` would reject\n * the string `\"true\"` this very file just imported.\n */\nfunction inferType(value: string): string {\n if (URL_LIKE.test(value)) {\n return \"z.url()\";\n }\n if (/^(true|false)$/i.test(value)) {\n return \"z.stringbool()\";\n }\n if (value.trim() !== \"\" && Number.isFinite(Number(value))) {\n return \"z.coerce.number()\";\n }\n return \"z.string()\";\n}\n\n/** Sorted, so the draft is identical on every machine. */\nexport function draftFields(entries: readonly DotenvEntry[]): SchemaField[] {\n return entries\n .map((entry) => {\n const key = accessPath(refFromVariable(entry.key)).join(\".\");\n return {\n key: IDENTIFIER.test(key) ? key : JSON.stringify(key),\n type: inferType(entry.value),\n };\n })\n .sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));\n}\n\n/**\n * Filenames are split on `.`, so a variable that becomes a dotted name would\n * parse back as a scope segment rather than the parameter it came from.\n */\nfunction assertImportable(ref: ParameterRef, variable: string): void {\n if (!ref.name.includes(\".\")) {\n return;\n }\n throw new PenvError(\n \"IMPORT_UNPARSEABLE_NAME\",\n `The variable ${variable} becomes the parameter \\`${ref.name}\\`, whose \\`.\\` would be read as a scope`,\n `Filenames are split on \\`.\\`. Rename ${variable} in the source file, then import it again.`,\n );\n}\n\n/**\n * Invariant 11: `enc`, `json`, `toml`, `yml`, `local`, and every declared\n * environment are reserved, and a collision is an error rather than a warning.\n *\n * A written `.penv/enc` does not merely import badly — it re-parses as a scope\n * segment, so every later `list()` throws and `get`, `generate`, `validate`, and\n * even `remove` stop working. The project can only be repaired by deleting the\n * file by hand, which is why this runs before anything is written rather than\n * leaving `penv validate` to report the wreckage afterwards.\n *\n * The error names the *variable*, not the parameter: the user is reading their\n * `.env`, where the line says `ENC=`, and `enc` is penv's word for it.\n */\nfunction assertNotReserved(\n ref: ParameterRef,\n variable: string,\n where: string,\n config: PenvConfig,\n): void {\n if (isReservedToken(ref.name, config)) {\n throw new ReservedTokenError(\"parameter\", variable, where);\n }\n}\n\n/**\n * The v0.1 gate: every variable survives `import` then `generate` unchanged,\n * *modulo declared name overrides*.\n *\n * `MY-VAR` imports to the parameter `my-var` and regenerates as `MY_VAR`, so the\n * application's `process.env[\"MY-VAR\"]` reads `undefined` after a round trip. A\n * flat `.env` cannot tell `MY-VAR` from `MY_VAR` once both collapse to one\n * parameter, so no escape scheme rescues it — the honest move is to refuse. An\n * explicit `names` override is the exception the gate allows: it makes the\n * generated name a stated decision instead of an accident. Silence does not.\n */\nfunction assertRoundTrips(ref: ParameterRef, variable: string, config: PenvConfig): void {\n if (roundTripsCleanly(variable)) {\n return;\n }\n // The declared override the gate's \"modulo\" clause means. Checked against the\n // real transform, so an override that does not actually restore the variable\n // is not mistaken for one that does.\n if (variableName(ref, config) === variable) {\n return;\n }\n const generated = variableName(ref, config);\n throw new PenvError(\n \"IMPORT_LOSSY_NAME\",\n `The variable ${variable} becomes the parameter \\`${ref.name}\\`, which regenerates as ${generated}`,\n `\\`penv generate\\` would write ${generated}, so anything reading ` +\n `\\`process.env[\"${variable}\"]\\` would read \\`undefined\\`. Declare the name you want in the ` +\n `\\`names\\` block of penv.config.ts — \\`names: { \"${ref.name}\": \"${variable}\" }\\` — then ` +\n `import it again. Nothing was imported.`,\n );\n}\n\nfunction collisionsIn(refs: readonly ParameterRef[], config: PenvConfig): void {\n const errors = checkNameCollisions(refs, config);\n const first = errors[0];\n if (first !== undefined) {\n throw first;\n }\n}\n\n/**\n * Invariant 10: a segment is an environment because `penv.config.ts` declares\n * it, never because it looks like one. This matches the whitelist — the thing\n * the invariant permits — and refuses everything else.\n *\n * Refusing is the whole point. Falling back to the unscoped default for an\n * undeclared segment is precisely the leak: `.env.staging` in a project that\n * never declared `staging` would become the value every environment reads.\n */\nfunction assertDeclared(segment: string, config: PenvConfig): string {\n if (config.environments.includes(segment)) {\n return segment;\n }\n throw new UnknownEnvironmentError(segment, config.environments);\n}\n\n/**\n * The scope the source filename names, in the vocabulary invariant 4 shares with\n * Next.js and Vite: `.env` > unscoped, `.env.<env>`, `.env.local`, and\n * `.env.<env>.local`.\n *\n * Parsing starts at the first `env` segment, because `import` reads whatever\n * file it is pointed at and the basename may carry a prefix. A file with no\n * `env` segment at all is the plain-`.env` case — there is no scope written on\n * it, so there is none to read, and the unscoped default is what it means.\n */\nfunction scopeFromFilename(file: string, config: PenvConfig): Scope {\n const name = basename(file);\n const segments = name.split(\".\");\n const start = segments.indexOf(DOTENV_SEGMENT);\n if (start === -1) {\n return { kind: \"unscoped\" };\n }\n\n const rest = segments.slice(start + 1).filter((segment) => segment.length > 0);\n const first = rest[0];\n const second = rest[1];\n\n if (first === undefined) {\n return { kind: \"unscoped\" };\n }\n\n if (second === undefined) {\n if (first === LOCAL) {\n return { kind: LOCAL };\n }\n return { kind: \"environment\", environment: assertDeclared(first, config) };\n }\n\n if (rest.length === 2 && second === LOCAL && first !== LOCAL) {\n return { kind: \"environment-local\", environment: assertDeclared(first, config) };\n }\n\n // The order is fixed at both ends of the import: the environment precedes\n // `local` in the dotenv filename this reads and in the value filename it\n // writes, so `.env.local.production` is an error rather than a synonym.\n if (first === LOCAL && rest.length === 2) {\n throw new FilenameGrammarError(\n name,\n \"`local` precedes the environment segment\",\n `The environment segment always precedes \\`local\\` — \\`.env.${second}.${LOCAL}\\` is the ` +\n `file Next.js and Vite read, and \\`.env.${LOCAL}.${second}\\` is not a synonym for it. ` +\n `Rename it to \\`.env.${second}.${LOCAL}\\`, then import it again. Nothing was imported.`,\n );\n }\n\n throw new FilenameGrammarError(\n name,\n `\\`${rest.join(\"` and `\")}\\` are ${rest.length} scope segments`,\n \"A dotenv file carries exactly one scope: `.env`, `.env.<environment>`, `.env.local`, or \" +\n \"`.env.<environment>.local`. Point `penv import` at one of those. Nothing was imported.\",\n );\n}\n\n/**\n * The environment a scope names, or `undefined` when it names none.\n *\n * The `default` is load-bearing rather than ceremonial: a fifth scope carrying\n * an environment would otherwise report `undefined` here, and import would fall\n * back to `--env` — silently widening exactly the way the three-level cascade did.\n */\nfunction environmentOf(scope: Scope): string | undefined {\n switch (scope.kind) {\n case \"environment\":\n case \"environment-local\":\n return scope.environment;\n case \"unscoped\":\n case \"local\":\n return undefined;\n default:\n return assertNever(scope, \"scope\");\n }\n}\n\n/**\n * The scope `--env <environment>` names, given the scope the filename named.\n *\n * `--env` reads as \"these are <environment>'s values\", so it names a scope and\n * not merely a validation target. Deriving the scope from the filename alone was\n * the scope-widening leak: `penv import prod-secrets.txt --env production` wrote\n * the unscoped default, and `development` read the production secret.\n *\n * A filename that already names an environment keeps its scope untouched: by the\n * time this runs the two agree, because a contradiction is an error. `.env.local`\n * names a scope but no environment, so the two compose — the filename says\n * personal override, `--env` says which environment it overrides, and together\n * they are `.env.<environment>.local`.\n */\nfunction scopeWithEnvironment(scope: Scope, environment: string): Scope {\n switch (scope.kind) {\n case \"unscoped\":\n return { kind: \"environment\", environment };\n case LOCAL:\n return { kind: \"environment-local\", environment };\n case \"environment\":\n case \"environment-local\":\n return scope;\n default:\n return assertNever(scope, \"scope\");\n }\n}\n\n/**\n * `--env`, normalized the way `resolveEnvironment` normalizes it — but a flag\n * that is present and blank is refused rather than normalized away.\n *\n * `--env \"$ENVIRONMENT\"` with the variable unset arrives here as `\"\"`. Reading\n * that as \"no `--env`\" silently demotes the scope the user asked for to the\n * unscoped default, so `penv import prod-secrets.txt --env \"\"` writes the\n * production secret to the file every environment falls back to — the leak this\n * flag exists to close, through a quieter door. An absent flag still means the\n * unscoped default: that is the user declining to name a scope, not failing to.\n */\nfunction explicitEnvironment(options: ImportOptions, source: string, config: PenvConfig): string {\n const value = options.environment?.trim() ?? \"\";\n if (value.length > 0) {\n return value;\n }\n throw new PenvError(\n \"IMPORT_ENV_FLAG_EMPTY\",\n `\\`--env\\` for the import of ${source} names no environment`,\n `Pass a declared environment — ${config.environments.map((e) => `\\`${e}\\``).join(\", \")} — e.g. ` +\n `\\`--env production\\`, or drop \\`--env\\` to import ${source} as the scope that has no ` +\n `environment. Nothing was imported.`,\n );\n}\n\n/**\n * `penv import .env.production --env development` names two environments and\n * means one of them. penv cannot know which, and both readings are destructive:\n * honouring `--env` validates the wrong environment, honouring the filename\n * ignores what the user typed. It says so instead of choosing.\n */\nfunction assertEnvironmentAgrees(\n derived: string | undefined,\n explicit: string | undefined,\n source: string,\n): void {\n if (derived === undefined || explicit === undefined || derived === explicit) {\n return;\n }\n throw new PenvError(\n \"IMPORT_ENV_CONFLICT\",\n `The file ${source} is scoped to environment ${derived}, but \\`--env ${explicit}\\` names ${explicit}`,\n `Drop \\`--env\\` to import ${source} as ${derived}, pass \\`--env ${derived}\\` to say the same ` +\n `thing twice, or point \\`penv import\\` at the file that holds ${explicit}'s values. ` +\n `Nothing was imported.`,\n );\n}\n\n/**\n * The config `import` must judge names against: the project's own when it has\n * one, and otherwise the one `penv init` writes, since that is the config the\n * scaffold below is about to put in place.\n *\n * Writing it *first* is what lets every name check run before a single value\n * file exists. It is safe to leave behind if a check then fails: it is byte for\n * byte the file `penv init` writes, it holds nothing read out of the `.env`, and\n * it is the file the reserved-token and `names` remedies both tell the user to\n * go and edit.\n */\n/**\n * The environment this run names, read lexically — before any config exists to\n * check it against.\n *\n * `scopeFromFilename` cannot answer this: it validates against the whitelist, and\n * on a greenfield project the whitelist is the thing being written. So the\n * segment is read here without being believed, handed to the scaffold as a\n * declaration, and then checked by the ordinary path like any other.\n *\n * Reading it is not inference. Invariant 10 forbids penv deciding that a file in\n * a tree belongs to an environment nobody declared; this is the user typing\n * `penv import .env.production` and thereby saying which environment the file is\n * for. The command line is a declaration — the only one available on a project\n * that has no config yet.\n */\nfunction environmentNamed(file: string, explicit: string | undefined): string | undefined {\n if (explicit !== undefined && explicit.trim().length > 0) {\n return explicit.trim();\n }\n const segments = basename(file).split(\".\");\n const start = segments.indexOf(DOTENV_SEGMENT);\n if (start === -1) {\n return undefined;\n }\n const first = segments.slice(start + 1).filter((segment) => segment.length > 0)[0];\n return first === undefined || first === LOCAL ? undefined : first;\n}\n\n/**\n * The config to check every name against, scaffolding one when the project has none.\n *\n * Writing it *first* is what lets every name check run before a single value\n * file exists. It is safe to leave behind if a check then fails: it holds\n * nothing read out of the `.env`, and it is the file the reserved-token and\n * `names` remedies both tell the user to go and edit.\n *\n * The scaffold declares the environment this import names, and nothing else.\n * `penv init` refuses to invent environments because it cannot observe a\n * deployment — but here the user has named one, and a config that omitted it\n * would be penv writing a file that makes penv's own next step fail.\n */\ninterface Adoption {\n readonly config: PenvConfig;\n /**\n * What the rest of the scaffold must write, and the reason this is returned\n * rather than recomputed.\n *\n * `scaffold` takes `decisions` with a default, so a caller that forgot them\n * compiled and quietly wrote `DEFAULT_DECISIONS` instead. Import forgot them:\n * the config it wrote said `schemaFile: \"src/env.ts\"` while the schema it\n * scaffolded a moment later went to `.penv/env.ts`, and the two disagreed for\n * exactly as long as the project lived. The optional parameter is what hid it\n * from the compiler; carrying the decisions is what stops the two halves of one\n * scaffold answering the same question differently.\n */\n readonly decisions: InitDecisions;\n}\n\n/** The decisions a config already records. The alias is read from the files that resolve it. */\nfunction decisionsOf(config: PenvConfig, cwd: string): InitDecisions {\n return {\n environments: config.environments,\n schemaFile: schemaFileOf(config),\n publicPrefixes: config.publicPrefixes ?? [],\n alias: detectAlias(cwd),\n };\n}\n\nfunction configInEffect(cwd: string, environment: string | undefined): Adoption {\n const existing = findConfigFile(cwd);\n if (existing !== undefined) {\n const config = loadConfigFrom(existing);\n return { config, decisions: decisionsOf(config, cwd) };\n }\n // The same plan `penv init` would make without being asked anything — import\n // is a scaffold too, and two scaffolds that disagreed about where the schema\n // goes would make the answer depend on which command the user reached for.\n const planned = planInit(cwd).decisions;\n const decisions: InitDecisions = {\n ...planned,\n environments: environment === undefined ? planned.environments : [environment],\n };\n writeConfigFile(cwd, decisions);\n return { config: openProject(cwd).config, decisions };\n}\n\n/**\n * Adopts the file: parses it, scaffolds the project, writes one value file per\n * variable and each attached comment into that parameter's meta, and backs the\n * source up. Validation is the caller's next step rather than part of adoption —\n * an inferred schema is a draft, and a draft that needs correcting has still\n * imported every value correctly.\n *\n * Adoption is all or nothing. Every name is checked against the config, and any\n * environment the source names resolved, before the tree is scaffolded or a\n * value written. The two names that fail here fail *destructively*: a reserved\n * name bricks every later command, and a lossy name renames the user's variable\n * behind their back. What the source names is resolved here rather than left to\n * the closing `validate` because a command that writes a tree and *then*\n * discovers it cannot name an environment has already half-adopted the project\n * it just refused. A half-imported tree would be the drift penv exists to\n * remove, introduced by penv itself.\n *\n * An environment nothing names is a different case, and not an error: an\n * unscoped import writes at the unscoped default, which needs no environment.\n * Only the validation that follows needs one, so it is skipped and said to be\n * skipped. Requiring one here would fail `penv import .env` on a greenfield\n * project — the first command the quickstart gives, where no environment could\n * plausibly be set yet — to satisfy a step that is the caller's next one.\n */\nexport function importDotenv(options: ImportOptions): ImportReport {\n const cwd = resolve(options.cwd);\n const file = isAbsolute(options.file) ? options.file : resolve(cwd, options.file);\n if (!existsSync(file)) {\n throw new PenvError(\n \"IMPORT_FILE_MISSING\",\n `There is no file at ${file} to import`,\n \"Point `penv import` at an existing dotenv file, e.g. `penv import .env`.\",\n );\n }\n\n const parsed = parseDotenv(readFileSync(file, \"utf8\"));\n const { config, decisions } = configInEffect(cwd, environmentNamed(file, options.environment));\n const source = displayPath(cwd, file);\n\n const named = scopeFromFilename(file, config);\n const derived = environmentOf(named);\n // Absent means the unscoped default; present-but-blank is refused, never\n // normalized into absent.\n const explicit =\n options.environment === undefined ? undefined : explicitEnvironment(options, source, config);\n assertEnvironmentAgrees(derived, explicit, source);\n // `--env` must reach the scope, not just the environment: reading it into the\n // environment alone is what wrote a production secret to the unscoped default.\n // Invariant 10 first — an undeclared `--env` names no scope to write at.\n const scope =\n explicit === undefined ? named : scopeWithEnvironment(named, assertDeclared(explicit, config));\n // The filename is an environment the user has already stated, so `penv import\n // .env.production` needs no `--env` to mean production. Nothing naming one is\n // the unscoped default's ordinary case, not a failure — the values still have\n // a scope to be written at, and only the closing validate goes without.\n const environment = lookupEnvironment(config, explicit ?? derived);\n\n const refs: ParameterRef[] = [];\n for (const entry of parsed.entries) {\n const ref = refFromVariable(entry.key);\n assertImportable(ref, entry.key);\n assertNotReserved(ref, entry.key, source, config);\n assertRoundTrips(ref, entry.key, config);\n refs.push(ref);\n }\n collisionsIn(refs, config);\n\n // Every check has passed, so from here the import runs to completion.\n // The decisions the config was written from, not the defaults: the two halves\n // of one scaffold must not disagree about where the schema lives.\n const steps = scaffold(cwd, draftFields(parsed.entries), true, decisions);\n const project = openProject(cwd);\n const tree = localTree(project);\n\n for (const [index, entry] of parsed.entries.entries()) {\n const ref = refs[index];\n if (ref === undefined) {\n continue;\n }\n tree.writeSync(\n { namespace: ref.namespace, name: ref.name, scope, encrypted: false },\n entry.value,\n );\n // A comment sitting directly above a variable describes it, so it becomes\n // that parameter's meta description and `generate` re-emits it as a comment.\n if (entry.description !== undefined) {\n const existing = tree.readMetaSync(ref);\n const meta: Meta = { ...existing, description: entry.description };\n tree.writeMetaSync(ref, meta);\n }\n }\n\n const backup = `${file}${BACKUP_SUFFIX}`;\n copyFileSync(file, backup);\n\n return {\n root: project.root,\n file,\n backup,\n scope,\n environment,\n environments: config.environments,\n variables: parsed.entries.length,\n orphanComments: parsed.orphanComments,\n steps,\n };\n}\n\nfunction displayPath(root: string, file: string): string {\n const rel = relative(root, file);\n return rel === \"\" || rel.startsWith(\"..\") ? file : rel.split(\"\\\\\").join(\"/\");\n}\n\n/**\n * Invariant 2 kept the user's `env.ts`; invariant 13 says so out loud.\n *\n * `penv init` then `penv import` is the ordinary path, and it lands here: the\n * schema penv scaffolded is an empty `z.object({})`, the draft that would have\n * declared the imported parameters is not written, and the closing `validate`\n * passes — an empty object validates against an empty schema. A ✓ on that line\n * reports a project where nothing is declared as a project that is fine.\n *\n * The count is every imported parameter, because penv declared none of them: it\n * did not write the draft, and it does not read the user's schema to guess which\n * ones they had already declared themselves.\n */\nfunction keptSchemaStep(step: InitStep, variables: number): Step {\n const plural = variables === 1 ? \"parameter\" : \"parameters\";\n return {\n glyph: WARN,\n // The step's own text, which names the file that was actually kept. This\n // line rebuilt it from a hardcoded `.penv/env.ts`, so a project whose schema\n // lives in `src/` was told penv had kept a file it does not have — the one\n // line whose whole job is \"your schema is untouched\" naming the wrong\n // schema. Only the glyph and the note are this function's business.\n text: step.text,\n note: `(yours — ${variables} imported ${plural} undeclared, draft schema skipped)`,\n };\n}\n\n/**\n * Invariant 13: the validation that did not run says so.\n *\n * A skipped check and a passed check must never look alike — the import wrote\n * every value, so a silent skip would read as a validated tree. The remedy names\n * a declared environment because the user has not chosen one yet; that is the\n * whole reason this line exists.\n */\nfunction skippedValidationStep(environments: readonly string[]): Step {\n const example = environments[0] ?? \"<environment>\";\n return {\n glyph: WARN,\n text: \"Skipped validation\",\n note: `(no environment set — run \\`penv validate --env ${example}\\`)`,\n };\n}\n\nexport function renderImport(\n result: ImportReport,\n validation: ValidateResult | undefined,\n): string[] {\n const steps: Step[] = [{ glyph: CHECK, text: `Found ${result.variables} variables` }];\n\n // Dropped, but never silently: a comment attached to nothing has no parameter\n // to belong to, and how many there were is the user's to know.\n if (result.orphanComments > 0) {\n const plural = result.orphanComments === 1 ? \"comment\" : \"comments\";\n steps.push({\n glyph: WARN,\n text: `Dropped ${result.orphanComments} orphan ${plural}`,\n note: \"attached to no variable, so nothing to describe\",\n });\n }\n\n for (const step of result.steps) {\n if (step.target === \"schema\" && step.action === \"kept\") {\n steps.push(keptSchemaStep(step, result.variables));\n continue;\n }\n // A conflicted step is the one init reports that is not a success — the same\n // reason it wears a warning there.\n const glyph = step.action === \"conflicted\" ? WARN : CHECK;\n steps.push(\n step.note === undefined\n ? { glyph, text: step.text }\n : { glyph, text: step.text, note: step.note },\n );\n }\n steps.push({ glyph: CHECK, text: `Created ${displayPath(result.root, result.backup)}` });\n\n const lines = formatSteps(steps);\n if (validation === undefined) {\n lines.push(...formatSteps([skippedValidationStep(result.environments)]));\n } else if (validation.ok) {\n lines.push(...formatSteps([{ glyph: CHECK, text: \"Validated configuration\" }]));\n } else {\n lines.push(...renderValidate(validation));\n }\n\n lines.push(\"\", \"Done. .penv/ is now your source of truth.\");\n return lines;\n}\n\nexport const importCommand = defineCommand({\n meta: {\n name: \"import\",\n description: \"Import an existing dotenv file; it becomes the source of truth\",\n },\n args: {\n file: {\n type: \"positional\",\n required: true,\n description: \"The dotenv file to import, e.g. .env\",\n },\n env: {\n type: \"string\",\n description:\n \"The environment these are the values of; scopes them to it. The filename supplies it \" +\n \"when it carries one\",\n },\n },\n run({ args }) {\n return guard(async () => {\n const cwd = process.cwd();\n const report = importDotenv({\n cwd,\n file: args.file,\n ...(args.env === undefined ? {} : { environment: args.env }),\n });\n // The environment `import` already resolved, so the closing validate cannot\n // target a different one than the values were just written for. Without one\n // there is nothing to validate against, and the render says it was skipped.\n const validation =\n report.environment === undefined\n ? undefined\n : await runValidate({ cwd, environment: report.environment });\n write(renderImport(report, validation));\n });\n },\n});\n","/**\n * What the codebase already says about itself.\n *\n * `penv init` asks a human to confirm a plan, and a plan the human has to fill\n * in from scratch is an interrogation. So penv reads the two facts it can\n * observe — the framework in `package.json`, and whether a `src/` directory\n * exists — and offers them as a suggestion.\n *\n * The line this module does not cross: a framework is an identity, never a\n * config key. Nothing here is written to `penv.config.ts` as `framework: \"next\"`\n * — the answers become concrete decisions (`schemaFile`, `publicPrefixes`) that\n * mean the same thing in a year, when the project has been rewritten twice and\n * penv would otherwise still be reinterpreting a name it read once.\n *\n * Everything here is a suggestion. The one thing that is never suggested is an\n * environment: deployment topology is not in `package.json`, and invariant 10\n * forbids inferring it.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { DEFAULT_SCHEMA_FILE } from \"@penvhq/core\";\n\n/** A framework penv recognised, and what it implies about a project's layout. */\nexport interface Detected {\n /** The framework's own name, as a human writes it — `\"Next.js\"`. */\n readonly name: string;\n /** Where this framework's projects keep their modules, relative to the root. */\n readonly schemaFile: string;\n /**\n * The conventional path penv stepped aside from, because a module that is not\n * penv's schema already lives there. Set only when it happened, so the plan can\n * say why the schema is not where the convention would have put it.\n */\n readonly displacedFrom?: string;\n /** The prefixes this framework inlines into its client bundle. */\n readonly publicPrefixes: readonly string[];\n}\n\n/**\n * One framework's signature. `packages` is checked against dependencies and\n * devDependencies alike: a framework is a framework wherever it was installed,\n * and the two lists disagree often enough that reading one is reading half.\n */\ninterface Signature {\n readonly name: string;\n readonly packages: readonly string[];\n readonly publicPrefixes: readonly string[];\n}\n\n/**\n * Ordered most specific first: TanStack Start is Vite underneath and Next.js\n * projects carry Vite for their tests, so a signature that matches a framework's\n * *foundation* must never answer before the framework itself does.\n *\n * Remix and React Router 7 are deliberately absent. Their public-variable story\n * is not one prefix, and a guess here is worse than the fallback: the fallback\n * is reported and asks, while a wrong prefix silently arms the one `doctor`\n * check that exists to keep a secret out of a browser bundle.\n */\nconst SIGNATURES: readonly Signature[] = [\n { name: \"Next.js\", packages: [\"next\"], publicPrefixes: [\"NEXT_PUBLIC_\"] },\n {\n name: \"TanStack Start\",\n packages: [\"@tanstack/react-start\", \"@tanstack/start\"],\n publicPrefixes: [\"VITE_\"],\n },\n { name: \"Astro\", packages: [\"astro\"], publicPrefixes: [\"PUBLIC_\"] },\n { name: \"Vite\", packages: [\"vite\"], publicPrefixes: [\"VITE_\"] },\n];\n\n/**\n * Whether the module at `file` looks like it exports penv's schema.\n *\n * A scan, not a parse, and deliberately conservative in one direction: it can\n * fail to recognise an exotic re-export and say \"no\", which costs a note and a\n * different filename. It cannot invent a `schema` that is not written down, so it\n * never claims someone else's module is penv's.\n *\n * The question this answers is not \"does the file exist\". `src/env.ts` existing\n * is the common case on a re-run — it is the schema penv wrote, and keeping it is\n * invariant 2 working. The question is whether the file at the path penv wants is\n * *penv's*, because the alternative is penv choosing a path already occupied by\n * someone else's module and then reporting, later and from somewhere else, that\n * it exports no schema.\n */\nfunction exportsSchema(file: string): boolean {\n let source: string;\n try {\n source = readFileSync(file, \"utf8\");\n } catch {\n return false;\n }\n return (\n // `export const schema = z.object({ ... })` — what penv scaffolds.\n /export\\s+(?:const|let|var)\\s+schema\\b/.test(source) ||\n // `export { schema }`, `export { shape as schema }`.\n /export\\s*\\{[^}]*\\bschema\\b[^}]*\\}/.test(source)\n );\n}\n\n/** True when something that is not penv's schema already lives at `relative`. */\nfunction occupied(cwd: string, relative: string): boolean {\n const file = join(cwd, ...relative.split(\"/\"));\n return existsSync(file) && !exportsSchema(file);\n}\n\n/**\n * Where a framework's projects keep the schema — and where penv puts it instead\n * when that address is already someone else's.\n *\n * `src/env.ts` is the convention and it is also a name projects already use for\n * their own env module. Proposing it regardless is how penv came to scaffold\n * around a file it could not use: it kept the user's module (invariant 2, right),\n * then `validate` failed with \"src/env.ts exports no `schema`\" — a complaint\n * about a path penv itself had chosen.\n *\n * Stepping aside is not a guess. The file being there, and not exporting a\n * schema, is a fact about the codebase — the kind penv may default from, because\n * a wrong answer is visible in the plan and writes nothing over anything.\n */\nexport function schemaFileFor(cwd: string): { file: string; displaced?: string } {\n const dir = existsSync(join(cwd, \"src\")) ? \"src/\" : \"\";\n const preferred = `${dir}env.ts`;\n if (!occupied(cwd, preferred)) {\n return { file: preferred };\n }\n\n const beside = `${dir}penv-env.ts`;\n if (!occupied(cwd, beside)) {\n return { file: beside, displaced: preferred };\n }\n // Both names taken by modules that are not penv's. `.penv/` is penv's own\n // directory, so it is the one address no other tool has a claim on.\n return { file: DEFAULT_SCHEMA_FILE, displaced: preferred };\n}\n\n/**\n * Every dependency name the manifest declares, or `undefined` when there is no\n * manifest to read. An unreadable or malformed `package.json` answers the same\n * way an absent one does — \"I cannot tell\" — because init's fallback is correct\n * and reported, while a parse error thrown from a suggestion would fail a\n * command that had not yet asked the user anything.\n */\nfunction dependenciesOf(cwd: string): ReadonlySet<string> | undefined {\n const manifest = manifestOf(cwd);\n if (manifest === undefined) {\n return undefined;\n }\n\n const names = new Set<string>();\n for (const field of [\"dependencies\", \"devDependencies\"] as const) {\n const block: unknown = manifest[field];\n if (block !== null && typeof block === \"object\" && !Array.isArray(block)) {\n for (const name of Object.keys(block)) {\n names.add(name);\n }\n }\n }\n return names;\n}\n\n/**\n * The project's manifest, or `undefined` when there is nothing readable to read.\n *\n * An absent or unparseable `package.json` is not an error here: detection's whole\n * contract is that it may answer \"I cannot tell\", and a project penv is asked to\n * scaffold before its manifest exists is a project, not a mistake.\n */\nfunction manifestOf(cwd: string): Readonly<Record<string, unknown>> | undefined {\n const file = join(cwd, \"package.json\");\n if (!existsSync(file)) {\n return undefined;\n }\n let manifest: unknown;\n try {\n manifest = JSON.parse(readFileSync(file, \"utf8\"));\n } catch {\n return undefined;\n }\n return manifest === null || typeof manifest !== \"object\" || Array.isArray(manifest)\n ? undefined\n : (manifest as Readonly<Record<string, unknown>>);\n}\n\n/**\n * The framework this project is built with, or `undefined` when penv cannot\n * tell. `undefined` is an answer, not a failure: init falls back to the default\n * schema path and says that it did.\n */\nexport function detectFramework(cwd: string): Detected | undefined {\n const dependencies = dependenciesOf(cwd);\n if (dependencies === undefined) {\n return undefined;\n }\n for (const signature of SIGNATURES) {\n if (signature.packages.some((name) => dependencies.has(name))) {\n const schema = schemaFileFor(cwd);\n return {\n name: signature.name,\n schemaFile: schema.file,\n ...(schema.displaced === undefined ? {} : { displacedFrom: schema.displaced }),\n publicPrefixes: signature.publicPrefixes,\n };\n }\n }\n return undefined;\n}\n\n/** The alias penv writes when the project says nothing about how it names its own modules. */\nexport const DEFAULT_ALIAS = \"@env\";\n\n/** The alias for a project that already speaks Node's subpath imports. */\nexport const IMPORTS_ALIAS = \"#env\";\n\n/**\n * The alias to offer, read from how the project already refers to itself.\n *\n * The two forms are not interchangeable, and the difference is not taste:\n *\n * - `@env` is a `tsconfig.json` `paths` entry. TypeScript understands it and a\n * bundler resolves it. Plain `node dist/index.js` does not — `paths` is erased\n * by the compiler, so the emitted `import ... from \"@env\"` reaches Node as a\n * package that is not installed.\n * - `#env` is a `package.json` `imports` entry, which Node resolves natively and\n * every current bundler honours. It needs a modern `moduleResolution` for the\n * types to follow, which is why it is not simply the default.\n *\n * A project carrying an `imports` block has already answered the question, so\n * that is what is offered. Anything else gets `@env`, which is what the docs\n * describe and what a framework project wants. This is a suggestion either way:\n * the human confirms it, and the answer is written down as a decision.\n */\nexport function detectAlias(cwd: string): string {\n return hasImportsBlock(cwd) ? IMPORTS_ALIAS : DEFAULT_ALIAS;\n}\n\nfunction hasImportsBlock(cwd: string): boolean {\n const manifest = manifestOf(cwd);\n const imports = manifest?.imports;\n return imports !== null && typeof imports === \"object\" && !Array.isArray(imports);\n}\n","/**\n * `penv init` — scaffold a project.\n *\n * Every step is idempotent, and two of them are write-once on purpose: the\n * schema module is yours the moment it exists (invariant 2 — penv scaffolds it,\n * never regenerates it), and `penv.config.ts` is the environment whitelist you\n * declared. Re-running init reports what it kept rather than overwriting it.\n *\n * What init writes is a set of decisions, and the two kinds are kept apart. penv\n * may default what it can *observe* — the framework in `package.json`, whether\n * `src/` exists — because a wrong guess about the codebase is visible in the\n * codebase. It must ask for what it cannot observe: which environments exist is\n * deployment topology, it is nowhere on disk, and a project that carries a\n * `staging` penv invented is a project whose config is fiction (invariant 10).\n * So `environments` starts empty, and `--yes` cannot fill it: `--yes` means \"I\n * trust your defaults for what you can see\", never \"invent my infrastructure\".\n */\n\nimport { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { createInterface } from \"node:readline/promises\";\nimport {\n DEFAULT_SCHEMA_FILE,\n isLegalEnvironmentName,\n loadConfigFrom,\n type PenvConfig,\n PenvError,\n RESERVED_TOKENS,\n schemaFileOf,\n schemaInsideTree,\n validateSchemaFile,\n} from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { DEFAULT_ALIAS, type Detected, detectAlias, detectFramework } from \"../detect.js\";\nimport { CHECK, columns, formatSteps, guard, type Step, WARN, write } from \"../ui.js\";\n\nexport const SCHEMA_FILE = \"env.ts\";\nexport const CONFIG_FILE = \"penv.config.ts\";\nexport const TSCONFIG_FILE = \"tsconfig.json\";\nexport const GITIGNORE_FILE = \".gitignore\";\nexport const PENV_DIR = \".penv\";\n\n/**\n * The alias forms penv can write, and the only two a specifier can take that is\n * not a package: `@name` resolves through tsconfig `paths`, `#name` through\n * package.json `imports`.\n */\nconst ALIAS_NAME = /^[@#][A-Za-z0-9_-]+$/;\n\n/** The prefix that means Node resolves the alias itself, with no bundler involved. */\nconst IMPORTS_PREFIX = \"#\";\n\nconst PACKAGE_FILE = \"package.json\";\n\n/** What init touched, so a caller can report it and a test can assert it. */\nexport type InitTarget = \"penv-dir\" | \"schema\" | \"config\" | \"tsconfig\" | \"gitignore\";\n/**\n * `conflicted` is the one that is not a success. penv wanted to write something,\n * found the user's file already saying something else about the same thing, and\n * left it alone — so the step is reported with a warning rather than a ✓, and the\n * text says what will not work until the user decides.\n */\nexport type InitAction = \"created\" | \"kept\" | \"updated\" | \"conflicted\";\n\nexport interface InitStep {\n readonly target: InitTarget;\n readonly action: InitAction;\n /** The reported line, in the docs' voice. */\n readonly text: string;\n readonly note?: string;\n}\n\n/**\n * The answers init writes down. Every one of these is a decision a human either\n * made or consented to — never an identity penv recorded to reinterpret later.\n * There is deliberately no `framework` here: `schemaFile` and `publicPrefixes`\n * still mean exactly what they say after the project is rewritten in something\n * else, and `framework: \"next\"` would not.\n */\nexport interface InitDecisions {\n /** The whitelist. Empty unless a human named them — penv never infers one. */\n readonly environments: readonly string[];\n /** The schema module, relative to the project root, POSIX. */\n readonly schemaFile: string;\n /** The prefixes the framework inlines into its client bundle. */\n readonly publicPrefixes: readonly string[];\n /**\n * How the user's code names the schema module — `@env` or `#env`.\n *\n * Two forms, resolved by two different things: `@env` is a tsconfig `paths`\n * entry that a bundler resolves and plain Node does not, and `#env` is a\n * package.json `imports` entry that Node resolves itself. Which one a project\n * wants is a fact about the project, so penv reads what it already does and\n * offers that.\n */\n readonly alias: string;\n}\n\n/** What init would write with no further input: the defaults, and nothing invented. */\nexport const DEFAULT_DECISIONS: InitDecisions = {\n environments: [],\n schemaFile: DEFAULT_SCHEMA_FILE,\n publicPrefixes: [],\n alias: DEFAULT_ALIAS,\n};\n\nexport interface InitResult {\n readonly root: string;\n readonly decisions: InitDecisions;\n readonly steps: readonly InitStep[];\n}\n\nexport interface InitOptions {\n readonly cwd: string;\n /** What to write. Omitted means the plan's defaults, as `--yes` takes them. */\n readonly decisions?: InitDecisions;\n}\n\n/*\n * The plan: what penv observed, what it would write, and why.\n */\n\n/** Flags that decide without asking, so a script never meets a prompt. */\nexport interface InitFlags {\n /** `--schema <path>`. */\n readonly schema?: string;\n /** `--env`, already split. Absent means no answer; present means the answer. */\n readonly environments?: readonly string[];\n /** `--alias <name>`. */\n readonly alias?: string;\n}\n\nexport interface InitPlan {\n readonly detected: Detected | undefined;\n /** What init writes unless a human edits it. */\n readonly decisions: InitDecisions;\n /** Environments the `.env*` files on disk are evidence for. Offered, never taken. */\n readonly suggestedEnvironments: readonly string[];\n /** Why each decision is what it is. Printed — a fallback penv takes silently is a guess. */\n readonly notes: readonly string[];\n}\n\n/**\n * Names that look like an environment in a `.env` filename but are not one:\n * `.env.example` is documentation, and the grammar's reserved tokens are\n * scope markers. Suggesting either would put a name into the whitelist that no\n * value file can ever be scoped to.\n */\nconst NOT_ENVIRONMENTS: readonly string[] = [...RESERVED_TOKENS, \"example\", \"sample\", \"template\"];\n\n/**\n * The environments the project's own `.env*` files are evidence for.\n *\n * This is not inference: nothing here reaches `penv.config.ts` unless a human\n * reads the suggestion and presses Enter. Invariant 10 is about what penv\n * *declares*, and showing someone the filenames they wrote is not a declaration\n * — it is the difference between \"you seem to have a production\" and penv\n * quietly deciding that you do.\n */\nexport function suggestEnvironments(root: string): string[] {\n let entries: string[];\n try {\n entries = readdirSync(root);\n } catch {\n return [];\n }\n\n const found = new Set<string>();\n for (const entry of entries) {\n if (!entry.startsWith(\".env.\")) {\n continue;\n }\n const segments = entry.slice(\".env.\".length).split(\".\");\n // `.env.production.local` is production's file; `.env.local` names no\n // environment at all, and neither does anything with more segments left\n // over, which is a filename penv has no reading of.\n const withoutLocal = segments.at(-1) === \"local\" ? segments.slice(0, -1) : segments;\n const name = withoutLocal.length === 1 ? withoutLocal[0] : undefined;\n if (name === undefined || !isLegalEnvironmentName(name) || NOT_ENVIRONMENTS.includes(name)) {\n continue;\n }\n found.add(name);\n }\n // Sorted so the same project shows the same line on every machine: directory\n // order is the filesystem's answer, not the project's.\n return [...found].sort();\n}\n\n/** A flag that is present but says nothing is refused, never read as absent. */\nfunction emptyFlag(flag: \"schema\" | \"env\" | \"alias\"): PenvError {\n return new PenvError(\n \"INIT_FLAG_EMPTY\",\n `\\`--${flag}\\` was given without a value`,\n flag === \"schema\"\n ? \"Name the module that exports the schema, e.g. `--schema src/env.ts`, or drop the flag \" +\n `to use ${DEFAULT_SCHEMA_FILE}.`\n : \"Name the environment, e.g. `--env production`, or drop the flag to leave the whitelist \" +\n \"empty and declare it in penv.config.ts.\",\n );\n}\n\n/** One list of environment names, however it was written. */\nfunction splitEnvironments(value: string): string[] {\n return value\n .split(\",\")\n .map((name) => name.trim())\n .filter((name) => name.length > 0);\n}\n\n/**\n * `--env` as the whitelist it declares, or `undefined` when it was not given —\n * which is no answer, not an empty one. Repeatable and comma-separated both\n * work: `--env development --env production` and `--env development,production`\n * are the same answer, and a shell that made one of them awkward is not a reason\n * to have declared a different set of environments.\n */\nexport function environmentsFromFlag(flag: unknown): readonly string[] | undefined {\n if (flag === undefined) {\n return undefined;\n }\n const given = Array.isArray(flag) ? (flag as readonly unknown[]) : [flag];\n const names = given.flatMap((value) => splitEnvironments(String(value)));\n if (names.length === 0) {\n throw emptyFlag(\"env\");\n }\n return [...new Set(names)];\n}\n\n/** The config the decisions describe, so core answers questions about it, not init. */\nfunction configOf(decisions: InitDecisions): PenvConfig {\n return { environments: decisions.environments, providers: {}, schemaFile: decisions.schemaFile };\n}\n\n/**\n * The decisions this project already recorded, or `undefined` when it has none.\n *\n * Only the config init itself would write or keep — the one beside `root`, not\n * whatever `findConfigFile` turns up two directories above. A monorepo's root\n * config is not this package's declaration, and `writeConfigFile` has always\n * looked exactly here.\n *\n * A config that exists and cannot be read is an error rather than an absence.\n * Treating it as absent is how the re-run bug worked in the first place: penv\n * would decide the project had declared nothing, re-detect, and scaffold a\n * second schema beside the one already there.\n */\nfunction declaredIn(root: string): PenvConfig | undefined {\n const file = join(root, CONFIG_FILE);\n if (!existsSync(file)) {\n return undefined;\n }\n return loadConfigFrom(file);\n}\n\n/**\n * What penv observed and what it proposes to write. The notes are the point as\n * much as the decisions are: a project that ends up with `.penv/env.ts` because\n * detection failed must be told that detection failed, or the fallback is\n * indistinguishable from a choice penv made on their behalf.\n *\n * Precedence is the whole design in one list: a flag is the human deciding now, a\n * config is the human having decided already, and detection is a suggestion that\n * loses to both. Guess once, declare forever — so once `penv.config.ts` exists,\n * re-detection cannot move what it says. Re-running init on a project that\n * declared `src/lib/env.ts` used to scaffold a *second* schema at the detected\n * path, warn that its own correct alias pointed at the wrong file, and announce\n * that a project with `environments: [\"production\"]` had declared none.\n */\nexport function planInit(root: string, flags: InitFlags = {}): InitPlan {\n const declared = declaredIn(root);\n const detected = detectFramework(root);\n const notes: string[] = [];\n\n if (declared !== undefined) {\n notes.push(`${CONFIG_FILE} already exists — init keeps every decision it records.`);\n } else if (detected === undefined) {\n notes.push(\n `No framework detected in package.json — the schema goes to ${DEFAULT_SCHEMA_FILE}.`,\n );\n } else {\n notes.push(`Detected ${detected.name}.`);\n if (detected.displacedFrom !== undefined) {\n notes.push(\n `${detected.displacedFrom} is already a module of yours that exports no \\`schema\\`, so ` +\n `the schema goes to ${detected.schemaFile}. penv never writes over a file it did not ` +\n `write — delete yours and re-run if you want it there, or pass \\`--schema\\`.`,\n );\n }\n }\n\n // Flag, then what the project already declared, then detection. `schemaFileOf`\n // rather than `config.schemaFile`: a config that omits the key has still\n // answered — with the default — and re-detection must not move a schema that\n // is already sitting where the project says it is.\n const schemaFile =\n flags.schema === undefined\n ? declared !== undefined\n ? schemaFileOf(declared)\n : (detected?.schemaFile ?? DEFAULT_SCHEMA_FILE)\n : flags.schema.trim();\n if (flags.schema !== undefined) {\n if (schemaFile.length === 0) {\n throw emptyFlag(\"schema\");\n }\n // Every rule a committed path has to satisfy lives in core, so `--schema`\n // is judged by the same validator `penv validate` will judge the config by.\n // Refusing here is refusing before a file is written; refusing there is\n // refusing after the project already has one in the wrong place.\n const error = validateSchemaFile({ environments: [], providers: {}, schemaFile })[0];\n if (error !== undefined) {\n throw error;\n }\n }\n\n const alias = flags.alias === undefined ? detectAlias(root) : flags.alias.trim();\n if (flags.alias !== undefined && alias.length === 0) {\n throw emptyFlag(\"alias\");\n }\n if (!ALIAS_NAME.test(alias)) {\n throw new PenvError(\n \"INIT_ALIAS_INVALID\",\n `\\`${alias}\\` is not an alias penv can write`,\n `An alias is \\`@name\\` — a tsconfig \\`paths\\` entry a bundler resolves — or \\`#name\\`, a ` +\n \"package.json `imports` entry Node resolves itself. Those are the two things a module \" +\n \"specifier can be that is not a package.\",\n );\n }\n // Only when penv worked it out. `--alias` needs no explanation of why penv\n // chose it, and this note would have explained a reason that was not true:\n // it fired on the *form* of the alias rather than on where it came from, so a\n // forced `#env` was told its own package.json had asked for it.\n if (flags.alias === undefined && alias.startsWith(IMPORTS_PREFIX)) {\n notes.push(\n `Your ${PACKAGE_FILE} declares \\`imports\\`, so the alias is \\`${alias}\\` — Node resolves it without a bundler.`,\n );\n }\n\n const suggestedEnvironments = suggestEnvironments(root);\n const environments = flags.environments ?? declared?.environments ?? [];\n // The empty whitelist is worth a line only when it is still empty. A project\n // that declared `production` being told it has declared nothing is penv\n // reading its own config wrong out loud.\n if (environments.length === 0) {\n notes.push(\n \"No environments declared: penv does not infer them, and a `--yes` run cannot invent them.\",\n );\n if (suggestedEnvironments.length > 0) {\n notes.push(\n `Your \\`.env\\` files mention ${suggestedEnvironments.join(\", \")} — declare the ones you ` +\n `really deploy in ${CONFIG_FILE}, with a provider for each.`,\n );\n }\n }\n\n return {\n detected,\n decisions: {\n environments,\n schemaFile,\n publicPrefixes: declared?.publicPrefixes ?? detected?.publicPrefixes ?? [],\n alias,\n },\n suggestedEnvironments,\n notes,\n };\n}\n\n/*\n * The prompt.\n *\n * A plan the human confirms, not an interrogation they answer: penv already\n * knows everything but the one fact it must not guess, so it shows the whole\n * page and asks once. The io is a parameter so the decision logic is a plain\n * function — the tests call it, they do not spawn a terminal.\n */\n\nexport interface PromptIo {\n readonly ask: (question: string) => Promise<string>;\n readonly write: (line: string) => void;\n}\n\n/** The plan as one screen. */\nexport function renderPlan(plan: InitPlan): string[] {\n const rows: string[][] = [];\n rows.push([\n \" environments\",\n plan.suggestedEnvironments.length === 0 ? \"\" : `[${plan.suggestedEnvironments.join(\", \")}]`,\n plan.suggestedEnvironments.length === 0\n ? \"<- name them, or Enter to leave the whitelist empty\"\n : \"<- from your .env files; edit, or Enter to accept\",\n ]);\n rows.push([\n \" schemaFile\",\n plan.decisions.schemaFile,\n plan.decisions.schemaFile === DEFAULT_SCHEMA_FILE ? \"\" : `(default: ${DEFAULT_SCHEMA_FILE})`,\n ]);\n for (const prefix of plan.decisions.publicPrefixes) {\n rows.push([\" publicPrefix\", prefix, \"\"]);\n }\n\n const headline =\n plan.detected === undefined\n ? \"No framework detected in package.json.\"\n : `Detected ${plan.detected.name}.`;\n return [headline, \"\", ...columns(rows), \"\"];\n}\n\nfunction environmentsHint(plan: InitPlan): string {\n return plan.suggestedEnvironments.length === 0\n ? \"environments (comma-separated, Enter for none) > \"\n : 'environments (Enter to accept, \"none\" for an empty whitelist) > ';\n}\n\n/**\n * The plan, confirmed. `undefined` is the human declining, which is an outcome\n * and not a failure: nothing is written and the run says so.\n *\n * An answer that is neither yes nor no declines, because the two mistakes are\n * not symmetrical — a decline costs a re-run, while reading \"no thanks\" as\n * consent scaffolds a project someone said no to.\n */\nexport async function promptForDecisions(\n plan: InitPlan,\n io: PromptIo,\n): Promise<InitDecisions | undefined> {\n for (const line of renderPlan(plan)) {\n io.write(line);\n }\n\n const answer = (await io.ask(environmentsHint(plan))).trim();\n const environments =\n answer.length === 0\n ? plan.suggestedEnvironments\n : answer.toLowerCase() === \"none\"\n ? []\n : splitEnvironments(answer);\n // The confirmation has to be about what is actually written, so an edited\n // line is echoed before `Proceed?` rather than confirmed in the abstract.\n if (answer.length > 0) {\n io.write(\"\");\n io.write(\n environments.length === 0\n ? \" environments [] (declare them later in penv.config.ts)\"\n : ` environments [${environments.join(\", \")}]`,\n );\n io.write(\"\");\n }\n\n const proceed = (await io.ask(\"Proceed? [Y/n] \")).trim().toLowerCase();\n if (proceed.length > 0 && proceed !== \"y\" && proceed !== \"yes\") {\n return undefined;\n }\n return { ...plan.decisions, environments };\n}\n\n/*\n * Templates.\n */\n\n/** One schema field for the draft `penv import` generates. */\nexport interface SchemaField {\n readonly key: string;\n /** The Zod expression, e.g. `z.url()`. */\n readonly type: string;\n}\n\nconst EMPTY_SCHEMA_BODY =\n \" // One key per parameter, e.g. `databaseUrl: z.url(),`. Nesting a key nests\\n\" +\n \" // the parameter: `redis: z.object({ password: z.string() })` is redis/password.\";\n\nconst DRAFT_HEADER =\n \"// DRAFT — generated by `penv import` from one sample of each value, and yours\\n\" +\n \"// to correct. Single-sample inference cannot know that a boolean seen as `true`\\n\" +\n \"// must also accept `1`/`0`, or that a string is really a URL. penv scaffolds\\n\" +\n \"// this file once and never regenerates it, so edits here are safe.\\n\";\n\nexport function renderSchemaModule(fields: readonly SchemaField[], draft: boolean): string {\n const body =\n fields.length === 0\n ? EMPTY_SCHEMA_BODY\n : fields.map((field) => ` ${field.key}: ${field.type},`).join(\"\\n\");\n\n return (\n `${draft ? DRAFT_HEADER : \"\"}import { z } from \"zod\";\\n` +\n `import { load } from \"@penvhq/penv\";\\n` +\n `\\n` +\n `// The shape. Import this (or z.infer<typeof schema>) when you only need the\\n` +\n `// type — tests, tooling — so you don't trigger config loading.\\n` +\n `export const schema = z.object({\\n${body}\\n});\\n` +\n `\\n` +\n `// The loaded, validated values for the current environment. Import this in app\\n` +\n `// code. Importing it loads configuration and throws (naming the parameter and\\n` +\n `// environment) if anything required is missing or invalid.\\n` +\n `export const env = load(schema);\\n`\n );\n}\n\n/**\n * The whitelist block. Empty is the honest answer to a question nothing on disk\n * can settle, so the comment carries what an empty file cannot: that penv left\n * it empty on purpose, and the exact shape of the two lines that fill it in.\n */\nfunction renderEnvironments(decisions: InitDecisions): string {\n const shared =\n \" // Environments are a whitelist. A filename segment is an environment only if\\n\" +\n \" // it is declared here — penv never infers one from a folder or a filename.\\n\";\n if (decisions.environments.length === 0) {\n return (\n `${shared}` +\n \" // It starts empty because which environments you deploy is not something penv\\n\" +\n \" // can read off your codebase, and an environment you do not have is worse\\n\" +\n \" // than one you have not declared yet. Name yours, and give each a provider:\\n\" +\n ' // environments: [\"development\", \"production\"],\\n' +\n ' // providers: { development: { type: \"filesystem\" }, production: { type: \"filesystem\" } },\\n' +\n \" environments: [],\\n\" +\n \"\\n\" +\n \" providers: {},\\n\"\n );\n }\n const names = decisions.environments.map((name) => JSON.stringify(name)).join(\", \");\n const providers = decisions.environments\n .map((name) => ` ${JSON.stringify(name)}: { type: \"filesystem\" },\\n`)\n .join(\"\");\n return (\n `${shared} environments: [${names}],\\n` +\n \"\\n\" +\n \" // One entry per environment: where that environment's values are read from.\\n\" +\n ` providers: {\\n${providers} },\\n`\n );\n}\n\n/** The config, carrying only the decisions that were actually made. */\nexport function renderConfigModule(decisions: InitDecisions): string {\n let body = renderEnvironments(decisions);\n\n // The default is written by not writing it: a key that restates the default is\n // noise the next reader has to check against the docs before they can ignore it.\n if (decisions.schemaFile !== DEFAULT_SCHEMA_FILE) {\n body +=\n \"\\n // The module that exports the schema. It is yours — penv scaffolds it once\\n\" +\n \" // and never regenerates it — so this says where you keep it.\\n\" +\n ` schemaFile: ${JSON.stringify(decisions.schemaFile)},\\n`;\n }\n if (decisions.publicPrefixes.length > 0) {\n const prefixes = decisions.publicPrefixes.map((prefix) => JSON.stringify(prefix)).join(\", \");\n body +=\n \"\\n // The prefixes your framework inlines into the browser bundle. `penv doctor`\\n\" +\n \" // reports a parameter your meta declares `secret: true` whose variable name\\n\" +\n \" // starts with one of these — penv is the only thing holding both facts.\\n\" +\n ` publicPrefixes: [${prefixes}],\\n`;\n }\n\n return `import { defineConfig } from \"@penvhq/penv\";\\n\\nexport default defineConfig({\\n${body}});\\n`;\n}\n\n/**\n * Invariant 17: value files are never committed; structure, the schema, meta,\n * and config are. The negated directory pattern keeps git descending into\n * namespace folders, which an excluded directory would otherwise hide entirely.\n *\n * The schema is un-ignored by name only when it lives in the tree. Outside it,\n * this file has no opinion on it at all, and a `!env.ts` naming nothing is a\n * line the next reader has to work out is dead.\n */\nexport function renderGitignore(decisions: InitDecisions): string {\n const inside = schemaInsideTree(configOf(decisions));\n const listed = inside === undefined ? \"\" : `${inside}, `;\n return (\n `# Written by penv. Value files hold configuration values and are never\\n` +\n `# committed; only the structure, ${listed}meta, and config are.\\n` +\n `*\\n` +\n `!*/\\n` +\n `!.gitignore\\n` +\n `${inside === undefined ? \"\" : `!${inside}\\n`}` +\n `!*.json\\n`\n );\n}\n\n/*\n * The tsconfig.json edit.\n *\n * The alias is inserted into the user's own file, so the file is scanned rather\n * than parsed and re-emitted: reformatting someone's tsconfig — dropping its\n * comments, resorting its keys — to add one path is not a minimal edit.\n */\n\nfunction skipTrivia(source: string, index: number): number {\n let i = index;\n for (;;) {\n const ch = source.charAt(i);\n if (ch === \" \" || ch === \"\\t\" || ch === \"\\n\" || ch === \"\\r\") {\n i += 1;\n continue;\n }\n if (ch === \"/\" && source.charAt(i + 1) === \"/\") {\n const end = source.indexOf(\"\\n\", i);\n i = end === -1 ? source.length : end + 1;\n continue;\n }\n if (ch === \"/\" && source.charAt(i + 1) === \"*\") {\n const end = source.indexOf(\"*/\", i + 2);\n i = end === -1 ? source.length : end + 2;\n continue;\n }\n return i;\n }\n}\n\n/** Index just past the closing quote of the string opening at `index`. */\nfunction endOfString(source: string, index: number): number {\n let i = index + 1;\n while (i < source.length) {\n const ch = source.charAt(i);\n if (ch === \"\\\\\") {\n i += 2;\n continue;\n }\n if (ch === '\"') {\n return i + 1;\n }\n i += 1;\n }\n return source.length;\n}\n\n/** Index just past the bracket matching the one at `index`. */\nfunction endOfBracket(source: string, index: number): number {\n const open = source.charAt(index);\n const close = open === \"{\" ? \"}\" : \"]\";\n let depth = 0;\n let i = index;\n while (i < source.length) {\n const ch = source.charAt(i);\n if (ch === '\"') {\n i = endOfString(source, i);\n continue;\n }\n if (ch === \"/\" && (source.charAt(i + 1) === \"/\" || source.charAt(i + 1) === \"*\")) {\n i = skipTrivia(source, i);\n continue;\n }\n if (ch === open) {\n depth += 1;\n i += 1;\n continue;\n }\n if (ch === close) {\n depth -= 1;\n i += 1;\n if (depth === 0) {\n return i;\n }\n continue;\n }\n i += 1;\n }\n return source.length;\n}\n\nfunction endOfValue(source: string, index: number): number {\n const ch = source.charAt(index);\n if (ch === '\"') {\n return endOfString(source, index);\n }\n if (ch === \"{\" || ch === \"[\") {\n return endOfBracket(source, index);\n }\n let i = index;\n while (i < source.length) {\n const c = source.charAt(i);\n if (c === \",\" || c === \"}\" || c === \"]\" || c === \"\\n\") {\n return i;\n }\n i += 1;\n }\n return source.length;\n}\n\ninterface Member {\n readonly valueStart: number;\n}\n\n/** The member named `key` directly inside the object whose `{` is at `open`. */\nfunction findMember(source: string, open: number, key: string): Member | undefined {\n const close = endOfBracket(source, open) - 1;\n let i = skipTrivia(source, open + 1);\n while (i < close) {\n if (source.charAt(i) !== '\"') {\n return undefined;\n }\n const keyEnd = endOfString(source, i);\n const name = source.slice(i + 1, keyEnd - 1);\n const colon = skipTrivia(source, keyEnd);\n if (source.charAt(colon) !== \":\") {\n return undefined;\n }\n const valueStart = skipTrivia(source, colon + 1);\n const valueEnd = endOfValue(source, valueStart);\n if (name === key) {\n return { valueStart };\n }\n let next = skipTrivia(source, valueEnd);\n if (source.charAt(next) === \",\") {\n next = skipTrivia(source, next + 1);\n }\n i = next;\n }\n return undefined;\n}\n\n/** The indentation of the line `index` sits on. */\nfunction lineIndent(source: string, index: number): string {\n const lineStart = source.lastIndexOf(\"\\n\", index) + 1;\n const match = /^[ \\t]*/.exec(source.slice(lineStart, index));\n return match?.[0] ?? \"\";\n}\n\n/** The file's own indentation unit, so the inserted line looks like its neighbours. */\nfunction indentUnit(source: string): string {\n const match = /\\n([ \\t]+)\"/.exec(source);\n return match?.[1] ?? \" \";\n}\n\nfunction insertMember(source: string, open: number, member: string, unit: string): string {\n const objectIndent = lineIndent(source, open);\n const entryIndent = objectIndent + unit;\n const close = endOfBracket(source, open) - 1;\n if (skipTrivia(source, open + 1) === close) {\n return `${source.slice(0, open + 1)}\\n${entryIndent}${member}\\n${objectIndent}${source.slice(close)}`;\n }\n return `${source.slice(0, open + 1)}\\n${entryIndent}${member},${source.slice(open + 1)}`;\n}\n\nfunction shapeError(what: string, target: string, alias: string): PenvError {\n return new PenvError(\n \"TSCONFIG_SHAPE\",\n `penv cannot add the \\`${alias}\\` path alias to tsconfig.json: ${what}`,\n `Add it by hand: \\`{ \"compilerOptions\": { \"paths\": { \"${alias}\": [\"${target}\"] } } }\\`.`,\n );\n}\n\nexport interface AliasEdit {\n readonly source: string;\n readonly changed: boolean;\n /**\n * What the alias already points at, when that is not penv's schema.\n *\n * The alias is how the user's code reaches penv, so an alias that resolves\n * somewhere else is not a small problem: `import { env } from \"@env\"` compiles,\n * runs, and hands back another module's export. Reporting \"kept the alias\"\n * because the *key* was present is how penv would say that was fine — a silent\n * seam, in the scaffolder of the tool whose subject is silent seams.\n *\n * Left as the user's, never rewritten: penv cannot tell a stale mapping from a\n * deliberate one, and the file is theirs.\n */\n readonly conflict?: string;\n}\n\n/**\n * `tsconfig.json` with the `@env` alias present, everything else untouched.\n * Already-aliased input comes back unchanged rather than gaining a duplicate.\n *\n * The alias is why the schema can live anywhere: application code imports\n * `@env`, and this line is the only thing that has to know where that is.\n */\nexport function insertEnvAlias(\n source: string,\n target: string = DEFAULT_SCHEMA_FILE,\n name: string = DEFAULT_ALIAS,\n): AliasEdit {\n const alias = `\"${name}\": [\"${target}\"]`;\n const root = skipTrivia(source, 0);\n if (source.charAt(root) !== \"{\") {\n throw shapeError(\"its contents are not a JSON object\", target, name);\n }\n\n const unit = indentUnit(source);\n const compilerOptions = findMember(source, root, \"compilerOptions\");\n if (compilerOptions === undefined) {\n return {\n source: insertMember(source, root, `\"compilerOptions\": { \"paths\": { ${alias} } }`, unit),\n changed: true,\n };\n }\n if (source.charAt(compilerOptions.valueStart) !== \"{\") {\n throw shapeError(\"`compilerOptions` is not an object\", target, name);\n }\n\n const paths = findMember(source, compilerOptions.valueStart, \"paths\");\n if (paths === undefined) {\n return {\n source: insertMember(source, compilerOptions.valueStart, `\"paths\": { ${alias} }`, unit),\n changed: true,\n };\n }\n if (source.charAt(paths.valueStart) !== \"{\") {\n throw shapeError(\"`compilerOptions.paths` is not an object\", target, name);\n }\n\n const existing = findMember(source, paths.valueStart, name);\n if (existing !== undefined) {\n // The key being present is not the question. Where it points is.\n const points = source.slice(existing.valueStart, endOfValue(source, existing.valueStart));\n return points.includes(`\"${target}\"`)\n ? { source, changed: false }\n : { source, changed: false, conflict: points.trim() };\n }\n return { source: insertMember(source, paths.valueStart, alias, unit), changed: true };\n}\n\n/**\n * `package.json` with the `#env` subpath import present, everything else untouched.\n *\n * The same scanning edit the tsconfig gets, for the same reason: a manifest is\n * the project's file, and rewriting it through `JSON.parse`/`stringify` to add\n * one key resorts nothing but reformats everything.\n *\n * `imports` is Node's own mechanism, so an alias written here needs no bundler to\n * resolve — which is the whole reason a project would choose it.\n */\nexport function insertImportsAlias(source: string, target: string, name: string): AliasEdit {\n const entry = `\"${name}\": \"./${target}\"`;\n const root = skipTrivia(source, 0);\n if (source.charAt(root) !== \"{\") {\n throw shapeError(\"its contents are not a JSON object\", target, name);\n }\n\n const unit = indentUnit(source);\n const imports = findMember(source, root, \"imports\");\n if (imports === undefined) {\n return { source: insertMember(source, root, `\"imports\": { ${entry} }`, unit), changed: true };\n }\n if (source.charAt(imports.valueStart) !== \"{\") {\n throw shapeError(\"`imports` is not an object\", target, name);\n }\n\n const existing = findMember(source, imports.valueStart, name);\n if (existing !== undefined) {\n const points = source.slice(existing.valueStart, endOfValue(source, existing.valueStart));\n return points.includes(`\"./${target}\"`)\n ? { source, changed: false }\n : { source, changed: false, conflict: points.trim() };\n }\n return { source: insertMember(source, imports.valueStart, entry, unit), changed: true };\n}\n\nfunction renderTsconfig(target: string, alias: string): string {\n return `{\\n \"compilerOptions\": {\\n \"paths\": { \"${alias}\": [\"${target}\"] }\\n }\\n}\\n`;\n}\n\n/*\n * The steps themselves. Each returns what it did so the caller reports it.\n */\n\nexport function ensurePenvDir(root: string): InitStep {\n const dir = resolve(root, PENV_DIR);\n if (existsSync(dir)) {\n return { target: \"penv-dir\", action: \"kept\", text: `Found ${PENV_DIR}/` };\n }\n mkdirSync(dir, { recursive: true });\n return { target: \"penv-dir\", action: \"created\", text: `Created ${PENV_DIR}/` };\n}\n\n/**\n * Invariant 2: the schema module is scaffolded once and never regenerated. An\n * existing file is the user's, whatever penv would have written instead — and\n * that holds wherever they keep it, so the check is against the chosen path and\n * not the default one.\n */\nexport function writeSchemaFile(\n root: string,\n fields: readonly SchemaField[],\n draft: boolean,\n decisions: InitDecisions = DEFAULT_DECISIONS,\n): InitStep {\n const file = join(root, ...decisions.schemaFile.split(\"/\"));\n if (existsSync(file)) {\n return {\n target: \"schema\",\n action: \"kept\",\n text: `Kept ${decisions.schemaFile}`,\n note: \"(yours — penv never regenerates it)\",\n };\n }\n mkdirSync(dirname(file), { recursive: true });\n writeFileSync(file, renderSchemaModule(fields, draft), \"utf8\");\n return {\n target: \"schema\",\n action: \"created\",\n text: `Generated ${decisions.schemaFile}`,\n note: draft ? \"(draft schema — review it, it's yours)\" : \"(schema + loader — yours to edit)\",\n };\n}\n\nexport function writeConfigFile(\n root: string,\n decisions: InitDecisions = DEFAULT_DECISIONS,\n): InitStep {\n const file = join(root, CONFIG_FILE);\n if (existsSync(file)) {\n return { target: \"config\", action: \"kept\", text: `Kept ${CONFIG_FILE}` };\n }\n writeFileSync(file, renderConfigModule(decisions), \"utf8\");\n return { target: \"config\", action: \"created\", text: `Generated ${CONFIG_FILE}` };\n}\n\nexport function writeTsconfigAlias(\n root: string,\n decisions: InitDecisions = DEFAULT_DECISIONS,\n): InitStep {\n const alias = decisions.alias;\n // `#env` is Node's mechanism and lives in the manifest; `@env` is TypeScript's\n // and lives in the tsconfig. Writing one into the other's file produces a key\n // nothing reads — the alias would simply never resolve, and penv would have\n // reported writing it.\n const imports = alias.startsWith(IMPORTS_PREFIX);\n const file = join(root, imports ? PACKAGE_FILE : TSCONFIG_FILE);\n const where = imports ? PACKAGE_FILE : TSCONFIG_FILE;\n\n if (!existsSync(file)) {\n // A project with no manifest is not one penv invents a manifest for: the\n // manifest is the project's identity, and `imports` is a key on something\n // that already exists. A tsconfig penv can honestly create from nothing.\n if (imports) {\n return {\n target: \"tsconfig\",\n action: \"conflicted\",\n text: `No ${PACKAGE_FILE} to add the ${alias} import to`,\n note: `(run \\`npm init\\` first, or use \\`--alias @env\\` to alias through ${TSCONFIG_FILE})`,\n };\n }\n writeFileSync(file, renderTsconfig(decisions.schemaFile, alias), \"utf8\");\n return {\n target: \"tsconfig\",\n action: \"created\",\n text: `Created ${TSCONFIG_FILE} with the ${alias} path alias`,\n };\n }\n\n const source = readFileSync(file, \"utf8\");\n const edit = imports\n ? insertImportsAlias(source, decisions.schemaFile, alias)\n : insertEnvAlias(source, decisions.schemaFile, alias);\n\n if (edit.conflict !== undefined) {\n return {\n target: \"tsconfig\",\n action: \"conflicted\",\n text: `${where} already maps ${alias} to ${edit.conflict}`,\n note: `(left alone — \\`import { env } from \"${alias}\"\\` will not reach ${decisions.schemaFile})`,\n };\n }\n if (!edit.changed) {\n return {\n target: \"tsconfig\",\n action: \"kept\",\n text: `Kept the ${alias} alias in ${where}`,\n };\n }\n writeFileSync(file, edit.source, \"utf8\");\n return {\n target: \"tsconfig\",\n action: \"updated\",\n text: `Added ${alias} alias to ${where}`,\n };\n}\n\n/**\n * The ignore file lives inside `.penv/`, where the value files are: penv owns it\n * outright, so it is rewritten when it drifts. A weakened ignore file is how a\n * plaintext secret gets committed, which invariant 17 exists to prevent.\n */\nexport function writeGitignore(\n root: string,\n decisions: InitDecisions = DEFAULT_DECISIONS,\n): InitStep {\n const file = join(root, PENV_DIR, GITIGNORE_FILE);\n const relative = `${PENV_DIR}/${GITIGNORE_FILE}`;\n const wanted = renderGitignore(decisions);\n const existing = existsSync(file) ? readFileSync(file, \"utf8\") : undefined;\n if (existing === wanted) {\n return { target: \"gitignore\", action: \"kept\", text: `Kept ${relative}` };\n }\n mkdirSync(join(root, PENV_DIR), { recursive: true });\n writeFileSync(file, wanted, \"utf8\");\n return {\n target: \"gitignore\",\n action: existing === undefined ? \"created\" : \"updated\",\n text: `${existing === undefined ? \"Created\" : \"Updated\"} ${relative}`,\n };\n}\n\n/** Everything `init` scaffolds, in the order it is reported. */\nexport function scaffold(\n root: string,\n fields: readonly SchemaField[],\n draft: boolean,\n decisions: InitDecisions = DEFAULT_DECISIONS,\n): InitStep[] {\n return [\n ensurePenvDir(root),\n writeSchemaFile(root, fields, draft, decisions),\n writeConfigFile(root, decisions),\n writeTsconfigAlias(root, decisions),\n writeGitignore(root, decisions),\n ];\n}\n\nexport function runInit(options: InitOptions): InitResult {\n const root = resolve(options.cwd);\n const decisions = options.decisions ?? planInit(root).decisions;\n return { root, decisions, steps: scaffold(root, [], false, decisions) };\n}\n\nexport function renderInit(result: InitResult): string[] {\n const steps: Step[] = result.steps.map((step) => {\n // A conflict is the one step that is not a success, so it must not wear the\n // glyph every success wears: a ✓ beside \"penv could not wire your alias\" is\n // the line a reader skims past.\n const glyph = step.action === \"conflicted\" ? WARN : CHECK;\n return step.note === undefined\n ? { glyph, text: step.text }\n : { glyph, text: step.text, note: step.note };\n });\n return [\n ...formatSteps(steps),\n \"\",\n `Done. Declare your parameters in ${result.decisions.schemaFile}, then \\`penv set <key>\\`.`,\n ...(result.decisions.environments.length === 0\n ? [\n `Then declare your environments in ${CONFIG_FILE}: penv leaves the whitelist empty ` +\n `rather than inventing one, and every command needs it.`,\n ]\n : []),\n ];\n}\n\n/** The prompt runs only against a real terminal; anything else has nobody to ask. */\nasync function askOnTty(plan: InitPlan): Promise<InitDecisions | undefined> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n try {\n return await promptForDecisions(plan, {\n ask: (question) => rl.question(question),\n write: (line) => process.stdout.write(`${line}\\n`),\n });\n } finally {\n rl.close();\n }\n}\n\nexport const initCommand = defineCommand({\n meta: { name: \"init\", description: \"Initialize a project (.penv/, env.ts, config, @env alias)\" },\n args: {\n yes: {\n type: \"boolean\",\n description:\n \"Take the detected defaults without asking. Environments still start empty — penv \" +\n \"cannot see your infrastructure\",\n },\n schema: {\n type: \"string\",\n description: `Where the schema module goes, e.g. src/env.ts (default: ${DEFAULT_SCHEMA_FILE})`,\n },\n alias: {\n type: \"string\",\n description:\n \"How your code names the schema: @env (tsconfig paths, needs a bundler) or #env \" +\n \"(package.json imports, resolved by node itself)\",\n },\n env: {\n type: \"string\",\n description:\n \"Declare an environment. Repeatable, or comma-separated: --env development,production\",\n },\n },\n run({ args }) {\n return guard(async () => {\n const root = resolve(process.cwd());\n const environments = environmentsFromFlag(args.env);\n const plan = planInit(root, {\n ...(args.schema === undefined ? {} : { schema: args.schema }),\n ...(args.alias === undefined ? {} : { alias: args.alias }),\n ...(environments === undefined ? {} : { environments }),\n });\n\n // No terminal is not a reason to guess: it is a reason to take the\n // defaults and say what they were, so a CI log carries the decisions.\n const asked = process.stdin.isTTY === true && args.yes !== true && environments === undefined;\n const decisions = asked ? await askOnTty(plan) : plan.decisions;\n if (decisions === undefined) {\n write([\"Nothing written. Re-run `penv init` when you want to scaffold.\"]);\n return;\n }\n if (!asked) {\n write([...plan.notes, \"\"]);\n }\n write(renderInit(runInit({ cwd: root, decisions })));\n });\n },\n});\n","/**\n * `penv key create --env <e>` — mint a key of the right shape.\n *\n * This exists because `penv encrypt` refuses to invent one. A key penv generated\n * behind your back is a key nobody can reproduce, restore, or rotate, and the\n * first time it matters is the first time it is gone. So minting is its own act,\n * run deliberately, and the key it prints is yours to store.\n *\n * Where penv stores it depends on the source. With `env`, the key *is* whatever\n * the process environment holds — a deploy unwraps it from a KMS and exports it —\n * so there is nowhere for penv to put it that would not be the repo-adjacent file\n * the design forbids; printing the export line is the whole job. With `keychain`,\n * the OS keychain is exactly the place a key may live, so penv stores it there and\n * prints nothing to copy — the key exists in one place, on this machine, which is\n * the point of the keychain.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport type { Keychain } from \"@penvhq/core\";\nimport { KEY_BYTES, KEYCHAIN_SERVICE, PenvError } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { defaultKeychain } from \"../keychain.js\";\nimport { openProject, targetEnvironment } from \"../project.js\";\nimport { guard, write } from \"../ui.js\";\n\nexport interface KeyCreateOptions {\n readonly cwd: string;\n readonly environment?: string;\n /** Replace an existing keychain key instead of refusing. Orphans values sealed under the old one. */\n readonly force?: boolean;\n /** Injected in tests: the keychain to store into. Defaults to the real OS binding. */\n readonly keychain?: Keychain;\n}\n\nexport interface KeyCreateResult {\n readonly source: \"env\" | \"keychain\";\n readonly environment: string;\n readonly id: string;\n /** Env source only: the variable to export the key under. */\n readonly variable?: string;\n /** Env source only: the key, base64, ready to export. penv holds no copy. */\n readonly key?: string;\n}\n\n/** Mirrors the transform in core's env key source, which is the thing that reads it. */\nfunction envVarFor(id: string): string {\n return `PENV_KEY_${id.replace(/[^A-Za-z0-9]/g, \"_\").toUpperCase()}`;\n}\n\nexport function runKeyCreate(options: KeyCreateOptions): KeyCreateResult {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n\n const declared = project.config.keys?.[environment];\n if (declared === undefined) {\n throw new PenvError(\n \"KEY_SOURCE_UNDECLARED\",\n `Environment ${environment} declares no key source, so penv does not know what a key for it would be`,\n \"Add a `keys` entry to penv.config.ts — e.g. \" +\n `\\`keys: { ${environment}: { source: \"env\", id: \"${environment}\" } }\\` — then run this again.`,\n );\n }\n\n const key = randomBytes(KEY_BYTES).toString(\"base64\");\n\n if (declared.source === \"keychain\") {\n const keychain = options.keychain ?? defaultKeychain;\n if (options.force !== true) {\n // Replacing the key orphans every value already sealed under the old one —\n // they could never be decrypted again. Refuse unless the user forces it.\n let existing: string | null;\n try {\n existing = keychain.getPassword(KEYCHAIN_SERVICE, declared.id);\n } catch (cause) {\n throw new PenvError(\n \"KEYCHAIN_UNAVAILABLE\",\n `penv could not read your OS keychain to check for an existing key \\`${declared.id}\\``,\n `Unlock your keychain and run this again. Original error: ${cause instanceof Error ? cause.message : String(cause)}`,\n );\n }\n if (existing !== null) {\n throw new PenvError(\n \"KEY_EXISTS\",\n `Environment ${environment} already has a key \\`${declared.id}\\` in your OS keychain`,\n \"Replacing it would orphan every value already sealed under it — they could never be \" +\n \"decrypted again. Re-run with `--force` only if you are certain nothing is sealed under \" +\n \"the current key.\",\n );\n }\n }\n keychain.setPassword(KEYCHAIN_SERVICE, declared.id, key);\n return { source: \"keychain\", environment, id: declared.id };\n }\n\n return {\n source: \"env\",\n environment,\n id: declared.id,\n variable: envVarFor(declared.id),\n key,\n };\n}\n\nexport function renderKeyCreate(result: KeyCreateResult): string[] {\n if (result.source === \"keychain\") {\n return [\n `A new key for environment ${result.environment}, stored in your OS keychain as \\`${result.id}\\`.`,\n \"\",\n \"penv kept no copy. Anything sealed under it is unreadable without your keychain, and running\",\n \"`penv key create` again would replace it — so it lives in exactly one place, on this machine.\",\n ];\n }\n return [\n `A new key for environment ${result.environment}. penv did not store it.`,\n \"\",\n ` ${result.variable}=${result.key}`,\n \"\",\n \"Export it where penv runs, and put it wherever this environment's secrets already live —\",\n \"a KMS, your CI's secret store, a password manager. Anything sealed under it is unreadable\",\n \"without it, and penv keeps no copy to fall back on.\",\n ];\n}\n\nexport const keyCommand = defineCommand({\n meta: { name: \"key\", description: \"Work with encryption keys\" },\n subCommands: {\n create: defineCommand({\n meta: { name: \"create\", description: \"Generate a key for an environment\" },\n args: {\n env: { type: \"string\", description: \"The environment the key is for\" },\n force: {\n type: \"boolean\",\n description: \"Replace an existing keychain key (orphans values sealed under the old one)\",\n },\n },\n run({ args }) {\n return guard(async () => {\n write(\n renderKeyCreate(\n runKeyCreate({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n ...(args.force === undefined ? {} : { force: args.force }),\n }),\n ),\n );\n });\n },\n }),\n },\n});\n","/**\n * The OS-keychain binding, and the one place the native module is touched.\n *\n * `@penvhq/core` defines the `Keychain` contract but carries no native dependency:\n * `load` runs in every deploy, and a native module in the runtime's tree is a\n * build failure in someone's container. So the binding lives here, in the CLI —\n * whose dependency budget is looser and which never ships inside a user's app —\n * and is registered into core (see `runMain`). Where it is never registered (the\n * runtime), a keychain source answers `unavailable`, which is the honest verdict.\n *\n * The native module is required lazily, so it loads only when a keychain key is\n * actually read or written — never merely because the CLI started, and never on\n * an env-source path that has no business touching it.\n */\n\nimport { createRequire } from \"node:module\";\nimport type { Keychain } from \"@penvhq/core\";\n\n/** The synchronous slice of `@napi-rs/keyring`'s `Entry` this binding uses. */\ninterface Entry {\n getPassword(): string | null;\n setPassword(password: string): void;\n}\ntype EntryConstructor = new (service: string, account: string) => Entry;\n\nlet cached: EntryConstructor | undefined;\n\nfunction entryConstructor(): EntryConstructor {\n if (cached === undefined) {\n const require = createRequire(import.meta.url);\n cached = (require(\"@napi-rs/keyring\") as { Entry: EntryConstructor }).Entry;\n }\n return cached;\n}\n\n/**\n * The real binding, backed by `@napi-rs/keyring`'s synchronous `Entry`. Its\n * `getPassword` returns `null` for a missing entry (never throws for absence) and\n * throws only when the keychain genuinely cannot be read — which the core source\n * turns into `unavailable`, not `absent`.\n */\nexport const defaultKeychain: Keychain = {\n getPassword(service, account) {\n const Entry = entryConstructor();\n return new Entry(service, account).getPassword();\n },\n setPassword(service, account, password) {\n const Entry = entryConstructor();\n new Entry(service, account).setPassword(password);\n },\n};\n","/**\n * `penv list` — every parameter, and the scope that wins for one environment.\n *\n * The winning scope is the point: `production` and `default` are both \"it\n * resolves\", and only one of them means the value was written for production.\n */\n\nimport type { Scope } from \"@penvhq/core\";\nimport { assertNever, resolveAll, variableName } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { keySourceFor, openProject, PENV_DIR, targetEnvironment } from \"../project.js\";\nimport { columns, guard, write } from \"../ui.js\";\n\nexport interface ListOptions {\n readonly cwd: string;\n readonly environment?: string;\n}\n\nexport interface ListEntry {\n readonly parameter: string;\n /** The generated `.env` variable, so the two names are legible side by side. */\n readonly variable: string;\n /** `<env>.local`, `local`, an environment name, `default`, or `absent`. */\n readonly scope: string;\n /** The winning value file relative to `.penv/`, or `undefined` when nothing wins. */\n readonly location: string | undefined;\n readonly encrypted: boolean;\n readonly viaUnscopedFallback: boolean;\n}\n\nexport interface ListResult {\n readonly environment: string;\n readonly parameters: readonly ListEntry[];\n}\n\n/**\n * The cascade level a winning scope names, spelled as its filename suffix so the\n * column reads back as the file on disk. Each of the four levels is distinct:\n * `production.local` and `local` are different files with different reach, and a\n * column that called both `local` would hide which one won.\n */\nfunction scopeLabel(scope: Scope): string {\n switch (scope.kind) {\n case \"environment\":\n return scope.environment;\n case \"local\":\n return \"local\";\n case \"environment-local\":\n return `${scope.environment}.local`;\n case \"unscoped\":\n return \"default\";\n default:\n return assertNever(scope, \"scope\");\n }\n}\n\nexport async function runList(options: ListOptions): Promise<ListResult> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n\n const keys = keySourceFor(project, environment);\n const parameters: ListEntry[] = [];\n // `list` names which file wins, never a value, so an undecryptable winner is\n // listed exactly like any other: the scope column is the answer here.\n for (const resolution of await resolveAll(environment, project.provider, keys)) {\n const winner = resolution.winner;\n const scope = winner?.file.scope;\n parameters.push({\n parameter: resolution.parameter,\n variable: variableName(resolution.ref, project.config),\n scope: scope === undefined ? \"absent\" : scopeLabel(scope),\n location: winner?.location,\n encrypted: winner?.file.encrypted === true,\n viaUnscopedFallback: resolution.viaUnscopedFallback,\n });\n }\n\n return { environment, parameters };\n}\n\nexport function renderList(result: ListResult): string[] {\n if (result.parameters.length === 0) {\n return [`No parameters in ${PENV_DIR}/ for environment ${result.environment}.`];\n }\n return columns(result.parameters.map((entry) => [entry.parameter, entry.scope, entry.variable]));\n}\n\nexport const listCommand = defineCommand({\n meta: { name: \"list\", description: \"List parameters\" },\n args: {\n env: { type: \"string\", description: \"The environment to resolve against\" },\n json: { type: \"boolean\", description: \"Print machine-readable JSON\" },\n },\n run({ args }) {\n return guard(async () => {\n const result = await runList({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n });\n write(args.json === true ? [JSON.stringify(result, null, 2)] : renderList(result));\n });\n },\n});\n","/**\n * `penv mv <from> <to>` — rename a parameter, every scope at once.\n *\n * A parameter is not one file. It is up to eight — four cascade levels, each\n * with a plaintext and an encrypted address — plus its meta, and a rename that\n * moved some of them would split one parameter into two. So this moves all of\n * them or none of them, and the whole plan is checked before a single byte is\n * written.\n *\n * **This is the only correct way to move an encrypted value.** A ciphertext is\n * sealed against the address it lives at, so `mv redis-password.production.enc\n * redis/password.production.enc` at the shell produces a file that will never\n * open again — the value is not moved, it is destroyed, and the shell reports\n * success. Re-sealing at the new address is the whole reason this command\n * exists: penv asked for namespacing to be \"a deliberate refactor afterwards\"\n * and then, once values could be encrypted, made doing it by hand a way to lose\n * them.\n *\n * It moves the tree and never the schema. `.penv/env.ts` is yours (invariant 2),\n * so renaming `database-url` to `database/url` leaves it declaring the old access\n * path — and the drift report is what says so. penv names the distance; you close\n * it. This command's report says which line to change rather than changing it.\n */\n\nimport type { Meta, ParameterRef, ValueFile } from \"@penvhq/core\";\nimport {\n accessPath,\n formatMetaFile,\n formatValueFile,\n openValue,\n PenvError,\n parameterId,\n sealValue,\n} from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport type { Project } from \"../project.js\";\nimport { assertWritableKey, keySourceFor, openProject, PENV_DIR, refFromKey } from \"../project.js\";\nimport { CHECK, formatRows, guard, type Row, write } from \"../ui.js\";\n\nexport interface MoveOptions {\n readonly cwd: string;\n readonly from: string;\n readonly to: string;\n}\n\nexport interface MovedFile {\n readonly from: string;\n readonly to: string;\n /** True when the value was opened and sealed again for its new address. */\n readonly resealed: boolean;\n}\n\nexport interface MoveResult {\n readonly from: string;\n readonly to: string;\n readonly files: readonly MovedFile[];\n /** The meta file's new location, or `undefined` when the parameter had none. */\n readonly meta: string | undefined;\n /** The access path the schema still declares, and the one it should now. */\n readonly schema: { readonly was: string; readonly now: string };\n}\n\n/** The environment a scope names, or `undefined` for the scopes that name none. */\nfunction environmentOf(file: ValueFile): string | undefined {\n const scope = file.scope;\n return scope.kind === \"environment\" || scope.kind === \"environment-local\"\n ? scope.environment\n : undefined;\n}\n\n/** One file's move, resolved to the bytes that will be written at the far end. */\ninterface Planned {\n readonly source: ValueFile;\n readonly target: ValueFile;\n readonly contents: string;\n readonly resealed: boolean;\n}\n\n/**\n * Reads one file and works out what it must say at its new address.\n *\n * A plaintext value is bytes and moves as bytes. An encrypted one cannot: the\n * address is authenticated, so the ciphertext is only valid where it is. It is\n * opened here and sealed again below — and if it cannot be opened, the whole move\n * is refused rather than carrying a file to a place it will never open from.\n */\nasync function planFile(\n project: Project,\n source: ValueFile,\n target: ValueFile,\n parameter: string,\n): Promise<Planned | undefined> {\n const stored = await project.provider.read(source);\n if (stored === undefined) {\n return undefined;\n }\n if (!source.encrypted) {\n return { source, target, contents: stored, resealed: false };\n }\n\n // A key is declared per environment, so a sealed value at a scope that names\n // none has no key penv can choose — the same refusal `penv set` makes, for the\n // same reason, and the same one that keeps penv from creating such a file.\n const environment = environmentOf(source);\n if (environment === undefined) {\n throw new PenvError(\n \"SECRET_SCOPE_AMBIGUOUS\",\n `${PENV_DIR}/${formatValueFile(source)} is encrypted at a scope that names no environment, so penv cannot tell which key would re-seal it`,\n \"Keys are declared per environment in the `keys` block of penv.config.ts. Decrypt it with \" +\n \"`penv decrypt`, move the parameter, then encrypt it again at its new address.\",\n );\n }\n\n const keys = keySourceFor(project, environment);\n const opened = openValue(source, stored, keys);\n if (opened.kind === \"failed\") {\n throw new PenvError(\n \"VALUE_UNDECRYPTABLE\",\n `${PENV_DIR}/${formatValueFile(source)} could not be decrypted, so penv cannot re-seal it at its new address: ${opened.failure.detail}`,\n \"A sealed value is bound to the file it lives in, so moving it means opening it and \" +\n \"sealing it again. Make the key available and run this again. Nothing has been moved.\",\n );\n }\n\n return {\n source,\n target,\n contents: sealValue(target, opened.value, keys, parameter, environment),\n resealed: true,\n };\n}\n\n/** Every file the provider actually holds for one parameter. */\nfunction filesOf(all: readonly ValueFile[], ref: ParameterRef): ValueFile[] {\n const id = parameterId(ref);\n return all.filter((file) => parameterId(file) === id);\n}\n\nexport async function runMove(options: MoveOptions): Promise<MoveResult> {\n const project = openProject(options.cwd);\n const from = refFromKey(options.from, project.config);\n assertWritableKey(options.to);\n const to = refFromKey(options.to, project.config);\n\n if (parameterId(from) === parameterId(to)) {\n throw new PenvError(\n \"PARAMETER_UNCHANGED\",\n `\\`${options.from}\\` and \\`${options.to}\\` are the same parameter`,\n \"Name a different destination, e.g. `penv mv redis-password redis/password`.\",\n );\n }\n\n const all = await project.provider.list();\n const sources = filesOf(all, from);\n const meta: Meta | undefined = await project.provider.readMeta(from);\n\n if (sources.length === 0 && meta === undefined) {\n throw new PenvError(\n \"PARAMETER_ABSENT\",\n `Parameter ${parameterId(from)} has no value files and no meta, so there is nothing to move`,\n `\\`penv list\\` shows every parameter penv holds.`,\n );\n }\n\n // Nothing is overwritten, ever. A destination that already exists is two\n // parameters being merged into one, which loses whichever penv wrote second —\n // the same loss `validate` refuses for name collisions (invariant 12).\n const occupied = filesOf(all, to);\n if (occupied.length > 0 || (await project.provider.readMeta(to)) !== undefined) {\n throw new PenvError(\n \"PARAMETER_EXISTS\",\n `Parameter ${parameterId(to)} already exists, and penv will not merge two parameters into one`,\n `Remove or rename ${parameterId(to)} first. \\`penv get ${options.to} --explain\\` shows every file it holds.`,\n );\n }\n\n // Planned in full before anything is written. Every read, every decryption and\n // every key lookup happens here, so a move that cannot finish fails having\n // changed nothing — rather than halfway, with a parameter that is now two.\n const planned: Planned[] = [];\n for (const source of sources) {\n const target: ValueFile = { ...source, namespace: to.namespace, name: to.name };\n const one = await planFile(project, source, target, parameterId(to));\n if (one !== undefined) {\n planned.push(one);\n }\n }\n\n for (const file of planned) {\n await project.provider.write(file.target, file.contents);\n }\n if (meta !== undefined) {\n await project.provider.writeMeta(to, meta);\n }\n\n // Removed only once every new file is on disk, so the value is never in\n // neither place. The cost is a window where it is in both, which a crash\n // leaves recoverable; the reverse leaves it gone.\n for (const file of planned) {\n await project.provider.remove(file.source);\n }\n if (meta !== undefined) {\n await project.provider.removeMeta(from);\n }\n\n return {\n from: parameterId(from),\n to: parameterId(to),\n files: planned.map((file) => ({\n from: formatValueFile(file.source),\n to: formatValueFile(file.target),\n resealed: file.resealed,\n })),\n // The meta's path, not the parameter's dotted id: `redis.password` is what\n // the schema calls it and `redis/password.json` is the file, and a report\n // that printed the first while moving the second names no file on disk.\n meta: meta === undefined ? undefined : formatMetaFile({ ...to, format: \"json\" }),\n schema: { was: accessPath(from).join(\".\"), now: accessPath(to).join(\".\") },\n };\n}\n\nexport function renderMove(result: MoveResult): string[] {\n const rows: Row[] = result.files.map((file) => ({\n glyph: CHECK,\n label: \"Moved\",\n subject: `${PENV_DIR}/${file.to}`,\n ...(file.resealed ? { detail: \"re-sealed for its new address\" } : {}),\n }));\n if (result.meta !== undefined) {\n rows.push({ glyph: CHECK, label: \"Moved\", subject: `${PENV_DIR}/${result.meta}` });\n }\n\n const lines = formatRows(rows);\n // The tree moved and the schema did not, because the schema is the user's file\n // and penv does not write it. Saying so here is cheaper than letting them find\n // out from a failing `validate` — and it names the edit rather than the fault.\n lines.push(\n \"\",\n ` .penv/env.ts still declares \\`${result.schema.was}\\`. Rename it to \\`${result.schema.now}\\`,`,\n \" or `penv validate` will report the value as unused and the declaration as unset.\",\n );\n return lines;\n}\n\nexport const mvCommand = defineCommand({\n meta: { name: \"mv\", description: \"Rename a parameter, every scope and its meta at once\" },\n args: {\n from: {\n type: \"positional\",\n required: true,\n description: \"The parameter now, e.g. redis-password\",\n },\n to: {\n type: \"positional\",\n required: true,\n description: \"The parameter after, e.g. redis/password\",\n },\n },\n run({ args }) {\n return guard(async () => {\n write(renderMove(await runMove({ cwd: process.cwd(), from: args.from, to: args.to })));\n });\n },\n});\n","/**\n * `penv pull` — materialise the local `.penv` tree from an environment's\n * source-of-truth provider. It is the inverse of the deploy-time injection most\n * stacks already have: instead of reading the tree to feed a backend, it reads\n * the backend to feed the tree.\n *\n * It only means anything when the environment declares a real backend\n * (`vault`, `mock`): those hold the truth somewhere penv does not edit in place,\n * and pulling copies it down so every other command — which reads the local tree\n * — sees it. An environment with no separate `providers` entry has the local\n * tree *as* its source of truth, so a pull would be the tree copying onto\n * itself; that degenerate case is reported as nothing to do, never a self-copy.\n *\n * Values cross verbatim. They are opaque envelope strings the source holds and\n * penv does not open here — a sealed value stays sealed, byte-for-byte, so the\n * key that opens it never has to be present to pull it.\n */\n\nimport type { Meta } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport {\n localTree,\n openProject,\n refsFrom,\n sourceProviderFor,\n targetEnvironment,\n} from \"../project.js\";\nimport { LOCAL_TREE_TYPE } from \"../registry.js\";\nimport { CHECK, formatRows, guard, write } from \"../ui.js\";\n\nexport interface PullOptions {\n readonly cwd: string;\n readonly environment?: string;\n}\n\nexport interface PullResult {\n readonly environment: string;\n /** The source provider's type — `filesystem` when the environment declares no separate backend. */\n readonly source: string;\n /**\n * True when the source *is* the local tree, so there was nothing to pull. The\n * caller distinguishes \"pulled nothing because the backend was empty\" from\n * \"there is no backend to pull from\" — opposite situations.\n */\n readonly localSource: boolean;\n /** Value files written into the local tree. */\n readonly values: number;\n /** Meta files written into the local tree. */\n readonly meta: number;\n /** Distinct parameters the pull touched, at any scope. */\n readonly refs: number;\n}\n\nexport async function runPull(options: PullOptions): Promise<PullResult> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const source = await sourceProviderFor(project, environment);\n\n // The local tree already IS the source of truth for an environment with no\n // declared backend: `sourceProviderFor` handed back the filesystem tree, and\n // pulling it onto itself would be a no-op dressed as work. Report the truth.\n if (source.type === LOCAL_TREE_TYPE) {\n return { environment, source: source.type, localSource: true, values: 0, meta: 0, refs: 0 };\n }\n\n const tree = localTree(project);\n const files = await source.list();\n\n let values = 0;\n for (const file of files) {\n const value = await source.read(file);\n // Absent is not written: `list` and `read` can disagree across a concurrent\n // prune, and a missing value is nothing to materialise.\n if (value === undefined) {\n continue;\n }\n // Verbatim — the value is an opaque envelope, sealed or not, and penv does\n // not open it to move it.\n tree.writeSync(file, value);\n values += 1;\n }\n\n // Meta is per-parameter, so it is pulled once per distinct ref rather than once\n // per value file — two scopes of one parameter share the one policy.\n const refs = refsFrom(files);\n let meta = 0;\n for (const ref of refs) {\n const block: Meta | undefined = await source.readMeta(ref);\n if (block === undefined) {\n continue;\n }\n tree.writeMetaSync(ref, block);\n meta += 1;\n }\n\n return { environment, source: source.type, localSource: false, values, meta, refs: refs.length };\n}\n\nexport function renderPull(result: PullResult): string[] {\n if (result.localSource) {\n return formatRows([\n {\n glyph: CHECK,\n label: \"Nothing to pull\",\n subject: `environment ${result.environment} has no separate source of truth`,\n detail: \"its values live in the local .penv tree already\",\n },\n ]);\n }\n\n return formatRows([\n {\n glyph: CHECK,\n label: \"Pulled\",\n subject: `${result.values} ${result.values === 1 ? \"value\" : \"values\"}`,\n detail: `from the ${result.source} provider for environment ${result.environment}`,\n },\n {\n glyph: CHECK,\n label: \"Parameters\",\n subject: `${result.refs} ${result.refs === 1 ? \"parameter\" : \"parameters\"}, ${result.meta} with meta`,\n detail: \"written into the local .penv tree\",\n },\n ]);\n}\n\nexport const pullCommand = defineCommand({\n meta: {\n name: \"pull\",\n description: \"Materialise the local .penv tree from an environment's source-of-truth provider\",\n },\n args: {\n env: { type: \"string\", description: \"The environment to pull\" },\n },\n run({ args }) {\n return guard(async () => {\n const result = await runPull({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n });\n write(renderPull(result));\n });\n },\n});\n","/**\n * `penv remove <key>` — delete one value file.\n *\n * The scope is selected exactly as `penv set` selects it, so what you removed is\n * the file you would have written. Meta is left alone: policy is a property of\n * the parameter across every environment, not of the value you just deleted.\n */\n\nimport type { ValueFile } from \"@penvhq/core\";\nimport { formatValueFile } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { openProject, PENV_DIR, refFromKey } from \"../project.js\";\nimport { CHECK, formatRows, guard, type Row, WARN, write } from \"../ui.js\";\nimport { type ScopeOptions, targetScope } from \"./set.js\";\n\nexport interface RemoveOptions extends ScopeOptions {\n readonly cwd: string;\n readonly key: string;\n}\n\nexport interface RemoveResult {\n readonly parameter: string;\n /** The value files that existed and are now gone, relative to `.penv/`. */\n readonly removed: readonly string[];\n /** Both files penv looked at, whether or not they were there. */\n readonly considered: readonly string[];\n}\n\nexport async function runRemove(options: RemoveOptions): Promise<RemoveResult> {\n const project = openProject(options.cwd);\n const ref = refFromKey(options.key);\n\n // The same scope selection `set` writes through, for the same reason: the file\n // `remove` names has to be the file `set` named, byte for byte.\n const scope = targetScope(project, options, options.key);\n // `.enc` is orthogonal to scope: the encrypted file at this scope is the same\n // parameter at the same precedence, so removing the scope removes both.\n const files: ValueFile[] = [false, true].map((encrypted) => ({\n namespace: ref.namespace,\n name: ref.name,\n scope,\n encrypted,\n }));\n\n const removed: string[] = [];\n for (const file of files) {\n if ((await project.provider.read(file)) === undefined) {\n continue;\n }\n await project.provider.remove(file);\n removed.push(formatValueFile(file));\n }\n\n return {\n parameter: options.key,\n removed,\n considered: files.map((file) => formatValueFile(file)),\n };\n}\n\nexport function renderRemove(result: RemoveResult): string[] {\n if (result.removed.length === 0) {\n const first = result.considered[0] ?? result.parameter;\n return formatRows([\n {\n glyph: WARN,\n label: \"Nothing to remove\",\n subject: `${PENV_DIR}/${first}`,\n detail: \"no value file at that scope\",\n },\n ]);\n }\n const rows: Row[] = result.removed.map((location) => ({\n glyph: CHECK,\n label: \"Removed\",\n subject: `${PENV_DIR}/${location}`,\n }));\n return formatRows(rows);\n}\n\nexport const removeCommand = defineCommand({\n meta: { name: \"remove\", description: \"Delete a parameter\" },\n args: {\n key: { type: \"positional\", required: true, description: \"The parameter, e.g. redis/password\" },\n env: { type: \"string\", description: \"Remove the <name>.<env> scope\" },\n local: {\n type: \"boolean\",\n description: \"Remove the personal override: <name>.<env>.local with --env, else <name>.local\",\n },\n },\n run({ args }) {\n return guard(async () => {\n write(\n renderRemove(\n await runRemove({\n cwd: process.cwd(),\n key: args.key,\n ...(args.env === undefined ? {} : { environment: args.env }),\n ...(args.local === undefined ? {} : { local: args.local }),\n }),\n ),\n );\n });\n },\n});\n","/**\n * `penv rotate <key>` — turn one parameter over to a new value, by the mechanism\n * its meta declares, against the environment's source-of-truth provider.\n *\n * The two mechanisms are two different physics, never one code path with a flag\n * (rotation.ts says as much). `dual-valid` is a *window*: the new value goes live\n * while the provider still serves the old one, both credentials valid at once,\n * and the window closes only when every reader has moved over. `atomic-cutover`\n * is an *instant*: one flip, old value gone the moment the new one lands, no\n * overlap to hold open. So the command shape mirrors the physics —\n *\n * - `--begin` / `--complete` bracket a `dual-valid` window (`active → rotating →\n * active`), and demand a {@link RetainingProvider}, because a window whose old\n * value the provider does not retain is not a window at all — the overlap the\n * mechanism promises would silently not exist. penv refuses that up front\n * rather than opening a grace window that is a fiction.\n * - a bare `penv rotate` is the `atomic-cutover` flip: write the new value and\n * stamp the completion in one step, never touching `rotatingSince`, never\n * requiring retention — there is no penv-layer overlap to record or to lean on.\n *\n * Like `push`, the real work is an exported plain function returning a structured\n * result, and `now` is injectable so the meta clocks are testable without mocking\n * time. The rotation clock itself lives in core (`beginRotation` /\n * `completeRotation`); this command only decides *which* to apply, writes the\n * value at the right moment relative to it, and persists both to the provider.\n */\n\nimport type {\n Meta,\n ParameterRef,\n Provider,\n RetainingProvider,\n RotationMechanism,\n RotationState,\n ValueFile,\n} from \"@penvhq/core\";\nimport {\n beginRotation,\n completeRotation,\n PenvError,\n retainsPrevious,\n rotationOf,\n} from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport type { Project } from \"../project.js\";\nimport { openProject, refFromKey, sourceProviderFor, targetEnvironment } from \"../project.js\";\nimport { LOCAL_TREE_TYPE } from \"../registry.js\";\nimport { CHECK, formatRows, guard, write } from \"../ui.js\";\nimport { readStdin, sealAwareWrite } from \"./set.js\";\n\nexport interface RotateOptions {\n readonly cwd: string;\n readonly key: string;\n readonly environment?: string;\n /** Open a `dual-valid` window: write the new value while the old is still retained. */\n readonly begin?: boolean;\n /** Close a `dual-valid` window: return to `active`, stamp the completion. */\n readonly complete?: boolean;\n /**\n * The new value. A `begin` and an `atomic-cutover` flip write it; a `complete`\n * does not touch the value at all, so it needs none. Injected in tests; on the\n * CLI it is the positional argument or stdin, the same source `set` reads.\n */\n readonly value?: string;\n /** Injected in tests: the wall-clock reading recorded in meta. Defaults to now. */\n readonly now?: string;\n}\n\n/** The single step a run performed — the three the two mechanisms decompose into. */\nexport type RotatePhase = \"begin\" | \"complete\" | \"cutover\";\n\nexport interface RotateResult {\n readonly parameter: string;\n readonly environment: string;\n readonly mechanism: RotationMechanism;\n readonly phase: RotatePhase;\n /** The source provider's type — where the value and its meta were written. */\n readonly source: string;\n /** True when this run wrote a new value. `begin` and `cutover` do; `complete` does not. */\n readonly wroteValue: boolean;\n /** The rotation state after this run — `rotating` after a begin, `active` otherwise. */\n readonly state: RotationState;\n /** When the current window opened, ISO. Set only after a `begin`, else `null`. */\n readonly rotatingSince: string | null;\n /** When a rotation last completed, ISO. Set after a `complete` or a `cutover`. */\n readonly lastRotated: string | null;\n}\n\n/**\n * The value file a rotation writes to a *backend* and reads back — the parameter\n * at its environment scope, verbatim.\n *\n * A rotating secret belongs to exactly one environment (the credential Vault\n * issues for production is not development's), so the environment scope is its\n * home, and pinning it here is what lets `readPrevious` find the prior version\n * during the window: the write and the retention read must address the same\n * value file byte-for-byte. `encrypted: false` because the value crosses to a\n * backend source of truth verbatim, the way `push` moves it — the backend holds\n * custody of its own store, and penv's envelope is the *local tree's* concern,\n * not the backend's. When the source of truth is instead the local tree,\n * {@link writeRotatedValue} routes to {@link sealAwareWrite}, which seals per\n * meta and removes the twin; this file shape is only ever the backend's.\n */\nfunction rotatingFile(ref: ParameterRef, environment: string): ValueFile {\n return {\n namespace: ref.namespace,\n name: ref.name,\n scope: { kind: \"environment\", environment },\n encrypted: false,\n };\n}\n\n/**\n * Writes the new value to the environment's source of truth, by the custody rule\n * the store's *type* sets — the fix for a rotation that used to persist the live\n * credential as cleartext.\n *\n * The local `.penv` tree is penv's own to seal, so a secret rotated into it must\n * be sealed and its plaintext twin removed, exactly as `set` does: otherwise the\n * value lands as cleartext `.penv/<name>.<env>`, which is committed to git and,\n * because plaintext outranks `.enc` at one scope, also shadows any sealed copy\n * already there. So the local tree goes through {@link sealAwareWrite}, honouring\n * meta's policy. A real backend (vault, mock) holds custody of its own store and\n * penv's envelope is not its concern — the value crosses verbatim via\n * {@link rotatingFile}, the way `push` sends plaintext for the sink to re-seal.\n *\n * `--begin` only ever reaches a backend (a dual-valid window demands a retaining\n * provider, which the local tree is not), but it is routed here too, so both\n * value-write sites share one custody decision.\n */\nasync function writeRotatedValue(\n project: Project,\n provider: Provider,\n ref: ParameterRef,\n environment: string,\n value: string,\n): Promise<void> {\n if (provider.type === LOCAL_TREE_TYPE) {\n await sealAwareWrite({\n project,\n provider,\n ref,\n scope: { kind: \"environment\", environment },\n value,\n environment,\n });\n return;\n }\n await provider.write(rotatingFile(ref, environment), value);\n}\n\n/** The new value a write step requires, or a refusal that names the phase needing it. */\nfunction requireNewValue(value: string | undefined, phase: RotatePhase, key: string): string {\n if (value === undefined) {\n throw new PenvError(\n \"ROTATION_NO_VALUE\",\n `A ${phase} rotation of ${key} writes a new value, and none was given`,\n \"Pass the new value as the argument — `penv rotate <key> <value>` — or pipe it in on stdin.\",\n );\n }\n return value;\n}\n\n/**\n * A `dual-valid` rotation against a provider that does not retain its previous\n * value — the one situation the mechanism cannot survive, refused before a single\n * write.\n *\n * The window's whole promise is that the old credential keeps working while the\n * new one takes over; a provider that overwrites in place breaks that the instant\n * `begin` writes, and no meta clock can put the old value back. So this is not a\n * best-effort with a warning — it is a hard refusal, thrown here so the caller\n * never opens a grace window that is already a lie. `atomic-cutover` reaches this\n * function's callers not at all: it has no overlap to retain.\n */\nfunction requireRetaining(provider: Provider, environment: string): RetainingProvider {\n if (!retainsPrevious(provider)) {\n throw new PenvError(\n \"ROTATION_NOT_RETAINING\",\n `A dual-valid rotation needs the previous value to stay readable during the grace window, and the \\`${provider.type}\\` provider for environment ${environment} does not retain it`,\n \"Point this environment at a provider that keeps prior versions (its `readPrevious` is what penv reads during the window), \" +\n \"or, if a momentary overlap is not required, declare the parameter `atomic-cutover` in its meta and flip it in one step.\",\n );\n }\n return provider;\n}\n\nexport async function runRotate(options: RotateOptions): Promise<RotateResult> {\n const project = openProject(options.cwd);\n const environment = targetEnvironment(project, options.environment);\n const ref = refFromKey(options.key, project.config);\n const provider = await sourceProviderFor(project, environment);\n\n const nowIso = options.now ?? new Date().toISOString();\n const before: Meta | undefined = await provider.readMeta(ref);\n const { mechanism } = rotationOf(before, environment);\n\n if (mechanism === undefined) {\n throw new PenvError(\n \"ROTATION_NO_MECHANISM\",\n `Parameter ${options.key} declares no rotation mechanism for environment ${environment}, so penv does not know how to rotate it`,\n 'Set `rotationMechanism` in the parameter\\'s meta to `\"dual-valid\"` (a grace-window overlap) or ' +\n '`\"atomic-cutover\"` (a single flip), then run `penv rotate` again.',\n );\n }\n\n const begin = options.begin === true;\n const complete = options.complete === true;\n\n // atomic-cutover: one flip, and `--begin`/`--complete` have no meaning for it —\n // there is no window to bracket. Refuse the flags rather than silently ignore\n // them, so a user who reached for a two-phase rotation learns their parameter\n // is not one before anything is written.\n if (mechanism === \"atomic-cutover\") {\n if (begin || complete) {\n throw new PenvError(\n \"ROTATION_MECHANISM_MISMATCH\",\n `Parameter ${options.key} is atomic-cutover, which flips in one step, so \\`--begin\\`/\\`--complete\\` do not apply`,\n \"Run `penv rotate <key> <value>` with no phase flag to flip it. `--begin`/`--complete` bracket a \" +\n \"dual-valid grace window, which atomic-cutover has none of.\",\n );\n }\n const value = requireNewValue(options.value, \"cutover\", options.key);\n // Value first, then the completion stamp — the flip and its record, in the\n // order that leaves the value present before anything claims it rotated. The\n // write honours the store's custody rule: sealed into the local tree per\n // meta, verbatim to a backend.\n await writeRotatedValue(project, provider, ref, environment, value);\n const after = completeRotation(before, environment, nowIso);\n await provider.writeMeta(ref, after);\n return result(ref, environment, mechanism, \"cutover\", provider.type, true, after);\n }\n\n // dual-valid from here: every path needs a retaining provider, and the two\n // phases are mutually exclusive — exactly one bracket per run.\n const retaining = requireRetaining(provider, environment);\n\n if (begin === complete) {\n throw new PenvError(\n \"ROTATION_PHASE_REQUIRED\",\n `A dual-valid rotation of ${options.key} needs exactly one of \\`--begin\\` or \\`--complete\\``,\n \"`--begin` writes the new value and opens the grace window; `--complete` closes it once every reader \" +\n \"has moved to the new value. Run them in that order, one at a time.\",\n );\n }\n\n if (begin) {\n const value = requireNewValue(options.value, \"begin\", options.key);\n // The new value is written while the provider still holds the previous one —\n // that co-existence IS the window, and `readPrevious` serves the old value\n // until `--complete` closes it. Value first, then `rotatingSince`, so the\n // clock never claims a window an unwritten value has not yet opened. A\n // retaining provider is always a backend, so this crosses verbatim; routed\n // through the shared helper so both write sites share one custody decision.\n await writeRotatedValue(project, retaining, ref, environment, value);\n const after = beginRotation(before, environment, nowIso);\n await retaining.writeMeta(ref, after);\n return result(ref, environment, mechanism, \"begin\", retaining.type, true, after);\n }\n\n // --complete: the window closes. No value is written — the new value has been\n // live since `--begin`; this only returns the clock to `active` and stamps the\n // completion. The provider's previous version may be pruned any time after.\n const after = completeRotation(before, environment, nowIso);\n await retaining.writeMeta(ref, after);\n return result(ref, environment, mechanism, \"complete\", retaining.type, false, after);\n}\n\n/** Reads the settled clocks back out of the meta just written, so the result is the record. */\nfunction result(\n ref: ParameterRef,\n environment: string,\n mechanism: RotationMechanism,\n phase: RotatePhase,\n source: string,\n wroteValue: boolean,\n after: Meta,\n): RotateResult {\n const { state, rotatingSince, lastRotated } = rotationOf(after, environment);\n return {\n parameter: [...ref.namespace, ref.name].join(\"/\"),\n environment,\n mechanism,\n phase,\n source,\n wroteValue,\n state,\n rotatingSince,\n lastRotated,\n };\n}\n\nexport function renderRotate(result: RotateResult): string[] {\n if (result.phase === \"begin\") {\n return formatRows([\n {\n glyph: CHECK,\n label: \"Rotating\",\n subject: result.parameter,\n detail: `dual-valid window open for environment ${result.environment} (since ${result.rotatingSince})`,\n },\n {\n glyph: CHECK,\n label: \"Previous\",\n subject: \"still readable\",\n detail: `on the ${result.source} provider until \\`penv rotate ${result.parameter} --complete\\``,\n },\n ]);\n }\n if (result.phase === \"complete\") {\n return formatRows([\n {\n glyph: CHECK,\n label: \"Rotated\",\n subject: result.parameter,\n detail: `dual-valid window closed for environment ${result.environment} (completed ${result.lastRotated})`,\n },\n ]);\n }\n return formatRows([\n {\n glyph: CHECK,\n label: \"Rotated\",\n subject: result.parameter,\n detail: `atomic-cutover flip for environment ${result.environment} (completed ${result.lastRotated})`,\n },\n ]);\n}\n\nexport const rotateCommand = defineCommand({\n meta: {\n name: \"rotate\",\n description: \"Rotate a parameter's value by the mechanism its meta declares\",\n },\n args: {\n key: { type: \"positional\", required: true, description: \"The parameter, e.g. redis/password\" },\n value: {\n type: \"positional\",\n required: false,\n description: \"The new value; read from stdin if omitted. Not needed with --complete\",\n },\n env: { type: \"string\", description: \"The environment to rotate in\" },\n begin: { type: \"boolean\", description: \"Open a dual-valid grace window with the new value\" },\n complete: { type: \"boolean\", description: \"Close a dual-valid grace window\" },\n },\n run({ args }) {\n return guard(async () => {\n // `--complete` writes no value, so it never blocks on stdin waiting for one\n // that will not come. Every other path reads the value the way `set` does.\n const value = args.complete === true ? undefined : (args.value ?? (await readStdin()));\n write(\n renderRotate(\n await runRotate({\n cwd: process.cwd(),\n key: args.key,\n ...(value === undefined ? {} : { value }),\n ...(args.env === undefined ? {} : { environment: args.env }),\n ...(args.begin === undefined ? {} : { begin: args.begin }),\n ...(args.complete === undefined ? {} : { complete: args.complete }),\n }),\n ),\n );\n });\n },\n});\n","/**\n * `penv watch` — re-run validation whenever the configuration changes.\n *\n * Watch mode reports `penv validate`'s verdict on a loop, and never a second\n * opinion about it: the diagnostics come from `runValidate` itself, so there is\n * no watch-mode verdict that could drift from the command CI runs.\n *\n * It prints one thing `validate` does not — the schema↔tree drift report, which\n * `runValidate` measures and hands back without letting it touch `ok`. The two\n * commands differ because their readers do. CI wants a verdict, and a warning\n * about a parameter the schema tolerates would be noise in a log nobody reads on\n * a passing run. The person with `watch` open is mid-edit, and the distance\n * between what they have just declared and what the tree holds is the thing they\n * are watching *for*. Same facts, same measurement, one of them worth printing\n * only where someone is looking.\n *\n * Three things decide the answer, so three things are watched: the `.penv/` tree\n * (the values and their meta), `penv.config.ts` (the environment whitelist, and\n * the `names` block), and the schema. The schema is watched on its own only when\n * `schemaFile` puts it outside `.penv/` — at the default it is inside the tree,\n * and a second watcher on it would report every edit twice.\n *\n * `node:fs` does the watching. A dependency-free watcher is worth the handful of\n * lines here: the events this needs are the ones the platform already reports,\n * and debouncing them is the whole of what a library would add.\n */\n\nimport type { FSWatcher } from \"node:fs\";\nimport { existsSync, watch } from \"node:fs\";\nimport { basename, dirname, resolve } from \"node:path\";\nimport { schemaFileOf, schemaInsideTree } from \"@penvhq/core\";\nimport { defineCommand } from \"citty\";\nimport { openProject } from \"../project.js\";\nimport type { DriftReport } from \"../schema.js\";\nimport { formatRows, guard, type Row, reportError, WARN, write } from \"../ui.js\";\nimport type { ValidateResult } from \"./validate.js\";\nimport { renderValidate, runValidate } from \"./validate.js\";\n\n/**\n * Long enough to coalesce an editor's save into one run, short enough to feel\n * immediate. An atomic save is a write, a rename, and sometimes a delete, and a\n * run per event would validate a tree mid-rewrite and report a file that exists\n * again by the time the user reads the line.\n */\nconst DEBOUNCE_MS = 100;\n\nexport interface WatchOptions {\n readonly cwd: string;\n readonly environment?: string;\n /** Defaults to {@link DEBOUNCE_MS}. */\n readonly debounceMs?: number;\n /** Called with every completed validation, starting with the initial one. */\n readonly onResult?: (result: ValidateResult) => void;\n /**\n * Called when a cycle could not produce a result at all — an unreadable\n * config, a watcher the platform dropped. Never called for a *failing*\n * validation: that is a result, and it goes to `onResult`.\n */\n readonly onError?: (error: unknown) => void;\n}\n\nexport interface WatchHandle {\n /** Stops watching. Idempotent, and safe to call from inside a callback. */\n close(): void;\n}\n\n/**\n * Watches, and re-validates on change.\n *\n * Returns a handle rather than blocking, so the loop is a plain object a test\n * can drive and close instead of a live process it would have to spawn. The\n * command below is the only thing that turns it into a process that waits.\n */\nexport function runWatch(options: WatchOptions): WatchHandle {\n // Fails fast, and before any watcher exists: a watch on a directory that is\n // not a penv project would report the same error on every keystroke instead.\n const project = openProject(options.cwd);\n const configFile = basename(project.configFile);\n const debounceMs = options.debounceMs ?? DEBOUNCE_MS;\n\n const watchers = new Set<FSWatcher>();\n let timer: ReturnType<typeof setTimeout> | undefined;\n let running = false;\n let pending = false;\n let closed = false;\n\n async function validate(): Promise<void> {\n if (closed) {\n return;\n }\n // One run at a time: a save that lands mid-run would otherwise read the tree\n // twice at once and report whichever finished last.\n if (running) {\n pending = true;\n return;\n }\n running = true;\n try {\n const result = await runValidate({\n cwd: options.cwd,\n ...(options.environment === undefined ? {} : { environment: options.environment }),\n });\n if (!closed) {\n options.onResult?.(result);\n }\n } catch (error) {\n // A file can vanish between the event and the read — that is what an\n // atomic save looks like from here. Report it and keep watching: the\n // rename that follows will schedule the run that gets the real answer.\n if (!closed) {\n options.onError?.(error);\n }\n } finally {\n running = false;\n if (pending && !closed) {\n pending = false;\n void validate();\n }\n }\n }\n\n function schedule(): void {\n if (closed) {\n return;\n }\n if (timer !== undefined) {\n clearTimeout(timer);\n }\n timer = setTimeout(() => {\n timer = undefined;\n void validate();\n }, debounceMs);\n }\n\n function stop(watcher: FSWatcher): void {\n watchers.delete(watcher);\n watcher.close();\n }\n\n /**\n * Waits for a vanished target to come back, by watching its parent for the\n * name to reappear.\n *\n * A branch switch is a delete and then a create, so a watch that merely\n * stopped at the delete would be silent for the rest of the session — the\n * user would be reading a report of a tree that has since returned. The\n * re-armed watcher validates on arrival rather than trusting the report the\n * deletion produced.\n */\n function armRecovery(target: string, recursive: boolean, only?: string): void {\n const parent = dirname(target);\n const name = basename(target);\n let recovery: FSWatcher | undefined;\n\n try {\n recovery = watch(parent, { recursive: false }, (_event, filename) => {\n if (closed || recovery === undefined) {\n return;\n }\n // The parent went too. Watching it would spin exactly the way the\n // vanished target did, and there is nothing left to recover from.\n if (!existsSync(parent)) {\n stop(recovery);\n return;\n }\n if (filename !== null && basename(filename) !== name) {\n return;\n }\n if (!existsSync(target)) {\n return;\n }\n stop(recovery);\n addWatcher(target, recursive, only);\n schedule();\n });\n } catch (error) {\n options.onError?.(error);\n return;\n }\n\n recovery.on(\"error\", (error) => {\n if (!closed) {\n options.onError?.(error);\n }\n });\n watchers.add(recovery);\n }\n\n /**\n * `recursive` is not available on every platform, so a watcher that cannot\n * have it watches the directory itself. Namespace folders below it go\n * unwatched there, which is a weaker watch — never a wrong validation, since\n * the answer always comes from a fresh `runValidate`.\n */\n function addWatcher(target: string, recursive: boolean, only?: string): void {\n let watcher: FSWatcher | undefined;\n\n const listen = (useRecursive: boolean): FSWatcher =>\n watch(target, { recursive: useRecursive }, (_event, filename) => {\n if (closed) {\n return;\n }\n // A deleted target does not stop its watcher, and on Windows does not\n // error either: it re-fires `rename` for the absent path tens of\n // thousands of times a second, forever. Left alone that pins a core,\n // and every event resets the debounce below, so the watch would burn\n // CPU while reporting nothing at all. The check costs a `stat` per\n // event, which is what a `.penv/` that is still there is worth.\n //\n // Deleting the tree is a change like any other, so it is scheduled\n // rather than reported as a failure: `runValidate` has a real verdict\n // for a missing `.penv/`, and watch's job is to say what validate says.\n if (!existsSync(target)) {\n if (watcher !== undefined) {\n stop(watcher);\n }\n armRecovery(target, recursive, only);\n schedule();\n return;\n }\n // Directories are watched rather than files so that an editor's\n // write-to-temp-then-rename is seen as a change to the real name. The\n // cost is hearing about neighbours, so the ones that matter are named.\n if (only !== undefined && (filename === null || basename(filename) !== only)) {\n return;\n }\n schedule();\n });\n\n try {\n watcher = listen(recursive);\n } catch (error) {\n if (!recursive) {\n options.onError?.(error);\n return;\n }\n try {\n watcher = listen(false);\n } catch (fallbackError) {\n options.onError?.(fallbackError);\n return;\n }\n }\n watcher.on(\"error\", (error) => {\n if (!closed) {\n options.onError?.(error);\n }\n });\n watchers.add(watcher);\n }\n\n addWatcher(project.penvDir, true);\n addWatcher(dirname(project.configFile), false, configFile);\n\n // The schema declares what must exist, so an edit to it changes the answer. A\n // schema inside the tree already has a watcher; one outside would have none,\n // and a watch that keeps reporting a verdict it can no longer see the reason\n // for is the silence this command exists to prevent.\n if (schemaInsideTree(project.config) === undefined) {\n const schemaFile = resolve(project.root, schemaFileOf(project.config));\n addWatcher(dirname(schemaFile), false, basename(schemaFile));\n }\n\n // The current answer, before anything changes: a watch that says nothing until\n // the next keystroke leaves the user guessing at the state they already have.\n void validate();\n\n return {\n close(): void {\n closed = true;\n if (timer !== undefined) {\n clearTimeout(timer);\n timer = undefined;\n }\n for (const watcher of [...watchers]) {\n stop(watcher);\n }\n },\n };\n}\n\n/**\n * One cycle's report: `penv validate`'s, with a rule above it — on a loop, the\n * reader's first question is where the last run ended — and the drift below it.\n *\n * Drift comes last because it is the part that is not a verdict. The rows above\n * say whether the configuration is valid; these say what the schema and the tree\n * disagree about, which is often *why*, and is worth reading even on a run that\n * passed.\n */\nexport function renderWatch(result: ValidateResult): string[] {\n return [\"\", ...renderValidate(result), ...renderDrift(result.drift, result.environment)];\n}\n\n/**\n * The drift rows. Nothing at all when the schema and the tree agree: a loop\n * reprints its whole report on every keystroke, and a block that says \"no drift\"\n * forever is the first thing the eye learns to skip past — taking the block that\n * matters with it.\n */\nexport function renderDrift(drift: DriftReport, environment: string): string[] {\n const rows: Row[] = [\n ...drift.declared.map((item) => ({\n glyph: WARN,\n label: \"Declared, no value\",\n subject: item.subject,\n detail: item.detail,\n })),\n ...drift.undeclared.map((item) => ({\n glyph: WARN,\n label: \"Unused parameter\",\n subject: item.variable,\n detail: \"present, not in schema\",\n })),\n ];\n if (rows.length === 0) {\n return [];\n }\n\n const lines = [\"\", `Schema and tree differ for ${environment}:`, ...formatRows(rows)];\n // The paste block, exactly as `doctor` prints it — the reader who sees drift\n // here and drift there is looking at one report, not two that resemble each other.\n for (const remedy of new Set(drift.declared.map((item) => item.remedy))) {\n lines.push(` ${remedy}`);\n }\n return lines;\n}\n\nexport const watchCommand = defineCommand({\n meta: {\n name: \"watch\",\n description: \"Re-validate whenever .penv/ or penv.config.ts changes\",\n },\n args: {\n env: { type: \"string\", description: \"The environment to validate\" },\n },\n run({ args }) {\n return guard(async () => {\n const handle = runWatch({\n cwd: process.cwd(),\n ...(args.env === undefined ? {} : { environment: args.env }),\n onResult: (result) => {\n write(renderWatch(result));\n },\n // A failing cycle is reported and watching continues. `reportError`\n // marks the process failed, which `validate` wants and a loop does not:\n // a cycle that failed mid-save ten minutes ago must not decide the exit\n // code of a session the user ended deliberately. The message is what is\n // wanted here, not the verdict.\n onError: (error) => {\n const previous = process.exitCode;\n reportError(error);\n process.exitCode = previous;\n },\n });\n write([\"Watching .penv/ and penv.config.ts. Ctrl-C to stop.\"]);\n await new Promise<void>((resolve) => {\n process.once(\"SIGINT\", () => {\n handle.close();\n resolve();\n });\n });\n });\n },\n});\n"],"mappings":"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","names":["import_core","import_citty","import_core","import_sink_github","import_citty","import_node_path","import_core","import_provider_filesystem","require","cached","import_core","import_core","import_core","result","import_node_path","import_node_url","import_core","import_citty","result","resolvePath","import_core","import_citty","import_core","import_citty","result","result","import_core","import_citty","skipped","result","import_node_path","import_core","import_citty","result","import_core","import_citty","import_node_fs","import_node_path","import_core","import_citty","import_node_fs","import_node_path","import_core","relative","import_node_fs","import_node_path","import_promises","import_core","import_citty","PENV_DIR","plan","relative","result","displayPath","result","import_core","import_citty","import_node_module","require","result","import_core","import_citty","scopeLabel","result","import_core","import_citty","environmentOf","occupied","result","import_citty","result","import_core","import_citty","result","import_core","import_citty","after","result","import_node_fs","import_node_path","import_core","import_citty","result","resolve","cittyRunMain"]}